الفصل 1: آلية الانتباه
المقدمة
آلية الانتباه هي الابتكار الأساسي الذي يجعل المحولات ممكنة. إنها تسمح للنماذج بالتركيز ديناميكيًا على الأجزاء ذات الصلة من المدخلات عند إنتاج كل مخرج، متجاوزةً قيود متجهات السياق ذات الحجم الثابت.
الفكرة وراء الانتباه
تشبيه بشري
فكر في كيفية قراءة جملة معقدة:
"لم يعبر الحيوان الشارع لأن هو كان متعبًا جدًا."
لفهم ما يشير إليه "هو"، تقوم عقليًا بالانتباه إلى "الحيوان" بدلاً من "الشارع". هذا هو بالضبط ما يفعله الانتباه حسابيًا.
الفكرة الأساسية
يحسب الانتباه مجموعًا مرجحًا للقيم، حيث يتم تحديد الأوزان بناءً على مدى صلة كل قيمة باستعلام معين:
الاستعلام، المفتاح، القيمة: الإسقاطات الثلاثة
فهم Q، K، V
| المكون | الدور | التشبيه |
|---|---|---|
| الاستعلام (Q) | ما نبحث عنه | استعلام بحث |
| المفتاح (K) | ما يقدمه كل موضع | إدخالات الفهرس |
| القيمة (V) | المحتوى الفعلي | الوثائق |
التعريف الرياضي
بالنظر إلى إدخال (تسلسل من n رموز، كل منها بأبعاد d):
حيث:
التنفيذ
import torch
import torch.nn as nn
import math
class AttentionProjections(nn.Module):
def __init__(self, d_model, d_k, d_v):
super().__init__()
self.W_Q = nn.Linear(d_model, d_k, bias=False)
self.W_K = nn.Linear(d_model, d_k, bias=False)
self.W_V = nn.Linear(d_model, d_v, bias=False)
def forward(self, x):
"""
x: (batch, seq_len, d_model)
Returns Q, K, V projections
"""
Q = self.W_Q(x) # (batch, seq_len, d_k)
K = self.W_K(x) # (batch, seq_len, d_k)
V = self.W_V(x) # (batch, seq_len, d_v)
return Q, K, V
الانتباه بالنقطة المضاعفة المحسوبة
الحساب خطوة بخطوة
الخطوة 1: حساب درجات الانتباه
هذا يعطينا مصفوفة حيث تمثل المدخلة مقدار ما يجب أن ينتبه الموضع إلى الموضع .
# Q: (batch, seq_len, d_k)
# K: (batch, seq_len, d_k)
scores = torch.matmul(Q, K.transpose(-2, -1))
# scores: (batch, seq_len, seq_len)
الخطوة 2: مقياس الدرجات
بدون المقياس، بالنسبة لـ الكبيرة، يمكن أن تنمو النواتج النقطية بشكل كبير في الحجم، مما يدفع softmax إلى مناطق ذات تدرجات صغيرة جدًا. المقياس بواسطة يحافظ على استقرار التباين.
d_k = Q.size(-1)
scaled_scores = scores / math.sqrt(d_k)
الخطوة 3: تطبيق Softmax
attention_weights = torch.softmax(scaled_scores, dim=-1)
# Each row sums to 1
الخطوة 4: مجموع مرجح للقيم
output = torch.matmul(attention_weights, V)
# output: (batch, seq_len, d_v)
التنفيذ الكامل
def scaled_dot_product_attention(Q, K, V, mask=None):
"""
Compute scaled dot-product attention.
Args:
Q: Query tensor (batch, seq_len, d_k)
K: Key tensor (batch, seq_len, d_k)
V: Value tensor (batch, seq_len, d_v)
mask: Optional mask tensor
Returns:
output: Attention output (batch, seq_len, d_v)
attention_weights: Attention weights (batch, seq_len, seq_len)
"""
d_k = Q.size(-1)
# Step 1 & 2: Compute scaled scores
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)
# Optional: Apply mask (for causal attention)
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
# Step 3: Softmax
attention_weights = torch.softmax(scores, dim=-1)
# Step 4: Weighted sum
output = torch.matmul(attention_weights, V)
return output, attention_weights
تصور الانتباه
مصفوفة الانتباه
بالنسبة لجملة مثل "The cat sat":
The cat sat
The [ 0.7 0.2 0.1 ]
cat [ 0.3 0.5 0.2 ]
sat [ 0.2 0.4 0.4 ]
كل صف يظهر مقدار ما ينتبه ذلك الموضع إلى جميع المواضع الأخرى.
كود للتصور
import matplotlib.pyplot as plt
import seaborn as sns
def visualize_attention(attention_weights, tokens):
"""
Visualize attention weights as a heatmap.
"""
plt.figure(figsize=(10, 8))
sns.heatmap(
attention_weights.detach().numpy(),
xticklabels=tokens,
yticklabels=tokens,
cmap='Blues',
annot=True,
fmt='.2f'
)
plt.xlabel('Keys')
plt.ylabel('Queries')
plt.title('Attention Weights')
plt.show()
الانتباه السببي (المقنع)
بالنسبة لنماذج اللغة التوليدية، يجب أن ينتبه كل موضع فقط إلى المواضع السابقة.
القناع السببي
def create_causal_mask(seq_len):
"""
Create a causal mask for autoregressive attention.
Position i can only attend to positions <= i.
"""
mask = torch.tril(torch.ones(seq_len, seq_len))
return mask
# Example for seq_len=4:
# [[1, 0, 0, 0],
# [1, 1, 0, 0],
# [1, 1, 1, 0],
# [1, 1, 1, 1]]
لماذا القناع السببي؟
أثناء التدريب، نريد من النموذج أن يتنبأ بالرمز التالي بناءً فقط على الرموز السابقة، وليس الرموز المستقبلية (التي لن تكون لديه في وقت الاستدلال).
def causal_attention(Q, K, V):
"""
Attention with causal masking.
"""
seq_len = Q.size(1)
mask = create_causal_mask(seq_len).to(Q.device)
return scaled_dot_product_attention(Q, K, V, mask)
تعقيد الانتباه
تعقيد الوقت
حيث:
- = طول التسلسل
- = أبعاد النموذج
هذا التعقيد التربيعي في طول التسلسل هو السبب في أن النماذج ذات السياق الطويل تمثل تحديًا.
تعقيد الذاكرة
بالنسبة لمصفوفة الانتباه نفسها (تخزين جميع الدرجات الزوجية).
تقنيات التحسين
تتناول عدة طرق تعقيد الانتباه التربيعي:
- Flash Attention: تنفيذ فعال في الذاكرة
- Linear Attention: تقريب الانتباه في O(n)
- Sparse Attention: الانتباه فقط إلى مجموعة فرعية من المواضع
- Sliding Window: الانتباه المحلي مع الرموز العالمية
وضع كل شيء معًا
class Attention(nn.Module):
"""
Complete attention module.
"""
def __init__(self, d_model, d_k=None, d_v=None, causal=False):
super().__init__()
d_k = d_k or d_model
d_v = d_v or d_model
self.W_Q = nn.Linear(d_model, d_k, bias=False)
self.W_K = nn.Linear(d_model, d_k, bias=False)
self.W_V = nn.Linear(d_model, d_v, bias=False)
self.W_O = nn.Linear(d_v, d_model, bias=False)
self.causal = causal
self.d_k = d_k
def forward(self, x, mask=None):
batch_size, seq_len, _ = x.size()
# Project to Q, K, V
Q = self.W_Q(x)
K = self.W_K(x)
V = self.W_V(x)
# Compute attention
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
# Apply causal mask if needed
if self.causal:
causal_mask = torch.tril(torch.ones(seq_len, seq_len, device=x.device))
scores = scores.masked_fill(causal_mask == 0, float('-inf'))
# Apply additional mask if provided
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
# Softmax and weighted sum
attn_weights = torch.softmax(scores, dim=-1)
output = torch.matmul(attn_weights, V)
# Output projection
output = self.W_O(output)
return output, attn_weights
النقاط الرئيسية
- الانتباه يحسب المجموعات المرجحة بناءً على الصلة
- Q، K، V هي ثلاث إسقاطات للإدخال بأدوار مميزة
- المقياس بواسطة يثبت التدريب
- القناع السببي يمنع النظر إلى الرموز المستقبلية
- التعقيد هو في طول التسلسل
نظرة مستقبلية
في الفصل التالي، سنستكشف كيفية استخدام الانتباه داخل تسلسل واحد (الانتباه الذاتي) وكيفية دمج آليات الانتباه المتعددة (الانتباه متعدد الرؤوس).