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

स्टेप 5 · एक पूरा छोटा GPT

हर हिस्सा जोड़कर एक ऐसा मॉडल तैयार किया गया है जिसे आप वाकई आज रात ट्रेन कर सकते हैं। 100 से भी कम लाइनों में, और बनावट में बिल्कुल एक फ्रंटियर मॉडल जैसा।

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

60 सेकंड में

स्टेप 5 · एक पूरा छोटा GPT

हर हिस्सा जोड़कर एक ऐसा मॉडल तैयार किया गया है जिसे आप वाकई आज रात ट्रेन कर सकते हैं। 100 से भी कम लाइनों में, और बनावट में बिल्कुल एक फ्रंटियर मॉडल जैसा।

1/5
आसान शब्दों में
अब हम इन हिस्सों को आपस में जोड़ते हैं: नंबर-लुकअप, चालीस थिंकिंग ब्लॉक्स, और एक आख़िरी लेयर जो अगले टुकड़े का अंदाज़ा लगाती है।
The whole modelpython
import torch, torch.nn as nn, torch.nn.functional as F
from dataclasses import dataclass

@dataclass
class Config:
    vocab_size: int = 8192
    n_layer: int = 6
    n_head: int = 6
    d_model: int = 384
    block_size: int = 256      # max context length
    dropout: float = 0.1

class TinyGPT(nn.Module):
    def __init__(self, cfg):
        super().__init__()
        self.cfg = cfg
        self.tok = nn.Embedding(cfg.vocab_size, cfg.d_model)
        self.pos = nn.Embedding(cfg.block_size, cfg.d_model)
        self.drop = nn.Dropout(cfg.dropout)
        self.blocks = nn.ModuleList(
            Block(cfg.d_model, cfg.n_head) for _ in range(cfg.n_layer))
        self.norm = RMSNorm(cfg.d_model)
        self.head = nn.Linear(cfg.d_model, cfg.vocab_size, bias=False)
        self.head.weight = self.tok.weight        # weight tying
        self.apply(self._init)

    def _init(self, m):
        if isinstance(m, nn.Linear):
            nn.init.normal_(m.weight, std=0.02)
        elif isinstance(m, nn.Embedding):
            nn.init.normal_(m.weight, std=0.02)

    def forward(self, idx, targets=None):
        B, T = idx.shape
        pos = torch.arange(T, device=idx.device)
        x = self.drop(self.tok(idx) + self.pos(pos))
        for b in self.blocks:
            x = b(x)
        logits = self.head(self.norm(x))          # (B, T, vocab)

        loss = None
        if targets is not None:
            loss = F.cross_entropy(
                logits.view(-1, logits.size(-1)),
                targets.view(-1))
        return logits, loss

    @torch.no_grad()
    def generate(self, idx, max_new=100, temperature=1.0, top_k=50):
        for _ in range(max_new):
            idx_cond = idx[:, -self.cfg.block_size:]      # crop to context
            logits, _ = self(idx_cond)
            logits = logits[:, -1, :] / temperature       # last position only
            if top_k:
                v, _ = torch.topk(logits, top_k)
                logits[logits < v[:, [-1]]] = -float("inf")
            probs = F.softmax(logits, dim=-1)
            nxt = torch.multinomial(probs, num_samples=1)
            idx = torch.cat((idx, nxt), dim=1)
        return idx

इन दो ज़रूरी लाइनों को फिर से पढ़ें

  1. 1

    टारगेट्स वही इनपुट्स हैं, बस एक कदम आगे खिसके हुए (shifted by one)

    targets = idx[1:]। यही पूरा ट्रेनिंग ऑब्जेक्टिव है। सीक्वेंस में हर जगह एक साथ अगले टोकन का अंदाज़ा लगाना। इसके अलावा कोई और सुपरविज़न नहीं है।
  2. 2

    जेनरेशन उसी फ़ॉरवर्ड पास का एक लूप है

    आख़िरी पोज़ीशन पर मौजूद logits लें, एक टोकन सैंपल करें, उसे आगे जोड़ें, और फिर से रन करें। एक LLM जो कुछ भी बनाता है, वह सब इसी लूप से निकलता है।

ट्रेन करने से पहले अपने पैरामीटर्स गिन लें

Where the parameters livepython
def count(cfg):
    emb  = cfg.vocab_size * cfg.d_model                 # tied with output head
    attn = 4 * cfg.d_model * cfg.d_model                # q, k, v, proj
    ff   = 3 * cfg.d_model * int(8 * cfg.d_model / 3)   # gate, up, down
    per_layer = attn + ff
    total = emb + cfg.n_layer * per_layer
    print(f"embedding  {emb/1e6:.1f}M")
    print(f"per layer  {per_layer/1e6:.1f}M  x {cfg.n_layer}")
    print(f"TOTAL      {total/1e6:.1f}M")
    return total

count(Config())     # ~ 14M parameters
सावधान रहें
किसी छोटे मॉडल के लिए एम्बेडिंग टेबल अक्सर सबसे बड़ा हिस्सा होती है। अगर आपके 14M-पैरामीटर वाले मॉडल में 3M पैरामीटर्स सिर्फ एम्बेडिंग के हैं, तो वोकैबुलरी को छोटा करना कैपेसिटी बढ़ाने का सबसे आसान और किफ़ायती तरीक़ा है।

जब आप इसे चलाएंगे तो क्या उम्मीद करें

