स्टेप 3 · अटेंशन, धीरे-धीरे समझें
वह एक विचार जिस पर यह पूरा क्षेत्र टिका है। प्रति टोकन तीन वेक्टर्स, एक डॉट प्रॉडक्ट, एक softmax। इसे चरण-दर-चरण समझने के लिए डायग्राम पर क्लिक करें।
60 सेकंड में
स्टेप 3 · अटेंशन, धीरे-धीरे समझें
वह एक विचार जिस पर यह पूरा क्षेत्र टिका है। प्रति टोकन तीन वेक्टर्स, एक डॉट प्रॉडक्ट, एक softmax। इसे चरण-दर-चरण समझने के लिए डायग्राम पर क्लिक करें।
| वेक्टर | नाम | साधारण अर्थ |
|---|---|---|
q | Query | मैं क्या ढूंढ रहा हूँ |
k | Key | मैं क्या हूँ, दूसरों को बताया गया |
v | Value | यदि आप मुझ पर ध्यान देंगे तो मैं क्या योगदान दूंगा |
डायग्राम के किसी भी बॉक्स पर टैप करें
इस टोकन के वर्तमान वेक्टर को एक सीखे गए मैट्रिक्स W_q से गुणा करके बनाया गया है। इसे उस सवाल के रूप में सोचें जो यह स्थिति बाकी अनुक्रम से पूछ रही है। "the animal did not cross the street because it was tired" में, "it" पर query मोटे तौर पर है "मैं किस संज्ञा (noun) की बात कर रहा हूँ?"
import torch, torch.nn as nn, torch.nn.functional as F
class CausalSelfAttention(nn.Module):
def __init__(self, d_model, n_head, dropout=0.0):
super().__init__()
assert d_model % n_head == 0
self.n_head = n_head
self.d_head = d_model // n_head
self.qkv = nn.Linear(d_model, 3 * d_model, bias=False)
self.proj = nn.Linear(d_model, d_model, bias=False)
self.drop = nn.Dropout(dropout)
def forward(self, x):
B, T, C = x.shape
q, k, v = self.qkv(x).split(C, dim=2)
# (B, T, C) -> (B, n_head, T, d_head)
q = q.view(B, T, self.n_head, self.d_head).transpose(1, 2)
k = k.view(B, T, self.n_head, self.d_head).transpose(1, 2)
v = v.view(B, T, self.n_head, self.d_head).transpose(1, 2)
# fused, memory-efficient, and applies the causal mask for us
y = F.scaled_dot_product_attention(q, k, v, is_causal=True)
y = y.transpose(1, 2).contiguous().view(B, T, C)
return self.drop(self.proj(y))मल्टीपल हेड्स क्यों?
ट्रैक B के लिए याद रखने योग्य बात
और देखें और पढ़ें
लैब
अटेंशन को दो बार लागू किया गया, और दोनों के समान होने की पुष्टि की गई।
समस्या
F.scaled_dot_product_attention के विरुद्ध सत्यापित करें। फिर अनुक्रम लंबाई 128, 512, 2048 पर मेमोरी और समय मापें और प्लॉट करें।def attention_by_hand(q, k, v):
d = q.size(-1)
scores = (q @ k.transpose(-2, -1)) / math.sqrt(d)
mask = torch.triu(torch.ones_like(scores, dtype=torch.bool), diagonal=1)
scores = scores.masked_fill(mask, float("-inf"))
return torch.softmax(scores, dim=-1) @ v
assert torch.allclose(attention_by_hand(q,k,v),
F.scaled_dot_product_attention(q,k,v,is_causal=True), atol=1e-4)आपका काम तब पूरा होगा जब
कठिन सवाल
उत्तर देखने से पहले ख़ुद जवाब देने की कोशिश करें। अगर आप इनके जवाब दे सकते हैं, तो आप पाठ समझ गए हैं।
Q11/sqrt(d) स्केलिंग हटाएँ। विफलता का सटीक अनुमान लगाएं, फिर सत्यापित करें।दिखाएं
अक्सर पूछे जाने वाले सवाल
हेड डायमेंशन के वर्गमूल से भाग क्यों दें?
उच्च-आयामी (high-dimensional) यादृच्छिक वेक्टर्स के डॉट प्रॉडक्ट डायमेंशन के वर्गमूल के साथ बढ़ते हैं। स्केलिंग के बिना, softmax संतृप्त (saturate) हो जाता है — एक भार 1 पर चला जाता है, बाकी 0 पर — और ग्रेडिएंट गायब हो जाते हैं। यह एक छोटा सा विवरण है जो प्रशिक्षण को संभव बनाता है।
क्या अटेंशन मेमोरी के समान है?
यह वर्तमान संदर्भ पर एक लुकअप की तरह अधिक है। फॉरवर्ड पास के बीच कुछ भी स्थिर नहीं रहता है। मॉडल जो कुछ भी "याद" रखता है वह या तो उसके भारों (weights) में होता है या वर्तमान में उसके सामने मौजूद टोकन में।
Value मैट्रिक्स key से अलग क्यों है?
ताकि प्रासंगिकता और सामग्री भिन्न हो सकें। एक निश्चित query के लिए एक टोकन बहुत आसानी से खोजा जा सकता है, जबकि एक बार मिलने पर वह कुछ बिल्कुल अलग योगदान दे सकता है। उन्हें एक साथ बाँधने से क्षमता स्पष्ट रूप से कम हो जाती है।
क्या मुझे अटेंशन को स्वयं लागू करने की आवश्यकता है?
इसे समझने के लिए एक बार हाथ से लिखें। फिर प्रोडक्शन में F.scaled_dot_product_attention का उपयोग करें — यह FlashAttention कर्नेल को भेजता है और एक साधारण कार्यान्वयन की तुलना में नाटकीय रूप से तेज़ और अधिक मेमोरी-कुशल है।
पाठ का टेस्ट
5 सवाल। पास होने और इस पाठ को पूरा करने के लिए 3 सही होने चाहिए (60%)।