Ves al contingut
8/30Capítol 8 de 30

Predicció del següent token: embeddings i què vol dir la perplexitat

Entrena un model de caràcters amb 32.033 noms i veu com gradient descent redescobreix una taula de recomptes.

En aquesta pàgina

Aquí tens deu noms produïts per un programa que no ha vist mai cap paraula:

TEXT
cexze   momakurailezitynn   konimittain   llayn   ka
da      moliellavo          emia          sade    ftlsp

Cap d’ells és un nom. Gairebé tots ho intenten. Es poden pronunciar, acaben on acaben els noms, i un d’ells — emia — és a una sola lletra d’un de real. El programa que els ha produït conté 729 nombres, no té cap noció de paraula, síl·laba o persona, i s’ha ajustat amb una sola passada comptant parelles adjacents de lletres.

Al final d’aquest capítol, una xarxa neuronal haurà reduït la puntuació d’aquest programa en un terç sobre la mateixa mesura. La part que val la pena esperar és el que la xarxa fa primer: reprodueix la taula de recomptes amb tres decimals en cada fila ben poblada, sense que ningú li ho demani, perquè tots dos objectes són respostes a la mateixa pregunta. Tot el que ve després és el que el recompte mai no hauria pogut fer.

L’objectiu és una identitat, no una decisió de disseny

Enllaç a la secció: L’objectiu és una identitat, no una decisió de disseny

El Capítol 7 et deixava amb una seqüència d’enters i cap motiu perquè un n’hagués de seguir un altre. Aquí tens el motiu, i és una línia del Capítol 2.

Un model de llenguatge és una funció que pren els tokens fins ara i retorna una distribució sobre quin token ve després: un nombre per entrada del vocabulari, no negatiu, que suma u. Res més. Per passar d’això a una probabilitat per a un document sencer, aplica la regla de la cadena de la probabilitat:

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})

Això és una identitat, certa per a qualsevol seqüència de qualsevol cosa, sense cap supòsit afegit. Per tant, un model que fa la feina petita — el següent token donats els anteriors — ja ha fet la feina gran d’assignar una probabilitat a cada document possible, exactament i de franc. La formulació popular d’això com un truc barat («només prediu la paraula següent») entén la lògica a l’inrevés: predir el següent token és modelar la distribució conjunta. Mai no hi havia una segona cosa a fer.

La loss se’n deriva igual de mecànicament. En cada posició, el model produeix una distribució qq i la veritat és un únic token conegut, així que la cross-entropy del Capítol 4 s’aplica sense canvis:

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

Això és la mitjana de la log-versemblança negativa: la recepta del Capítol 2 amb una distribució categòrica a l’espai on abans hi havia la gaussiana. I com que la distribució real és one-hot, la seva entropia és zero, de manera que, per la identitat del Capítol 4, la cross-entropy és igual a la divergència KL: fer baixar aquest nombre i acostar les creences del model a les dades són el mateix acte.

Una conseqüència mereix una frase pròpia, perquè és el fet econòmic que sosté tot el camp. Les etiquetes són les dades, desplaçades una posició. Ningú no anota res. Un bilió de tokens de text és un bilió d’exemples preetiquetats, i per això el corpus d’entrenament d’un model modern és «internet» i no «un dataset que algú ha construït».

Abans de qualsevol xarxa, la baseline: 32.033 noms, un per línia, i la tasca de produir-ne més, una lletra cada vegada.1

El vocabulari són 26 lletres més un símbol de frontera . que marca tant l’inici com el final d’un nom, de manera que el model ha d’aprendre on comencen els noms i on s’aturen. Això són 27 símbols, i el model més petit possible és una taula de quantes vegades cada símbol ha seguit cada altre símbol.

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   

Dues línies d’aritmètica i el model queda ajustat — i no és una heurística: dividir els recomptes pels totals de fila és l’estimació de màxima versemblança per a una distribució categòrica, que és la recepta del Capítol 2 amb el càlcul ja fet.

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

