सामग्री पर जाएँ
8/30अध्याय 8 / 30

Next-token prediction: embedding और perplexity का अर्थ

32,033 नामों पर character model train करें और देखें gradient descent counts तालिका को फिर खोजता है—फिर क्यों perplexity मिलती नहीं।

इस पेज पर

यहाँ दस नाम हैं, जिन्हें एक ऐसे program ने बनाया है जिसने कभी कोई शब्द नहीं देखा:

TEXT
cexze   momakurailezitynn   konimittain   llayn   ka
da      moliellavo          emia          sade    ftlsp

इनमें से कोई भी नाम नहीं है। लगभग सभी कोशिश कर रहे हैं। वे उच्चारण योग्य हैं, वे वहीं खत्म होते हैं जहाँ नाम खत्म होते हैं, और उनमें से एक — emia — किसी असली नाम से केवल एक अक्षर दूर है। इन्हें बनाने वाले program में 729 संख्याएँ हैं, उसे शब्द, syllable या व्यक्ति की कोई समझ नहीं है, और उसे अक्षरों के आस-पास आने वाले जोड़ों की counting के एक ही pass से fit किया गया था।

इस chapter के अंत तक एक neural network उसी माप पर उस program के score को एक-तिहाई घटा चुका होगा। असल में रुकने लायक हिस्सा यह है कि network सबसे पहले क्या करता है: वह बिना कहे हर अच्छी तरह populated row पर count table को तीन decimal places तक reproduce करता है, क्योंकि ये दोनों objects एक ही सवाल के जवाब हैं। उसके बाद की हर चीज़ वह है जो counting कभी नहीं कर सकती थी।

अध्याय 7 ने आपको integers की एक sequence दी थी और यह बताने की कोई वजह नहीं दी थी कि एक के बाद दूसरा क्यों आए। वजह यहाँ है, और यह अध्याय 2 की एक line है।

एक language model वह function है जो अब तक के tokens लेता है और लौटाता है कि अगला token कौन-सा आएगा, इसकी एक distribution: vocabulary की हर entry के लिए एक number, non-negative, कुल मिलाकर एक। और कुछ नहीं। इससे पूरे document की probability तक जाने के लिए probability का chain rule लगाएँ:

P(x1,x2,,xT)=t=1TP(xtx1,,xt1)P(x_1, x_2, \ldots, x_T) = \prod_{t=1}^{T} P(x_t \mid x_1, \ldots, x_{t-1})

यह एक identity है, किसी भी चीज़ की किसी भी sequence के लिए सच, बिना किसी assumption के। इसलिए जो model छोटा काम करता है — पिछले tokens को देखते हुए अगला token — वह पहले ही हर संभव document को probability assign करने का बड़ा काम ठीक-ठीक और मुफ्त में कर चुका है। इसे cheap trick की तरह पेश करने वाली लोकप्रिय framing ("यह तो बस अगले शब्द की prediction करता है") logic को उल्टा समझती है: अगले token की prediction करना ही joint distribution को model करना है। करने के लिए कभी कोई दूसरी चीज़ थी ही नहीं।

Loss भी उतनी ही mechanical तरह से आता है। हर position पर model एक distribution qq बनाता है और सच एक ज्ञात token है, इसलिए अध्याय 4 की cross-entropy बिना बदले लागू होती है:

L=1Tt=1Tlogqθ(xtx<t)L = -\frac{1}{T}\sum_{t=1}^{T} \log q_\theta(x_t \mid x_{<t})

यह average negative log-likelihood है — अध्याय 2 की recipe, बस Gaussian की जगह categorical distribution रखी हुई। और चूँकि true distribution one-hot है, उसकी entropy zero है, इसलिए अध्याय 4 की identity के अनुसार cross-entropy KL divergence के बराबर है: इस number को नीचे धकेलना और model की beliefs को data की तरफ खींचना एक ही काम है।

एक consequence अपनी अलग sentence deserve करता है, क्योंकि पूरी field के नीचे यही economic fact है। Labels वही data हैं, बस एक position shift किए हुए। कोई भी किसी चीज़ को annotate नहीं करता। Text के एक trillion tokens, पहले से labelled एक trillion examples हैं; इसलिए modern model का training corpus "the internet" होता है, "किसी ने बनाया हुआ dataset" नहीं।

किसी भी network से पहले, baseline: 32,033 नाम, हर line में एक, और काम है उन्हें एक-एक अक्षर करके और बनाना।1

Vocabulary 26 letters और एक boundary symbol . है, जो name की शुरुआत और अंत दोनों को mark करता है, इसलिए model को सीखना पड़ता है कि names कहाँ शुरू होते हैं और कहाँ रुकते हैं। यह 27 symbols हुए, और सबसे छोटा possible model एक table है कि हर symbol के बाद हर दूसरे symbol कितनी बार आया।

bigram.pyPYTHON
N = torch.zeros((27, 27), dtype=torch.int32)
for w in words:
    cs = ["."] + list(w) + ["."]
    for a, b in zip(cs, cs[1:]):
        N[stoi[a], stoi[b]] += 1

