يا حبايب، السلام عليكم ورحمة الله وبركاته. معكم أخوكم أبو عمر.
خلوني أحكي لكم قصة صارت معي قبل كم سنة، أيام ما كنا لسا بنتحسس طريقنا في عالم الشركات الناشئة والذكاء الاصطناعي. كنا في فريق صغير، متحمسين وشغفنا يوصل للسما. مشروعنا كان بناء نموذج ذكاء اصطناعي يقدر يميز الأكلات الفلسطينية التقليدية من الصور. والله يا عمي، بعد أسابيع من جمع البيانات وتدريب النموذج، صارت النتيجة خرافية! النموذج صار يميز الكنافة النابلسية من بعيد، ويعرف المسخن من ريحته (مجازًا طبعًا)، ويفرق بين المقلوبة والمفتول بدقة 95%.
الفرحة كانت عارمة، والمستثمر انبسط، والعملاء المحتملون صاروا يجهزوا حالهم. لكن، زي ما بحكوها، “فرحتنا ما تمت”. بعد فترة، طلب منا العميل إضافة ميزة جديدة: تمييز أنواع جديدة من الأكلات العالمية، مثل البيتزا والسوشي والبرجر، عشان يتوسع في السوق. قلنا “بسيطة”، شو المشكلة؟
أخذنا البيانات الجديدة، ودربنا نموذجنا عليها… وهون كانت الكارثة. النموذج الجديد صار يعرف البيتزا والسوشي بشكل ممتاز، لكنه “نسي” أصله! صار يشوف صورة الكنافة ويحكي عنها “بيتزا بالجبنة شكلها غريب”، والمسخن صار عنده “دجاج مشوي مش مفهوم”. ببساطة، النموذج فقد كل المعرفة اللي تعبنا عليها شهور. حسيته زي اللي تعلم لغة جديدة ونسي لغة أمه. كانت لحظة إحباط كبيرة، وصرنا نسأل حالنا: “شو هالحكي؟ معقول كل مرة بدنا نضيف شغلة جديدة لازم نعيد كل الشغل من الصفر ونجمع كل البيانات القديمة والجديدة؟”.
هذه الحادثة كانت مدخلي الشخصي المؤلم والمكلف لعالم مشكلة اسمها “النسيان الكارثي”، والحل اللي غيّر طريقة تفكيرنا بالكامل: “التعلم المستمر”.
ما هو ‘النسيان الكارثي’ (Catastrophic Forgetting)؟
القصة اللي حكيتها هي تجسيد حي لمشكلة أساسية في الشبكات العصبية التقليدية. النسيان الكارثي هو ميل النموذج لفقدان المعرفة التي اكتسبها سابقًا عند تدريبه على مهمة جديدة.
عشان نبسطها، تخيل إن ذاكرة النموذج عبارة عن مجموعة من الأوزان (weights) في الشبكة العصبية. لما ندرب النموذج على مهمة (أ)، مثل تمييز الأكل الفلسطيني، هذه الأوزان تتปรับ (adjust) بطريقة معينة لتخزين هذه المعرفة. لما نيجي ندرب نفس النموذج على مهمة (ب) جديدة، مثل تمييز الأكل العالمي، عملية التدريب بتعدل نفس الأوزان عشان تتناسب مع المهمة الجديدة، وفي هذه العملية، “تمسح” أو “تخرب” التعديلات اللي كانت خاصة بالمهمة (أ). النتيجة؟ النموذج يتقن المهمة (ب) وينسى المهمة (أ) تمامًا.
“النسيان الكارثي يجعل نماذجنا كالأوعية التي لا يمكن ملؤها إلا بإفراغها أولًا، وهذا ضد فكرة الذكاء الحقيقي الذي يبني على المعرفة لا يمحوها.”
جحيم إعادة التدريب من الصفر (The Hell of Retraining from Scratch)
الحل البديهي اللي فكرنا فيه وقتها، واللي كثير شركات بتعمله، هو إعادة تدريب النموذج من الصفر في كل مرة. يعني، نجمع بيانات المهمة (أ) وبيانات المهمة (ب) في مجموعة بيانات ضخمة واحدة، وندرب النموذج عليها من جديد. هذا الحل، رغم أنه ينجح تقنيًا، إلا أنه كارثي من نواحٍ أخرى:
1. التكلفة والموارد (Cost and Resources)
تدريب النماذج الكبيرة يحتاج لقوة حاسوبية هائلة (GPUs)، وهذا يعني تكلفة كهرباء وتكلفة استئجار سحابة (cloud) بالآلاف، وربما مئات الآلاف من الدولارات. إعادة التدريب في كل مرة يعني حرق الأموال بشكل مستمر.
2. الوقت (Time)
تدريب نموذج من الصفر قد يستغرق أيامًا أو أسابيع. هل يمكن لمنتجك أن يتحمل التوقف عن التطور لهذه الفترة في كل مرة تريد إضافة ميزة جديدة؟ بالطبع لا.
3. تعقيد إدارة البيانات (Data Management Complexity)
مع كل مهمة جديدة، ستحتاج إلى الاحتفاظ بجميع البيانات السابقة. بعد فترة، ستجد نفسك تدير قواعد بيانات ضخمة ومعقدة، وهذا يفتح بابًا لمشاكل MLOps تتعلق بتخزين البيانات، والتحكم في إصداراتها، وضمان جودتها.
هنا أدركنا أننا بحاجة إلى طريقة أفضل. طريقة تسمح لنماذجنا بالتطور والتعلم المستمر، تمامًا مثل البشر.
الحل السحري: ‘التعلم المستمر’ (Continual Learning)
التعلم المستمر (Continual Learning أو Lifelong Learning) هو فرع من فروع تعلم الآلة يهدف إلى تطوير نماذج قادرة على تعلم المهام الجديدة بشكل متسلسل (sequentially) دون أن تنسى المهام التي تعلمتها سابقًا. الهدف هو محاكاة قدرة الإنسان على اكتساب المعرفة وتراكمها على مدار حياته.
هناك ثلاث عائلات رئيسية من الاستراتيجيات لتحقيق التعلم المستمر، وكل واحدة منها لها فلسفتها الخاصة.
الاستراتيجية الأولى: استراتيجيات إعادة التشغيل (Replay-based Methods)
هذه هي الفكرة الأبسط والأكثر بديهية. بدلًا من الاحتفاظ بكل البيانات القديمة، ماذا لو احتفظنا بعينة صغيرة وممثلة منها فقط؟
الفكرة: عند تدريب النموذج على المهمة الجديدة (ب)، نقوم بخلط البيانات الجديدة مع عينة صغيرة من بيانات المهمة القديمة (أ). هذه العينة الصغيرة تعمل بمثابة “مراجعة” أو “تذكير” للنموذج بمعرفته السابقة.
مثال عملي: في قصة نموذج الطعام، بدلًا من حذف كل صور الكنافة والمسخن، كنا سنحتفظ بـ 50 صورة من كل صنف (بدلًا من الآلاف) ونخلطها مع صور البيتزا والسوشي أثناء التدريب. هذا يجبر النموذج على إيجاد أوزان تعمل بشكل جيد مع القديم والجديد معًا.
مثال كود (مفهومي):
# buffer_size: حجم العينة التي سنحتفظ بها من كل مهمة قديمة
buffer = ReplayBuffer(buffer_size=100)
# تدريب على المهمة الأولى (Task 1: الأكل الفلسطيني)
for data, label in task1_loader:
# ... عملية التدريب العادية ...
model.train(data, label)
# إضافة عينات لذاكرة المراجعة
buffer.add_samples(data, label)
# تدريب على المهمة الثانية (Task 2: الأكل العالمي)
for new_data, new_label in task2_loader:
# سحب عينة من الذاكرة القديمة
old_data, old_label = buffer.get_random_samples(batch_size=32)
# دمج البيانات القديمة والجديدة في دفعة تدريب واحدة
combined_data = concat(new_data, old_data)
combined_label = concat(new_label, old_label)
# تدريب النموذج على الدفعة المدمجة
model.train(combined_data, combined_label)
الاستراتيجية الثانية: استراتيجيات التنظيم (Regularization-based Methods)
هذه الفكرة أكثر ذكاءً من الناحية الرياضية. بدلًا من مراجعة البيانات القديمة، ماذا لو قمنا بـ “حماية” الأجزاء المهمة من ذاكرة النموذج؟
الفكرة: عند تدريب النموذج على المهمة الجديدة، نضيف “عقوبة” (penalty term) إلى دالة الخسارة (loss function). هذه العقوبة تمنع النموذج من تغيير الأوزان التي كانت مهمة جدًا للمهام السابقة. أشهر خوارزمية هنا هي Elastic Weight Consolidation (EWC).
كيف تعمل EWC؟ بعد التدريب على المهمة (أ)، تحدد الخوارزمية أي من أوزان النموذج هي “الأكثر أهمية” لتلك المهمة. عند التدريب على المهمة (ب)، تقول الخوارزمية للنموذج: “لك الحرية في تغيير الأوزان غير المهمة كما تشاء، ولكن إذا حاولت تغيير هذه الأوزان المهمة، فسأفرض عليك عقوبة كبيرة”.
مثال كود (مفهومي):
# بعد التدريب على المهمة الأولى، نحسب أهمية كل وزن
ewc = EWC(model, task1_data)
# تدريب على المهمة الثانية
for new_data, new_label in task2_loader:
# حساب الخسارة للمهمة الجديدة
new_task_loss = calculate_loss(model(new_data), new_label)
# حساب عقوبة تغيير الأوزان المهمة
ewc_penalty = ewc.penalty(model)
# الخسارة الإجمالية = خسارة المهمة الجديدة + (لامدا * عقوبة EWC)
# لامدا (lambda) هو معامل يوازن بين أهمية تعلم الجديد والحفاظ على القديم
total_loss = new_task_loss + lambda * ewc_penalty
# تحديث الأوزان بناءً على الخسارة الإجمالية
total_loss.backward()
optimizer.step()
الاستراتيجية الثالثة: استراتيجيات العزل المعماري (Architecture-based Methods)
هذه هي الفكرة الأكثر تطرفًا. إذا كانت المشكلة هي أن المهام تتصارع على نفس الأوزان، فلماذا لا نعطي كل مهمة أجزاءها الخاصة من النموذج؟
الفكرة: بدلًا من تعديل الشبكة الحالية، نقوم بتوسيعها ديناميكيًا مع كل مهمة جديدة. يمكن أن يكون هذا عن طريق إضافة طبقات جديدة، أو عصبونات (neurons) جديدة، أو حتى “مسار” كامل داخل الشبكة مخصص للمهمة الجديدة.
مثال: في تقنية مثل Progressive Neural Networks، عندما تأتي مهمة جديدة، يتم “تجميد” الشبكة القديمة (تصبح أوزانها غير قابلة للتغيير)، ويتم إنشاء شبكة جديدة (عمود جديد) بجانبها. هذا العمود الجديد يتعلم المهمة الجديدة، ويُسمح له بالاستفادة من مخرجات الطبقات في الأعمدة القديمة، لكن لا يُسمح له بتغييرها. هذا يضمن عدم نسيان المهام القديمة بنسبة 100%، لكنه يأتي على حساب زيادة حجم النموذج مع كل مهمة.
نصائح أبو عمر العملية
بعد سنوات من التعامل مع هذه المشكلة، اسمحوا لي أن أقدم لكم خلاصة خبرتي في نقاط عملية:
- ابدأ بالبسيط: استراتيجيات إعادة التشغيل (Replay) غالبًا ما تكون هي الأسهل في التنفيذ وتعطي نتائج جيدة جدًا. ابدأ بها دائمًا كنقطة أساس (baseline) قبل أن تعقد الأمور.
- لا يوجد حل واحد يناسب الجميع: اختيار الاستراتيجية يعتمد على قيودك. هل لديك ذاكرة محدودة؟ ربما استراتيجيات التنظيم (Regularization) أفضل. هل لا يمكنك تحمل أي نسيان على الإطلاق؟ ربما استراتيجيات العزل المعماري هي الحل، إذا كنت تستطيع تحمل زيادة حجم النموذج.
- فكر بـ MLOps من اليوم الأول: إذا اخترت استراتيجية إعادة التشغيل، كيف ستدير “ذاكرة المراجعة” (replay buffer)؟ كيف ستضمن أن العينات فيها ممثلة حقًا؟ هذه أسئلة تتعلق بهندسة البيانات والـ MLOps ويجب التفكير فيها مبكرًا.
- القياس هو المفتاح: كيف تعرف أنك تنجح؟ لا تعتمد فقط على دقة النموذج في المهمة الجديدة. قِس أيضًا دقته على المهام القديمة بعد تعلم الجديدة. هناك مقاييس متخصصة مثل “متوسط الدقة التراكمية” (Average Incremental Accuracy) و”معدل النسيان” (Forgetting Rate) التي يجب أن تتابعها.
الخلاصة: من النسيان إلى التطور المستمر 🚀
يا جماعة، التحول من عقلية “إعادة التدريب من الصفر” إلى عقلية “التعلم المستمر” ليس مجرد تحول تقني، بل هو تحول فلسفي في كيفية بناء أنظمة الذكاء الاصطناعي. إنه الانتقال من بناء أدوات جامدة إلى بناء أنظمة قادرة على النمو والتكيف والتطور مع مرور الوقت.
النسيان الكارثي كان كابوسًا كلفنا وقتًا ومالًا وأصابنا بالإحباط. لكن من رحم هذه المعاناة، تعلمنا درسًا قيمًا واكتشفنا عالم التعلم المستمر، الذي فتح لنا آفاقًا جديدة لبناء نماذج أكثر ذكاءً وكفاءة واستدامة.
نصيحتي الأخيرة لكم: لا تقبلوا بالنسيان كأمر واقع. ابحثوا، جربوا، وطبقوا تقنيات التعلم المستمر. فالمستقبل ليس للنماذج التي تعرف الكثير فحسب، بل للنماذج التي لا تنسى ما تعلمته أبدًا.
يلا يا حبايب، خلينا نبني أنظمة ذكية ما بتنسى أصلها. في أمان الله.