هذا المقال يتطلب مستوى متوسط. لو عندك خلفية أساسية عن نماذج اللغة (تعرف يعني إيه باراميتر وتوكن)، هتمشي معاه لآخره.
ركز في الرقم ده: نموذج DeepSeek-V3 فيه 671 مليار باراميتر، ومع ذلك بيحسب كل توكن بسرعة نموذج حجمه 37 مليار تقريبًا. مش سحر، ده أسلوب معماري اسمه خليط الخبراء (Mixture of Experts أو MoE). في نهاية المقال هتعرف بالظبط إزاي بيشتغل، وإمتى يستاهل تستخدمه، وإمتى لأ.
خليط الخبراء (MoE): إزاي النموذج الأكبر يطلع أسرع في الحساب
المشكلة باختصار
في النموذج التقليدي (dense) كل باراميتر بيشتغل على كل توكن. يعني لو كبّرت النموذج 10 أضعاف علشان يبقى أذكى، تكلفة الحساب بتكبر 10 أضعاف كمان. المعادلة دي بتخلّي النماذج العملاقة غالية جدًا في التشغيل. السؤال: تقدر تزوّد "معرفة" النموذج من غير ما تزوّد الحساب بنفس النسبة؟
الفكرة بمثال بسيط الأول
تخيّل مستشفى فيها 8 دكاترة متخصصين: قلب، عظام، جلدية، عيون... وهكذا. لما يدخل مريض، مش كل الـ8 بيكشفوا عليه. في موظف استقبال بيبص على الحالة ويحوّلها لأنسب دكتور أو اتنين بس. النتيجة: المريض بياخد رأي متخصص، والمستشفى بتخدم ناس كتير في نفس الوقت لأن كل دكتور مشغول بحالات مجاله فقط.
MoE بيعمل نفس الحاجة جوه النموذج. بدل طبقة واحدة ضخمة بتشتغل على كل توكن، عندك مجموعة "خبراء" (شبكات فرعية)، وموظف الاستقبال هنا اسمه الموجِّه (Router أو Gating network). الموجِّه بيقرأ التوكن ويقرر أي خبيرين بس هيشتغلوا عليه.
دلوقتي الشرح العلمي الدقيق
في نموذج الـ Transformer، بيتم استبدال طبقة الـ Feed-Forward العادية بطبقة MoE. الطبقة دي فيها N خبير (كل خبير شبكة FFN مستقلة) وموجِّه صغير. لكل توكن:
- الموجِّه بيحسب درجة (score) لكل خبير.
- بيختار أعلى k خبير فقط (غالبًا k=2). ده اسمه Top-k gating.
- مخرجات الخبراء المختارين بتتجمع بأوزان مأخوذة من softmax على درجاتهم.
المصطلح المفتاح هنا Sparse activation: تفعيل متناثر. النموذج ضخم في المجمل، لكن اللي "بيشتغل فعلاً" لكل توكن جزء صغير منه. ده الفرق بين إجمالي المعاملات (total params) والمعاملات النشطة (active params).
import torch, torch.nn.functional as F
x = torch.randn(1, 4) # توكن واحد بحجم 4
router = torch.nn.Linear(4, 8) # موجِّه لـ 8 خبراء
logits = router(x) # درجة لكل خبير
topk = torch.topk(logits, k=2) # اختر أعلى خبيرين فقط
weights = F.softmax(topk.values, -1) # وزّع الأهمية بينهم
print("الخبراء المختارون:", topk.indices.tolist())
print("الأوزان:", weights.squeeze().tolist())
# خبيران من 8 بس بيشتغلوا -> ~25% من حساب هذه الطبقة