P = N.float()
P = P / P.sum(1, keepdim=True)            # one distribution per row   

Arithmetic की दो lines और model fit हो गया — और यह heuristic नहीं है: counts को row totals से divide करना categorical distribution का maximum-likelihood estimate है, यानी अध्याय 2 की recipe जिसमें calculus पहले ही किया जा चुका है।

TEXT
names: 32033        train/val/test: 25626 / 3203 / 3204
training bigrams: 182583

the six most likely letters after 'a':
    a -> '.'  0.1944   a -> 'n'  0.1600   a -> 'r'  0.0967
    a -> 'l'  0.0749   a -> 'h'  0.0690   a -> 'y'  0.0606

इससे sample करें — current letter की row से एक letter चुनें, उस row पर जाएँ, boundary symbol आने तक दोहराएँ — और आपको इस chapter के ऊपर वाले names मिलते हैं। वे एक खास और informative तरीके से fail करते हैं: locally plausible, globally nonsense। momakurailezitynn में अक्षरों का हर adjacent pair ऐसा pair है जो real names में आता है; बस ऐसे सत्रह pair लगातार आ गए हैं। Model के पास एक अक्षर की memory है, इसलिए उसे पता नहीं चल सकता कि वह बहुत लंबा चलता जा रहा है।

Held-out names पर loss 2.4546 nats है। यह number अपने आप में कुछ नहीं बताता, इसलिए perplexity मौजूद है:

PPL=exp ⁣(1Ttlogq(xtx<t))=eL\mathrm{PPL} = \exp\!\left(-\frac{1}{T}\sum_t \log q(x_t \mid x_{<t})\right) = e^{L}

बिना किसी library से काम कराए, इसे पूरा लिखें:

perplexity.pyPYTHON
@torch.no_grad()
def perplexity(logits, Y):
    logp = F.log_softmax(logits, dim=1)          # log q for every symbol
    chosen = logp[torch.arange(len(Y)), Y]       # log q of the one that came next   
    return torch.exp(-chosen.mean())             

Exponentiating logarithm को undo करता है और number को चीज़ें गिनने की units में लौटा देता है। यह क्या count करता है, इसका साफ तरीका है एक ऐसे model को measure करना जो कुछ भी नहीं जानता — जो context की परवाह किए बिना हर symbol को probability 1/271/27 देता है:

TEXT
uniform over 27 symbols            loss 3.2958 nats   ppl  27.000
bigram counts, add-one smoothed    loss 2.4546 nats   ppl  11.642

ठीक 27.000, क्योंकि elog27=27e^{\log 27} = 27Perplexity उन equally likely options की effective संख्या है जिनमें से model चुन रहा है। 27 की perplexity का मतलब है "कुछ पता नहीं, कुछ भी हो सकता है"। Count model की 11.642 का मतलब है कि एक अक्षर का context उसे इतना uncertain छोड़ता है जैसे कोई व्यक्ति सत्ताईस की बजाय लगभग बारह options में से अंधाधुंध चुन रहा हो — इसलिए perplexity quote की जाती है और raw loss नहीं।

इसके साथ दो चीज़ें गलत होती हैं, और दूसरी published papers में भी गलत होती है।

Zero probabilities घातक हैं। Table की 729 cells में से 113 training में कभी नहीं आतीं — इसका 15.5 % खाली है। यह तब तक ठीक है जब तक held-out set उनमें से किसी में land नहीं करता, और validation में सात bigrams ऐसा करते हैं, उनमें dq, zj और qo दो बार शामिल हैं। Probability zero का मतलब log -\infty है, जिसका मतलब infinite loss और infinite perplexity: तीन हजार में एक नाम metric को destroy कर देता है। सामान्य patch है normalise करने से पहले हर count में 1 जोड़ देना, जिसकी यहाँ लगभग कोई cost नहीं है (2.4524 की जगह 2.4546)। लेकिन patch एक confession है। Count model बिल्कुल generalise नहीं कर सकता। उसके पास यह शक करने का कोई तरीका नहीं कि qo plausible है क्योंकि qu common है और o कहीं और u की तरह behave करता है, क्योंकि उसे यह notion ही नहीं कि दो symbols एक-दूसरे से resemble कर सकते हैं। हर cell अकेले सीखी जाती है, और इसे ठीक करना ही इस chapter का बाकी काम है।

Perplexity प्रति token कीमत है, और token एक free parameter है। यह वही गलती है जो models compare करते समय लगातार दिखती है, और एक बार देखने पर समझना आसान है। अध्याय 7 से English prose का वही corpus लें, वही interpolated bigram model लें, और केवल यह बदलें कि text को कैसे काटा गया है:

unitvocabularytest में tokenscross-entropyperplexitybits per character
characters7614,4692.521712.453.6378
BPE, 512 merges3296,8713.854747.212.6407
BPE, 2,048 merges1,8204,2335.7468313.202.4254
words2,9916,2843.562735.262.2322

इन rows में perplexity 25 के factor से बदलती है। Model के बारे में कुछ नहीं बदला; केवल predicted की जाने वाली चीज़ का size बदला। पूरे word की prediction करना letter की prediction से कठिन है, इसलिए हर prediction की cost ज्यादा है — और predictions कम करनी पड़ती हैं।