Mostreja’n — tria una lletra de la fila de la lletra actual, mou-te a aquella fila, repeteix fins que aparegui el símbol de frontera — i obtens els noms del principi d’aquest capítol. Fallen d’una manera concreta i informativa: localment plausibles, globalment absurds. Cada parella adjacent de lletres a momakurailezitynn és una parella que apareix en noms reals; simplement n’hi ha disset seguides. El model té una lletra de memòria, així que no pot saber que s’està allargant massa.

La loss sobre noms reservats és de 2,4546 nats. Aquest nombre no vol dir res per si sol, i per això existeix la perplexitat:

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}

Escrit complet, sense cap biblioteca fent la feina:

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())             

Exponenciar desfà el logaritme i retorna el nombre a les unitats de comptar coses. La manera neta de veure què compta és mesurar un model que no sap absolutament res — un que assigna probabilitat 1/271/27 a cada símbol independentment del context:

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

Exactament 27,000, perquè elog27=27e^{\log 27} = 27. La perplexitat és el nombre efectiu d’opcions igualment probables entre les quals tria el model. Una perplexitat de 27 vol dir «ni idea, podria ser qualsevol cosa». L’11,642 del model de recompte vol dir que una lletra de context el deixa tan incert com algú que tria a cegues entre unes dotze opcions en lloc de vint-i-set — i per això es cita la perplexitat i no la loss bruta.

Hi ha dues coses que hi fallen, i la segona falla en articles publicats.

Les probabilitats zero són fatals. De les 729 cel·les de la taula, 113 no apareixen mai a l’entrenament: el 15,5 % és buit. Això va bé fins que el conjunt reservat cau en una d’elles, i set bigrames de validació ho fan, entre ells dq, zj i qo dues vegades. Probabilitat zero vol dir log -\infty, que vol dir loss infinita i perplexitat infinita: un nom de cada tres mil destrueix la mètrica. El pegat habitual és sumar 1 a cada recompte abans de normalitzar, cosa que aquí costa gairebé res (2,4546 en lloc de 2,4524). Però el pegat és una confessió. Un model de recompte no pot generalitzar gens. No té cap manera de sospitar que qo és plausible perquè qu és comú i o es comporta com u en altres llocs, ja que no té cap noció que dos símbols es puguin assemblar. Cada cel·la s’aprèn sola, i arreglar això és el motiu de la resta d’aquest capítol.

La perplexitat és un preu per token, i el token és un paràmetre lliure. Aquest és l’error que apareix constantment quan es comparen models, i és fàcil de veure un cop t’hi fixes. Pren el mateix corpus de prosa anglesa del Capítol 7, el mateix model de bigrames interpolat, i canvia només com es talla el text:

unitatvocabularitokens al testcross-entropyperplexitatbits per caràcter
caràcters7614.4692,521712,453,6378
BPE, 512 fusions3296.8713,854747,212,6407
BPE, 2.048 fusions1.8204.2335,7468313,202,4254
paraules2.9916.2843,562735,262,2322

La perplexitat varia per un factor de 25 entre aquestes files. No ha canviat res del model; només la mida de la cosa que es prediu. Predir una paraula sencera és més difícil que predir una lletra, així que costa més per predicció — i hi ha menys prediccions a fer.

Ara llegeix l’última columna, que divideix el cost total pel nombre de caràcters i el converteix en bits. Reordena la taula. Per perplexitat, el rànquing és caràcters, paraules, BPE-512, BPE-2048; per bits per caràcter, és paraules, BPE-2048, BPE-512, caràcters. El model de caràcters passa del primer lloc a l’últim. El model de 2.048 fusions, que per perplexitat sembla 6,6 vegades pitjor que el de 512 fusions, de fet és el millor dels dos: 2,4254 bits contra 2,6407.

