Attention és a transformer blokk: levezetés egy átlagból
Az átlagból indulunk ki, megmérjük, hol bukik el, majd a javításból természetesen előáll az attention képlete.
Ezen az oldalon
Ide egy 7. fejezetből származó tokenizerrel, egy 8. fejezetből származó embedding táblával és a hozzájuk tartozó céllal érkezel: az eddigi tokenek alapján adjunk valószínűséget a következőre.
A középső rész hiányzik. A token előrejelzéséhez a modellnek egy vektorra van szüksége, amely összefoglal mindent, ami előtte áll, és amit eddig felépítettél, semmi sem állít elő ilyet. A token embeddingje nem ez — az egy bigram modell, és nem tudhatja, hogy a mondat kérdéssel kezdődött. Az összes korábbi embedding összefűzése sem ez: a számuk minden lépésben változik, egy fix súlymátrix pedig nem tud változó hosszúságú bemenetet fogadni.
Tehát: egy fix méretű vektor, amely változó számú vektort foglal össze. Ez a teljes probléma, és az attention az, amit akkor kapsz, ha a lehető leglustább módon oldod meg, majd kijavítod azt a két dolgot, ami elromlik.
A válasz, amely a területen megvolt, és miért nem azt építjük
Link a szakaszhoz: A válasz, amely a területen megvolt, és miért nem azt építjük1997-től nagyjából 2017-ig az összefoglaló egy recurrent állapot volt: tarts fenn egy vektort, és frissítsd minden tokennél, . Fix méret, változó bemenet, pontosan a megfelelő forma.
Három módon bukott el, és ennek a fejezetnek az architektúrája mindháromra választ ad. A lépésen át történő backpropagation Jacobi-mátrixokat szoroz össze, ezért a gradient eltűnik vagy felrobban — ugyanaz a betegség, amelyet az 5. fejezet egyetlen csomóponton belül mért. Az LSTM1 pontosan ez ellen készült, és a használható tartományt tízes lépésekről százasokra tolta, anélkül hogy megváltoztatta volna a tényt: az 5. tokenből származó információ csak 495 egymást követő frissítést túlélve jut el az 500. tokenig. A teljes forrásnak egyetlen vektorba kellett beleférnie: sequence-to-sequence fordításban2 egy encoder a bemenetet a végső állapotába tömöríti. Bahdanau, Cho és Bengio 2014-ben, három évvel a transformer előtt, megnevezték ezt a szűk keresztmetszetet és kijavították azzal, hogy a decoder az encoder összes állapotának súlyozott összegét vehette, olyan súlyokkal, amelyeket maga számolt ki.3 Minden, ami alább következik, ugyanez az ötlet: egy sorozat saját magára alkalmazza, a recurrence törlésével. És a frissítés felépítéséből adódóan szekvenciális: -hez kell , és egy tízezer magos GPU ezzel semmit sem tud kezdeni. A győztes architektúra nem nyilvánvalóan okosabb; egyszerűen az, amelynek drága lépése mátrixszorzás.
A másik klasszikus induktív torzítás, a konvolúció — egy kis szűrő végigtolása a teljes bemeneten, hogy egy bárhol észlelt jellemző mindenhol észlelhető legyen — itt szintén nem épül fel; képekhez szinte pontosan ez a megfelelő, és ezt egy látásról szóló kurzusra bízzuk. Sem recurrence, sem konvolúció nem tér vissza ezen oldal után, ezért egyik sem kap fejezetet: az 1. fejezet megígérte, hogy a kihagyásokat kimondjuk, nem elhallgatjuk.
A lehető legolcsóbb összefoglaló
Link a szakaszhoz: A lehető legolcsóbb összefoglalóA legkézenfekvőbb függvény, amely változó számú vektorból egy vektort ad vissza, az átlag:
Tetszőleges számú bemenet, fix kimeneti méret, differenciálható, ingyenes. Egy embedding tábla plusz ez az átlag plusz egy lineáris réteg a szókészletre: tizenöt sorban kész a teljes nyelvi modell. Csakhogy rettenetes, és az egész levezetés abból áll, hogy pontosan hogyan rettenetes.
Az alábbi korpusz egy megabájtnyi Shakespeare, 1 115 394 karakter, olyan byte-level BPE tokenizerrel feldolgozva, amilyet a 7. fejezetben építettünk, 1024-es szókészlettel: 459 760 token, átlagosan 2,43 karakter/token, 90/10 arányban felosztva. Minden modell 128 széles, 128 tokent lát, és 3000 AdamW-lépésig tanul mellett, 64-es batch mérettel. A perplexity a visszatartott spliten szerepel.4
| modell | paraméterek | validációs perplexity |
|---|---|---|
| csak az aktuális token, context nélkül | 263 168 | 59.71 |
| plusz minden előtte álló egységes átlaga | 263 168 | 248.07 |
| plusz tanult position embeddingek | 279 552 | 245.93 |
| egységes átlag a tokenhez hozzáadva, nem helyette | 263 168 | 60.45 |
Olvasd el a második sort kétszer. A context átlagolása nem kicsit segít; négyszer rosszabbá teszi a modellt annál, mintha teljesen figyelmen kívül hagyná a contextet. Két oka van, mindkettő empirikus helyett bizonyítható.
Az átlag nem lát sorrendet. Az összeadás kommutatív, ezért az ablak megkeverése változatlanul hagyja az összefoglalót — nem megközelítőleg:
A = torch.tril(torch.ones(T, T))
A = A / A.sum(1, keepdim=True) # rows of the averaging matrix
y = x[torch.randperm(T)] # the same tokens, shuffled
print((A[-1] @ x - A[-1] @ y).abs().max().item())2.9802322387695312e-08Lebegőpontos zaj egy átrendezett összegen: a két összefoglaló ugyanaz a vektor. Egy olyan modell, amelynek a contextre vonatkozó egyetlen nézete egy átlag, nem tudja megkülönböztetni azt, hogy a kutya megharapta az embert, attól, hogy az ember megharapta a kutyát. A harmadik sor bizonyítja, hogy ez nem javítható azzal, ha pozíciókat adunk a bemenetekhez — egy tanult position embedding minden tokenen az átlagolás előtt 2,14 pontot hozott a 188-ból. A pozíciók bekerülnek az összegbe, az összeg pedig elfelejti őket.
És az átlag elnyomja a jelent. A 100. pozíción az aktuális token az összefoglaló egy százada. Erre van egy olcsó javításod, amit már birtokolsz: tartsd meg a tokent, és add hozzá az összefoglalót — residual kapcsolat, a 6. fejezetből, és a negyedik sor mutatja, mit csinál. Miután a hígulást kijavítottuk, az egységes átlag semmit sem ad hozzá: 60.45 a 59.71-es baseline-nal szemben. Minden token benne van, azonos súllyal, az azonos súlyozás pedig ugyanaz, mint az információ hiánya.
A probléma nem az átlagolás. Hanem a súlyok.
Az átlag mátrixszorzás, a mask pedig softmax
Link a szakaszhoz: Az átlag mátrixszorzás, a mask pedig softmaxEgy növekvő prefix átlagolása ciklusnak tűnik. Valójában egyetlen szorzás egy alsó háromszögmátrixszal, amelynek sorai egyre összegeznek — és egyben pontosan egy softmax:
loop = torch.stack([x[:t + 1].mean(0) for t in range(T)]) # the obvious version
A = torch.tril(torch.ones(T, T))
A = A / A.sum(1, keepdim=True)
mat = A @ x # the same thing
S = torch.zeros(T, T).masked_fill(torch.tril(torch.ones(T, T)) == 0, float("-inf"))
soft = F.softmax(S, dim=-1) @ x # and the same thing againloop vs matmul max |diff| = 5.960464477539063e-08
loop vs softmax max |diff| = 5.960464477539063e-08
the averaging matrix A (rows sum to 1, upper triangle is zero):
1.000 0.000 0.000 0.000 0.000 0.000
0.500 0.500 0.000 0.000 0.000 0.000
0.333 0.333 0.333 0.000 0.000 0.000
0.250 0.250 0.250 0.250 0.000 0.000
0.200 0.200 0.200 0.200 0.200 0.000
0.167 0.167 0.167 0.167 0.167 0.167Egy transformer három névvel ellátott komponense már a képernyőn van. A háromszög a causal mask, amelyet a cél kényszerít ki: ha a pozíció láthatná a pozíciót, a válasz benne lenne a bemenetben — ugyanaz a szivárgás, amelynek auditálását a 6. fejezet kérte, csak most az architektúrán belül. A softmax az, ahogyan a mask megvalósul: a tiltott elemeket értékre állítva pontosan nullára küldi őket, és normalizálja, ami megmarad, így a maszkolás és a normalizálás egy művelet. (Használj -et, ne -1e9-t: ez az az érték, amit a masking jelent, float16-ra castolva -ként megmarad, és megkímél attól, hogy eldöntsd, az általad választott konstans elég nagy-e ahhoz a tartományhoz, amelyben épp vagy — ez pedig a 2. fejezet lebegőpontos doboza, amely olyan kérdést tesz fel, amelyre nem kell válaszolnod.) A pontszámok pedig a szabad paraméterek. Az egységes átlagot akkor kapod, ha minden engedélyezett pontszám ugyanaz a szám; tegyél oda bármilyen számokat, és a softmax érvényes súlyokká alakítja őket.
A fejezet hátralévő része egyetlen kérdés: honnan jönnek ezek a számok?
Query, key, value
Link a szakaszhoz: Query, key, valueNem lehetnek puszta paraméterek. Egy tanult mátrix minden mondatnál azonos lenne — tudná kódolni azt, hogy „nézz négy tokennel vissza”, de azt soha, hogy „nézd azt a főnevet, amelyre ez a névmás utal”. A pozíciót a pozícióhoz kapcsoló súlynak attól kell függenie, mi van mindkét pozícióban, mert a relevancia viszony, nem tulajdonság: az az szó nem önmagában releváns, hanem valamihez képest.
Két vektorból számot visszaadó legolcsóbb függvény az 1. fejezetbeli skalárszorzat. Pontozd a pozíciót a pozíció számára -ként, és a mechanizmus működik — rosszul, két olyan módon, amely minden mást kikényszerít. Egy vektor saját magával vett skalárszorzata a normájának négyzete, ezért minden token többnyire önmagára figyelne. A viszony pedig szimmetrikus lenne: ha az az erősen figyel az állat szóra, akkor az állat is erősen figyel az az szóra, ami a nyelvre nem igaz, ahol egy melléknév sokkal jobban igényli a főnevét, mint a főnév a melléknevet.
Adj tehát minden tokennek két szerepet, mint két tanult lineáris leképezést róla: mit keres ez a pozíció, , a query; és mivel kínálja fel magát megtalálásra, , a key. A pontszám legyen , és a szimmetria eltűnik, mert : egy token hirdethet egy dolgot, és kereshet egy másikat.
Egy dolog még mindig hibás. A súlyozott összeg magukon a -eken futott, ami arra kényszeríti, hogy ami másolódik, ugyanaz legyen, mint ami illesztődik. Az illesztés olyan jellemzőket akar, amelyek azonosítanak egy tokent; a másolás olyan jellemzőket, amelyek később hasznosak. Tanuljunk tehát egy harmadik leképezést, , a value-t, és ezeket összegezzük.
A képlet most már könyvelés:
ahol a causal mask, nulla az átlón és alatta, felette. Kódban harminc sor, amelyből húsz shape:
class Head(nn.Module):
"""One head of causal self-attention."""
def __init__(self, d_model, d_head, block):
super().__init__()
self.q = nn.Linear(d_model, d_head, bias=False)
self.k = nn.Linear(d_model, d_head, bias=False)
self.v = nn.Linear(d_model, d_head, bias=False)
self.d_head = d_head
self.register_buffer("mask", torch.tril(torch.ones(block, block)).bool())
def forward(self, x):
T = x.shape[1]
q, k, v = self.q(x), self.k(x), self.v(x)
s = q @ k.transpose(-2, -1) / math.sqrt(self.d_head)
s = s.masked_fill(~self.mask[:T, :T], float("-inf"))
w = F.softmax(s, dim=-1)
return w @ v Pontozás, mask, normalizálás, keverés. Minden más projekció.
Osztás a négyzetgyökkel, és ami ellen véd
Link a szakaszhoz: Osztás a négyzetgyökkel, és ami ellen védA szinte minden magyarázata azt mondja: „hogy a softmax ne telítődjön”, ami igaz, és semmit sem magyaráz meg. Az érvelés két sor variancia a 2. fejezetből. Ha és elemei függetlenek, nulla várható értékkel és egy varianciával, akkor minden szorzat varianciája egy, a független dolgok varianciái pedig összeadódnak:
Tehát a pontszámok szórása . Húszezer véletlen páron mérve:
d Var(q.k) std sqrt(d)
4 3.975 1.994 2.000
16 16.071 4.009 4.000
64 64.249 8.016 8.000
256 253.065 15.908 16.000
1024 1015.562 31.868 32.000Miért számít ez: a softmax skálaérzékeny úgy, ahogy egy lineáris réteg nem az. Egy lineáris réteg bemenetének megduplázása megduplázza a kimenetét; a pontszámok tízzel szorzása softmax előtt egy lágy keveréket kemény választássá alakít. Egy sor 64 pontszámmal, osztással és anélkül:
| legnagyobb súly, osztatlan | entrópia | effektív tokenek | legnagyobb súly, osztott | entrópia | effektív tokenek | |
|---|---|---|---|---|---|---|
| 4 | 0.205 | 2.944 | 19.0 | 0.081 | 3.758 | 42.9 |
| 16 | 0.438 | 1.692 | 5.4 | 0.075 | 3.849 | 46.9 |
| 64 | 0.489 | 0.874 | 2.4 | 0.085 | 3.673 | 39.4 |
| 256 | 0.9999 | 0.0007 | 1.0 | 0.143 | 3.547 | 34.7 |
| 1024 | 1.0000 | 0.0000 | 1.0 | 0.132 | 3.644 | 38.3 |
Az „effektív tokenek” az entrópia exponenciálisa: hány pozíciót átlagol a sor valójában. Osztatlanul, mellett, egy frissen inicializált head pontosan egy tokenre figyel a 64-ből, pusztán a véletlen mintavétel alapján.
Ez előreirányban rossz, visszafelé még rosszabb, olyan alakban, amelyet az 5. fejezet már megmért egy -en. Egyetlen elemre elkötelezett softmaxnak alig van deriváltja: Jacobi-mátrixának diagonálisa , mindkét végén nulla. Kétezer véletlen soron:
| osztatlan | osztott | telített sorok (legnagyobb súly 0.99 felett) | |
|---|---|---|---|
| 4 | 0.8427 | 0.9568 | 0.2 % → 0.0 % |
| 64 | 0.2940 | 0.9609 | 17.9 % → 0.0 % |
| 256 | 0.1406 | 0.9609 | 49.1 % → 0.0 % |
| 1024 | 0.0681 | 0.9611 | 70.4 % → 0.0 % |
mellett tízből hét sor már a tanulás kezdete előtt befagy, és egy befagyva induló head nem tudja megtanulni, mire nézzen. Osztva a mennyiség minden szélességnél 0,96 körül lapos, és semmi sem telítődik.
Most az a rész, amelyet senki sem publikál: megváltoztatja a végső perplexityt? Töröld az osztást, és taníts négy head-szélességen:
| head szélesség | osztatlan | osztva -gyel | osztva -gyel |
|---|---|---|---|
| négy head, | 37.29 | 38.07 | 37.89 |
| egy head, | 48.51 | 46.10 | 45.99 |
| egy head, | 65.37 | 47.53 | — |
| egy head, | 67.06 | 49.15 | — |
| egy head, | 76.69 | 59.17 | — |
Az első két sor a fenti 3000 lépéses keretből származik; az utolsó három rövidebb futás — 1500 lépés, 32-es batch, egy head, normalizálás nélkül a projekciók előtt — mindkét variánsnál azonos beállításokkal.
mellett az osztás semmit sem ér, és az nélküli futás nagyon enyhén előrébb van. Ez nem felhatalmazás az elhagyására, mert 256-nál 18 perplexity-pontot ér, 1024-nél pedig 17-et. A mechanizmus magukban a pontszámokban látszik:
| pontszám szórása inicializáláskor | 1500 lépés után, osztatlan | 1500 lépés után, osztott | telített sorok, osztatlan | osztott | |
|---|---|---|---|---|---|
| 256 | 10.49 | 121.67 | 2.13 | 91.9 % | 0.8 % |
| 512 | 15.13 | 836.85 | 2.66 | 98.7 % | 1.3 % |
| 1024 | 21.15 | 5147.46 | 3.44 | 99.9 % | 16.5 % |
Az osztatlan head nem tér magához. Elszabadul: pontszámainak szórása inicializáláskor 21-ről 5147-re nő, az attention entrópiája nullára esik, és a sorok 99,9 %-a súlyának több mint 0,99 részét egyetlen tokenre teszi. Amint egy head kemény kiválasztóvá válik, a gradientje majdnem nulla, és semmi sem húzza vissza, ezért az összeomlás stabil. Az osztott head ugyanazon tanulás után 3,44-es pontszám-szóráson ül, ami még mindig megváltoztatható lágy keverék.
Vaswani és társai pontosan ezt mondják, és nem többet — azt sejtik, hogy a szorzatok „nagy nagyságrendűvé válnak nagy értékeinél”, és osztanak.5 A nagy szó tartja a terhet, a táblák pedig megmutatják, hol kezdődik a nagy: 32-nél semmi, 256-ra minden.
Több mint egy vélemény, és a kétharmad, amelyről senki sem beszél
Link a szakaszhoz: Több mint egy vélemény, és a kétharmad, amelyről senki sem beszélEgy head pozíciónként egy softmax sort jelent, tehát egyetlen választ tart arra, hogy „mi releváns itt”. A the animal that crossed the wet street után a következő szó előrejelzéséhez egyszerre kell a szintaktikai hely, az alany és az előző token, egyetlen valószínűségi eloszlás pedig nem tud három helyen koncentrálódni. Futtass tehát több headet párhuzamosan, mindegyiket szélességgel, fűzd össze, és keverd még egy mátrixszal: a szélességet felosztottad, nem hozzáadtál.
Az attention pontosan egy dolgot is csinál — információt mozgat pozíciók között. A fenti kódban minden művelet lineáris a jellemzőtengely mentén, az 5. fejezet pedig bizonyította, mi egy lineáris leképezésekből álló verem. Ezért minden blokk tartalmaz egy kis MLP-t is, amely minden pozícióra külön alkalmazódik, négyszeresére bővíti a szélességet, majd visszatér, középen GELU-val. A munkamegosztást érdemes megjegyezni: az attention pozíciók között kever, a feed-forward network pozíción belül számol.
A teljes létra, minden sor egy elemet adva a felette lévő sorhoz:
| modell | paraméterek | validációs perplexity |
|---|---|---|
| egységes átlag, hozzáadva | 279 552 | 60.45 |
| egy attention head, a token helyett | 328 704 | 55.47 |
| egy attention head, hozzáadva | 328 704 | 46.10 |
| négy head egy helyett | 345 216 | 43.21 |
| plusz a feed-forward network | 476 928 | 39.87 |
| plusz LayerNorm — a teljes blokk | 477 696 | 38.07 |
A tanult súlyok 14 perplexity-ponttal verik az egységeseket, ami ennek a fejezetnek az egész érve egyetlen sorban. Négy head további 3 pontot vesz 16 512 extra paraméterért. Ugyanaz a head pedig 9 ponttal többet ér hozzáadva, mint helyettesítve: az attention információt hoz be, nem dönti el, mi egy pozíció.
Most nézzük, hol ülnek valójában a paraméterek, ami meglepi azokat, akik csak az ábrát látták:
| szélesség | headek | attention | feed-forward | összesen blokkonként |
|---|---|---|---|---|
| 128 | 4 | 65 664 (33.2 %) | 131 712 (66.6 %) | 197 888 |
| 768 | 12 | 2 360 064 (33.3 %) | 4 722 432 (66.6 %) | 7 085 568 |
| 4096 | 32 | 67 112 960 (33.3 %) | 134 238 208 (66.7 %) | 201 367 552 |
Minden transformer blokk kétharmada a feed-forward network, minden skálán, mert az attention négy mátrixot tartalmaz, az MLP pedig ennek megfelelően nyolcat. Bármit is tud egy modell, az azt tartó paraméterek többsége a pozíciónkénti MLP-ben van.
Residualok és LayerNorm, a 6. fejezetből örökölve
Link a szakaszhoz: Residualok és LayerNorm, a 6. fejezetből örökölveA LayerNormot a 6. fejezet építette fel és mérte meg, ez a fejezet pedig úgy használja, ahogy ott maradt; a residual kapcsolatok ott kaptak nevet és ablationt, és itt épülnek be. A fenti „hozzáadva, nem helyettesítve” sorok residual kapcsolatok, az átlagnál 188, egy headnél 9 perplexity-pontot érnek. A LayerNorm7 minden példát a saját jellemzői mentén normalizál, a 6. fejezet pedig megadta az okokat, amiért itt ez élte túl, nem a BatchNorm — nincs batch-függés, nincs futó statisztika, azonos tanításkor és inferencekor, közömbös a sorozathosszra — és mindegyik követelménnyé válik, amikor egyetlen felhasználónak egyszerre egy tokent generálsz, ahová a 13. fejezet végül eljut. 768 paraméterbe kerül, és 1,8 perplexity-pontot hoz.
class Block(nn.Module):
def forward(self, x):
x = x + self.att(self.ln1(x))
x = x + self.ff(self.ln2(x))
return xNézd meg, hol ül a normalizálás: minden alréteg bemenetén, miközben a bemenettől a kimenetig futó residual út soha nincs normalizálva. Ez a pre-norm. A 2017-es cikk az ellenkezőjét teszi, x = LayerNorm(x + Att(x)) — post-norm, amely magára a residual útra tesz LayerNormot.
Xiong és társai a különbséget az inicializáláskori gradienten keresztül magyarázták, amely post-norm hálózatban mélységgel rosszul skálázódik — ezért kellett az eredeti transformernek tanulási ráta warmup, hogy egyáltalán tanuljon.8 Tizenkét blokk, 1000 lépés, tanulási ráta :
gradient norm per block at initialisation, before any step
pre-norm block 1 0.0498 ... block 12 0.0657 ratio last/first 1.32
post-norm block 1 0.0977 ... block 12 0.1613 ratio last/first 1.65
pre-norm, no warmup perplexity 37.82
pre-norm, 200-step warmup perplexity 37.62
post-norm, no warmup perplexity 308.05
post-norm, 200-step warmup perplexity 37.88A post-norm warmup nélkül nyolcszor rosszabb, post-norm warmuppal pedig pontosan hozza a pre-normot. A warmup itt nem általánosan jó gyakorlat; folt a normalizálás egy konkrét elrendezésére, és a LayerNorm áthelyezése megszünteti a szükségességét. Ezért 2019 óta lényegében minden modell pre-norm, és ezért a 2017-es ábrát történetként, nem specifikációként kell olvasni.
Hol van egy token?
Link a szakaszhoz: Hol van egy token?Töröld a position embeddingeket, és a modell még mindig tanul; egyszerűen nem tudja megmondani, hol van bármi, és ez szimmetria, nem tanítási hiba. Az attention pontszámában semmi sem említi magukat a vagy értékeket, ezért a bemenet permutálása permutálja a kimenetet: a self-attention permutáció-ekvivariáns. Ez az átlag sorrendvaksága jobb álruhában — a causal mask visszahoz valamennyi sorrendet, hiszen minden pozíció más prefixet lát, de egy prefixen belül minden sorrend egyforma.
Négy módszer pozíció bejuttatására, 64-tokenes ablakokon tanítva, 64-en, 128-on és 256-on értékelve — túl minden hosszon, amit láttak:
| pozíciók | perplexity 64-nél | 128-nál | 256-nál |
|---|---|---|---|
| semmi | 48.79 | 52.63 | 57.52 |
| tanult abszolút embeddingek | 38.63 | 108.47 | 181.94 |
| fix szinuszok | 42.96 | 95.26 | 152.25 |
| RoPE | 44.12 | 50.52 | 84.84 |
| ALiBi | 44.95 | 43.51 | 42.49 |
Tanult abszolút embeddingek — pozíciónként egy vektor, a tokenhez adva — nyernek a tanított hosszon, aztán lezuhannak a szakadékba, mert a 100. pozíció soha nem volt batchben, és az embeddingje még mindig az a véletlen vektor, amiként indult. A szinuszok, az eredeti választás, tanulás helyett számítottak, geometriailag elosztott frekvenciájú szinuszokból és koszinuszokból; a 2017-es cikk azt remélte, hogy ez extrapolál, a táblázat pedig azt mondja, hogy nem — a függvény definiált a 200. pozíción, de a modell sosem tanulta meg ott olvasni. A RoPE9 semmit sem ad hozzá, ehelyett elforgatja a queryt és a keyt a pozícióval arányos szöggel, kétdimenziós szeletekben; mivel egy skalárszorzat mindkét oldalának azonos elforgatása változatlanul hagyja azt, a pontszám végül csak -től függ, így a pozíció ingyen relatívvá válik, és nincs tábla, amely kifogyna. Romlik, de romlik, nem zuhan. Az ALiBi10 itt a legegyszerűbb és legfurcsább eredmény: lineáris büntetés a pontszámon a távolsággal arányosan, headenként eltérő meredekséggel. A perplexityje javul, ahogy az ablak túlnő a tanítási hosszon, 44.95-ről 42.49-re, mert a büntetés bármely távolságon definiált, és minden head ugyanazt teszi tovább, amire tanították.
A tanulság túléli a táblázatot: más probléma az olyan architektúra, amely valamit nem tud reprezentálni, mint az, amely soha nem tanulta meg azt a tartományt, és a második az, amelyik harap. Ez áll minden „128K-ra bővítettük a contextet” bejelentés gépezete mögött is — ezek szinte mindig egy rotary kódolás újraskálázásai, és ezért mondja a 16. fejezet, hogy a context limit mozog, nem eltűnik.
A dropout ugyanígy öröklődik: megjelenik az attention súlyokon a softmax után, minden alréteg kimenetén a residual hozzáadás előtt, és az embedding összegén, pontosan azt téve, amit a 6. fejezet leírt. Nagy pretraining futásokban gyakran nullára állítják, mert egy modell, amely minden tokent egyszer lát, nincs igazán abban a helyzetben, hogy overfiteljen.
Mennyibe kerül
Link a szakaszhoz: Mennyibe kerülA rétegben két tensor alakja , ahol a tokenek száma: a pontszámok és a softmax utáni súlyok. Minden más — minden projekció, az egész MLP — lineáris -ban.
Egy attention réteg, 512 széles, 8 head, egyes batch, float32, laptop GPU-n. A két milliszekundumos oszlopot csak az arányaik miatt olvasd: falióra-idők egy 8 GB-os laptopkártyán, amely 1785 MHz-ről 300 MHz alá throttlingol, amikor felforrósodik, ezért ugyanez a kód hideg futásban hétszer-tízszer gyorsabban tér vissza, terhelt állapotban pedig még lassabban. A megabájtos oszlopok allocator byte-számlálók, és nem mozdulnak.
tokens ms total ms x4 ms projections attn matrix MB peak MB MB x4
128 2.246 - 1.324 0.5 14.6 -
256 2.855 1.27 2.113 2.0 19.2 1.31
512 5.761 2.02 3.105 8.0 34.4 1.79
1024 16.414 2.85 4.008 32.0 89.1 2.59
2048 51.573 3.14 9.989 128.0 296.1 3.32
4096 225.432 4.37 20.176 512.0 1100.1 3.72
8192 832.838 3.69 40.106 2048.0 4300.1 3.91
16384 OUT OF MEMORY 8192.0
fitted exponent (log-log slope, last four rows): time ~ n^1.91 memory ~ n^1.87A x4 oszlopok az előző sorhoz viszonyított arányok, és duplázása időben és memóriában is pontosan 4 felé konvergál — az utolsó lépésnél 3,91 az elméleti 4-hez képest. A projekciós oszlop a kontroll: 4,0 ms 1024 tokennél, 40,1 ms 8192-nél, tízszeres szorzó nyolcszoros bemenetért. Lineáris, ahogy ígértük.
Aztán az utolsó sor. Egy attention réteg, egy sorozat, modell nélkül körülötte, kifut a memóriából egy 8 GB-os GPU-n 16 384 tokennél — önmagában a pontszámmátrix 8 GB lenne, mert 8 head × 16 384 × 16 384 × 4 byte. Nem a modell; egyetlen köztes tensor egyetlen rétegben.
Ez a fizikai tény három későbbi fejezet alatt. Ezért van egyáltalán limitje a context window-nak, amit a 16. fejezet árrá alakít. Ezért létezik a FlashAttention, amely ugyanazt az eredményt csempékben számolja ki anélkül, hogy valaha tárolná a mátrixot — előbb memóriaoptimalizáció, mint sebességoptimalizáció.11 És ez a hosszú prompt árának aritmetikája, amelyet a 24. fejezet egy agent ciklusban fizet meg — külön ügy attól a másik megállapításától, hogy egy modell a hosszú contextet rosszabbul is használja, amit megmér, és nem ezt a képletet hibáztatja érte.
Részletek megjelenítése
A két cache-zsugorító variáns, itt megnevezve, a 13. fejezetben kifizetve.
A generálás cache-eli a már feldolgozott tokenek keyeit és value-it — tokenenként egy key és egy value, headenként és rétegenként. A multi-query attention12 megtartja a query projekciót, de egyetlen key és value projekciót használ, amelyet minden head megoszt, így a cache-t -tel osztja. A grouped-query attention13 köztes megoldás: a headek csoportosítva vannak, minden csoport egy keyt és value-t oszt meg, így a szokásos attention, pedig multi-query. 2023 óta szinte minden nyílt modell ezt használja 4 vagy 8 csoporttal. Egyik sem a minőségért létezik; mindkettő annak a cache-nek a méretéért, a 13. fejezet pedig elvégzi az aritmetikát, amely ebből azt csinálja: „melyik modell fér el a GPU-dban”.
Két forma, és az egyik mérete
Link a szakaszhoz: Két forma, és az egyik méreteA 2017-es cikk egy encoder-decoder felépítést ír le: egy stack a forrást olvassa maszk nélküli attentionnel, egy második causally generálja a célt, középen pedig egy harmadik attention-fajta, ahol a decoder queryjei találkoznak az encoder keyeivel. Ez fordításhoz helyes, ahol a bemenet és a kimenet két sorozat.
Ami nyert, az a decoder-only fél volt — egy stack, végig causal, bemenet és kimenet ugyanabban a sorozatban — és az ok nem az elegancia. A „jósoljuk meg a következő tokent” bármilyen szövegen fut, így a tanítóhalmaz az internet, nem párhuzamos korpusz, és minden azzá az egy feladattá válik: egy fordítás olyan dokumentum, amely forrást, majd célt tartalmaz, egy kérdés és válasza dokumentum, egy beszélgetés közepén tool calllal dokumentum. A 11. fejezet arról szól, hogyan gyártjuk az utóbbit. Az encoderek nem tűntek el — az egyik egyszerre látja a teljes bemenetet, ami pontosan az, amit akkor akarsz, amikor a feladat egy szöveg reprezentálása, nem a folytatása, és ezért származnak a 19. fejezet retrieval embeddingjei encoderekből, nem abból a modellből, amelyik cseveg.
A blokk definiálása után a modellméret aritmetika. Blokkonként, szélességgel és négyszeres bővítéssel: a -hez, mind a négyen biasokkal, ahogy a GPT-2-ben vannak — a fenti tábla ezek közül háromnál elhagyja a biast, ezért mellett 2304-gyel kevesebb blokkonként; az MLP-hez; két LayerNormhoz — , plusz egy token tábla és abszolút pozíciókhoz . A GPT-2 small alakjára — , 12 blokk, 50 257-es szókészlet, 1024-es context, a kimeneti réteg megosztja az embedding súlyokat:
token embeddings 50,257 x 768 = 38,597,376
position embeddings 1,024 x 768 = 786,432
one block 7,087,872
12 blocks 85,054,464
final LayerNorm 2 x 768 = 1,536
total (weights tied) 124,439,808Ez a modell publikált mérete. A képlet nem közelítés; ez maga a modell. Azt is vedd észre, hogy egy kis modell közel harmada az embedding tábla, ezért a szókészlet mérete architekturális döntés, nem preprocessing — ez az a trade-off, amelyet a 7. fejezet felállított.
Mire néz valójában egy head?
Link a szakaszhoz: Mire néz valójában egy head?A perplexity egy korpuszról szóló szám. Más kérdés, mit csinál egy head, és egy megabájtnyi Shakespeare-en tanított modell rossz műszer hozzá: egy 500 000 paraméteres modell attention mapjéről az őszinte állítás az, hogy többnyire nem értelmezhető. Tehát: egy nyelv, ahol a kérdésnek van helyes válasza.
A klasszikus illusztráció: the animal did not cross the street because it was too tired, ahol az it az állat, szemben azzal, hogy …because it was too wet, ahol egyetlen szó a referenst az utcára mozgatja. Ezek Winograd-sémák14 — mondatpárok, amelyek egy szó kivételével azonosak, és ez a szó dönti el, mire utal a névmás.
Ezeket azonban csalással is meg lehet oldani, és ezt a részt hagyják ki a tutorialok. Ha a két jelölt egy állat és egy hely, a tired és a wet kategória alapján azonosítja a referenst, és egy modell, amely csak azt tudja, mely szavak vannak jelen, sorrendismeret nélkül is helyesen válaszol. A feladat ezen verzióján, visszatartott állat/hely párokkal mérve:
uniform causal average held-out referent accuracy 100.0 %
one transformer block held-out referent accuracy 91.7 %A bag of words veri a transformert. Bármely demonstráció, amely erre a mondatra épül, semmit sem bizonyít az attentionről.
Zárjuk be tehát a lyukat: húzzunk mindkét jelöltet ugyanabból a tizenhat főnévből álló készletből, amelyek bármelyike bármelyik helyen megjelenhet, a mellékneveket pedig szerep szerint osszuk, nem kategória szerint — négy miatt it az átkelő (tired, scared, slow, weak), négy miatt az átkelt dolog (wet, wide, busy, steep).
the {x} did not cross the {y} because it was too {adj} , so the {ref} waited .Tanítsuk szokásos next-token prediktorként, pontozzunk egy pozíciót — a so the utáni szót —, és a visszatartott halmazt olyan főnévpárokból építsük, amelyek fordított sorrendje szerepelt a tanításban, hogy bármi, ami tudja, melyik két főnév van jelen, de nem tudja, melyik jött előbb, visszafelé válaszoljon.
| modell | paraméterek | visszatartott | a másik főnevet nevezi meg |
|---|---|---|---|
| csak aktuális token | 5 796 | 5.2 % | 5.2 % |
| egységes causal átlag | 5 796 | 27.9 % | 50.0 % |
| egy head tanult attention | 18 084 | 35.4 % | 64.6 % |
| négy head | 22 244 | 75.0 % | 15.6 % |
| egy transformer blokk | 55 716 | 92.7 % | 4.2 % |
| két transformer blokk | 105 508 | 100.0 % | 0.0 % |
A két jelenlévő főnév között a véletlen esély 50 %. Az egységes átlag 27,9 %-on landol, és a pár rossz főnevével pontosan az idő felében válaszol — ez annak az aláírása, hogy valami tudja, mely szavak vannak ott, de semmit sem tud a sorrendjükről, ahogy a három szakasszal korábbi shuffle teszt megjósolta.
Most a térkép: az attention azon a pozíción, amelynek meg kell neveznie a referenst, blokkonként a négy head átlagában, a két mondatra, amelyek egy szóban térnek el. Egy egységes átlag 0,067-et tenne mind a tizenöt látható tokenre.
the animal did not cross the street because it was too tired , so the animal waited .
blk 1 the:0.00 animal:0.70 did:0.00 not:0.00 cross:0.00 the:0.00 street:0.06
because:0.00 it:0.00 was:0.00 too:0.00 tired:0.00 ,:0.05 so:0.00 the:0.19
blk 2 the:0.00 animal:0.00 did:0.00 not:0.00 cross:0.00 the:0.00 street:0.00
because:0.00 it:0.00 was:0.00 too:0.00 tired:1.00 ,:0.00 so:0.00 the:0.00
the animal did not cross the street because it was too wet , so the street waited .
blk 1 the:0.00 animal:0.70 did:0.00 not:0.00 cross:0.00 the:0.00 street:0.06
because:0.00 it:0.00 was:0.00 too:0.00 wet:0.00 ,:0.05 so:0.00 the:0.19
blk 2 the:0.00 animal:0.00 did:0.00 not:0.00 cross:0.03 the:0.00 street:0.49
because:0.00 it:0.00 was:0.00 too:0.20 wet:0.03 ,:0.00 so:0.00 the:0.25Az 1. blokk mindkét mondatban azonos — 0,70 az első főnéven, bármi is a melléknév. Ez nem kudarc, hanem bizonyíték: az első rétegben egy pozíció queryje a pozíció saját tokenjének és indexének függvénye, és a 14. pozícióban álló the mindkét mondatban ugyanaz a token. Egy első rétegbeli head nem kondicionálhat olyan szóra, amelyet még nem hozott el. Ezért az 1. blokk az egyetlen hasznos dolgot teszi, amit tehet, és előrehúzza az első főnevet.
A 2. blokkban válnak szét a mondatok, és ugyanaz a sor mind a nyolc melléknéven megmutatja a szabályt, amelyet a modell megtalált:
| melléknév | 2. blokk az animal-ön | a street-en | a melléknéven | válasz |
|---|---|---|---|---|
| tired, scared, slow, weak | 0.000 | 0.000 | 1.000 | animal |
| wet, wide, busy, steep | 0.000 | 0.491 | 0.00–0.03 | street |
Átkelő-melléknév esetén a második blokk teljes súlyát a melléknévre teszi, mert a válasz már a residual streamben van — az 1. blokk odatette —, és csak megerősítés kell neki. Átkelt-dolog melléknév esetén inkább elmegy, és előhozza a másik főnevet. Ez kétugrásos circuit: az egyik head előremozgat egy jelöltet, egy későbbi réteg headje pedig elolvas egy tokent, amely eldönti, megtartsa-e. A rétegek közötti kompozíció a mechanizmus, és ezért ért el egy blokk 92,7 %-ot, kettő pedig 100 %-ot.
Ugyanez a legjobban dokumentált circuit formája valódi modellekben is. Induction headek — egy previous-token head, amely a következő rétegben egy olyan headet táplál, amely kiegészíti a [A][B] … [A] → [B] mintát — azok, amelyeket az Anthropic interpretability munkái az in-context learning nagy része mögött azonosítanak, és a pretraining során felismerhető pillanatban alakulnak ki. Ez a fejezet nem kísérli meg ezt az elemzést: a hivatkozásokban mindkét cikkel együtt delegálja, mert circuitöket kiolvasni egy valódi modellből kutatási terület, nem szakasz.
Végül az implementáció. A fenti harminc sor, a PyTorch saját súlyaiból másolva:
ours vs nn.MultiheadAttention max |diff| = 1.7881393432617188e-07
ours vs F.scaled_dot_product_attention max |diff| = 1.7881393432617188e-07olyan kimeneteken, amelyek átlagos nagysága 0,159: ugyanaz az aritmetika más sorrendben, float32 pontossággal.
Hová megyünk innen
Link a szakaszhoz: Hová megyünk innenMegvan az architektúra, amelyre a kurzus hátralévő részének minden modellje épül, és kisebb, mint a híre: egy súlyozott átlag, amelynek súlyai tanultak, egy pozíciónkénti MLP, amely a paraméterek kétharmadát tartja, két normalizálás és két összeadás, stackelve.
Ami nincs meg, az egy bármit is tudó modell, és a stackelés önmagában nem javítja meg. Két blokk ezen a korpuszon 14,49-es training perplexityt és 40,57-es validációs perplexityt ér el, szemben az egy blokk 18,77 és 38,07 értékével — több kapacitás, jobb azon, amit látott, rosszabb azon, amit nem, vagyis a 6. fejezet táblázata transformerrel. A távolság e modell és azok között, amelyekkel a 14–30. fejezetek beszélgetnek, nem architekturális. Ugyanaz a blokk, többször ismételve, sokkal több szövegen.
Ez könyvelési problémává teszi, és a könyvelés furcsább, mint amilyennek látszik. Mennyi szöveg kell, és honnan szerzi meg bárki? Mennyi aritmetika, és hogyan becsülöd meg azelőtt, hogy elköltötted a pénzt? Rögzített költségvetés mellett jobb nagyobb modellt készíteni, vagy több adatot mutatni neki — és van helyes válasz, vagy csak divat? A 10. fejezet mindháromra méréssel válaszol, és árat tesz a kérdés legolcsóbb hasznos formájára: ma mennyibe kerül egy GPT-2-szerű modellt nulláról betanítani?
Források és módszer
Link a szakaszhoz: Források és módszerHárom magyarázat jobb ennél az anyagnál abban, amire készült, és ez a fejezet úgy íródott, hogy mellettük legyen olvasható. Jay Alammar The Illustrated Transformer című írása az adatáramlás valaha rajzolt legjobb képe. A Harvard NLP The Annotated Transformer anyaga a 2017-es cikk futó kóddal, sorról sorra közbeszőve. Andrej Karpathy Let's build GPT: from scratch, in code, spelled out videója két óra alatt élőben építi fel ugyanezt a modellt, és a fenti ablation-létra ugyanaz a gerinc, más korpuszon mérve. Az interpretability kérdéshez, amelyet ez a fejezet csak érint, az elsődleges források Elhage és társai A Mathematical Framework for Transformer Circuits (2021), valamint Olsson és társai In-context Learning and Induction Heads (2022) munkái, mindkettő az Anthropic interpretability csoportjától.
Hivatkozások
Link a szakaszhoz: Hivatkozások-
Hochreiter, S. és Schmidhuber, J. Long Short-Term Memory. Neural Computation 9(8), 1735–1780. o. (1997). ↩
-
Sutskever, I., Vinyals, O. és Le, Q. V. Sequence to Sequence Learning with Neural Networks. arXiv:1409.3215 (2014). Az encoder-decoder, amelynek egyetlen context vektora a szűk keresztmetszet. ↩
-
Bahdanau, D., Cho, K. és Bengio, Y. Neural Machine Translation by Jointly Learning to Align and Translate. arXiv:1409.0473 (2014). Attention, három évvel a transformer előtt. ↩
-
A perplexity az átlagos tokenenkénti cross-entropy exponenciálisa, a 8. fejezetből. Itt minden szám ugyanazt a tokenizert és ugyanazt a validációs splitet használja, ami az egyetlen feltétel, amely mellett két perplexity egyáltalán összehasonlítható. ↩
-
Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł. és Polosukhin, I. Attention Is All You Need. arXiv:1706.03762 (2017). A 3.2.1. szakasz az az egy mondat -ről, amelynek mérésére ez a fejezet egy teljes szakaszt szán. ↩
-
Shazeer, N., Mirhoseini, A., Maziarz, K., Davis, A., Le, Q., Hinton, G. és Dean, J. Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. arXiv:1701.06538 (2017). ↩
-
Ba, J. L., Kiros, J. R. és Hinton, G. E. Layer Normalization. arXiv:1607.06450 (2016). A 6. fejezet vezette be és mérte meg; itt változatlanul használjuk. ↩
-
Xiong, R., Yang, Y., He, D., Zheng, K., Zheng, S., Xing, C., Zhang, H., Lan, Y., Wang, L. és Liu, T.-Y. On Layer Normalization in the Transformer Architecture. arXiv:2002.04745 (2020). A pre-norm mögötti gradient-elemzés, és az érv, hogy a warmup tünet. ↩
-
Su, J., Lu, Y., Pan, S., Murtadha, A., Wen, B. és Liu, Y. RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864 (2021). ↩
-
Press, O., Smith, N. A. és Lewis, M. Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation. arXiv:2108.12409 (2021). A fent reprodukált extrapolációs eredmény. ↩
-
Dao, T., Fu, D. Y., Ermon, S., Rudra, A. és Ré, C. FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. arXiv:2205.14135 (2022). ↩
-
Shazeer, N. Fast Transformer Decoding: One Write-Head is All You Need. arXiv:1911.02150 (2019). ↩
-
Ainslie, J., Lee-Thorp, J., de Jong, M., Zemlyanskiy, Y., Lebrón, F. és Sanghai, S. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245 (2023). ↩
-
Levesque, H. J., Davis, E. és Morgenstern, L. The Winograd Schema Challenge. KR (2012). Az animal / street mondat mögötti konstrukció, amelyet minden attention tutorial használ. ↩