एक LLM बनाएँमध्यमपाठ 397 मिनट का पाठ

स्टेप 3 · अटेंशन, धीरे-धीरे समझें

वह एक विचार जिस पर यह पूरा क्षेत्र टिका है। प्रति टोकन तीन वेक्टर्स, एक डॉट प्रॉडक्ट, एक softmax। इसे चरण-दर-चरण समझने के लिए डायग्राम पर क्लिक करें।

पाठ वीडियो में

60 सेकंड में

स्टेप 3 · अटेंशन, धीरे-धीरे समझें

वह एक विचार जिस पर यह पूरा क्षेत्र टिका है। प्रति टोकन तीन वेक्टर्स, एक डॉट प्रॉडक्ट, एक softmax। इसे चरण-दर-चरण समझने के लिए डायग्राम पर क्लिक करें।

1/4
आसान शब्दों में
हर शब्द एक सवाल पूछता है ("मैं क्या ढूंढ रहा हूँ?"), हर शब्द एक लेबल पहनता है ("यहाँ है जो मैं हूँ"), और हर शब्द एक संदेश लेकर चलता है ("यह है जो मैं आपको बताऊंगा")। प्रत्येक शब्द उन शब्दों को सबसे अधिक सुनता है जिनका लेबल उसके सवाल का सबसे अच्छा उत्तर देता है।
औपचारिक रूप से, प्रत्येक टोकन अपनी एम्बेडिंग को तीन सीखे गए मैट्रिसेस से गुणा करके तीन वेक्टर बनाता है:
वेक्टरनामसाधारण अर्थ
qQueryमैं क्या ढूंढ रहा हूँ
kKeyमैं क्या हूँ, दूसरों को बताया गया
vValueयदि आप मुझ पर ध्यान देंगे तो मैं क्या योगदान दूंगा

डायग्राम के किसी भी बॉक्स पर टैप करें

Query · qwhat I wantKey · kwhat I offerValue · vwhat I carryq · kᵀ / √da score per pairsoftmaxWeightssum to 1weighted byOutputa blended messageevery token does this against every token, in parallel
Query

इस टोकन के वर्तमान वेक्टर को एक सीखे गए मैट्रिक्स W_q से गुणा करके बनाया गया है। इसे उस सवाल के रूप में सोचें जो यह स्थिति बाकी अनुक्रम से पूछ रही है। "the animal did not cross the street because it was tired" में, "it" पर query मोटे तौर पर है "मैं किस संज्ञा (noun) की बात कर रहा हूँ?"

प्रत्येक चरण पर क्लिक करें। अटेंशन एक मैट्रिक्स गुणा, एक स्केल, एक मास्क, एक softmax, और एक और मैट्रिक्स गुणा है। ट्रांसफॉर्मर में बाकी सब कुछ बस इसके चारों ओर की प्लंबिंग है।
Causal self-attention, completepython
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))

मल्टीपल हेड्स क्यों?

एक अटेंशन ऑपरेशन केवल एक तरह से औसत निकाल सकता है। वेक्टर को heads में विभाजित करने से मॉडल एक साथ कई अटेंशन पैटर्न चला सकता है — एक हेड सिंटैक्स को ट्रैक करता है, दूसरा ट्रैक करता है कि सर्वनाम किस इकाई को संदर्भित करता है, दूसरा स्थिति को ट्रैक करता है। उनकी गणना समानांतर में की जाती है और उन्हें आपस में जोड़ दिया जाता है, इसलिए हेड्स लगभग मुफ्त होते हैं।
सावधान रहें
वह लागत जिससे आप बच नहीं सकते: अटेंशन हर टोकन की तुलना हर टोकन से करता है, इसलिए कंप्यूट और मेमोरी अनुक्रम की लंबाई के वर्ग (square) के साथ बढ़ती है। संदर्भ (context) को दोगुना करने से काम चार गुना हो जाता है। यही एकमात्र तथ्य FlashAttention, स्लाइडिंग विंडो, GQA और मॉड्यूल 48 में हर लॉन्ग-कॉन्टेक्स्ट ट्रिक को संचालित करता है।

ट्रैक B के लिए याद रखने योग्य बात

यह करें
अटेंशन ही कारण है कि सिस्टम की कोई ट्रस्ट बाउंड्री नहीं होती। संदर्भ में मौजूद प्रत्येक टोकन हर दूसरे टोकन को प्रभावित कर सकता है, जिसका भार केवल सीखी गई प्रासंगिकता पर निर्भर करता है — कभी भी स्रोत पर नहीं। इस तंत्र में यह लिखने की कोई जगह नहीं है कि "लेकिन वह भाग एक वेब पेज से आया था"। सुरक्षा समस्या आर्किटेक्चरल है, कोई गायब फ़ीचर नहीं।