Per tant, una perplexitat només és comparable entre dos models que comparteixen tokenizer, i els models amb tokenizers diferents només es poden comparar en bits per caràcter: la quantitat que Shannon va mesurar el 1951 fent que subjectes humans endevinessin la lletra següent d’un text en anglès, i que va acotar aproximadament en un bit per caràcter.2 El nostre millor bigrama és a 2,23 bits, que resumeix força bé quant camí li queda encara a aquest capítol.

Ara construeix el mateix model com una xarxa. Necessitarà ordres de magnitud més aritmètica per arribar al mateix lloc, i arribar al mateix lloc és precisament el punt.

Substitueix la taula per una matriu de pesos WW de forma 27×2727 \times 27. Converteix la lletra actual en un vector one-hot, multiplica, i anomena logits el resultat: les puntuacions no normalitzades del Capítol 4. Després softmax, després cross-entropy, després 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

La línia ressaltada conté una definició que val la pena tenir. Multiplicar un vector one-hot per una matriu en selecciona una fila, de manera que la multiplicació és una cerca — i cada implementació se salta l’aritmètica i fa la cerca directament, que és el que és W[xs].

Això és una taula d’embedding. Una matriu amb una fila per entrada del vocabulari, indexada per token id. Ni geometria, ni semàntica, ni cap algoritme separat: una taula de cerca el contingut de la qual resulta que s’aprèn amb gradient descent juntament amb tota la resta. Tota afirmació mística sobre l’«embedding space» toca fons aquí.

Entrena-la i mira cap on va:

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

L’última columna és la diferència absoluta més gran entre qualsevol cel·la de softmax(W) i la cel·la corresponent de la taula de recompte, i va cap a zero. Després de 3.000 passos, el desacord més gran en qualsevol de les 729 cel·les és 0,004048 i la mitjana és 0,000224. La pitjor cel·la és qi, vista dotze vegades en tot el conjunt d’entrenament; entre les 22 files amb més d’un miler d’aparicions, el pitjor desacord és 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, partint de nombres aleatoris i sense que se li digués res més que «fes gran la log-probabilitat de la lletra següent», va redescobrir la taula de recompte. I ho havia de fer: els recomptes són l’estimació de màxima versemblança, la cross-entropy és la log-versemblança negativa, així que tots dos procediments optimitzen el mateix objectiu i aquest objectiu té un únic òptim. La xarxa no va aprendre alguna cosa semblant a comptar. Va convergir al recompte, lentament.

Això planteja la pregunta justa de per què algú s’hi molestaria. Perquè la taula de recompte no té cap lloc on anar a partir d’aquí, i la xarxa sí.

El context és el coll d’ampolla, no la capacitat

Enllaç a la secció: El context és el coll d’ampolla, no la capacitat

Amplia el model perquè miri més d’un caràcter anterior. Aquesta és l’arquitectura de Bengio de 2003, l’ancestre directe de tots els models de la resta d’aquest curs:4 pren els tres últims caràcters, passa cadascun per una taula d’embedding cap a una fila de 10 dimensions, concatena les files en 30 nombres, fes-los passar per la capa oculta del Capítol 5, i acaba amb una capa de sortida que produeix un logit per entrada del vocabulari.

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)

Fixa’t què és nou i què no. La capa oculta és la del Capítol 5, sense canvis; la loss és la del Capítol 4, sense canvis. Les novetats són la taula d’embedding al davant i una capa de sortida tan ampla com el vocabulari del Capítol 7 — i aquesta segona és la part cara de tots els models de llenguatge que s’han construït mai, perquè un vocabulari real té 100.000 entrades i aquesta multiplicació de matrius s’executa a cada posició.

El mateix codi, entrenat de manera idèntica, canviant només la mida de la context window:

contextparàmetresloss de validacióperplexitat de validació
recompte, 1 caràcter7292,454611,642
neural, 1 caràcter7.8972,457711,678
neural, 3 caràcters11.8972,11458,285
neural, 8 caràcters21.8972,05067,773

