يا جماعة الخير، السلام عليكم.
خلوني أحكيلكم قصة صارت معي قبل كم سنة. كنا شغالين على نظام ذكاء اصطناعي لواحد من العملاء الكبار، نظام بتنبأ باحتمالية تخلّف العملاء عن سداد القروض. الفريق كان شغال ليل نهار، جمعنا الداتا، نظفناها، وعملنا هندسة خصائص (feature engineering) زي ما بحكي الكتاب. بنينا نموذج XGBoost وصلت دقته لـ 94% على بيانات الاختبار. إشي برفع الراس، والكل كان مبسوط، من أصغر واحد بالفريق للمدير الكبير.
أجا يوم العرض التقديمي للعميل. جبنا حالات حقيقية من عندهم (بدون الكشف عن هويتها طبعاً) عشان نورجيهم قوة النموذج. أول حالة، ثاني حالة، ثالث حالة… كله تمام والنموذج بتنبأ صح. فجأة، واحد من مدراء البنك أعطانا حالة لعميل “ذهبي”، تاريخه الائتماني بلمع لمعان، ولا عمره اتأخر دفعة. حطينا بياناته في النظام… والنتيجة؟ “احتمالية عالية للتخلف عن السداد”.
صمت رهيب عمّ القاعة. الكل بطلع فيي. مدير البنك سأل سؤال بسيط ومباشر: “ليش؟ على أي أساس نموذجكم بحكي هيك؟”.
والله يا جماعة، المنظر كان محرج. كلنا بنطلع ببعض ومش عارفين شو نجاوب. الجواب التقني “لأنه هيك معادلات الـ Gradient Boosting بتشتغل” مش رح يقنع حدا. نموذجنا، اللي صرفنا عليه شهور، صار فجأة صندوق أسود ما حدا فاهم شو جواته. هاي اللحظة كانت نقطة تحول بالنسبة إلي، وخلتني أبحث بجنون عن حل لمشكلة “جحيم لا أعرف لماذا”. وهون بدأت رحلتي مع عالم الذكاء الاصطناعي القابل للتفسير (XAI).
ما هو “الصندوق الأسود” ولماذا هو مشكلة؟
كثير من نماذج تعلم الآلة القوية، مثل الشبكات العصبية العميقة أو نماذج التعلّم المعزز (Ensemble methods) مثل XGBoost و Random Forest، هي بطبيعتها “صناديق سوداء” (Black Boxes).
ببساطة، إنت بتعطيها مدخلات (بيانات)، وهي بتعطيك مخرجات (تنبؤات). لكن الآلية الداخلية اللي بتوصل فيها من المدخلات للمخرجات بتكون معقدة جداً لدرجة إنه من شبه المستحيل على البشر فهمها بشكل مباشر. طيب وين المشكلة؟
- فقدان الثقة: كيف ممكن أثق بقرار (خاصة لو كان قرار مصيري مثل تشخيص طبي أو قرار ائتماني) إذا ما كنت بعرف “ليش” تم اتخاذه؟
- صعوبة التصحيح (Debugging): لما النموذج يغلط، كيف بدك تعرف وين الغلط وصلحته إذا ما كنت فاهم منطقه؟
- العدالة والتحيز (Fairness & Bias): ممكن النموذج يكون تعلم تحيزات موجودة في البيانات (مثل التحيز ضد عرق أو جنس معين) ويقوم باتخاذ قرارات ظالمة بدون ما نعرف.
- المتطلبات التنظيمية: في قطاعات كثيرة مثل البنوك والصحة، صار في قوانين (مثل GDPR في أوروبا) بتعطي المستخدم الحق في معرفة تفسير القرارات الآلية اللي بتأثر عليه.
من هون، ظهرت الحاجة الماسة لأدوات تفتح هالصندوق الأسود وتضوي الضو جواته. وهون بيجي دور أبطال قصتنا: LIME و SHAP.
LIME: إضاءة شمعة في الظلام
LIME هو اختصار لـ Local Interpretable Model-agnostic Explanations. من اسمه بنقدر نفهم ثلاث شغلات رئيسية:
- Local (محلي): LIME ما بحاول يفسر النموذج كله مرة وحدة، لأنه هاد شبه مستحيل. بدلاً من ذلك، هو بركز على تفسير قرار واحد فقط في كل مرة.
- Model-agnostic (غير معتمد على نموذج معين): أحلى إشي في LIME إنه بشتغل مع أي نموذج تعلم آلة، سواء كان شبكة عصبية، Random Forest, SVM… شو ما كان. ما بهمه شو في جوا الصندوق الأسود.
- Interpretable (قابل للتفسير): بقدملك تفسير بسيط ومفهوم.
كيف بشتغل LIME؟ (الخلاصة المفيدة)
تخيل إنك بدك تفسر ليش النموذج تبعنا قرر إنه العميل “الذهبي” رح يتخلف عن السداد. LIME بعمل إشي ذكي جداً:
- بياخد بيانات العميل الأصلي.
- بقوم بعمل “تشويش” بسيط على هاي البيانات. يعني بغير شوي في قيمة القرض، شوي في الدخل الشهري، شوي في عدد سنوات الخبرة… وهكذا. وبهيك، هو بخلق آلاف العينات الجديدة “الشبيهة” بالعميل الأصلي.
- بمرر كل هاي العينات الجديدة على نموذجك الأسود وبشوف شو تنبؤاته.
- الآن صار عنده مجموعة بيانات جديدة (البيانات المشوشة مع تنبؤات النموذج الأسود). بيستخدم هاي البيانات عشان يبني نموذج “بسيط” و “شفاف” (مثل نموذج الانحدار الخطي Linear Regression) فوقها، وهاد النموذج البسيط بقدر يفسر سلوك النموذج المعقد في المنطقة المحيطة بالعميل الأصلي فقط.
نصيحة من أبو عمر: فكر في LIME كأنه “تقريب خطي محلي”. مثل ما في حساب التفاضل والتكامل بنقرّب منحنى معقد بخط مستقيم عند نقطة معينة، LIME بقرّب نموذجك المعقد بنموذج بسيط عند تنبؤ معين.
مثال عملي مع الكود
لنفترض عنا نموذج Random Forest بتنبأ بجودة النبيذ بناءً على خصائصه الكيميائية. بدنا نفسر ليش النموذج أعطى تقييم معين لعينة نبيذ محددة.
# افترض أن 'rf_model' هو نموذجنا المدرب
# و 'X_train' هي بيانات التدريب
# و 'sample_to_explain' هي العينة التي نريد تفسيرها
import lime
import lime.lime_tabular
# 1. إنشاء أداة التفسير
explainer = lime.lime_tabular.LimeTabularExplainer(
training_data=X_train.values,
feature_names=X_train.columns,
class_names=['bad', 'good'],
mode='classification'
)
# 2. توليد التفسير لعينة واحدة
explanation = explainer.explain_instance(
data_row=sample_to_explain,
predict_fn=rf_model.predict_proba
)
# 3. عرض التفسير (عادة يتم عرضه كصورة)
explanation.show_in_notebook(show_table=True)
# أو حفظه كملف HTML
# explanation.save_to_file('explanation.html')
النتيجة رح تكون رسم بياني بسيط بورجيك أهم الخصائص اللي أثرت على القرار. مثلاً، رح يورجيك إنه “نسبة الكحول” دفعت التنبؤ باتجاه “جيد” (باللون الأخضر)، بينما “نسبة الحموضة” دفعت التنبؤ باتجاه “سيء” (باللون الأحمر).
SHAP: توزيع الغنائم بالعدل
إذا كان LIME هو الحل السريع والسهل للتفسيرات المحلية، فـ SHAP هو الحل الأكثر عمقاً وقوة. SHAP هو اختصار لـ SHapley Additive exPlanations.
الفكرة الأساسية لـ SHAP مستوحاة من “نظرية الألعاب” (Game Theory) وتحديداً “قيم شابلي” (Shapley Values) اللي تم تطويرها في الخمسينات. الفكرة هي كيفية توزيع “المكافأة” أو “الغنيمة” بشكل عادل بين مجموعة من اللاعبين اللي ساهموا في تحقيقها.
في عالمنا، “اللعبة” هي التنبؤ، “اللاعبون” هم الخصائص (features) تبعونك، و”المكافأة” هي الفرق بين تنبؤ النموذج والتنبؤ الأساسي (المتوسط).
كيف بتفرق SHAP عن LIME؟
SHAP بتفوق على LIME في نقطتين أساسيتين:
- التفسيرات العالمية (Global Explanations): بالإضافة للتفسيرات المحلية (زي LIME)، SHAP بعطيك فهم شامل لكل الخصائص وتأثيرها على النموذج ككل. بتقدر تعرف شو هي أهم الخصائص بشكل عام، وكيف بتأثر على التنبؤات.
- الاتساق النظري (Theoretical Consistency): SHAP مبني على أساس رياضي صلب من نظرية الألعاب، وهذا بضمن إنه تفسيراته متسقة ومنطقية. LIME أحياناً ممكن يكون غير مستقر لأنه بيعتمد على التشويش العشوائي للبيانات.
نصيحة من أبو عمر: لا تفكر فيهم كأعداء، بل كأدوات مختلفة في صندوق العدة. LIME زي المفك السريع اللي بتستخدمه لشغلة بسيطة. SHAP زي طقم المفات الكامل اللي بتستخدمه لما بدك تفكك المحرك كله وتفهم كل قطعة فيه.
مثال عملي مع الكود
لنكمل مع نفس مثال النبيذ. الآن سنستخدم SHAP.
import shap
# 1. إنشاء أداة التفسير الخاصة بـ SHAP (أفضل استخدام TreeExplainer للنماذج الشجرية)
explainer = shap.TreeExplainer(rf_model)
# 2. حساب قيم SHAP لكل البيانات (هذا هو الجزء الذي يستغرق وقتاً)
shap_values = explainer.shap_values(X_test)
# --- الآن يبدأ السحر: أنواع المخططات المختلفة ---
# 3. تفسير تنبؤ واحد (مثل LIME) باستخدام Force Plot
shap.initjs() # لتهيئة العرض في المتصفح
shap.force_plot(explainer.expected_value[1], shap_values[1][0,:], X_test.iloc[0,:])
# 4. الحصول على نظرة عامة لأهمية الخصائص (Global)
shap.summary_plot(shap_values[1], X_test)
# 5. تحليل تأثير خاصية واحدة بشكل مفصل
shap.dependence_plot("alcohol", shap_values[1], X_test)
مع SHAP، أنت لا تحصل على تفسير واحد، بل ترسانة كاملة:
- Force Plot: يوضح لك كيف دفعت كل خاصية التنبؤ بعيداً عن القيمة الأساسية، إما إيجاباً أو سلباً. شبيه جداً بنتيجة LIME ولكنه أكثر دقة.
- Summary Plot (Beeswarm): هذا هو أقوى مخطط في SHAP. يجمع كل التنبؤات معاً ويظهر لك لكل خاصية:
- أهميتها: الخصائص في الأعلى هي الأهم.
- تأثيرها: النقاط على اليمين تزيد من قيمة التنبؤ، وعلى اليسار تقللها.
- علاقتها بالقيم: لون النقطة يخبرك ما إذا كانت قيمة الخاصية عالية (أحمر) أم منخفضة (أزرق).
من هذا المخطط، يمكنك استنتاج قواعد مثل “بشكل عام، كلما زادت نسبة الكحول، زاد تقييم النبيذ”.
- Dependence Plot: يركز على خاصية واحدة ويظهر كيف يتغير تأثيرها على التنبؤ مع تغير قيمتها.
الخلاصة: من الظلام إلى النور 💡
العودة إلى قصتي مع العميل. بعد تلك الحادثة المحرجة، أصبح استخدام أدوات مثل LIME و SHAP جزءاً لا يتجزأ من أي مشروع تعلم آلة نقوم به. لم نعد نقدم نموذجاً ونقول “هذه هي دقته”. بل أصبحنا نقول “هذه هي دقته، وهذه هي الطريقة التي يفكر بها، وهذه هي الخصائص التي يعتمد عليها”.
هذا التحول لم يجعل نماذجنا أفضل فحسب، بل بنى جسراً من الثقة مع عملائنا. أصبحوا شركاء في فهم النموذج وتحسينه، بدلاً من أن يكونوا مجرد متلقين لقراراته الغامضة.
نصيحتي الأخيرة لك: لا تجعل “الدقة” (Accuracy) هي مقياسك الوحيد للنجاح. النموذج الذي لا تستطيع تفسيره هو نموذج لا تستطيع الوثوق به بالكامل، ولا تستطيع تطويره بفعالية. استثمر وقتاً في تعلم وتطبيق أدوات الـ XAI. إنها الفاصل بين بناء نموذج “يعمل” وبناء نموذج “موثوق، عادل، ومفهوم”.
يلا شدوا حيلكم، وخلي شغلكم دايماً منوّر! 💪