अब आखिरी column पढ़ें, जो कुल cost को characters की संख्या से divide करता है और उसे bits में convert करता है। यह table का order बदल देता है। Perplexity के हिसाब से ranking है characters, words, BPE-512, BPE-2048; bits per character के हिसाब से है words, BPE-2048, BPE-512, characters। Character model first place से last पर चला जाता है। 2,048-merge model, जो perplexity से 512-merge वाले से 6.6 गुना खराब दिखता है, असल में दोनों में बेहतर है: 2.6407 के मुकाबले 2.4254 bits।

इसलिए perplexity केवल उन दो models के बीच comparable है जो tokenizer share करते हैं, और अलग tokenizers वाले models को केवल bits per character में compare किया जा सकता है — वही quantity जिसे Shannon ने 1951 में human subjects से English text का अगला letter guess कराकर measure किया था, और जिसे roughly one bit per character पर bound किया था।2 हमारा best bigram 2.23 bits पर बैठता है, जो fair summary है कि इस chapter को अभी कितना आगे जाना है।

अब उसी model को network की तरह बनाएँ। उसे उसी जगह तक पहुँचने में orders of magnitude ज्यादा arithmetic लगेगा, और उसी जगह पहुँचना ही point है।

Table को shape 27×2727 \times 27 की एक weight matrix WW से replace करें। Current letter को one-hot vector में बदलें, multiply करें, और result को logits कहें — अध्याय 4 के unnormalised scores। फिर softmax, फिर cross-entropy, फिर gradient descent।

neural_bigram.pyPYTHON
W = torch.randn((27, 27), requires_grad=True)

for step in range(3000):
    logits = W[xs]                            
    loss = F.cross_entropy(logits, ys)
    W.grad = None
    loss.backward()
    W.data -= 50.0 * W.grad

Highlighted line में एक definition है जिसे याद रखना चाहिए। One-hot vector को matrix से multiply करना उसकी एक row select करता है, इसलिए multiply एक lookup है — और हर implementation arithmetic skip करके lookup सीधे करती है, जो W[xs] है।

यही embedding table है। Vocabulary entry प्रति एक row वाली matrix, जिसे token id से index किया जाता है। कोई geometry नहीं, कोई semantics नहीं, कोई अलग algorithm नहीं: एक lookup table जिसकी contents बाकी सबके साथ gradient descent से सीखी जाती हैं। "embedding space" के बारे में हर mystical claim की जड़ यहीं है।

इसे train करें और देखें यह कहाँ जाता है:

TEXT
  step     1   train 3.7550   val 3.3882   max gap to the count table 0.757269
  step   100   train 2.4732   val 2.4726   max gap to the count table 0.388354
  step  1000   train 2.4557   val 2.4549   max gap to the count table 0.041862
  step  3000   train 2.4547   val 2.4544   max gap to the count table 0.004048

आखिरी column softmax(W) की किसी भी cell और count table की matching cell के बीच सबसे बड़ा absolute difference है, और यह zero की तरफ जाता है। 3,000 steps के बाद 729 cells में कहीं भी सबसे बड़ा disagreement 0.004048 है और mean 0.000224। सबसे खराब cell qi है, जो पूरे training set में बारह बार दिखी; 1,000 से ज्यादा occurrences वाली 22 rows में सबसे खराब disagreement 0.000562 है।

TEXT
                 count table   network
    a -> '.'        0.1945     0.1945
    a -> 'n'        0.1601     0.1601
    a -> 'r'        0.0967     0.0967

Gradient descent ने, random numbers से शुरू करके और सिर्फ "अगले letter की log-probability बड़ी करो" सुनकर, counts की table फिर से खोज निकाली। और उसे ऐसा करना ही था: counts maximum-likelihood estimate हैं, cross-entropy negative log-likelihood है, इसलिए दोनों procedures वही objective optimise करती हैं और उस objective का एक optimum है। Network ने counting जैसा कुछ नहीं सीखा। वह धीरे-धीरे counting तक converge हुआ।

इससे यह fair सवाल उठता है कि कोई bother क्यों करे। क्योंकि count table यहाँ से आगे कहीं नहीं जा सकती, और network जा सकता है।

Model को एक से ज्यादा previous character देखने तक extend करें। यह Bengio की 2003 architecture है, इस course में आगे आने वाले हर model की direct ancestor:4 आखिरी तीन characters लें, हर एक को embedding table से 10-dimensional row में map करें, rows को concatenate करके 30 numbers बनाएँ, उन्हें अध्याय 5 की hidden layer से push करें, और output layer से finish करें जो vocabulary entry प्रति एक logit produce करती है।

mlp.pyPYTHON
C  = torch.randn((27, 10))          # the embedding table
W1 = torch.randn((3 * 10, 200))     # the hidden layer from Chapter 5
W2 = torch.randn((200, 27))         # one output per vocabulary entry

emb = C[X].view(-1, 30)             # three lookups, concatenated   
h = torch.tanh(emb @ W1 + b1)
logits = h @ W2 + b2                
loss = F.cross_entropy(logits, Y)