La segona fila és la interessant. Una xarxa amb una capa oculta de 200 unitats i onze vegades més paràmetres que la taula de recompte rendeix exactament igual que la taula de recompte i no millor. La capacitat mai no havia estat la limitació. Un caràcter de context permet una certa loss i res del que hi cargolis al damunt pot baixar-ne més, perquè la informació no hi és.

Dona-li tres caràcters i la perplexitat cau d’11,68 a 8,29 — una reducció del 29 %, comprada amb 4.000 paràmetres extra. Aquí supera el recompte exactament pel motiu diagnosticat abans: un model de recompte sobre contextos de tres caràcters necessita 273=19,68327^3 = 19{,}683 files, la majoria buides o amb una sola observació, i les aprèn totes per separat. La xarxa comparteix. Si a, e i i acaben amb files d’embedding semblants, el que aprèn després de bra es transfereix a bre sense haver vist mai bre. Aquesta transferència és tot el valor de la taula d’embedding, i és la diferència entre les files dos i tres.

Les mostres milloren en conseqüència:

TEXT
deliah   nellara   joce     kael      quintis
salayson  reety    khyrmin  mahnen    madiaryxia

Encara no és una llista de noms reals. Però deliah, nellara i kael no desentonarien en una, i els monstres interminables han desaparegut: el més llarg de vint mostres del model de recompte té dinou lletres; el més llarg de vint d’aquest en té tretze.

Què hi ha realment dins la taula d’embedding

Enllaç a la secció: Què hi ha realment dins la taula d’embedding

La taula és 27×1027 \times 10: una fila de deu nombres per caràcter, tots inicialitzats aleatòriament i moguts només pel gradient de la loss del caràcter següent. Ningú no hi va posar res. Llavors, què hi ha acabat?

L’eina per preguntar-ho és la similitud del cosinus, que és el producte escalar del Capítol 1 amb les longituds dividides:

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

Mesura l’angle entre dos vectors i n’ignora les longituds, que és el que vols quan la longitud d’una fila reflecteix amb quina freqüència ha aparegut el seu token més que no pas què vol dir. Normalitza primer cada vector a longitud 1 — com fan els sistemes reals, una vegada, en el moment d’indexar — i la similitud del cosinus és simplement el producte escalar.

Aquí tens els veïns més propers d’uns quants caràcters a la taula entrenada:

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

Una part d’això és el que promet el folklore. c i k són intercanviables en noms, i també ho són i i y; j i z són totes dues consonants rares, sobretot inicials, que es comporten de manera semblant. El símbol de frontera . no és a prop de gairebé res — 0,077 de la lletra més propera — perquè és l’únic símbol que marca una posició i no un so.

I una part no. El veí més proper de a és h, no una altra vocal. Mitjanat sobre totes les parelles:

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

Les vocals s’assemblen més entre elles que no pas a les consonants, i l’efecte és real però petit. Contrastat amb 2.000 grups de cinc lletres triats aleatòriament, 58 d’aquests grups se separen com a mínim igual de netament — una diferència significativa al voltant de p=0.03p = 0.03. Real, doncs, però gens semblant a l’illa geomètrica nítida que els relats populars sobre embeddings suggereixen.

Aquesta és la descripció honesta d’una taula d’embedding, i val la pena conservar-la per a la resta del curs. No és un mapa del significat. És un canvi de coordenades, après en lloc de dissenyat, l’única feina del qual és facilitar la feina de la capa següent — la mateixa frase que el Capítol 5 feia servir per a la capa oculta que plegava el pla per resoldre XOR. Qualsevol estructura que hi trobis hi és perquè va reduir la loss, i l’estructura que no redueix la loss senzillament no hi és.

word2vec, GloVe i l’aritmètica que tothom cita

