لو شوفت إن DeepSeek V3 بـ 671 مليار باراميتر بيرد على سؤالك في نفس وقت موديل 37 مليار، اعرف إن ده مش تحسين بسيط في الـ GPU. ده تغيير في معمارية الموديل اسمها Mixture of Experts. الفكرة: الموديل الكبير ده بيفعّل 5.5% بس من نفسه لكل توكن. الباقي نايم.
Mixture of Experts: نمط المعمارية اللي بقى المعيار في 2026
المشكلة باختصار
الموديلات اللي زادت قدرتها بعد GPT-3 كانت بتزود الباراميترز. الباراميترز الأكتر يعني ذاكرة أكتر و FLOPs أكتر لكل توكن. النتيجة: تكلفة استدلال بتطلع خطّيًا مع الحجم. موديل 70B تقريبًا 5x أبطأ من موديل 13B على نفس الـ GPU. علشان كده الفرق بين قدرات الموديلات الكبيرة وزمن الاستجابة كان بيتسع كل سنة.
MoE بتحل المعادلة دي بفصل "حجم المعرفة" عن "حجم الحساب". تقدر تزود الباراميترز 20x من غير ما تزود تكلفة الاستدلال أكتر من 10–15%.
مثال للمبتدئ: المستشفى التخصصي
تخيّل مستشفى فيها 256 طبيب، كل طبيب متخصص في حاجة: قلب، عيون، عظام، مخ، إلى آخره. لما مريض يدخل، فيه موظف استقبال شاطر بيسأله سؤال أو اتنين، وبيوديه لـ 8 أطباء بس من الـ 256 — اللي تخصصهم قريب من حالته. باقي الـ 248 طبيب قاعدين في مكاتبهم بيشربوا قهوة.
المستشفى دي عندها معرفة هائلة (256 تخصص)، بس كل مريض بياخد وقت زيارة 8 أطباء فقط. لو كان كل مريض لازم يعدّي على الـ 256، الزحمة هتقتل المستشفى. ده بالظبط اللي بتعمله MoE.
موظف الاستقبال = الراوتر (Router/Gating Network). الأطباء = الخبراء (Experts). عدد الأطباء اللي بيشوفوا المريض = Top-K. التخصصات الجانبية اللي مش بتشتغل = Sparse activation.
التعريف العلمي بالظبط
في الـ Transformer العادي، كل طبقة فيها Self-Attention + Feed-Forward Network (FFN) واحدة. الـ FFN بياخد كل التوكنز ويمررها على نفس المصفوفات.
في طبقة MoE، الـ FFN الواحدة بتتقسّم لـ N خبير (FFN صغيرة)، وبيتضاف Gating Network (شبكة Linear بسيطة) دورها يحسب لكل توكن probabilities على الخبراء، ويختار أعلى K منهم. ده اللي بيتسمى Top-K Routing. الإخراج = جمع موزون لإخراج الـ K خبير اللي اتفعلوا.
الفرضية الأساسية: التخصص بينشأ تلقائيًا أثناء التدريب. الراوتر بيتعلم إن التوكنز الخاصة بالكود تروح لخبراء، وتوكنز اللغة الطبيعية تروح لخبراء تانيين، وهكذا. ما حدش بيفرض التخصص يدوي.
كود PyTorch: ابني MoE Layer من الصفر
import torch
import torch.nn as nn
import torch.nn.functional as F
class Expert(nn.Module):
"""خبير واحد = FFN صغيرة عادية"""
def __init__(self, d_model, d_hidden):
super().__init__()
self.fc1 = nn.Linear(d_model, d_hidden)
self.fc2 = nn.Linear(d_hidden, d_model)
def forward(self, x):
return self.fc2(F.silu(self.fc1(x)))
class MoELayer(nn.Module):
def __init__(self, d_model=768, d_hidden=2048,
num_experts=8, top_k=2):
super().__init__()
self.experts = nn.ModuleList(
[Expert(d_model, d_hidden) for _ in range(num_experts)]
)
self.gate = nn.Linear(d_model, num_experts, bias=False)
self.top_k = top_k
def forward(self, x):
# x shape: [batch, seq_len, d_model]
logits = self.gate(x) # [B, T, E]
weights, idx = logits.topk(self.top_k, dim=-1)
weights = F.softmax(weights, dim=-1)
out = torch.zeros_like(x)
for k in range(self.top_k):
expert_idx = idx[..., k] # أيّ خبير لكل توكن
w = weights[..., k].unsqueeze(-1)
for e in range(len(self.experts)):
mask = (expert_idx == e)
if mask.any():
out[mask] += w[mask] * self.experts[e](x[mask])
return out
# اختبار سريع
layer = MoELayer(d_model=768, num_experts=8, top_k=2)
x = torch.randn(2, 16, 768) # batch=2, seq=16
print(layer(x).shape) # torch.Size([2, 16, 768])