ध्यान दें कि नया क्या है और क्या नहीं। Hidden layer अध्याय 5 की है, unchanged; loss अध्याय 4 का है, unchanged। नई चीज़ें हैं सामने embedding table और output layer जो अध्याय 7 की vocabulary जितनी wide है — और यह दूसरी चीज़ अब तक बने हर language model का expensive part है, क्योंकि real vocabulary में 100,000 entries होती हैं और यह matrix multiply हर position पर चलता है।

वही code, identically trained, केवल context window का size बदलकर:

contextparametersvalidation lossvalidation perplexity
counting, 1 character7292.454611.642
neural, 1 character7,8972.457711.678
neural, 3 characters11,8972.11458.285
neural, 8 characters21,8972.05067.773

दूसरी row interesting है। 200-unit hidden layer और count table से ग्यारह गुना ज्यादा parameters वाला network count table जितना ही अच्छा perform करता है और उससे बेहतर नहीं। Limitation कभी capacity थी ही नहीं। एक character का context एक निश्चित loss allow करता है और आप जो भी bolt on करें, उससे नीचे नहीं जा सकते, क्योंकि information वहाँ है ही नहीं।

उसे तीन characters दें और perplexity 11.68 से 8.29 तक गिरती है — 29 % की cut, 4,000 extra parameters की कीमत पर। यह यहाँ counting को ठीक उसी कारण से beat करता है जिसकी diagnosis पहले की गई थी: तीन-character contexts पर count model को 273=19,68327^3 = 19{,}683 rows चाहिए, जिनमें से ज्यादातर empty होंगी या single observation रखती होंगी, और वह हर एक को अकेले सीखता है। Network share करता है। अगर a, e और i की embedding rows similar हो जाती हैं, तो bra के बाद जो वह सीखता है वह bre में transfer हो जाता है, भले उसने bre कभी न देखा हो। यही transfer embedding table की पूरी value है, और यही rows two और three के बीच का gap है।

Samples उसी अनुसार improve होते हैं:

TEXT
deliah   nellara   joce     kael      quintis
salayson  reety    khyrmin  mahnen    madiaryxia

अब भी real names की list नहीं। लेकिन deliah, nellara और kael ऐसी list में अजीब नहीं लगेंगे, और run-on monsters गायब हैं: count model के बीस samples में सबसे लंबा nineteen letters है, इस वाले के बीस samples में सबसे लंबा thirteen।

Table 27×1027 \times 10 है: हर character के लिए दस numbers की एक row, सभी randomly initialise हुए और केवल next-character loss के gradient से move किए गए। किसी ने उसमें कुछ नहीं डाला। तो उसमें आखिर आया क्या?

पूछने का tool है cosine similarity, जो अध्याय 1 का dot product है जिसमें lengths divide कर दी गई हैं:

cos(a,b)=abab\cos(\mathbf{a}, \mathbf{b}) = \frac{\mathbf{a} \cdot \mathbf{b}}{\lVert \mathbf{a} \rVert \, \lVert \mathbf{b} \rVert}

यह दो vectors के बीच का angle measure करता है और उनकी lengths ignore करता है, जो आप तब चाहते हैं जब किसी row की length यह reflect करती है कि उसका token कितनी बार आया, न कि उसका मतलब क्या है। पहले हर vector को length 1 पर normalise करें — जैसा real systems indexing time पर एक बार करते हैं — और cosine similarity बस dot product है।

Trained table में कुछ characters के nearest neighbours यहाँ हैं:

TEXT
  'c' -> 'k':+0.598      'j' -> 'z':+0.650      'i' -> 'y':+0.541
  'u' -> 'e':+0.482      'a' -> 'h':+0.367      '.' -> 'q':+0.077

इसमें से कुछ वही है जिसका folklore वादा करता है। c और k names में interchangeable हैं, और i तथा y भी; j और z दोनों rare, mostly-initial consonants हैं जो एक जैसे behave करते हैं। Boundary symbol . किसी चीज़ के पास नहीं है — अपने closest letter से 0.077 — क्योंकि वह अकेला symbol है जो sound की बजाय position mark करता है।

और कुछ वैसा नहीं है। a का nearest neighbour कोई दूसरा vowel नहीं बल्कि h है। सभी pairs पर average करने पर:

TEXT
mean cosine, vowel to vowel         : +0.1889
mean cosine, consonant to consonant : +0.0765
mean cosine, vowel to consonant     : -0.0042

Vowels एक-दूसरे से consonants की तुलना में ज्यादा मिलते-जुलते हैं, और effect real है लेकिन छोटा। पाँच letters के 2,000 randomly chosen groups के against test करने पर उनमें से 58 groups कम-से-कम इतनी cleanly separate होते हैं — लगभग p=0.03p = 0.03 पर significant gap। यानी real, लेकिन embeddings के popular accounts में implied crisp geometric island जैसा बिल्कुल नहीं।