Enllaç a la secció: word2vec, GloVe i l’aritmètica que tothom cita

Si la part útil és la taula, pots anar-la a buscar directament. Això és word2vec: conserva la cerca d’embedding i llença el model de llenguatge.5

L’objectiu skip-gram with negative sampling és una línia. Per a una parella real (centre, context) extreta del corpus, empeny cap amunt el seu producte escalar; per a kk parelles falses extretes d’una distribució de soroll, empeny-lo cap avall: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})

Això és una classificació binària — «aquestes dues paraules han aparegut realment juntes?» — i és barat precisament perquè mai no toca tot el vocabulari, que és el que va fer pràctic entrenar amb milers de milions de paraules el 2013. GloVe arriba a vectors semblants des de l’altra direcció, factoritzant la matriu de recomptes globals de coocurrència en lloc de passar per exemples en streaming.7 Tots dos s’ajusten exactament a l’estadística a partir de la qual s’havia construït la taula de recompte. Són recompte, comprimit.

Entrenats sobre text8 — 17.005.207 paraules de la Wikipedia en anglès, 71.290 de les quals apareixen com a mínim cinc vegades, 100 dimensions, tres passades — els vectors surten amb la propietat que els va fer famosos:

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

Ningú no va proporcionar una categoria per a instruments o per a numerals. Ara, la part famosa: pren king, resta man, suma woman, i troba el vector més proper al resultat.

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)

El vector més proper a king - man + woman és king. No és una peculiaritat d’un exemple. El conjunt d’avaluació de Mikolov planteja preguntes de la forma a : b :: c : ? — 8.869 de semàntiques (paris : france :: rome : italy) i 10.675 de sintàctiques (walking : walked :: swimming : swam) — i, entre les 4.103 preguntes semàntiques que aquest vocabulari pot respondre, el guanyador és una de les tres paraules d’entrada el 99,8 % de les vegades. Les demostracions publicades no ho esmenten, perquè la regla de puntuació estàndard elimina a, b i c abans de mirar. És una regla legítima, i fa més feina que l’aritmètica:

com es tria la respostasemànticsintàctic
offset, amb les entrades excloses (estàndard)17,0 %11,9 %
offset, sense excloure res0,1 %0,4 %
veí més proper només de c, entrades excloses13,1 %9,3 %
veí més proper només de b, entrades excloses2,3 %0,4 %

La tercera fila és la que cal deixar reposar. Llença a i b, no facis cap aritmètica, retorna el que sigui més proper a c — i conserves el 77 % de la puntuació semàntica. La major part del que sembla raonament analògic és proximitat més una regla que prohibeix les respostes òbvies, que és el que Linzen va mesurar en vectors entrenats correctament i el que les baseline anteriors repliquen.8 Aquests vectors concrets són petits — 17 milions de paraules davant dels milers de milions que hi ha darrere dels models publicats — així que llegeix els percentatges com una forma, no com l’estat de l’art. La forma és el que sobreviu a totes les escales: l’aritmètica és real, i molt més feble que l’única demostració que tothom cita.

Estàtic i contextual: un vector per paraula, o un per aparició

Enllaç a la secció: Estàtic i contextual: un vector per paraula, o un per aparició

Tot el que hem vist fins ara té un límit dur incorporat a l’estructura de dades. Una taula té una fila per token. La paraula bank rep un vector, el mateix en una frase sobre un riu i en una frase sobre una hipoteca — necessàriament, perquè una cerca per id no pot dependre de res més.

La solució és deixar de llegir el vector de la taula i començar a calcular-lo a partir de la frase. Això és un contextual embedding, introduït per ELMo el 2018 i convertit en estàndard per BERT el mateix any.910 Mesurat sobre el model real, els nombres són més nítids que l’explicació:

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

