تخطَّ إلى المحتوى

🤖 شرح الذكاء الاصطناعي وتعلّم الآلة

كيف تعمل النماذج اللغوية الكبيرة (LLMs)؟

الدرس 49 من 65· ⏱ 7 دقائق قراءة

هذا الدرس كان محفوظًا من قِبل درس 68: معمارية Transformers بالاسم المستقبلي 102-llms-how-they-work، وقد حان وقت تنفيذه. هنا نشرح كيف تستخدم النماذج اللغوية الكبيرة بنية Transformer لتوليد نصّ — على مستوى المعمارية لا على مستوى رياضيات Q/K/V التي غُطّيت في 68.

حدود هذه الصفحة: إذا كنت تبحث عن prompt engineering، أو استدعاء LLM API، أو fine-tuning، فهذا ليس درسك. هنا نشرح كيف تعمل النماذج الكبيرة داخليًا على مستوى مفاهيمي. انظر الدروس اللاحقة.

Transformer ≠ LLM

هذا التمييز جوهري ويحتاج أن يكون واضحًا منذ البداية:

Transformer = معمارية (architecture)
              Self-Attention + FFN + Residual + LayerNorm
              بدون أوزان محددة، بدون تدريب

LLM = نموذج كبير مدرَّب (trained model)
      مبني باستخدام Transformer (أو معمارية مشابهة)
      + بيانات تدريب ضخمة
      + هدف تعلّم (next-token prediction)
      + عملية تدريب (pre-training، ثم مراحل لاحقة)
      + stack استدلال (inference)
      = ملفّ أوزان بمليارات المعاملات + بنية تحتية للاستخدام

بعبارة أخرى: Transformer مثل محرّك السيارة — تصميم هندسي. LLM مثل سيارة محددة الصنع — تطبيق ملموس لهذا المحرّك بمواصفات وبيانات محدّدة.

Transformer (درس 68)LLM (هذا الدرس)
Q/K/V نظريًاكيف تُستخدم Q/K/V لتوليد نصّ
Self-Attention blockكيف تُكدَّس عشرات/mئات الكتل
Encoder vs Decoder نظريًاDecoder-only كنمط شائع للـ LLM
بدون حجم محددمليارات المعاملات
بدون بياناتتدرّب على تريليونات الرموز

ارجع لدرس 68 للمراجعة المعمارية. هنا سنركّز على الصورة الكاملة.

من المدخل إلى الإخراج — المسار المفاهيمي

المدخل (نصّ):
  "كيف أتعلّم"

↓ Tokenization (درس 81)

الرموز (IDs):
  [127, 8432, 901]

↓ Embedding (درس 82)
↓ N × Transformer Decoder blocks (كل كتلة فيها self-attention + FFN)

الحالة المخفية (hidden state):
  تمثيل غني لكل رمز في سياقه

↓ LayerNorm + LM Head (طبقة خطية أخيرة)

Logits:
  متجه بحجم المفردات لكل موضع (هنا يهمّ الموضع الأخير)

↓ Softmax

احتمالات الرموز التالية:
  توزيع احتمالي على كل المفردات

↓ Sampling (درس 105)

الرمز التالي:
  رمز واحد مختار من التوزيع

↓ يُضاف للسياق → تتكرّر العملية

المكوّنات الرئيسية لـ LLM

1. Tokenizer (درس 81)

يحوّل النصّ إلى IDs والعكس. ينتمي للـ checkpoint — تغيّر الـ tokenizer يعني تغيّرًا جذريًا في كيفية معالجة المدخل.

2. Embedding table

كل ID يُحوَّل إلى متجه عالي البُعد (مثل 4096 رقمًا). الطبقة الأولى من النموذج.

3. Stacked Transformer Decoder Blocks

العمود الفقري. عشرات إلى مئات الكتل، كل واحدة:

input
  ↓
LayerNorm
  ↓