Embedding table का honest description यही है और course के बाकी हिस्से के लिए इसे याद रखना worth है। यह meaning का map नहीं है। यह coordinates का change है, design किया हुआ नहीं बल्कि learned, जिसका एकमात्र काम अगली layer का काम आसान बनाना है — वही sentence जो अध्याय 5 ने उस hidden layer के लिए इस्तेमाल किया था जिसने XOR solve करने के लिए plane को fold किया था। इसमें जो भी structure आपको दिखता है, वह इसलिए है क्योंकि उसने loss कम किया; और जो structure loss कम नहीं करता, वह बस मौजूद नहीं है।

word2vec, GloVe, और वह arithmetic जिसे सब quote करते हैं

सेक्शन का लिंक: word2vec, GloVe, और वह arithmetic जिसे सब quote करते हैं

अगर useful हिस्सा table है, तो आप सीधे उसी के पीछे जा सकते हैं। यही word2vec है: embedding lookup रखें, language model फेंक दें।5

skip-gram with negative sampling objective एक line है। Corpus से लिए गए real (centre, context) pair के लिए उनका dot product ऊपर push करें; noise distribution से लिए गए kk fake pairs के लिए उसे नीचे push करें:6

logσ(vcvo)+i=1klogσ(vcvni)\log \sigma(\mathbf{v}_c \cdot \mathbf{v}_o) + \sum_{i=1}^{k} \log \sigma(-\mathbf{v}_c \cdot \mathbf{v}_{n_i})

यह binary classification है — "क्या ये दो words सच में साथ आए थे?" — और यह सस्ता ठीक इसलिए है क्योंकि यह full vocabulary को कभी touch नहीं करता, जिसने 2013 में billions of words पर training practical बनाई। GloVe दूसरी दिशा से similar vectors तक पहुँचता है, examples stream करने के बजाय global co-occurrence counts की matrix factorise करके।7 दोनों ठीक उसी statistic पर fit होते हैं जिससे count table बनी थी। वे counting हैं, compressed।

text8 पर trained — English Wikipedia के 17,005,207 words, जिनमें 71,290 कम-से-कम पाँच बार आए, 100 dimensions, तीन passes — vectors उस property के साथ निकलते हैं जिसने उन्हें famous बनाया:

TEXT
king     -> charles 0.700, son 0.693, queen 0.686, henry 0.669, throne 0.667
physics  -> chemistry 0.672, electromagnetism 0.661, quantum 0.654, theoretical 0.624
guitar   -> bass 0.733, vocals 0.732, acoustic 0.728, guitars 0.703, drums 0.685
three    -> seven 0.892, two 0.877, one 0.875, five 0.871, four 0.870

किसी ने instruments या numerals के लिए category supply नहीं की। अब famous हिस्सा: king लें, man घटाएँ, woman जोड़ें, और result के nearest vector को खोजें।

TEXT
king - man + woman
   nothing excluded : king 0.693, elizabeth 0.657, wife 0.629, woman 0.607
   a, b, c excluded : elizabeth 0.657, wife 0.629, mary 0.607   (queen is 4th, 0.604)

king - man + woman का nearest vector king है। यह एक example की quirk नहीं है। Mikolov का evaluation set a : b :: c : ? form के questions रखता है — 8,869 semantic वाले (paris : france :: rome : italy) और 10,675 syntactic वाले (walking : walked :: swimming : swam) — और यह vocabulary जिन 4,103 semantic questions का answer दे सकती है, उनमें winner तीन input words में से एक 99.8 % of the time होता है। Published demonstrations इसका ज़िक्र नहीं करते, क्योंकि standard scoring rule देखने से पहले a, b और c को delete कर देता है। यह legitimate rule है, और arithmetic से ज्यादा काम वही कर रहा है:

answer कैसे चुना गयाsemanticsyntactic
offset, inputs excluded के साथ (standard)17.0 %11.9 %
offset, कुछ भी excluded नहीं0.1 %0.4 %
अकेले c का nearest neighbour, inputs excluded13.1 %9.3 %
अकेले b का nearest neighbour, inputs excluded2.3 %0.4 %

तीसरी row पर ठहरना चाहिए। a और b फेंक दें, कोई arithmetic न करें, c के nearest को return कर दें — और आप semantic score का 77 % रख लेते हैं। Analogical reasoning जैसा जो दिखता है उसका अधिकांश proximity plus एक rule है जो obvious answers को forbid करता है, यही Linzen ने properly trained vectors पर measure किया था और ऊपर के baselines ने replicate किया।8 ये particular vectors छोटे हैं — published models के पीछे के billions की तुलना में 17 million words — इसलिए percentages को shape की तरह पढ़ें, state of the art की तरह नहीं। Shape हर scale पर survive करती है: arithmetic real है, और उस एक demonstration से बहुत कमजोर है जिसे सब quote करते हैं।

Static और contextual: हर word के लिए एक vector, या हर occurrence के लिए एक

सेक्शन का लिंक: Static और contextual: हर word के लिए एक vector, या हर occurrence के लिए एक

अब तक की हर चीज़ में data structure के अंदर एक hard limit बनी हुई है। Table में हर token के लिए एक row होती है। Word bank को एक vector मिलता है, river वाली sentence में भी वही और mortgage वाली sentence में भी वही — necessarily, क्योंकि id से lookup किसी और चीज़ पर depend नहीं कर सकता।

