چیتشیت
ترنسفورمرها و اتنشن
Transformers and Attention
محاسبه اتنشن، اعمال ماسک، تفکیک هدها، افزودن موقعیتها و چیدن بلوکها روی هم. PyTorch و NumPy برگرفته از درسها.
فهرست مطالب
یک بلوک رمزگشای پیشنرمالسازی لایهای (Pre-LN)
معماریگذر رو به جلو (forward) اتنشن
گامبهگام- qkv_projیک لایه خطی
(B, T, D)را به(B, T, 3 * D)نگاشت میکند. - Splitتفکیک به Q، K، V و سپس تغییر شکل به
(B, H, T, d_head). - Scoresعملیات
q @ k.transpose(-2, -1)ابعاد(B, H, T, T)را میدهد. - Scaleتقسیم امتیازها بر
sqrt(d_head). - Mask and softmaxدرایههای آینده مقدار
-infمیگیرند، سپس سافتمکس روی کلیدها. - Weighted sumمحاسبه
weights @ V، سپس merge هدها به(B, T, D). - out_projیک لایه خطی
(D, D)هدها را ترکیب میکند.
ابعاد
دستورها| Tensor | شکل (Shape) |
|---|---|
Token ids | (B, T)، int64 |
Token embedding matrix | (V, D) |
Input to attention | (B, T, D) |
QKV projection output | (B, T, 3 * D) |
Q, K, V per head | (B, H, T, d_head)، d_head = D // H |
Scores and weights | (B, H, T, T) |
Logits | (B, T, 50257) برای GPT-2 small |
Cross attention weights | (batch, T_dec, T_enc) |
فرمولهای کلیدی
مفهومها- Attention
- $\text{Attention}(Q, K, V) = \mathop{\mathrm{softmax}}\left( \frac{Q K^T}{\sqrt{d_k}} \right) V$
- Head width
- $d_{\text{head}} = d_{\text{model}} / n_{\text{heads}}$
- Causal mask
- $M_{ij} = \begin{cases} 0 & \text{if } j \le i \\ -\infty & \text{if } j > i \end{cases}$
- Sinusoidal even
- $PE_{(pos, 2i)} = \sin\left(pos / 10000^{2i / d_{\text{model}}}\right)$
- Sinusoidal odd
- $PE_{(pos, 2i+1)} = \cos\left(pos / 10000^{2i / d_{\text{model}}}\right)$
- RoPE angle
- $\theta_i = \text{base}^{-2i / d_{\text{head}}}$. امتیاز به $(m - n)$ بستگی دارد.
- ALiBi
- $\text{attn\_score}[i, j] = \frac{q_i \cdot k_j}{\sqrt{d}} - m_h \cdot |i - j|$
- Stable softmax
- $\mathop{\mathrm{softmax}}(x - c) = \mathop{\mathrm{softmax}}(x)$
وظایف در کد
کار و کد| وظیفه | کد |
|---|---|
| اعمال ماسک علّی | scores.masked_fill(mask_slice == 0, float("-inf")) |
| سافتمکس روی کلیدها | F.softmax(scores, dim=-1) |
| Merge هدها | x.transpose(1, 2).contiguous().view(b, t, h * dh) |
| افزودن موقعیتها | x = tok + pos.unsqueeze(0) |
| پر کردن جدول سینوسی | pe[:, 0::2] = torch.sin(angle) |
| چرخش Q و K | apply_rope(x, pos, base=10000) |
| کرنل ادغامشده با GQA | scaled_dot_product_attention(q, k, v, is_causal=True, enable_gqa=True) |
| اشتراک ماتریس وزنهای LM head | self.lm_head.weight = self.tok_embed.weight |
گذر رو به جلو MultiHeadSelfAttention
کدpython
self.qkv_proj = nn.Linear(d_model, 3 * d_model, bias=True) # Q، K، V در یک matmul
causal_mask = torch.tril(torch.ones(max_context_length, max_context_length))
self.register_buffer("causal_mask", causal_mask, persistent=False) # بدون grad
qkv = self.qkv_proj(x) # (B, T, 3D)
q, k, v = qkv.chunk(3, dim=-1) # three (B, T, D) views
q = self._split_heads(q) # (B, H, T, d_head)
k = self._split_heads(k)
v = self._split_heads(v)
scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.d_head)
mask_slice = self.causal_mask[:t, :t] # بالا چپ (T, T)
scores = scores.masked_fill(mask_slice == 0, float("-inf"))
weights = F.softmax(scores, dim=-1) # مجموع سطرها برابر 1
context = self._merge_heads(torch.matmul(weights, v)) # (B, T, D)
out = self.out_proj(context) # هدها را ترکیب میکند
پیشفرضها و اعداد
پیشفرضها| تنظیم | پیشفرض | نکته |
|---|---|---|
Sinusoidal and RoPE base | 10000 | افزایش پایه RoPE برای بافت طولانیتر |
mlp_expansion | 4 | بخش MLP از D به 4D به D است |
d_head | 64 | 64 یا 128 در محیط عملیاتی |
Init std | 0.02 | وزنهای Linear و Embedding |
Residual projection scale | 1 / sqrt(2 * num_layers) | out_proj و fc2 |
GPT-2 small d_model | 768 | 12 هد، 12 لایه، حدود 124M |
KV bytes per token per layer | 2 * n_kv_heads * d_head * dtype_size | تمام هدهای KV، K و V |
Compute optimal ratio | 20 | توکن به ازای هر پارامتر |
عیبیابی
عیبیابیValueErrorروی d_model و n_heads- علت
- مقدار D بر H بخشپذیر نیست
- راهحل
- انتخاب H به گونهای که D بر آن بخشپذیر باشد
seq_lenاز max_context_length بیشتر است- علت
- مقدار T از ماسک بزرگتر است
- راهحل
- برش به تعداد context_length توکن آخر
تقلب مدل روی توکن بعدی
- علت
- نبود ماسک علّی
- راهحل
- ماسک کردن مثلث بالایی با
-inf
خروجی
infاز Softmax- علت
expیک عدد بزرگ- راهحل
- ابتدا بیشینه سطر را تفریق کنید
توقف یادگیری
- علت
- امتیازها مقیاسبندی نشدهاند
- راهحل
- تقسیم بر
sqrt(d_head)
واگرایی پشتهی عمیق لایهها
- علت
- پسنرمالسازی لایهای (Post-LN) روی مسیر باقیمانده
- راهحل
- استفاده از پیشنرمالسازی لایهای (Pre-LN)
اشتراک ماتریس وزنها هیچ صرفهجویی ندارد
- علت
- وزنها کپی شدهاند، نه به اشتراک گذاشته
- راهحل
- تخصیص همان پارامتر یکسان
خروجی نامناسب فراتر از طول آموزشدیده
- علت
- امبدینگهای موقعیت تعمیمپذیر نیستند
- راهحل
- استفاده از RoPE با مقیاسبندی پایه
کوتهنوشتها
اصطلاحها- MHA
- اتنشن چندسر. N هد پرسوجو، N هد K/V.
- MQA
- اتنشن چندپرسوجو. یک تصویر K/V مشترک.
- GQA
- اتنشن پرسوجوی گروهبندیشده. هدهای K/V کمتر، تکرار برای انطباق با Q.
- MLA
- اتنشن چندسر نهفته. K و V در یک فضای نهفته با رتبه پایین.
- RoPE
- امبدینگ موقعیت دورانی. چرخش Q و K بر اساس موقعیت.
- ALiBi
- اتنشن با بایاسهای خطی. جریمه فاصله روی امتیازها.
- RMSNorm
- نرمالسازی لایهای بدون میانگین.
- KV cache
- ذخیره K و V مربوط به هر توکن پیشوند.
پرسشها
پرسش و پاسخ- چرا تقسیم بر sqrt(d_k)؟
- ضربهای داخلی بزرگ سافتمکس را اشباع کرده و گرادیانها ناپدید میشوند.
- چرا -inf در ماسک؟
- چون exp(-inf) = 0، در نتیجه موقعیتهای آینده وزن صفر میگیرند.
- چرا افزودن موقعیتها؟
- اتنشن بهتنهایی نسبت به جایگشت ناوردا (پایا) است.
- چرا GQA؟
- حافظه KV cache را به نسبت N/G کاهش میدهد در حالی که کیفیت تقریباً حفظ میشود.
- آیا Flash Attention تقریبی است؟
- خیر. یک (max, sum) در حال اجرا آن را دقیق نگه میدارد.
نکات کاربردی
نکتهها- بررسی کنید مجموع سطرهای وزن برابر 1 باشد.
- بررسی کنید توکنهای آینده خروجیهای گذشته را تغییر ندهند.
- در مقداردهی اولیه تصادفی، انتظار تابع زیان (loss) نزدیک به log(V) داشته باشید.
- شمارش پارامترها را با مدل مرجع مقایسه کنید.
- دراپاوت را بعد از سافتمکس و بعد از لایه خطی دوم MLP قرار دهید.
- از وزنهای اتنشن بهعنوان اثبات استدلال استفاده نکنید.