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

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

Language Models & Next-Token Prediction

الدرس 48 من 65· ⏱ 5 دقائق قراءة

بعد Generative AI overview، نخطو خطوة أعمق في النماذج اللغوية: ما الذي تفعله بالضبط، وكيف تحسب الرمز التالي. هذا الدرس يضع الأساس الذي يقوم عليه كل درس لاحق في هذه الموجة.

ما هو Language Model؟

Language Model = نموذج يأخذ سياقًا نصّيًا ويُرجع توزيع احتمالي للرمز الذي يأتي بعده.

input  (سياق):        "العاصمة الرسمية لفرنسا هي"
output (distribution): {
                         "باريس":    0.62,
                         "مدينة":    0.08,
                         "لندن":     0.03,
                         ...
                       }

من هذا التوزيع يُختار رمز واحد (ليس دائمًا الأعلى احتمالًا)، ويُضاف إلى السياق، وتتكرّر العملية:

خطوة 1:  "العاصمة الرسمية لفرنسا هي"      →  P(.)
خطوة 2:  "العاصمة الرسمية لفرنسا هي باريس" →  P(.)
خطوة 3:  "العاصمة الرسمية لفرنسا هي باريس ."  →  P(.)
... حتّى بلوغ حدّ الإيقاف.

هذه الحلقة تُسمّى autoregressive generation (توليد ذاتي الانحدار): كل رمز يُولَّد يعتمد على كل ما سبقه.

Tokens — لا كلمات

النموذج لا يرى "كلمات" كما يراها البشر. يرى رموزًا (tokens) ينتجها tokenizer خاصّ بالنموذج. راجع درس Tokenization في NLP للتفاصيل الكاملة حول الخوارزميات، لكن الفكرة الأساسية هنا:

النصّ البشري:    "أحبّ البرمجة"
تمثيل رمزيّ محتمل: ["أحب", "ّ", "البر", "مجة"]      # subwords
                أو ["أحب", "البرمجة"]                # whole words
                أو ["أ", "ح", "ب", " ", "ا", ...]   # characters

عدد الرموز يختلف عن عدد الكلمات — ولا توجد قاعدة عامة للتحويل بينهما. للتحقّق الدقيق، استخدم tokenizer الـ checkpoint الفعلية.

المفردات (Vocabulary)

Vocabulary = مجموعة كل الرموز التي يعرفها النموذج.

  • حجم المفردات يختلف: من عشرات الآلاف (نماذج قديمة) إلى مئويات الآلاف (نماذج حديثة).
  • كل رمز له معرّف عددي فريد (ID). النموذج يعمل على IDs، لا على نصوص.
  • كل ID يُربط بـ embedding متعلَّم أثناء التدريب (ارجع لـ Embeddings في NLP).
vocab = {"<unk>": 0, "<pad>": 1, "<bos>": 2, ..., "مرحبا": 12345, ...}

من السياق إلى الاحتمالات — الخطوات

1. Tokenization

تحويل النصّ إلى IDs:

"العاصمة لفرنسا" → ["ال", "عاصمة", " ل", "فر", "نسا"]  →  [421, 9012, 18, 7531, 9012]

2. Embedding + Contextualization

كل ID يُحوَّل إلى متجه، ثم تمرّ هذه المتجهات عبر طبقات النموذج (Transformer blocks) فيتغيّر تمثيل كل رمز بناءً على سياقه (الدرس 68: معمارية Transformers يشرح هذه المعمارية).

3. Logits

في الموضع الأخير، يُنتج النموذج متجها بحجم المفردات، كل عنصر فيه = "نتيجة خام" (logit) لكل رمز ممكن:

import numpy as np

# مخرج وهمي بعد طبقة أخيرة (حجمه = حجم المفردات، مثلاً 50000)
logits = np.array([2.1, -0.5, 1.8, ..., 0.3])
vocab_size = len(logits)

4. Softmax — تحويل الدرجات إلى احتمالات

Softmax تأخذ logits وتحوّلها إلى توزيع احتمالي (كل القيم بين 0 و 1، ومجموعها 1):

def softmax(logits):
    # لتفادي overflow نطرح max
    shifted = logits - np.max(logits)
    exp = np.exp(shifted)
    return exp / np.sum(exp)

probs = softmax(logits)
# probs.sum() == 1.0, كل عنصر ∈ [0, 1]
logits    →  softmax  →  probabilities
[2.1, -0.5, 1.8]   →   [0.65, 0.05, 0.43 / sum]
                      ↓
                    [0.57, 0.04, 0.39]    # مجموعها 1