Fix है table से vector पढ़ना बंद करना और sentence से उसे compute करना शुरू करना। यही contextual embedding है, जिसे 2018 में ELMo ने introduce किया और उसी साल BERT ने standard बना दिया।910 Real model पर measured, numbers explanation से ज्यादा sharp हैं:

TEXT
sentence A: "He sat on the bank of the river and watched the water go by."
sentence B: "She deposited the cheque at the bank on the corner of the street."

static vector for 'bank' (a row of the input embedding table)
    cosine A vs B ........................ 1.000000

contextual vector for 'bank', layer by layer
    layer  |  A vs B  |  A vs another river sentence  |  B vs another money sentence
        0  |  0.9512  |            0.9512             |            0.9359
        4  |  0.5647  |            0.8987             |            0.7716
        9  |  0.4284  |            0.8699             |            0.7568
       12  |  0.5278  |            0.8702             |            0.7335

पहली row exact है, approximate नहीं: bank का static vector दोनों sentences में वही 768 numbers है, इसलिए cosine construction से 1 है। नौ layers बाद दोनों occurrences 0.43 पर बैठती हैं, जबकि दो अलग river sentences में bank 0.87 पर रहता है। इस process में किसी ने कहीं sense label नहीं किया; senses इसलिए अलग हुए क्योंकि उन्हें अलग करना training objective — neighbours से hidden token guess करना — satisfy करना आसान बनाता है।

दो details ध्यान deserve करती हैं। Layer 0 पहले से 1.0 की बजाय 0.9512 है, क्योंकि position embeddings जोड़ दी गई हैं और word हर sentence में अलग जगह बैठता है। और similarity layers 11 और 12 पर फिर बढ़ती है: pretrained model की final layers उसके training objective के लिए specialised होती हैं, और अक्सर representation लेने की best place नहीं होतीं।

विवरण दिखाएँ

Optional: weight tying.

bert-base-uncased में embedding table 30,522×76830{,}522 \times 768 है — 23,440,896 numbers, model के 109,482,240 parameters का 21.4 %। Small language model में fraction और भी बड़ा होता है, इसलिए एक trick लगभग universal है: input table और logits produce करने वाली output layer same matrix होती हैं, एक बार row lookup से और एक बार transposed इस्तेमाल होती हैं। Output layer पहले से हर vocabulary entry को एक vector assign करती है — वह हर एक के against dot product लेती है — और tying कहता है कि token को read करने में इस्तेमाल vector और उसे write करने में इस्तेमाल vector same object होना चाहिए। यह parameters काटता है और perplexity सुधारता है, दोनों एक साथ, जो notice करने लायक rare है।

Meaning से corpus search करने के लिए आपको प्रति sentence एक vector चाहिए। वे मिल जाएँ तो search trivial है — semantic retrieval का पूरा सार यही है, और अध्याय 19 इसके around की हर चीज़ के बारे में है:

search.pyPYTHON
E = normalise(embed(sentences))       # (200, d), every row of length 1
q = normalise(embed([query]))         # (1, d)
scores = q @ E.T                      # one matrix multiply   
top5 = scores[0].argsort()[::-1][:5]

इसलिए असल सवाल सिर्फ यह है कि embed कहाँ से आता है। Obvious move है pretrained language model लेना, हर sentence को उससे चलाना और token vectors को average करना। यहाँ वह method चार alternatives के against है, दो तरीकों से scored: STS benchmark के 1,379 pairs पर cosine और human similarity judgements के बीच rank correlation, और उन pairs में से 200 सबसे strongly paraphrased pairs से बने index पर top-1 retrieval — हर pair की एक side indexed, दूसरी query के रूप में।

sentence कैसे embedded हैrank correlation200-sentence index पर top-1
binary word overlap (कोई model नहीं)0.550089.0 %
ऊपर trained static vectors का mean0.526385.5 %
BERT, [CLS] token0.203067.0 %
BERT, token vectors का mean0.472984.0 %
MiniLM, contrastively trained0.820392.0 %

बीच की तीन rows को पहली दो के against पढ़ें। 109-million-parameter pretrained transformer, obvious तरीके से इस्तेमाल करने पर, sentence similarity judge करने में यह गिनने से भी खराब है कि दो sentences कितने words share करती हैं — और अभी-अभी trained 100-dimensional text8 vectors को average करने से भी खराब। [CLS] token, जिसे tutorials अब भी recommend करते हैं क्योंकि BERT को sentence-level objective attached करके pretrain किया गया था, उसका आधा भी नहीं।

यह BERT में defect नहीं है। यह objective है। Language model train होता है ताकि उसके hidden states token predict करें; वहाँ कुछ भी दो paraphrases को पास लाने को नहीं कहता, और ऐसी geometry को reward नहीं करता जिसमें cosine का मतलब "same meaning" हो। आखिरी row एक model है जो size में पाँचवाँ हिस्सा है (22,713,216 parameters) और पूरी तरह different loss पर trained है: contrastive learning, जहाँ examples pairs होते हैं — question और उसका answer, sentence और उसका paraphrase — और objective true pairs को साथ खींचता है और sampled negatives को दूर धकेलता है। यही Sentence-BERT का contribution है और पूरी embedding-model industry की origin।11 Dense Passage Retrieval सीधे search पर वही recipe apply करता है, queries के लिए एक encoder और passages के लिए एक।12