La primera fila és exacta, no aproximada: el vector estàtic de bank és els mateixos 768 nombres en totes dues frases, així que el cosinus és 1 per construcció. Nou capes després, les dues aparicions són a 0,43, mentre que bank en dues frases diferents sobre rius es queda a 0,87. Ningú no ha etiquetat cap sentit enlloc d’aquest procés; els sentits se separen perquè separar-los facilita satisfer l’objectiu d’entrenament: endevinar un token ocult a partir dels seus veïns.

Dos detalls mereixen atenció. La capa 0 ja és 0,9512 en lloc d’1,0, perquè s’hi han afegit embeddings de posició i la paraula ocupa un lloc diferent a cada frase. I la similitud torna a pujar a les capes 11 i 12: les capes finals d’un model pretrained estan especialitzades en el seu objectiu d’entrenament, i sovint no són el millor lloc d’on extreure una representació.

Mostra els detalls

Opcional: weight tying.

A bert-base-uncased, la taula d’embedding és 30,522×76830{,}522 \times 768: 23.440.896 nombres, el 21,4 % dels 109.482.240 paràmetres del model. En un model de llenguatge petit, la fracció encara és més gran, i per això un truc és gairebé universal: la taula d’entrada i la capa de sortida que produeix els logits són la mateixa matriu, usada una vegada per cerca de files i una altra transposada.11 La capa de sortida ja assigna un vector a cada entrada del vocabulari — pren un producte escalar contra cadascun — i lligar pesos diu que el vector que es fa servir per llegir un token i el vector que es fa servir per escriure’l han de ser el mateix objecte. Redueix paràmetres i millora la perplexitat alhora, cosa prou rara per fixar-s’hi.

Un embedding model no és un model de llenguatge

Enllaç a la secció: Un embedding model no és un model de llenguatge

Per cercar un corpus per significat necessites un vector per frase. Donats aquests vectors, la cerca és trivial — això és tot el semantic retrieval, i el Capítol 19 tracta de tot el que hi ha al voltant:

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]

Així que l’única pregunta real és d’on surt embed. El moviment obvi és prendre un model de llenguatge pretrained, passar-hi cada frase i fer la mitjana dels vectors de token. Aquí tens aquest mètode contra quatre alternatives, puntuat de dues maneres: la correlació de rang entre el cosinus i els judicis humans de similitud sobre les 1.379 parelles del benchmark STS, i recuperació top-1 sobre un índex construït amb les 200 parelles més fortament parafrasejades d’aquelles — un costat de cada parella indexat, l’altre utilitzat com a consulta.

com s’incrusta la frasecorrelació de rangtop-1 en un índex de 200 frases
solapament binari de paraules (sense cap model)0,550089,0 %
mitjana dels vectors estàtics entrenats abans0,526385,5 %
BERT, el token [CLS]0,203067,0 %
BERT, mitjana dels vectors de token0,472984,0 %
MiniLM, entrenat contrastivament0,820392,0 %

Llegeix les tres files del mig en comparació amb les dues primeres. Un transformer pretrained de 109 milions de paràmetres, utilitzat de la manera òbvia, és pitjor jutjant la similitud entre frases que comptar quantes paraules comparteixen dues frases — i pitjor que fer la mitjana dels vectors text8 de 100 dimensions entrenats fa un moment. El token [CLS], que els tutorials encara recomanen perquè BERT es va pretrained amb un objectiu a nivell de frase associat, és pitjor que la meitat d’això.

Això no és un defecte de BERT. És l’objectiu. Un model de llenguatge s’entrena perquè els seus estats ocults prediguin un token; res d’això demana que dues paràfrasis acabin a prop, i res no recompensa una geometria en què el cosinus vulgui dir «mateix significat». L’última fila és un model d’una cinquena part de la mida (22.713.216 paràmetres) entrenat amb una loss completament diferent: contrastive learning, on els exemples són parelles — una pregunta i la seva resposta, una frase i la seva paràfrasi — i l’objectiu estira les parelles veritables juntes mentre empeny negatius mostrejats cap enfora. Aquesta és la contribució de Sentence-BERT i l’origen de tota la indústria dels embedding models.12 Dense Passage Retrieval aplica la mateixa recepta directament a la cerca, amb un encoder per a consultes i un per a passatges.13

