Next-token prediction: embedding och vad perplexity betyder
Träna en teckenmodell på 32 033 namn och se gradient descent återupptäcka en räknetabell – plus varför perplexity sällan matchar.
På den här sidan
Här är tio namn producerade av ett program som aldrig har sett ett ord:
cexze momakurailezitynn konimittain llayn ka
da moliellavo emia sade ftlspInget av dem är ett namn. Nästan alla försöker. De går att uttala, de slutar där namn brukar sluta, och ett av dem — emia — är en enda bokstav från ett riktigt namn. Programmet som skapade dem rymmer 729 tal, har ingen föreställning om ord, stavelser eller personer, och anpassades med en enda genomgång där intilliggande bokstavspar räknades.
I slutet av det här kapitlet kommer ett neuralt nätverk att ha sänkt programmets resultat med en tredjedel på samma mått. Det som gör det värt att stanna kvar är vad nätverket gör först: det återskapar räknetabellen med tre decimalers noggrannhet på varje välfylld rad, utan att bli ombett, eftersom de två objekten är svar på samma fråga. Allt därefter är sådant som räknande aldrig hade kunnat göra.
Målet är en identitet, inte ett designval
Länk till avsnittet: Målet är en identitet, inte ett designvalKapitel 7 lämnade dig med en sekvens av heltal och ingen anledning till att ett skulle följa på ett annat. Här är anledningen, och den är en rad från Kapitel 2.
En språkmodell är en funktion som tar hittillsvarande tokens och returnerar en fördelning över vilken token som kommer härnäst: ett tal per post i vokabulären, icke-negativt, med summa ett. Inget annat. För att gå från det till en sannolikhet för ett helt dokument använder man sannolikhetens kedjeregel:
Det är en identitet, sann för vilken sekvens av vad som helst, utan antaganden. Alltså har en modell som gör det lilla jobbet — nästa token givet de tidigare — redan gjort det stora jobbet att tilldela en sannolikhet till varje möjligt dokument, exakt och gratis. Den populära inramningen av detta som ett billigt trick (”den förutsäger bara nästa ord”) vänder logiken bak och fram: att förutsäga nästa token är att modellera den gemensamma fördelningen. Det fanns aldrig en andra sak att göra.
Förlusten följer lika mekaniskt. Vid varje position producerar modellen en fördelning och sanningen är en enda känd token, så Kapitel 4:s korsentropi gäller oförändrad:
Det är den genomsnittliga negativa log-likelihooden — Kapitel 2:s recept med en kategorisk fördelning på platsen där gaussfördelningen satt. Och eftersom den sanna fördelningen är one-hot är dess entropi noll, så enligt Kapitel 4:s identitet är korsentropin lika med KL-divergensen: att driva ned detta tal och dra modellens uppfattningar mot datans är samma handling.
En konsekvens förtjänar en egen mening, eftersom den är det ekonomiska faktumet under hela fältet. Etiketterna är datan, förskjuten ett steg. Ingen annoterar någonting. En biljon tokens text är en biljon färdigetiketterade exempel, vilket är varför träningskorpusen för en modern modell är ”internet” och inte ”en dataset som någon byggde”.
Den ärliga baslinjen: att räkna
Länk till avsnittet: Den ärliga baslinjen: att räknaFöre något nätverk, baslinjen: 32 033 namn, ett per rad, och uppgiften att producera fler av dem en bokstav i taget.1
Vokabulären är 26 bokstäver plus en gränssymbol . som markerar både början och slutet på ett namn, så modellen måste lära sig var namn börjar och var de slutar. Det är 27 symboler, och den minsta möjliga modellen är en tabell över hur ofta varje symbol följde varje annan symbol.
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 Två rader aritmetik och modellen är anpassad — och den är inte en heuristik: att dela antal med radsummor är maximum-likelihood-skattningen för en kategorisk fördelning, vilket är Kapitel 2:s recept med kalkylen redan gjord.
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.0606Sampla från den — välj en bokstav från raden för den aktuella bokstaven, gå till den raden, upprepa tills gränssymbolen dyker upp — och du får namnen längst upp i kapitlet. De misslyckas på ett specifikt och informativt sätt: lokalt plausibla, globalt nonsens. Varje intilliggande bokstavspar i momakurailezitynn är ett par som förekommer i riktiga namn; det råkar bara vara sjutton sådana i rad. Modellen har en bokstavs minne, så den kan inte veta att den har hållit på för länge.
Perplexity, och hur du ska läsa det
Länk till avsnittet: Perplexity, och hur du ska läsa detFörlusten på undanhållna namn är 2,4546 nats. Det talet betyder ingenting på egen hand, och det är därför perplexity finns:
Utskrivet, utan att något bibliotek gör arbetet:
@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()) Exponentiering gör om logaritmen och återför talet till enheten att räkna saker. Det rena sättet att se vad den räknar är att mäta en modell som inte vet någonting alls — en som tilldelar sannolikheten till varje symbol oavsett sammanhang:
uniform over 27 symbols loss 3.2958 nats ppl 27.000
bigram counts, add-one smoothed loss 2.4546 nats ppl 11.642Exakt 27,000, eftersom . Perplexity är det effektiva antalet lika sannolika alternativ som modellen väljer mellan. En perplexity på 27 betyder ”ingen aning, det kan vara vad som helst”. Räknemodellens 11,642 betyder att en bokstavs context gör den lika osäker som någon som väljer blint mellan ungefär tolv alternativ i stället för tjugosju — vilket är varför perplexity citeras och den råa förlusten inte gör det.
Två saker går fel med den, och den andra går fel i publicerade artiklar.
Nollsannolikheter är ödesdigra. Av de 729 cellerna i tabellen förekommer 113 aldrig i träning — 15,5 % av den är tom. Det är fint tills den undanhållna uppsättningen hamnar i en sådan cell, och sju bigram i valideringen gör det, bland dem d→q, z→j och q→o två gånger. Sannolikhet noll betyder log , vilket betyder oändlig förlust och oändlig perplexity: ett namn på tre tusen förstör måttet. Den vanliga lagningslappen är att lägga till 1 till varje antal före normalisering, vilket nästan inte kostar något här (2,4546 i stället för 2,4524). Men lagningslappen är ett erkännande. En räknemodell kan inte generalisera alls. Den har inget sätt att ana att q→o är plausibelt eftersom q→u är vanligt och o beter sig som u på andra ställen, eftersom den inte har någon föreställning om att två symboler kan likna varandra. Varje cell lärs in ensam, och att fixa det är vad resten av kapitlet handlar om.
Perplexity är ett pris per token, och token är en fri parameter. Det här är misstaget som ständigt dyker upp när modeller jämförs, och det är lätt att se när man tittar. Ta samma korpus med engelsk prosa från Kapitel 7, samma interpolerade bigrammodell, och ändra bara hur texten skärs upp:
| enhet | vokabulär | tokens i test | korsentropi | perplexity | bitar per tecken |
|---|---|---|---|---|---|
| tecken | 76 | 14 469 | 2,5217 | 12,45 | 3,6378 |
| BPE, 512 sammanslagningar | 329 | 6 871 | 3,8547 | 47,21 | 2,6407 |
| BPE, 2 048 sammanslagningar | 1 820 | 4 233 | 5,7468 | 313,20 | 2,4254 |
| ord | 2 991 | 6 284 | 3,5627 | 35,26 | 2,2322 |
Perplexity varierar med en faktor 25 mellan de raderna. Inget med modellen ändrades; bara storleken på det som förutsägs. Att förutsäga ett helt ord är svårare än att förutsäga en bokstav, så det kostar mer per förutsägelse — och det finns färre förutsägelser att göra.
Läs nu den sista kolumnen, som i stället delar den totala kostnaden med antalet tecken och konverterar den till bitar. Den ordnar om tabellen. Med perplexity är rangordningen tecken, ord, BPE-512, BPE-2048; med bitar per tecken är den ord, BPE-2048, BPE-512, tecken. Teckenmodellen går från första plats till sista. Modellen med 2 048 sammanslagningar, som med perplexity ser 6,6 gånger sämre ut än modellen med 512 sammanslagningar, är i själva verket den bättre av de två med 2,4254 bitar mot 2,6407.
Alltså är en perplexity bara jämförbar mellan två modeller som delar tokenizer, och modeller med olika tokenizers kan bara jämföras i bitar per tecken — den storhet Shannon mätte 1951 genom att låta mänskliga försökspersoner gissa nästa bokstav i engelsk text, och begränsade till ungefär en bit per tecken.2 Vår bästa bigrammodell ligger på 2,23 bitar, vilket är en rättvis sammanfattning av hur långt det här kapitlet fortfarande har kvar.
Samma sak, inlärd
Länk till avsnittet: Samma sak, inlärdBygg nu samma modell som ett nätverk. Det kommer att kräva storleksordningar mer aritmetik för att komma till samma plats, och poängen är just att komma till samma plats.
Ersätt tabellen med en viktmatris med formen . Gör den aktuella bokstaven till en one-hot-vektor, multiplicera och kalla resultatet logits — de onormaliserade poängen från Kapitel 4. Sedan softmax, sedan korsentropi, sedan gradient descent.
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.gradDen markerade raden innehåller en definition värd att ha. Att multiplicera en one-hot-vektor med en matris väljer en rad i den, så multiplikationen är en uppslagning — och varje implementation hoppar över aritmetiken och gör uppslagningen direkt, vilket är vad W[xs] är.
Det är en embedding-tabell. En matris med en rad per post i vokabulären, indexerad med token-id. Ingen geometri, ingen semantik, ingen separat algoritm: en uppslagstabell vars innehåll råkar läras in av gradient descent tillsammans med allt annat. Varje mystiskt påstående om ”embedding space” bottnar här.
Träna den och se vart den går:
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.004048Den sista kolumnen är den största absoluta skillnaden mellan någon cell i softmax(W) och motsvarande cell i räknetabellen, och den går mot noll. Efter 3 000 steg är den största oenigheten någonstans i de 729 cellerna 0,004048 och medelvärdet är 0,000224. Den värsta cellen är q→i, sedd tolv gånger i hela träningsmängden; bland de 22 raderna med fler än tusen förekomster är den värsta oenigheten 0,000562.
count table network
a -> '.' 0.1945 0.1945
a -> 'n' 0.1601 0.1601
a -> 'r' 0.0967 0.0967Gradient descent, med start från slumpmässiga tal och utan att få veta något annat än ”gör log-sannolikheten för nästa bokstav stor”, återupptäckte räknetabellen. Och det var den tvungen att göra: antalen är maximum-likelihood-skattningen, korsentropi är den negativa log-likelihooden, så båda procedurerna optimerar samma mål och det målet har ett optimum. Nätverket lärde sig inte något som liknar räknande. Det konvergerade till räknande, långsamt.
Vilket väcker den rimliga frågan varför någon skulle bry sig. För att räknetabellen inte har någonstans att gå härifrån, och nätverket har det.
Context är flaskhalsen, inte kapaciteten
Länk till avsnittet: Context är flaskhalsen, inte kapacitetenUtöka modellen så att den tittar på mer än ett tidigare tecken. Det här är Bengios arkitektur från 2003, den direkta förfadern till varje modell i resten av kursen:4 ta de tre sista tecknen, mappa vart och ett genom en embedding-tabell till en 10-dimensionell rad, sammanfoga raderna till 30 tal, skjut dem genom det dolda lagret från Kapitel 5, och avsluta med ett output-lager som producerar en logit per post i vokabulären.
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)Notera vad som är nytt och vad som inte är det. Det dolda lagret är Kapitel 5:s, oförändrat; förlusten är Kapitel 4:s, oförändrad. Nyheterna är embedding-tabellen längst fram och ett output-lager lika brett som Kapitel 7:s vokabulär — och den andra delen är den dyra delen i varje språkmodell som någonsin byggts, eftersom en riktig vokabulär har 100 000 poster och denna matrismultiplikation körs vid varje position.
Samma kod, tränad identiskt, med bara storleken på context window ändrad:
| context | parametrar | valideringsförlust | valideringsperplexity |
|---|---|---|---|
| räknande, 1 tecken | 729 | 2,4546 | 11,642 |
| neural, 1 tecken | 7 897 | 2,4577 | 11,678 |
| neural, 3 tecken | 11 897 | 2,1145 | 8,285 |
| neural, 8 tecken | 21 897 | 2,0506 | 7,773 |
Den andra raden är den intressanta. Ett nätverk med ett dolt lager på 200 enheter och elva gånger så många parametrar som räknetabellen presterar exakt lika bra som räknetabellen och inte bättre. Kapaciteten var aldrig begränsningen. Ett teckens context tillåter en viss förlust och ingenting du skruvar på kan komma under den, eftersom informationen inte finns där.
Ge den tre tecken och perplexity faller från 11,68 till 8,29 — en minskning på 29 %, köpt med 4 000 extra parametrar. Den slår räknande här av precis den anledning som diagnosticerades tidigare: en räknemodell över treteckens-context behöver rader, de flesta tomma eller med en enda observation, och den lär in var och en för sig. Nätverket delar. Om a, e och i får liknande embedding-rader överförs det den lär sig efter bra till bre utan att den någonsin har sett bre. Den överföringen är hela värdet med embedding-tabellen, och den är gapet mellan rad två och tre.
Samplen förbättras därefter:
deliah nellara joce kael quintis
salayson reety khyrmin mahnen madiaryxiaFortfarande inte en lista med riktiga namn. Men deliah, nellara och kael skulle inte se malplacerade ut på en sådan, och de utdragna monstren är borta: det längsta av tjugo sampel från räknemodellen är nitton bokstäver, det längsta av tjugo från den här är tretton.
Vad som faktiskt finns i embedding-tabellen
Länk till avsnittet: Vad som faktiskt finns i embedding-tabellenTabellen är : en rad med tio tal per tecken, alla slumpmässigt initierade och flyttade endast av gradienten från nästa-tecken-förlusten. Ingen lade något där. Så vad hamnade i den?
Verktyget för att fråga är cosinuslikhet, vilket är skalärprodukten från Kapitel 1 med längderna bortdelade:
Den mäter vinkeln mellan två vektorer och ignorerar deras längder, vilket är vad du vill när en rads längd speglar hur ofta dess token förekom snarare än vad den betyder. Normalisera varje vektor till längd 1 först — som riktiga system gör, en gång, vid indexering — och cosinuslikhet är helt enkelt skalärprodukten.
Här är de närmaste grannarna till några tecken i den tränade tabellen:
'c' -> 'k':+0.598 'j' -> 'z':+0.650 'i' -> 'y':+0.541
'u' -> 'e':+0.482 'a' -> 'h':+0.367 '.' -> 'q':+0.077En del av det är vad folktron utlovar. c och k är utbytbara i namn, och det är även i och y; j och z är båda sällsynta, mestadels initiala konsonanter som beter sig lika. Gränssymbolen . ligger nära ingenting alls — 0,077 till sin närmaste bokstav — eftersom den är den enda symbolen som markerar en position snarare än ett ljud.
Och en del är det inte. Den närmaste grannen till a är h, inte en annan vokal. I genomsnitt över alla par:
mean cosine, vowel to vowel : +0.1889
mean cosine, consonant to consonant : +0.0765
mean cosine, vowel to consonant : -0.0042Vokalerna liknar varandra mer än de liknar konsonanter, och effekten är verklig men liten. Testat mot 2 000 slumpmässigt valda grupper om fem bokstäver är 58 av dessa grupper separerade minst lika rent — ett gap signifikant vid ungefär . Verkligt, alltså, men inget i närheten av den skarpa geometriska ö som populära beskrivningar av embeddings antyder.
Det är den ärliga beskrivningen av en embedding-tabell och den är värd att hålla fast vid under resten av kursen. Den är inte en karta över betydelse. Den är ett koordinatbyte, inlärt snarare än designat, vars enda jobb är att göra nästa lagers jobb lätt — samma mening som Kapitel 5 använde för det dolda lagret som vek planet för att lösa XOR. All struktur du hittar i den finns där för att den sänkte förlusten, och struktur som inte sänker förlusten finns helt enkelt inte där.
word2vec, GloVe och aritmetiken alla citerar
Länk till avsnittet: word2vec, GloVe och aritmetiken alla citerarOm den användbara delen är tabellen kan du gå direkt på den. Det är word2vec: behåll embedding-uppslagningen, kasta bort språkmodellen.5
Målet skip-gram with negative sampling är en rad. För ett verkligt (centrum, context)-par från korpusen, tryck upp deras skalärprodukt; för fejkpar dragna från en brusfördelning, tryck ned den:6
Det är en binär klassificering — ”förekom de här två orden verkligen tillsammans?” — och den är billig just därför att den aldrig rör hela vokabulären, vilket var det som gjorde träning på miljarder ord praktisk 2013. GloVe kommer fram till liknande vektorer från andra hållet, genom att faktorisera matrisen med globala samförekomsttal i stället för att strömma genom exempel.7 Båda anpassas till exakt den statistik som räknetabellen byggdes av. De är räknande, komprimerat.
Tränade på text8 — 17 005 207 ord från engelska Wikipedia, 71 290 av dem med minst fem förekomster, 100 dimensioner, tre genomgångar — kommer vektorerna ut med egenskapen som gjorde dem berömda:
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.870Ingen tillhandahöll en kategori för instrument eller för räkneord. Nu den berömda delen: ta king, subtrahera man, addera woman, och hitta den närmaste vektorn till resultatet.
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)Den närmaste vektorn till king - man + woman är king. Det är inte en egenhet hos ett exempel. Mikolovs utvärderingsmängd ställer frågor av formen a : b :: c : ? — 8 869 semantiska (paris : france :: rome : italy) och 10 675 syntaktiska (walking : walked :: swimming : swam) — och över de 4 103 semantiska frågor som den här vokabulären kan besvara är vinnaren ett av de tre input-orden 99,8 % av tiden. De publicerade demonstrationerna nämner det inte, eftersom standardregeln för poängsättning tar bort a, b och c innan den tittar. Det är en legitim regel, och den gör mer arbete än aritmetiken:
| hur svaret väljs | semantisk | syntaktisk |
|---|---|---|
| offset, med input-orden uteslutna (standard) | 17,0 % | 11,9 % |
| offset, utan att något utesluts | 0,1 % | 0,4 % |
närmaste granne till c ensam, input uteslutna | 13,1 % | 9,3 % |
närmaste granne till b ensam, input uteslutna | 2,3 % | 0,4 % |
Den tredje raden är den att sitta med. Kasta bort a och b, gör ingen aritmetik alls, returnera vad som än ligger närmast c — och du behåller 77 % av den semantiska poängen. Det mesta av det som ser ut som analogiskt resonerande är närhet plus en regel som förbjuder de uppenbara svaren, vilket är vad Linzen mätte på korrekt tränade vektorer och vad baslinjerna ovan replikerar.8 Just dessa vektorer är små — 17 miljoner ord mot miljarderna bakom de publicerade modellerna — så läs procenttalen som en form, inte som state of the art. Formen är det som överlever i varje skala: aritmetiken är verklig, och mycket svagare än den enda demonstration som alla citerar.
Statisk och kontextuell: en vektor per ord, eller en per förekomst
Länk till avsnittet: Statisk och kontextuell: en vektor per ord, eller en per förekomstAllt hittills har en hård gräns inbyggd i datastrukturen. En tabell har en rad per token. Ordet bank får en vektor, samma i en mening om en flod och en mening om ett bolån — med nödvändighet, eftersom en uppslagning via id inte kan bero på något annat.
Lösningen är att sluta läsa vektorn ur tabellen och börja beräkna den från meningen. Det är en contextual embedding, introducerad av ELMo 2018 och standardiserad av BERT samma år.910 Mätt på den riktiga modellen är siffrorna skarpare än förklaringen:
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.7335Den första raden är exakt, inte ungefärlig: den statiska vektorn för bank är samma 768 tal i båda meningarna, så cosinus är 1 per konstruktion. Nio lager senare ligger de två förekomsterna på 0,43, medan bank i två olika flodmeningar stannar på 0,87. Ingen etiketterade någon betydelse någonstans i processen; betydelserna separerades därför att separationen gör träningsmålet — att gissa en dold token från dess grannar — lättare att uppfylla.
Två detaljer är värda uppmärksamhet. Lager 0 är redan 0,9512 snarare än 1,0, eftersom positions-embeddings har lagts till och ordet sitter på olika plats i varje mening. Och likheten stiger igen i lager 11 och 12: de sista lagren i en förtränad modell är specialiserade på dess träningsmål, och är ofta inte den bästa platsen att ta en representation från.
Visa detaljer
Valfritt: weight tying.
I bert-base-uncased är embedding-tabellen — 23 440 896 tal, 21,4 % av modellens 109 482 240 parametrar. I en liten språkmodell är andelen ännu större, vilket är varför ett trick är nästan universellt: input-tabellen och output-lagret som producerar logits är samma matris, använd en gång genom raduppslagning och en gång transponerad.11 Output-lagret tilldelar redan varje post i vokabulären en vektor — det tar en skalärprodukt mot var och en — och tying säger att vektorn som används för att läsa en token och vektorn som används för att skriva den ska vara samma objekt. Det minskar parametrar och förbättrar perplexity samtidigt, vilket är tillräckligt ovanligt för att noteras.
En embedding model är inte en språkmodell
Länk till avsnittet: En embedding model är inte en språkmodellFör att söka i en korpus efter betydelse behöver du en vektor per mening. Givet dem är sökningen trivial — det här är hela semantisk retrieval, och Kapitel 19 handlar om allt runt omkring den:
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]Så den enda verkliga frågan är var embed kommer ifrån. Det uppenbara draget är att ta en förtränad språkmodell, köra varje mening genom den och ta medelvärdet av token-vektorerna. Här är den metoden mot fyra alternativ, poängsatta på två sätt: rangkorrelationen mellan cosinus och mänskliga likhetsbedömningar över de 1 379 paren i STS-benchmarken, och top-1-retrieval på ett index byggt av de 200 starkast parafraserade av dessa par — ena sidan av varje par indexerad, den andra använd som query.
| hur meningen embed:as | rangkorrelation | top-1 på ett index med 200 meningar |
|---|---|---|
| binärt ordöverlapp (ingen modell alls) | 0,5500 | 89,0 % |
| medelvärde av de statiska vektorerna tränade ovan | 0,5263 | 85,5 % |
BERT, [CLS] token | 0,2030 | 67,0 % |
| BERT, medelvärde av token-vektorer | 0,4729 | 84,0 % |
| MiniLM, tränad kontrastivt | 0,8203 | 92,0 % |
Läs de tre mittersta raderna mot de två första. En förtränad transformer med 109 miljoner parametrar, använd på det uppenbara sättet, är sämre på att bedöma meningslikhet än att räkna hur många ord två meningar delar — och sämre än att ta medelvärdet av de 100-dimensionella text8-vektorerna som tränades nyss. [CLS] token, som tutorials fortfarande rekommenderar eftersom BERT förtränades med ett meningsnivåmål kopplat till den, är sämre än hälften av det.
Det är inte en defekt i BERT. Det är målet. En språkmodell tränas så att dess dolda tillstånd förutsäger en token; inget där ber två parafraser hamna nära varandra, och inget belönar en geometri där cosinus betyder ”samma betydelse”. Den sista raden är en modell som är en femtedel så stor (22 713 216 parametrar) tränad på en helt annan förlust: contrastive learning, där exemplen är par — en fråga och dess svar, en mening och dess parafras — och målet drar sanna par samman medan samplade negativa exempel trycks isär. Det är Sentence-BERT:s bidrag och ursprunget till hela embedding model-industrin.12 Dense Passage Retrieval använder samma recept direkt för sök, med en encoder för queries och en för passages.13
Alltså, den praktiska regeln:
En embedding model är inte en språkmodell med sista lagret borttaget. Det är en annan modell med ett annat mål, oftast mycket mindre, vars cosinus betyder det du vill att det ska betyda eftersom den tränades på par där det var målet. Tabellen ovan är kostnaden för att ersätta den ena med den andra.
Och familjen misslyckas med ordföljd. ”Hunden bet mannen” och ”mannen bet hunden” har identiska påsar av ord, så ordöverlapp och medelvärdet av statiska vektorer ger dem cosinus exakt 1,000000, och mean-pooled BERT, som faktiskt ser position, landar fortfarande nästan där — och den kontrastivt tränade MiniLM placerar dem fortfarande på 0,979. Om din retrieval-uppgift avgörs av vem som gjorde vad mot vem kommer ingen cosinuströskel att rädda dig.
Kapitel 19 bygger ett produktionssystem för retrieval på denna grund och landar i en konkret cosinusgräns. Den sista mätningen i det här kapitlet är vad som gör ett sådant tal försvarbart snarare än magiskt.
Dimensionalitetens förbannelse, i en tabell
Länk till avsnittet: Dimensionalitetens förbannelse, i en tabellRiktiga embeddings har hundratals eller tusentals komponenter, och avstånd beter sig konstigt där uppe. Ta 1 000 slumpmässiga punkter i enhetskuben med dimensioner och titta på kvoten mellan det största och det minsta avståndet mellan två av dem:
| dimensioner | närmaste par | fjärmaste par | kvot |
|---|---|---|---|
| 2 | 0,0007 | 1,3612 | 1921,66 |
| 10 | 0,2361 | 2,3397 | 9,91 |
| 100 | 3,0047 | 5,1752 | 1,72 |
| 1 000 | 11,7809 | 14,0306 | 1,19 |
| 10 000 | 39,6152 | 42,0125 | 1,06 |
I tiotusen dimensioner är det fjärmaste punktparet bara 6 % längre ifrån varandra än det närmaste paret. Allt är ungefär lika långt från allt annat, ”närmaste granne” slutar bära särskilt mycket information, och det är dimensionalitetens förbannelse — liksom en anledning till att stora vektordatabaser inte gör exakt närmaste-granne-sökning. Den andra sidan av samma mynt är det som gör cosinuströsklar användbara: mätt över tusen par av slumpmässiga enhetsvektorer ligger medelcosinus på i 100 dimensioner och i 768, med standardavvikelser på 0,0968 och 0,0357 — och i 768 dimensioner överskrider bara 0,2 % av slumpmässiga par 0,1 i absolutvärde. En uppmätt likhet på 0,4 är därför inte ”40 % lika”; den ligger långt utanför allt slumpen producerar, vilket är varför trösklar mellan 0,3 och 0,7 separerar signal från brus i stället för att ligga mitt i det.
Vart det här går härnäst
Länk till avsnittet: Vart det här går härnästModellen i det här kapitlet läser ett fast antal tidigare tecken, slår upp vart och ett och limmar ihop resultaten i ordning. Den designen har två problem, och de är samma problem.
Titta igen på context-tabellen: att gå från tre tecken till åtta nästan fördubblade parametrarna och köpte 0,06 nats. Kostnaden växer linjärt med context — varje extra position behöver sin egen platta i den första viktmatrisen — och nyttan gör det inte. Tryck upp den till tusen tokens och det första lagret ensamt väger mer än resten av modellen, det mesta spenderat på positioner som inte spelar roll för någon given förutsägelse.
Vilket är det andra problemet: modellen har inget sätt att avgöra vilka av de tidigare tokens som spelar roll. Position två får sina egna vikter och position sju får sina egna, permanent, oavsett vad som finns i dem. När modellen stavar nell är det avgörande tecknet det direkt föregående. När en mening innehåller ett pronomen kan ordet som fixerar dess referent ligga fyrtio tokens bak — och ingen fast slot kan tilldelas ”fyrtio bak”, eftersom nästa gång blir det sex.
Det vi vill ha är en modell som beräknar, för varje förutsägelse, hur mycket varje tidigare token ska räknas — vikter över context som produceras av innehållet snarare än fixeras av layouten. Skriv ned det noggrant och det börjar som något helt vardagligt: ett medelvärde över tidigare tokens. Låt sedan vikterna i det medelvärdet läras in, och låt dem bero på vilken token som frågar.
Det är attention, och det är Kapitel 9.
Källor och metod
Länk till avsnittet: Källor och metodOckså värt att läsa parallellt: kapitel 3 i Jurafsky och Martins Speech and Language Processing, som behandlar n-grammodeller, smoothing och perplexity mycket noggrannare än det finns plats för här, inklusive varför interpolation och back-off slår att lägga till ett; Stanford CS229-anteckningarna §17.1–17.2 för språkmodellering från den probabilistiska sidan; och Linzens artikel ovan, som är kort och värd att läsa i sin helhet.
Referenser
Länk till avsnittet: Referenser-
Namngenereringsexemplet, datasetet och progressionen från en räknetabell till ett Bengio-liknande nätverk följer Andrej Karpathys building makemore-serie, vars två första delar är det bästa komplementet till det här kapitlet. ↩
-
Shannon, C. E. Prediction and Entropy of Printed English. Bell System Technical Journal 30(1), s. 50–64 (1951). Mänskliga försökspersoner som gissar nästa bokstav i engelska, och den ursprungliga mätningen i bitar per tecken. ↩
-
Shannon, C. E. A Mathematical Theory of Communication. Bell System Technical Journal 27 (1948). Källkodningssatsen, och identifieringen av prediktion med komprimering. ↩
-
Bengio, Y., Ducharme, R., Vincent, P. och Jauvin, C. A Neural Probabilistic Language Model. Journal of Machine Learning Research 3, s. 1137–1155 (2003). Arkitekturen som används ovan: en embedding per ord, sammanfogad över ett fast fönster, genom ett dolt lager, till en softmax över vokabulären. ↩
-
Mikolov, T., Chen, K., Corrado, G. och Dean, J. Efficient Estimation of Word Representations in Vector Space. arXiv:1301.3781 (2013). CBOW och skip-gram, och analogimängden som används ovan. ↩
-
Mikolov, T., Sutskever, I., Chen, K., Corrado, G. och Dean, J. Distributed Representations of Words and Phrases and their Compositionality. arXiv:1310.4546 (2013). Negative sampling, subsampling av frekventa ord, och brusfördelningen upphöjd till 3/4 som används ovan. ↩
-
Pennington, J., Socher, R. och Manning, C. GloVe: Global Vectors for Word Representation. EMNLP 2014. Ordvektorer från en faktorisering av den globala samförekomstmatrisen i stället för strömmade lokala fönster. ↩
-
Linzen, T. Issues in evaluating semantic spaces using word analogies. RepEval 2016, arXiv:1606.07736. Källan till de offsetfria baslinjer som replikerats ovan. ↩
-
Peters, M. et al. Deep contextualized word representations. arXiv:1802.05365 (2018). ELMo: en vektor per förekomst, beräknad av en dubbelriktad språkmodell. ↩
-
Devlin, J., Chang, M.-W., Lee, K. och Toutanova, K. BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. arXiv:1810.04805 (2018). Modellen som mättes i bank-experimentet. ↩
-
Press, O. och Wolf, L. Using the Output Embedding to Improve Language Models. arXiv:1608.05859 (2016), och Inan, H., Khosravi, K. och Socher, R. Tying Word Vectors and Word Classifiers. arXiv:1611.01462 (2016). Två oberoende argument för samma trick. ↩
-
Reimers, N. och Gurevych, I. Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. arXiv:1908.10084 (2019). Dess inledande mätning — mean-pooled BERT som underpresterar mot genomsnittliga statiska vektorer på meningslikhet — är vad tabellen ovan reproducerar. ↩
-
Karpukhin, V. et al. Dense Passage Retrieval for Open-Domain Question Answering. arXiv:2004.04906 (2020). Kontrastiv träning av en två-encoder-retriever; den direkta förfadern till Kapitel 19:s retrieval-stack. ↩