तो practical rule:

embedding model last layer हटाया हुआ language model नहीं है। यह अलग objective पर अलग model है, आमतौर पर बहुत छोटा, जिसका cosine वही मतलब रखता है जो आप चाहते हैं क्योंकि उसे ऐसे pairs पर train किया गया था जहाँ वही target था। ऊपर की table एक को दूसरे की जगह रखने की cost है।

और यह family word order पर fail करती है। "The dog bit the man" और "the man bit the dog" में words के identical bags हैं, इसलिए word overlap और static-vector average उन्हें exactly 1.000000 cosine देते हैं, और mean-pooled BERT, जो position देखता है, फिर भी लगभग वहीं पहुँचता है — और contrastively trained MiniLM भी उन्हें 0.979 पर रखता है। अगर आपकी retrieval task इस पर निर्भर है कि किसने किसके साथ क्या किया, तो कोई cosine threshold आपको नहीं बचाएगा।

अध्याय 19 इसी footing पर production retrieval system बनाता है और concrete cosine cut-off तक पहुँचता है। इस chapter की आखिरी measurement ही ऐसे number को magic की बजाय defensible बनाती है।

Real embeddings में सैकड़ों या हजारों components होते हैं, और वहाँ distances अजीब behave करते हैं। dd dimensions के unit cube में 1,000 random points लें और उनमें से किसी भी दो के बीच largest और smallest distance का ratio देखें:

dimensionsnearest pairfarthest pairratio
20.00071.36121921.66
100.23612.33979.91
1003.00475.17521.72
1,00011.780914.03061.19
10,00039.615242.01251.06

दस हजार dimensions में points की farthest pair closest pair से केवल 6 % ज्यादा दूर है। सब कुछ लगभग हर चीज़ से equidistant है, "nearest neighbour" बहुत information carry करना बंद कर देता है, और यही dimensionality का curse है — साथ ही यह एक वजह है कि large vector databases exact nearest-neighbour search नहीं करते। इसी सिक्के का दूसरा पहलू cosine thresholds को workable बनाता है: random unit vectors के हजार pairs पर measured, mean cosine 100 dimensions में 0.0052-0.0052 और 768 में +0.0003+0.0003 पर बैठता है, standard deviations 0.0968 और 0.0357 — और 768 dimensions में random pairs में केवल 0.2 % absolute value में 0.1 से ऊपर जाते हैं। इसलिए 0.4 की measured similarity "40 % alike" नहीं है; वह chance से बनने वाली किसी भी चीज़ से बहुत बाहर है, इसलिए 0.3 से 0.7 के बीच thresholds signal को noise से अलग करते हैं, उसके बीच में बैठते नहीं।

इस chapter का model previous characters की एक fixed संख्या पढ़ता है, हर एक को lookup करता है और results को order में glue कर देता है। इस design में दो problems हैं, और वे वही problem हैं।

Context table को फिर देखें: तीन characters से आठ पर जाने से parameters लगभग double हो गए और 0.06 nats मिले। Cost context के साथ linearly बढ़ती है — हर extra position को पहली weight matrix का अपना slab चाहिए — और benefit नहीं। इसे हजार tokens तक push करें और first layer अकेली model के बाकी हिस्से से भारी हो जाती है, जिसका अधिकांश हिस्सा उन positions पर खर्च होता है जो किसी given prediction के लिए matter नहीं करतीं।

दूसरी problem यही है: model के पास यह decide करने का कोई तरीका नहीं कि previous tokens में से कौन matter करते हैं। Position two को अपने weights मिलते हैं और position seven को अपने, permanently, उनमें जो भी हो। जब model nell spell कर रहा होता है, decisive character ठीक पहले वाला होता है। जब sentence में pronoun होता है, उसके referent को fix करने वाला word forty tokens पीछे हो सकता है — और कोई fixed slot "forty back" को assign नहीं किया जा सकता, क्योंकि अगली बार वह six होगा।

हमें ऐसा model चाहिए जो हर prediction के लिए compute करे कि हर earlier token कितना count करे — context पर weights जो layout से fixed नहीं बल्कि content से produced हों। इसे carefully लिखें और यह किसी पूरी तरह mundane चीज़ की तरह शुरू होता है: previous tokens का average। फिर उस average के weights को learned होने दें, और उन्हें इस पर depend करने दें कि कौन-सा token पूछ रहा है।

यही attention है, और यही अध्याय 9 है।