5. اختيار الرمز التالي

من التوزيع probs، يُختار رمز واحد. عدة استراتيجيات:

  • Greedy: الأعلى احتمالًا (الأبسط، لكن قد يكون متكرّرًا).
  • Sampling: عيّنة عشوائية من التوزيع.
  • Top-k / Top-p: تقييد العيّنة بأعلى k رمز أو بتراكم احتمال p.

التفاصيل في درس Decoding و Sampling.

6. التكرار

الرمز المختار يُضاف إلى السياق، وتتكرّر العملية من جديد حتى بلوغ:

  • رمز إيقاف خاص (<eos>)، أو
  • حدّ أقصى لعدد الرموز المولَّدة (max_new_tokens).

مثال تعليمي صغير — ليس LLM حقيقي

هذا المثال يوضّح الفكرة، لا يعطي نموذجًا حقيقيًا. يتعلّم من نصّ عربي صغير جدًا:

import re
from collections import defaultdict, Counter

# 1. corpus صغير جدًا (للتوضيح فقط)
corpus = [
    "أحبّ البرمجة",
    "أحبّ القراءة",
    "أحبّ التعلّم",
]

def simple_tokenize(text):
    return re.findall(r"\S+", text)  # تجزئة بالمسافات (تعليمية فقط)

tokens_per_sentence = [simple_tokenize(s) for s in corpus]

# 2. تعلّم bigram distribution: P(الكلمة التالية | السابقة)
transitions = defaultdict(Counter)
for sent in tokens_per_sentence:
    for prev, curr in zip(sent, sent[1:]):
        transitions[prev][curr] += 1

# 3. P("التعلّم" | "أحبّ")
def prob(next_word, prev_word):
    counter = transitions.get(prev_word)
    if not counter:
        return 0.0
    total = sum(counter.values())
    return counter[next_word] / total

print(prob("التعلّم", "أحبّ"))   # ~0.33
print(prob("البرمجة", "أحبّ"))  # ~0.33
print(prob("القراءة", "أحبّ"))  # ~0.33

النتيجة: عند البدء بـ"أحبّ"، التوزيع الاحتمالي للكلمة التالية يقسّم الاحتمال بين "البرمجة"، "القراءة"، "التعلّم" (bigram model بدائية).

حدود المثال:

  • لا يستخدم embeddings أو transformer.
  • لا يفهم معانيًا، فقط تكرار أنماط إحصائية ضيّقة.
  • corpus صغير جدًا يعطي توزيعات متفرّقة.

نماذج LLM الحقيقية تستخدم مليارات المعاملات وtrillions من الرموز في التدريب، فتتعلّم أنماطًا أعمق بكثير. لكن الفكرة الجوهرية واحدة: حساب P(التالي | السياق) ثم تكرار.

التدريب مقابل الاستدلال

التدريب (Training): يتعلّم النموذج معاملاته من corpus ضخم. تكلفة عالية، مرّة واحدة عادةً. لا تفعلها بنفسك للنماذج الكبيرة.

الاستدلال (Inference): تستخدم النموذج المدرَّب لتوليد مخرجات. تكلفة لكل طلب، تتكرّر مع كل استخدام.

Training   : corpus → model parameters (تعديل أوزان)
Inference  : context → trained model → output (الأوزان ثابتة)

درس 103: Pre-training و Instruction Tuning يفصّل مراحل التدريب.

أخطاء شائعة

  • "الرمز التالي = الكلمة التالية": خطأ — راجع Tokenization درس 81.
  • "Softmax = دالة تفعيل مثل ReLU": لا، ReLU تضيف عدم خطية. Softmax تحوّل logits إلى احتمالات (مهمة مختلفة).
  • "Greedy يعطي أفضل نتيجة دائمًا": ليس بالضرورة. غالبًا يولّد نصًّا متكرّرًا. Sampling مع قيود أفضل في مهام إبداعية.
  • "النموذج يختار الكلمة الأعلى احتمالًا دائمًا": ليس في النماذج الحديثة — يستخدم sampling مع temperature و top-p.

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

شرح Language Models & Next-Token Prediction — الذكاء الاصطناعي وتعلّم الآلة بالعربي
Language Models & Next-Token Predictionالذكاء الاصطناعي وتعلّم الآلة بالعربي · The Code Fix

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

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