Causal Multi-Head Self-Attention     ← فقط ينتبه إلى الرموز السابقة
  ↓ (residual)
LayerNorm
  ↓
Feed-Forward Network (FFN)
  ↓ (residual)
output

"Causal" هنا كلمة محورية: كل رمز لا يرى إلا ما قبله. هذا يختلف عن encoder حيث كل رمز يرى الكل. السبب:

decoder-only LLM يولّد من اليسار لليمين:
  في موضع t، يُسمح له بالنظر إلى [0, 1, ..., t-1] فقط.
  لا يُسمح له بالنظر إلى [t, t+1, ...] لأنها لم تُولَّد بعد.

هذا ينفّذ عبر causal mask: مصفوفة تحجب الانتباه إلى المواضع المستقبلية.

4. LM Head (طبقة الإخراج)

طبقة خطية بسيطة تحوّل الحالة المخفية الأخيرة (لآخر موضع) إلى logits بحجم المفردات. ثم softmax، ثم sampling.

5. عدد المعاملات

معظم "حجم" النموذج يأتي من:

  • Embedding table: vocab_size × d_model.
  • كل كتلة: 4 مصفوفات في attention + 2 في FFN (مضروبة في d_model²).

نموذج بحجم 7B (7 مليار) معامل وd_model=4096 ومفردات 50000 يعني:

embedding ≈ 50000 × 4096 = 200M
per block ≈ 4 × 4096² (attention) + 2 × 4096 × 11000 (FFN, typically 4×) ≈ 67M + 90M = ~157M
N blocks = (7B - 200M) / 157M ≈ 43 block

الأرقام الدقيقة تختلف حسب الإعداد، لكن الفكرة أن كتل Transformer تشكّل الجزء الأكبر.

نافذة السياق (Context Window)

Context window = الحدّ الأقصى لعدد الرموز (مدخلًا + مخرجًا) التي يستطيع النموذج معالجتها في طلب واحد.

context_window = input_tokens + output_tokens (≤ الحدّ الأقصى)

اعتبارات مهمة:

  • نظام + تعليمات + رسائل سابقة + مدخل جديد + tool results كلّها تستهلك السياق (راجع درس 104).
  • نافذة كبيرة لا تعني ذاكرة كاملة: النموذج لا "يتذكّر" خارج النافذة.
  • النوافذ تختلف بين النماذج: 8K، 32K، 128K، 200K، 1M، أو أكبر — وكلها بتقنيات مختلفة.

KV Cache — مفهوم فقط

هذا تحسين للاستدلال، مفيد فهمه على المستوى المفاهيمي:

المشكلة: عند توليد كل رمز جديد، النموذج يحسب self-attention على كل السياق السابق. الحساب يتكرّر لكل رمز.

الحلّ: تخزين مؤقت لقيم K و V للمدخل مرة واحدة، وإعادة استخدامها في كل خطوة توليد.

بدون KV cache:
  رمز 1 → حساب attention على [1]
  رمز 2 → حساب attention على [1, 2]         ← re-compute 1
  رمز 3 → حساب attention على [1, 2, 3]      ← re-compute 1, 2

مع KV cache:
  رمز 1 → حساب، تخزين KV[1]
  رمز 2 → استخدام KV[1] المحفوظ + حساب KV[2]
  رمز 3 → استخدام KV[1,2] المحفوظ + حساب KV[3]

النتيجة: تسريع كبير (خصوصًا في النماذج الكبيرة والنوافذ الطويلة). لكن يستهلك ذاكرة أكبر مع نموّ السياق.

التفاصيل الكاملة لـ KV cache خارج نطاق هذه الصفحة. يكفي فهم المفهوم: تخزين مؤقت للحالة الداخلية لتجنّب إعادة الحساب.

Inference Loop — حلقة الاستدلال