साथ में पढ़ने लायक: Jurafsky और Martin की Speech and Language Processing का chapter 3, जो n-gram models, smoothing और perplexity को यहाँ की जगह से कहीं ज्यादा careful तरीके से treat करता है, जिसमें यह भी शामिल है कि interpolation और back-off adding one से बेहतर क्यों हैं; probabilistic side से language modelling के लिए Stanford CS229 notes §17.1–17.2; और ऊपर का Linzen paper, जो छोटा है और पूरा पढ़ने लायक है।

  1. Name-generation example, dataset और count table से Bengio-style network तक progression Andrej Karpathy की building makemore series को follow करते हैं, जिसके पहले दो parts इस chapter के best companion हैं।

  2. Shannon, C. E. Prediction and Entropy of Printed English. Bell System Technical Journal 30(1), pp. 50–64 (1951). Human subjects द्वारा English का अगला letter guess करना, और original bits-per-character measurement।

  3. Shannon, C. E. A Mathematical Theory of Communication. Bell System Technical Journal 27 (1948). Source coding theorem, और prediction की compression से पहचान।

  4. Bengio, Y., Ducharme, R., Vincent, P. and Jauvin, C. A Neural Probabilistic Language Model. Journal of Machine Learning Research 3, pp. 1137–1155 (2003). ऊपर इस्तेमाल architecture: हर word के लिए एक embedding, fixed window पर concatenated, hidden layer से होकर vocabulary पर softmax तक।

  5. Mikolov, T., Chen, K., Corrado, G. and Dean, J. Efficient Estimation of Word Representations in Vector Space. arXiv:1301.3781 (2013). CBOW और skip-gram, और ऊपर इस्तेमाल analogy set।

  6. Mikolov, T., Sutskever, I., Chen, K., Corrado, G. and Dean, J. Distributed Representations of Words and Phrases and their Compositionality. arXiv:1310.4546 (2013). Negative sampling, frequent words का subsampling, और ऊपर इस्तेमाल 3/4 power पर उठाई गई noise distribution।

  7. Pennington, J., Socher, R. and Manning, C. GloVe: Global Vectors for Word Representation. EMNLP 2014. Streamed local windows के बजाय global co-occurrence matrix के factorisation से word vectors।

  8. Linzen, T. Issues in evaluating semantic spaces using word analogies. RepEval 2016, arXiv:1606.07736. ऊपर replicated offset-free baselines का source।

  9. Peters, M. et al. Deep contextualized word representations. arXiv:1802.05365 (2018). ELMo: हर occurrence के लिए एक vector, bidirectional language model से computed।

  10. Devlin, J., Chang, M.-W., Lee, K. and Toutanova, K. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. arXiv:1810.04805 (2018). bank experiment में measured model।

  11. Reimers, N. and Gurevych, I. Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. arXiv:1908.10084 (2019). इसकी opening measurement — sentence similarity पर mean-pooled BERT का averaged static vectors से worse perform करना — वही है जिसे ऊपर की table reproduce करती है।

  12. Karpukhin, V. et al. Dense Passage Retrieval for Open-Domain Question Answering. arXiv:2004.04906 (2020). Two-encoder retriever की contrastive training; अध्याय 19 के retrieval stack का direct ancestor।


निर्माता

David Vicente Campos

NeuraLIA Labs के संस्थापक और MyRealFood के सह-संस्थापक

मैं लेओन विश्वविद्यालय से कंप्यूटर इंजीनियर हूँ। मैंने MyRealFood की सह-स्थापना की, जहाँ CTO के रूप में मैंने वह ऐप बनाया जिसे लाखों लोग बेहतर खान-पान के लिए इस्तेमाल कर चुके हैं, और मैंने NeuraLIA Labs की स्थापना की, जहाँ मैं AI प्रोडक्ट्स बनाता हूँ। यहाँ मैं उन बातों के बारे में लिखता हूँ जो इस सफ़र में मुझे समझनी पड़ीं, उस तरह जिस तरह काश किसी ने मुझे समझाई होतीं।

लेखक के बारे में और जानें

NeuraLIA Labs द्वारा प्रकाशित।

नए पोस्ट अपने इनबॉक्स में पाएं

AI समाचार, गाइड और प्रोडक्ट अपडेट — जब भी हम कुछ उपयोगी प्रकाशित करें, एक छोटा ईमेल।

कोर्स सूची

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev13 मिनट पढ़ें

Jev AI मॉडल गद्य के लिए नहीं, निर्णयों के लिए बना है

TypeSafe AI का Jev ध्यान खींच रहा है क्योंकि यह सॉफ्टवेयर इंटेलिजेंस को संभावना की समस्या मानता है: सही शाखा चुनें, भरोसे का स्तर जोड़ें, और जब कोड को निर्णय चाहिए तो LLM से टेक्स्ट लिखवाने पर खर्च न करें।

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering14 मिनट पढ़ें

लॉन्ग-होराइजन AI एजेंट्स के लिए कॉन्टेक्स्ट इंजीनियरिंग

लंबे समय तक चलने वाले एजेंट सिर्फ इसलिए असफल नहीं होते कि विंडो छोटी है। वे तब असफल होते हैं जब फ़ाइलें, टूल आउटपुट और पुराना इतिहास उस काम को ही पीछे धकेल देते हैं जिसे एजेंट को पूरा करना था।

मॉडल चुनने का काम LIA पर छोड़ने के लिए तैयार हैं?

हर AI मॉडल एक ही जगह — आज ही मुफ़्त शुरू करें।