ट्रेनिंग का समयLossयह क्या बनाता है
30 सेकंड~5.5उल्टे-सीधे कैरेक्टर्स
2 मिनट~3.0शब्दों जैसा दिखने वाला बिना सिर-पैर का टेक्स्ट, जिसमें सही स्पेसिंग हो
10 मिनट~2.0असली शब्द, लेकिन टूटी-फूटी ग्रामर
1 घंटा~1.5धाराप्रवाह लगने वाले वाक्य, जिनका कोई मतलब नहीं होता
रात भर में, छोटे डेटासेट पर~1.2रटना (याद करना) — चेक करें कि कहीं ओवरफ़िटिंग तो नहीं हो रही
यह करें
इस पूरे ट्रैक में अपनी आँखों से देखने के लिए यह बदलाव सबसे कीमती चीज़ है। बीस मिनट के अंदर बकवास टेक्स्ट को ग्रामर में बदलते देखना इन सिस्टम्स के बारे में आपकी सोच को हमेशा के लिए बदल देता है। गाइड की कोई और चीज़ इसकी जगह नहीं ले सकती।

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

Let's reproduce GPT-2 (124M)Andrej Karpathy · 4 hr · video
Let's build GPT: from scratchAndrej Karpathy · video

लैब

आपके द्वारा खुद ट्रेन किया गया एक लैंग्वेज मॉडल, जो असली शब्द बना रहा है।

~45 min

समस्या

Module 41 के TinyGPT को कुछ MB टेक्स्ट पर ट्रेन करें। हर 200 स्टेप्स पर इससे सैंपल लें और हर सैंपल को संभाल कर रखें। देखें कि कैसे बकवास टेक्स्ट शब्दों में और फिर ग्रामर में बदलता है। इसके बाद loss और सैंपल क्वालिटी का ग्राफ़ बनाएं।
शुरुआती कोडpython
if step % 200 == 0:
    ctx = torch.zeros((1,1), dtype=torch.long, device=device)
    print(f"--- step {step} loss {loss.item():.3f} ---")
    print(decode(model.generate(ctx, max_new=120)[0].tolist()))
Google Colab खोलें ↗इस कोड के लिए आपके अपने सेटअप की ज़रूरत है (एक मॉडल, एक GPU या अतिरिक्त पैकेज)। इसे Google Colab में चलाएं: File → Upload notebook।

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

कठिन सवाल

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

Q1आपका ट्रेनिंग loss लगातार गिर रहा है लेकिन सैंपल्स में सुधार होना बंद हो गया है। इसके दो सबसे संभावित कारण बताएं और यह भी बताएं कि दोनों में फ़र्क कैसे पहचानें।दिखाएं
रटना (Memorisation): मॉडल भाषा सीखने के बजाय आपके छोटे डेटा को याद कर रहा है — ट्रेनिंग और वैलिडेशन loss की तुलना करके इसे चेक करें; दोनों के बीच बढ़ता अंतर इसकी पुष्टि करता है। या फिर आप गलत तरीक़े से सैंपलिंग कर रहे हैं: किसी छोटे मॉडल पर ग्रीडी डीकोडिंग करने से क्वालिटी चाहे जो भी हो, बार-बार दोहराया जाने वाला टेक्स्ट ही बनता है — टेम्परेचर और top-k को बदलकर इसे चेक करें। पहली समस्या के लिए ज़्यादा या बेहतर डेटा की ज़रूरत होती है; दूसरी समस्या में ट्रेनिंग में किसी बदलाव की ज़रूरत नहीं होती, इसलिए आप सबसे पहले इसे ही चेक करते हैं।

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

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

मुझे कौन सा डेटासेट इस्तेमाल करना चाहिए?

कुछ मेगाबाइट की एक सिंगल टेक्स्ट फ़ाइल से शुरुआत करें — पब्लिक-डोमेन किताबों का कलेक्शन अच्छा काम करता है। इतना छोटा कि मिनटों में बदलाव करके देखा जा सके, और इतना बड़ा कि मॉडल इसे आसानी से सिर्फ रट न ले। इसके बाद TinyStories या किसी छोटे वेब-टेक्स्ट सैंपल जैसी चीज़ पर बढ़ें।

मेरा loss 10 के आसपास क्यों अटका हुआ है?

यह लगभग हमेशा मॉडल बग के बजाय डेटा या शेप का बग होता है। चेक करें कि टारगेट्स ठीक एक कदम आगे खिसके (shifted) हैं या नहीं, कहीं आप गलती से पैडिंग को टारगेट्स के रूप में तो नहीं भेज रहे हैं, और आपके टोकन ids वोकैबुलरी की रेंज के अंदर हैं या नहीं।

क्या मैं इसे लैपटॉप पर चला सकता हूँ?

हाँ, इस साइज़ पर चला सकते हैं। Apple Silicon (MPS बैकएंड के ज़रिए) या सादा CPU एक छोटी फ़ाइल पर 14M कॉन्फ़िगरेशन को कुछ ही मिनटों में ट्रेन कर देगा। अगर मेमोरी कम पड़ रही हो तो block_size कम कर दें।

यह GPT-2 से कैसे अलग है?

स्केल में, और कुछ सुधारों में। GPT-2 स्मॉल में 124M पैरामीटर्स, 12 लेयर्स, d_model 768, कॉन्टेक्स्ट 1024 हैं, और इसे 40 GB टेक्स्ट पर ट्रेन किया गया था। यह वही आर्किटेक्चर है जिसमें नंबर्स को कम किया गया है और RMSNorm व SwiGLU को जोड़ा गया है।

पाठ का टेस्ट

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

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