Per tant, la regla pràctica:

Un embedding model no és un model de llenguatge amb l’última capa eliminada. És un model diferent amb un objectiu diferent, normalment molt més petit, el cosinus del qual vol dir el que vols que vulgui dir perquè s’ha entrenat amb parelles on aquest era l’objectiu. La taula anterior és el cost de substituir l’un per l’altre.

I la família falla amb l’ordre de les paraules. «The dog bit the man» i «the man bit the dog» tenen bosses de paraules idèntiques, així que el solapament de paraules i la mitjana de vectors estàtics els donen un cosinus exactament 1,000000, i BERT amb mean pooling, que sí que veu la posició, encara queda gairebé en això — i MiniLM entrenat contrastivament encara els situa a 0,979. Si la teva tasca de retrieval depèn de qui ha fet què a qui, cap llindar de cosinus no et salvarà.

El Capítol 19 construeix un sistema de retrieval de producció sobre aquesta base i arriba a un llindar de cosinus concret. L’última mesura d’aquest capítol és el que fa que un nombre així sigui defensable i no màgic.

La maledicció de la dimensionalitat, en una taula

Enllaç a la secció: La maledicció de la dimensionalitat, en una taula

Els embeddings reals tenen centenars o milers de components, i les distàncies es comporten de manera estranya allà dalt. Pren 1.000 punts aleatoris al cub unitari de dd dimensions i mira la ràtio entre la distància més gran i la més petita entre qualsevol parella:

dimensionsparella més properaparella més llunyanaràtio
20,00071,36121921,66
100,23612,33979,91
1003,00475,17521,72
1.00011,780914,03061,19
10.00039,615242,01251,06

En deu mil dimensions, la parella de punts més llunyana és només un 6 % més lluny que la parella més propera. Tot és aproximadament equidistant de tota la resta, «veí més proper» deixa de portar gaire informació, i aquesta és la maledicció de la dimensionalitat — així com una de les raons per les quals les bases de dades vectorials grans no fan cerca exacta del veí més proper. L’altra cara de la mateixa moneda és el que fa que els llindars de cosinus siguin viables: mesurat sobre un miler de parelles de vectors unitaris aleatoris, el cosinus mitjà se situa a 0.0052-0.0052 en 100 dimensions i a +0.0003+0.0003 en 768, amb desviacions estàndard de 0,0968 i 0,0357 — i en 768 dimensions només el 0,2 % de les parelles aleatòries supera 0,1 en valor absolut. Per tant, una similitud mesurada de 0,4 no és «un 40 % semblants»; és molt fora del que produeix l’atzar, i per això els llindars entre 0,3 i 0,7 separen el senyal del soroll en lloc de quedar-se al mig.

El model d’aquest capítol llegeix un nombre fix de caràcters anteriors, busca cadascun a la taula i enganxa els resultats en ordre. Aquest disseny té dos problemes, i són el mateix problema.

Torna a mirar la taula de context: passar de tres caràcters a vuit gairebé va duplicar els paràmetres i va comprar 0,06 nats. El cost creix linealment amb el context — cada posició extra necessita el seu propi bloc de la primera matriu de pesos — i el benefici no. Porta-ho a mil tokens i només la primera capa ja pesa més que la resta del model, amb la major part gastada en posicions que no importen per a cap predicció concreta.

Aquest és el segon problema: el model no té cap manera de decidir quins dels tokens anteriors importen. La posició dos té els seus pesos i la posició set té els seus, permanentment, sigui el que sigui que hi hagi. Quan el model està escrivint nell, el caràcter decisiu és l’immediatament anterior. Quan una frase conté un pronom, la paraula que en fixa el referent pot ser quaranta tokens enrere — i no es pot assignar cap ranura fixa a «quaranta enrere», perquè la pròxima vegada en seran sis.

