انتقل إلى المحتوى الرئيسي

الوحدة 3 — تتبّع التجارب مع MLflow

في الوحدة السابقة ثبّتنا البيئة والبذور، فأصبحنا قادرين على إعادة إنتاج نموذج بعينه. لكن في مرحلة التطوير، عالِمة البيانات لا تُدرّب نموذجًا واحدًا: بل تُجرّب عشرين أو خمسين. من دون تتبّع منهجي، تتحوّل هذه التجارب إلى فوضى غير قابلة للاسترجاع. ذلك ما تحلّه MLflow.

ما يُسجَّل تلقائيًا في تجربة

فكرة MLflow بسيطة: كلّ تشغيل تدريب (Run) يحفظ ثلاثة أنواع من المعلومات في مكان واحد يُسمّى Experiment:

  • المعلمات (parameters): كلّ ما اخترناه قبل التدريب (learning_rate، n_estimators، اسم الخوارزمية).
  • المقاييس (metrics): كلّ ما قِسناه بعد التدريب (train_auc، val_auc، training_time_seconds).
  • المخرجات (artifacts): كلّ ملفّ نُنتجه (النموذج نفسه، مصفوفة الالتباس كصورة، تقرير التصنيف كنصّ).

في مثال التسرّب لدينا، تشغيل تدريب واحد يُسجَّل هكذا:

import mlflow
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score

mlflow.set_experiment("churn-baseline")

with mlflow.start_run(run_name="rf-200-arbres"):
mlflow.log_param("n_estimators", 200)
mlflow.log_param("max_depth", 12)
mlflow.log_param("random_state", 42)

model = RandomForestClassifier(n_estimators=200, max_depth=12, random_state=42)
model.fit(X_train, y_train)

val_auc = roc_auc_score(y_val, model.predict_proba(X_val)[:, 1])
mlflow.log_metric("val_auc", val_auc)

mlflow.sklearn.log_model(model, artifact_path="model")

بعد التنفيذ، كلّ شيء موجود: المعلمات الثلاث، المقياس، والنموذج نفسه محفوظًا بصيغة يمكن تحميلها لاحقًا. لا شيء يُنسى، ولا شيء يُكتَب على القرص بدون أن يُربط بتشغيل معلوم.

مقارنة التشغيلات

MLflow تُتيح واجهة ويب بأمر واحد: mlflow ui. فتَظهر جميع التشغيلات في جدول واحد، ونستطيع فرزها حسب أيّ مقياس، أو تحديد اثنين للمقارنة الجانبية. هذا يُغيّر تجربة العمل: بدلًا من فتح ثلاثة دفاتر ومحاولة تذكّر أيّ منها يستعمل أي معلمة، نفتح صفحة واحدة تعرض الفرق.

نقطة عملية مهمّة: اسم التجربة يجب أن يعكس هدفًا، لا خوارزمية. تسمية جيّدة: churn-baseline، churn-avec-metrique-lifetime، churn-desequilibre. تسمية سيّئة: test1، random-forest-2، essais-lundi. فبعد شهرين، الاسم هو ما يسمح بالعثور على التجربة، لا محتواها.

التسجيل التلقائي: مصيدة تُبدو نعمة

MLflow تُقدّم mlflow.sklearn.autolog() (ونظائرها لـPyTorch وXGBoost) الذي يُسجّل تلقائيًا كلّ المعلمات والمقاييس دون كتابة log_param يدويًا. مغرٍ جدًا لتقليل الشفرة النموذجية.

الاستعمال الصحيح: نشغّله للتجارب الاستكشافية، ونُغلقه للتجارب التي تُرَشَّح للإنتاج. لماذا؟ لأنّه يُسجّل كلّ شيء، بما فيه معلمات لا نضبطها ولا تعنينا، ويُخفي المعلمات المهمّة بين مئة معلمة تافهة. كما أنّه لا يُسجّل الأشياء الخاصّة بنا (المقاييس المشتقّة، والنصوص التوضيحية).

القاعدة: صراحة أفضل من تلقائية، خصوصًا للتجارب التي ستُقارَن ستّة أشهر بعد إجرائها.

الخادم المشترك للفريق

في التطوير الفردي، MLflow يعمل محلّيًا ويحفظ في مجلّد mlruns/. لكن حين يعمل عدّة أشخاص على نفس المشروع، هذا لا يعمل: تجارب زميلة على حاسوبها ليست مرئية لك، وربطُ تجربة بالتزام Git يفقد معناه.

الحلّ: خادم MLflow مركزي. تُشغَّل خدمة mlflow server على خادم مشترك، مع قاعدة بيانات (PostgreSQL) لتخزين البيانات الوصفية، وتخزين موضوعي (S3 مثلًا) لتخزين المخرجات. كلّ عضو من الفريق يُوجّه شفرته إلى نفس الخادم:

mlflow.set_tracking_uri("http://mlflow.equipe-ia.internal:5000")

منذ هذه اللحظة، كلّ تشغيل مرئي للجميع، ومقارن، ومسترجَع. هذا شرط الحدّ الأدنى قبل التفكير في سجلّ نماذج (الوحدة القادمة) أو خطّ CI/CD (الوحدة 7).

علامات Git: الربط بالشفرة

MLflow يُسجّل تلقائيًا mlflow.source.git.commit إذا شغّلنا داخل مستودع Git، وهو الالتزام الحالي. ننصح بتشغيل تدريبنا دائمًا على شجرة عمل نظيفة (git status خالٍ)، وإلّا فإنّ الالتزام المُسجَّل لا يعكس الشفرة الفعلية المستعملة. من دون هذه القاعدة، تجربة بأداء ممتاز قد لا تكون قابلة للاسترجاع لأنّ الشفرة التي أنتجتها لم تُلتَزَم أبدًا.

حقل «الملاحظات» ليس زخرفة

MLflow يوفّر حقل mlflow.set_tag("notes", "...") لكلّ تشغيل. اعتد كتابة سطر أو سطرين: «جرّبتُ تسوية L2 = 0,01، الأداء أسوأ من 0,001، والسبب أظنّه إشباع النموذج». هذه الملاحظة هي التي ستجعل التجربة قابلة للفهم بعد ثلاثة أشهر، لا الجدول الرقمي.

في الخلاصة

  • كلّ تشغيل تدريب يجب أن يُسجَّل بمعلماته ومقاييسه ومخرجاته في تجربة MLflow ذات اسم دلاليّ.
  • المقارنة عبر واجهة MLflow تُلغي حاجة تذكّر أيّ دفتر يحوي أيّ نموذج؛ وهذا مصدر رئيسي للأخطاء الصامتة.
  • التسجيل التلقائي مفيد للاستكشاف، ولكن يُغلق للتجارب المُرَشَّحة للإنتاج لصالح تسجيل صريح ومُختار.
  • الخادم المشترك (PostgreSQL + تخزين موضوعي) شرطٌ لعمل جماعي؛ وربط كلّ تشغيل بالتزام Git يجعل الاسترجاع ممكنًا فعلًا.