# هذا pseudocode يوضّح الفكرة، ليس كود SDK جاهز
def generate_step_by_step(model, tokenizer, prompt, max_new_tokens, stop_token_id):
    tokens = tokenizer.encode(prompt)
    generated = []

    for step in range(max_new_tokens):
        # 1. تمرير السياق عبر النموذج
        logits = model.forward(tokens)        # logits[last_pos, :]

        # 2. sampling لاختيار الرمز التالي (درس 105)
        next_token = sample(logits, ...)

        # 3. فحص شرط الإيقاف
        if next_token == stop_token_id:
            break

        # 4. إضافة الرمز للسياق
        tokens = tokens + [next_token]
        generated.append(next_token)

    return tokenizer.decode(generated)

كل تكرار = استدلال كامل على النموذج (لكن KV cache يخفف التكلفة في التكرارات اللاحقة).

Parameters vs Context vs Generated Tokens

ثلاثة مفاهيم تُخلط أحيانًا:

المصطلحالمعنى
Parametersأوزان النموذج (مليارات الأرقام). ثابتة بعد التدريب. تحدّد "ما يعرفه النموذج".
Context tokensالرموز التي تُمرَّر للنموذج كمدخل. ديناميكية، تتغيّر مع كل طلب.
Generated tokensالرموز التي يُنتجها النموذج كمخرج. تتزايد تدريجيًا حتى شرط الإيقاف.
input_tokens  +  generated_tokens  ≤  context_window
   ↑                    ↑
  أنت ترسله      النموذج يولّده

كيف تختلف النماذج عن بعضها؟

نقاط الاختلاف الجوهرية (كل نموذج يختار توليفة مختلفة):

  • حجم المعاملات (7B، 70B، 405B...).
  • بيانات التدريب (تنوّع، لغات، ترخيص).
  • Tokenizer (BPE، SentencePiece، SentencePiece + BPE-style... راجع درس 81).
  • بنية دقيقة (RoPE، ALiBi، GQA، MQA، sliding window...).
  • نافذة السياق.
  • مراحل ما بعد التدريب (instruction tuning، preference optimization، tool-use training... راجع درس 103).

كل نقطة تستحقّ بحثًا مستقلًا. لا توجد "بنية LLM قياسية واحدة" — التطور مستمر.

أخطاء شائعة

  • "LLM يفهم النصّ": مجاز. النموذج يتعلّم أنماطًا إحصائية عميقة، ولا "يفهم" بالمعنى البشري. قد ينتج نصًّا صحيح نحويًا لكنه خاطئ واقعيًا.
  • "نموذج أكبر = أذكى بالضرورة": ليس بالضرورة في كل مهمة. للنصوص الطويلة قد يتفوّق نموذج بنافذة أكبر. للمهام البسيطة قد يكون نموذج صغير محسّن أفضل وأرخص.
  • "LLM يحفظ كل بيانات التدريب حرفيًا": يتعلّم أنماطًا. قد يظهر تشابه نصّي عرضي مع corpus، لكنه ليس "قاعدة بيانات" يُستخرج منها.
  • "Context window = ذاكرة دائمة": لا. تنتهي بانتهاء الـ session ما لم تخزّنها أنت بنفسك في الـ prompt أو في تطبيق خارجي.

الخطوات التالية

ملاحظة النطاق: هذا الدرس حدّه المعماري المفاهيمي. ضبط دقيق (fine-tuning) للنماذج الكبيرة، و RAG، و الوكلاء، و MLOps تُغطّى في الموجات التالية.

شرح كيف تعمل النماذج اللغوية الكبيرة (LLMs)؟ — الذكاء الاصطناعي وتعلّم الآلة بالعربي
كيف تعمل النماذج اللغوية الكبيرة (LLMs)؟الذكاء الاصطناعي وتعلّم الآلة بالعربي · The Code Fix

📚 لمزيد من التعمّق في الذكاء الاصطناعي وتعلّم الآلة، راجِع توثيق scikit-learn الرسمي.

هل كان هذا الدرس مفيدًا؟