El que volem és un model que calculi, per a cada predicció, quant hauria de comptar cada token anterior — pesos sobre el context produïts pel contingut en lloc de fixats pel disseny. Escriu-ho amb cura i comença com una cosa completament ordinària: una mitjana sobre els tokens anteriors. Després deixa que els pesos d’aquesta mitjana s’aprenguin, i deixa que depenguin de quin token està fent la pregunta.

Això és attention, i és el Capítol 9.


També val la pena llegir en paral·lel: el capítol 3 de Speech and Language Processing de Jurafsky i Martin, que tracta els models n-gram, el smoothing i la perplexitat amb molta més cura de la que hi cap aquí, incloent-hi per què la interpolació i el back-off superen sumar u; les notes de Stanford CS229 §17.1–17.2 per al modelatge de llenguatge des del costat probabilístic; i l’article de Linzen de més amunt, que és curt i val la pena llegir sencer.

  1. L’exemple de generació de noms, el dataset i la progressió des d’una taula de recompte fins a una xarxa d’estil Bengio segueixen la sèrie building makemore d’Andrej Karpathy, les dues primeres parts de la qual són el millor complement d’aquest capítol.

  2. Shannon, C. E. Prediction and Entropy of Printed English. Bell System Technical Journal 30(1), pp. 50–64 (1951). Subjectes humans endevinant la lletra següent de l’anglès escrit, i la mesura original de bits per caràcter.

  3. Shannon, C. E. A Mathematical Theory of Communication. Bell System Technical Journal 27 (1948). El teorema de codificació de fonts, i la identificació de predicció amb compressió.

  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). L’arquitectura utilitzada més amunt: un embedding per paraula, concatenat sobre una finestra fixa, passant per una capa oculta, fins a un softmax sobre el vocabulari.

  5. Mikolov, T., Chen, K., Corrado, G. and Dean, J. Efficient Estimation of Word Representations in Vector Space. arXiv:1301.3781 (2013). CBOW i skip-gram, i el conjunt d’analogies utilitzat més amunt.

  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, submostreig de paraules freqüents, i la distribució de soroll elevada a la potència 3/4 utilitzada més amunt.

  7. Pennington, J., Socher, R. and Manning, C. GloVe: Global Vectors for Word Representation. EMNLP 2014. Vectors de paraula a partir d’una factorització de la matriu global de coocurrència en lloc de finestres locals en streaming.

  8. Linzen, T. Issues in evaluating semantic spaces using word analogies. RepEval 2016, arXiv:1606.07736. La font de les baseline sense offset replicades més amunt.

  9. Peters, M. et al. Deep contextualized word representations. arXiv:1802.05365 (2018). ELMo: un vector per aparició, calculat per un model de llenguatge bidireccional.

  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). El model mesurat a l’experiment de bank.

  11. Press, O. and Wolf, L. Using the Output Embedding to Improve Language Models. arXiv:1608.05859 (2016), and Inan, H., Khosravi, K. and Socher, R. Tying Word Vectors and Word Classifiers. arXiv:1611.01462 (2016). Dos arguments independents per al mateix truc.

  12. Reimers, N. and Gurevych, I. Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. arXiv:1908.10084 (2019). La seva mesura inicial — BERT amb mean pooling rendint pitjor que vectors estàtics mitjanats en similitud de frases — és el que reprodueix la taula anterior.

  13. Karpukhin, V. et al. Dense Passage Retrieval for Open-Domain Question Answering. arXiv:2004.04906 (2020). Entrenament contrastiu d’un recuperador amb dos encoders; l’ancestre directe del stack de retrieval del Capítol 19.

A punt per deixar que triï LIA?

Crea amb tots els models d'IA en un sol lloc — comença gratis avui mateix.