الانتباه و Transformers — التعلم العميق
الانتباه و Transformers
في 2017 قدّم بحث بعنوان "Attention Is All You Need" بنية Transformer، وهي اليوم أساس الترجمة الآلية والمساعدات الذكية والنماذج اللغوية الكبيرة، وحتى كثير من نماذج الرؤية.
ما مشكلة RNN؟
- تعالج الكلمات واحدة تلو الأخرى: لا توازي، فالتدريب بطيء.
- المعلومات من بداية جملة طويلة تمر عبر عشرات الخطوات فتضعف.
الفكرة: كل كلمة "تنظر" لكل الكلمات مباشرة
في جملة "وضع الطالب الكتاب على الطاولة لأنه كان ثقيلاً"، ماذا تعني "لأنه"؟ الانتباه يسمح لتمثيل "لأنه" أن يأخذ معلومات من "الكتاب" مباشرة، بوزن يتعلمه النموذج.
الانتباه بالاستعلام والمفتاح والقيمة
كل كلمة تُحوّل إلى ثلاثة متجهات (بضربها في ثلاث مصفوفات أوزان متعلمة):
| المتجه | التشبيه |
|---|---|
| Query (الاستعلام) | "ما الذي أبحث عنه؟" |
| Key (المفتاح) | "ما الذي أحتويه؟" |
| Value (القيمة) | "المعلومة التي أقدمها إن اختارني أحد" |
Attention(Q, K, V) = softmax(Q·Kᵀ / √d) · V1. Q·Kᵀ: درجة تطابق كل كلمة مع كل كلمة.
2. القسمة على √d: تمنع الدرجات من الكبر الزائد فيتشبع softmax.
3. softmax: تحويل الدرجات إلى أوزان انتباه مجموعها 1 لكل كلمة.
4. ضرب الأوزان في V: كل كلمة تصبح مزيجاً موزوناً من معلومات الكلمات الأخرى.
المثال الكامل ينفذ هذا بـ NumPy في سطور قليلة ويطبع مصفوفة الانتباه.
الانتباه متعدد الرؤوس
بدل انتباه واحد، عدة "رؤوس" بأوزان مختلفة تعمل بالتوازي: رأس قد يتعلم العلاقات النحوية، وآخر الضمائر ومرجعها، وثالث الكلمات المتجاورة. تُدمج مخرجاتها.
الترتيب: الترميز الموضعي
الانتباه وحده لا يعرف ترتيب الكلمات ("القط أكل الفأر" = "الفأر أكل القط")! لذلك نضيف لتضمين كل كلمة ترميزاً موضعياً يحمل رقم موقعها.
كتلة Transformer
المدخلات + ترميز موضعي
← انتباه ذاتي متعدد الرؤوس ← جمع مع المدخل (اتصال تخطٍّ) ← Layer Normalization
← شبكة كثيفة صغيرة لكل كلمة ← جمع ← Layer Normalization
(تُكدّس الكتلة عشرات المرات)اتصالات التخطي (residual) و Layer Normalization تجعل تدريب عشرات الطبقات ممكناً.
عائلتان رئيسيتان
| | المُرمِّز (Encoder) | المُفكِّك (Decoder) |
|---|---|---|
| الانتباه | ثنائي الاتجاه: كل كلمة ترى الجملة كلها | مقنَّع: كل كلمة ترى ما قبلها فقط |
| التدريب | ملء كلمات محجوبة | توقع الكلمة التالية |
| أمثلة | BERT | عائلة GPT ومعظم المساعدات الذكية |
| الاستخدام | الفهم: التصنيف، استخراج المعلومات | التوليد: الكتابة، الحوار، الكود |
النموذج اللغوي التوليدي في جوهره: Decoder ضخم دُرب على توقع الكلمة (الجزء) التالية على كميات هائلة من النصوص، ثم ضُبط لاتباع التعليمات.
في Keras
from tensorflow import keras
from tensorflow.keras import layers
inputs = keras.Input(shape=(20, 64)) # 20 كلمة، تضمين بطول 64
attn = layers.MultiHeadAttention(num_heads=4, key_dim=16)(inputs, inputs) # انتباه ذاتي
x = layers.LayerNormalization()(inputs + attn) # اتصال تخطٍّ + تقييس
ff = layers.Dense(128, activation="gelu")(x)
ff = layers.Dense(64)(ff)
outputs = layers.LayerNormalization()(x + ff)
block = keras.Model(inputs, outputs)عملياً نادراً ما تبني Transformer من الصفر: تأخذ نموذجاً مدرباً (مكتبة Hugging Face Transformers مثلاً) وتضبطه — نقل التعلم مرة أخرى.
الكلفة
الانتباه يقارن كل كلمة بكل كلمة: الكلفة تنمو مع مربع طول النص. لهذا للنماذج "نافذة سياق" محدودة، ولهذا ظهرت تقنيات انتباه أكفأ.
تمرين
في المثال الكامل غيّر المتجهات بحيث تشبه "لأنه" كلمة "الكتاب" أكثر، وراقب كيف يتغير صف "لأنه" في مصفوفة الانتباه. ثم طبّق قناعاً سببياً (كل كلمة ترى ما قبلها فقط) بوضع −∞ فوق القطر قبل softmax.
import numpy as np
def softmax(x, axis=-1):
e = np.exp(x - x.max(axis=axis, keepdims=True))
return e / e.sum(axis=axis, keepdims=True)
def attention(Q, K, V, causal=False):
d = Q.shape[-1]
scores = Q @ K.T / np.sqrt(d) # تطابق كل كلمة مع كل كلمة
if causal: # قناع: لا تنظر للمستقبل (نماذج التوليد)
scores = np.where(np.triu(np.ones_like(scores), k=1) == 1, -np.inf, scores)
weights = softmax(scores) # أوزان الانتباه: كل صف مجموعه 1
return weights @ V, weights
words = ["الطالب", "وضع", "الكتاب", "لأنه", "ثقيل"]
rng = np.random.default_rng(0)
d_model = 8
X = rng.normal(size=(len(words), d_model)) # تضمينات (عشوائية للتوضيح)
# نجعل تضمين "لأنه" قريباً من "الكتاب" لنرى أثر ذلك على الانتباه
X[3] = X[2] + rng.normal(0, 0.1, d_model)
# مصفوفات الإسقاط (في نموذج حقيقي تُتعلم بالتدريب)
Wq, Wk, Wv = (rng.normal(0, 0.5, (d_model, d_model)) for _ in range(3))
Q, K, V = X @ Wq, X @ Wk, X @ Wv
out, w = attention(Q, K, V)
print("مصفوفة الانتباه (الصف = الكلمة التي تنظر):")
print(" " + " ".join(f"{t:>6}" for t in words))
for t, row in zip(words, w):
print(f"{t:>8} " + " ".join(f"{v:6.2f}" for v in row))
i = words.index("لأنه")
print(f"\n'لأنه' تنتبه أكثر إلى: {words[int(w[i].argmax())]}")
print("شكل المخرج:", out.shape, "← كل كلمة صارت مزيجاً من معلومات الكلمات الأخرى")
_, wc = attention(Q, K, V, causal=True)
print("\nمع القناع السببي، صف 'وضع':", wc[1].round(2), "← لا ينظر لما بعده")اختبر فهمك