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

الوحدة 5 — سجلّ النماذج ومراحل الترقية

في الوحدة 3 سجّلنا كلّ تشغيل تدريب في MLflow، وفي الوحدة 4 ربطنا النموذج بشفرته وبياناته. الآن نحتاج جوابًا على سؤال جديد: من بين خمسين تجربة، أيّها النموذج الحاليّ في الإنتاج؟ ومن قرّر ذلك، ومتى؟ هذا ما يوفّره سجلّ النماذج.

من التجربة إلى النموذج المُسجَّل

كلّ تشغيل MLflow يحفظ نموذجًا في مخرجاته، لكنّ هذا النموذج «مجهول» بالنسبة للتشغيلات الأخرى. سجلّ النماذج يُقدّم فكرتين إضافيتين:

  • نموذج مُسمّى (Registered Model): وحدة منطقية تحمل اسمًا ثابتًا مثل churn-classifier. يمكن أن تحتوي على عدّة إصدارات (Versions).
  • إصدار (Version): نموذج ملموس، له رقم متزايد (1، 2، 3…)، ومصدره تشغيل معلوم في تجربة معلومة.

من الشفرة:

import mlflow

run_id = "abcdef1234"
mlflow.register_model(
model_uri=f"runs:/{run_id}/model",
name="churn-classifier",
)

بعد هذا الأمر، السجلّ يحتوي على churn-classifier بإصدار جديد. الإصدارات مُتراكِمة أبدًا: لا نحذف الإصدار 5 لأنّ الإصدار 6 يعمل، بل نُبقيه كي يبقى الرجوع إليه ممكنًا.

الأسماء البديلة والمراحل

هنا يدخل مفهوم الأسماء البديلة (aliases). بدلًا من قول «الإصدار 12 في الإنتاج»، نُعرِّف اسمًا بديلًا @production نُشير به إلى الإصدار الحاليّ:

client = mlflow.tracking.MlflowClient()
client.set_registered_model_alias(
name="churn-classifier",
alias="production",
version=12,
)

الشفرة في الإنتاج تُحمّل دائمًا models:/churn-classifier@production، ولا تعرف رقم الإصدار. عند الترقية، نُغيّر مقصد الاسم البديل، والشفرة تلتقط الجديد بلا تعديل.

الأسماء البديلة الاعتيادية:

  • @candidate: إصدار جديد يخضع للاختبار
  • @staging: نُصلي عليه اختبار قبل الإنتاج (بيئة مماثلة)
  • @production: يخدم الطلبات الفعلية
  • @shadow: يُحسب توقّعه بالتوازي مع الإنتاج للمقارنة، دون تسليمه للعميل

هذه أفضل من نظام «Stages» القديم في MLflow (Staging، Production…) الذي كان يفرض تنظيمًا صارمًا؛ الأسماء البديلة أكثر مرونة وقادرة على تمثيل أكثر من بيئة واحدة في الإنتاج.

المصادقة قبل الترقية

هذه هي النقطة الحرجة. لا يجب أبدًا أن يستطيع إصدار الوصول إلى @production دون مرور بمصادقة صريحة. لماذا؟ لأنّ نموذجًا سيّئًا في الإنتاج يخسر مالًا حقيقيًّا، وأحيانًا يُعرّض المستخدمين لضرر (توصية طبّية خاطئة، رفض قرض غير مبرَّر…).

المصادقة تُنجَز بواسطة خطّ CI/CD (الوحدة 7)، وتشمل عادةً:

  1. اختبارات على النموذج نفسه: هل يتجاوز AUC معيارًا أدنى؟ هل الأداء على المجموعات الفرعية (نساء/رجال، شباب/كبار) مقبول؟ هل زمن التنبّؤ تحت 100 ميلي ثانية؟
  2. اختبار في بيئة مماثلة (@staging): يُنشَر لبضع ساعات على منسوخ من بيانات الإنتاج، ونتحقّق من الأداء الفعلي.
  3. موافقة إنسانية: على الأقلّ بضغطة زرّ من مسؤول تقني. الأتمتة الكاملة إلى الإنتاج بدون إنسان في الحلقة خطرة للنماذج ذات الأثر المهم.

الترقية الآلية دون مصادقة (if val_auc > 0.85: promote()) خطأ كلاسيكي يستحقّ اسمه: الترقية العمياء. AUC ممتاز على المصادقة قد يخفي تدهورًا حادًّا على مجموعة أقلّية، أو مقياسًا آخر ذا أهمّية أعمال.

التراجع إلى نسخة سابقة

عندما يظهر خلل في الإنتاج، أوّل ردّ فعل يجب أن يكون العودة إلى النسخة السابقة، لا التحقيق. لأنّ التحقيق يستغرق ساعات، والخلل يخسر مالًا كلّ دقيقة.

مع الأسماء البديلة، التراجع فوري:

client.set_registered_model_alias(
name="churn-classifier",
alias="production",
version=11, # الإصدار السابق
)

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

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

البيانات الوصفية الإلزامية

كلّ إصدار مُسجَّل يجب أن يحمل بيانات وصفية تُجيب على أسئلة الحوكمة:

  • من دَرَّب هذا النموذج؟ (اسم عالِمة البيانات، فريقها)
  • متى تدرَّب؟ (تاريخ)
  • على ماذا تدرَّب؟ (نسخة البيانات، مصدرها)
  • ما هي مقاييس أدائه الرئيسية؟ (AUC، مقاييس عدل، زمن الاستدلال)
  • ما هي حدوده المعروفة؟ (لا يعمل على مشتركين تحت 3 أشهر، مثلًا)

في MLflow نُنجز ذلك بـset_model_version_tag(). في مشاريع أكبر تظهر مواصفة Model Card (بطاقة النموذج) التي اقترحتها Google، وهي مستند منظّم يجمع كلّ هذه المعلومات ويُتاح مع النموذج للامتثال.

قاعدة الاثنين

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

في الخلاصة

  • سجلّ النماذج يُميّز بين النموذج المُسمّى (وحدة منطقية) والإصدار (نموذج ملموس مرقّم)؛ الإصدارات لا تُحذف أبدًا.
  • الأسماء البديلة (@production، @staging) تفصل الشفرة عن رقم الإصدار، وتجعل الترقية والتراجع مسألة إعادة توجيه.
  • الترقية إلى الإنتاج دون مصادقة صريحة (اختبارات + بيئة مماثلة + موافقة إنسانية) خطأ يُعرَف باسم «الترقية العمياء».
  • التراجع يجب أن يكون أمرًا واحدًا موثَّقًا وقابلًا للتنفيذ في دقائق؛ التحقيق يأتي بعد استعادة الخدمة.