और देखें और पढ़ें

Attention in transformers, step by step3Blue1Brown · video
Let's build GPT: from scratchAndrej Karpathy · attention section · video

लैब

अटेंशन को दो बार लागू किया गया, और दोनों के समान होने की पुष्टि की गई।

~25 min

समस्या

स्पष्ट लूप्स के साथ शुरुआत से कॉज़ल सेल्फ-अटेंशन लिखें। फ्लोटिंग-पॉइंट टॉलरेंस के भीतर F.scaled_dot_product_attention के विरुद्ध सत्यापित करें। फिर अनुक्रम लंबाई 128, 512, 2048 पर मेमोरी और समय मापें और प्लॉट करें।
शुरुआती कोडpython
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)
Google Colab खोलें ↗इस कोड के लिए आपके अपने सेटअप की ज़रूरत है (एक मॉडल, एक GPU या अतिरिक्त पैकेज)। इसे Google Colab में चलाएं: File → Upload notebook।

आपका काम तब पूरा होगा जब

कठिन सवाल

उत्तर देखने से पहले ख़ुद जवाब देने की कोशिश करें। अगर आप इनके जवाब दे सकते हैं, तो आप पाठ समझ गए हैं।

Q11/sqrt(d) स्केलिंग हटाएँ। विफलता का सटीक अनुमान लगाएं, फिर सत्यापित करें।दिखाएं
d-आयामी वेक्टर्स के डॉट प्रॉडक्ट sqrt(d) की तरह बढ़ते हैं, इसलिए d=64 पर लॉजिट्स ~8x बड़े होते हैं। Softmax संतृप्त हो जाता है: एक भार ~1 पर चला जाता है, बाकी ~0 पर, softmax के माध्यम से ग्रेडिएंट गायब हो जाते हैं, और लेयर सीखना बंद कर देती है — लॉस डाइवर्ज होने के बजाय जल्दी स्थिर (plateau) हो जाता है। स्केल के साथ और उसके बिना प्रति लेयर softmax एन्ट्रापी प्रिंट करके सत्यापित करें; आप इसे शून्य की ओर गिरते हुए देखेंगे।

जारी रखने के लिए कृपया साइन इन करें।

अक्सर पूछे जाने वाले सवाल

हेड डायमेंशन के वर्गमूल से भाग क्यों दें?

उच्च-आयामी (high-dimensional) यादृच्छिक वेक्टर्स के डॉट प्रॉडक्ट डायमेंशन के वर्गमूल के साथ बढ़ते हैं। स्केलिंग के बिना, softmax संतृप्त (saturate) हो जाता है — एक भार 1 पर चला जाता है, बाकी 0 पर — और ग्रेडिएंट गायब हो जाते हैं। यह एक छोटा सा विवरण है जो प्रशिक्षण को संभव बनाता है।

क्या अटेंशन मेमोरी के समान है?

यह वर्तमान संदर्भ पर एक लुकअप की तरह अधिक है। फॉरवर्ड पास के बीच कुछ भी स्थिर नहीं रहता है। मॉडल जो कुछ भी "याद" रखता है वह या तो उसके भारों (weights) में होता है या वर्तमान में उसके सामने मौजूद टोकन में।

Value मैट्रिक्स key से अलग क्यों है?

ताकि प्रासंगिकता और सामग्री भिन्न हो सकें। एक निश्चित query के लिए एक टोकन बहुत आसानी से खोजा जा सकता है, जबकि एक बार मिलने पर वह कुछ बिल्कुल अलग योगदान दे सकता है। उन्हें एक साथ बाँधने से क्षमता स्पष्ट रूप से कम हो जाती है।

क्या मुझे अटेंशन को स्वयं लागू करने की आवश्यकता है?

इसे समझने के लिए एक बार हाथ से लिखें। फिर प्रोडक्शन में F.scaled_dot_product_attention का उपयोग करें — यह FlashAttention कर्नेल को भेजता है और एक साधारण कार्यान्वयन की तुलना में नाटकीय रूप से तेज़ और अधिक मेमोरी-कुशल है।

पाठ का टेस्ट

5 सवाल। पास होने और इस पाठ को पूरा करने के लिए 3 सही होने चाहिए (60%)।

टेस्ट देने और अपनी प्रोग्रेस सेव करने के लिए साइन इन करें