Ugrás a tartalomra
9/309/30. fejezet

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 tt 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 t1t-1 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ük

1997-től nagyjából 2017-ig az összefoglaló egy recurrent állapot volt: tarts fenn egy h\mathbf{h} vektort, és frissítsd minden tokennél, ht=f(ht1,xt)\mathbf{h}_t = f(\mathbf{h}_{t-1}, \mathbf{x}_t). 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 TT lépésen át történő backpropagation TT Jacobi-mátrixokat szoroz össze, ezért a gradient eltűnik vagy felrobban — ugyanaz a betegség, amelyet az 5. fejezet egyetlen tanh\tanh 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: ht\mathbf{h}_t-hez kell ht1\mathbf{h}_{t-1}, é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 legkézenfekvőbb függvény, amely változó számú vektorból egy vektort ad vissza, az átlag:

ct=1ti=1txi\mathbf{c}_t = \frac{1}{t}\sum_{i=1}^{t} \mathbf{x}_i

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 10310^{-3} mellett, 64-es batch mérettel. A perplexity a visszatartott spliten szerepel.4

modellparaméterekvalidációs perplexity
csak az aktuális token, context nélkül263 16859.71
plusz minden előtte álló egységes átlaga263 168248.07
plusz tanult position embeddingek279 552245.93
egységes átlag a tokenhez hozzáadva, nem helyette263 16860.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:

order.pyPYTHON
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())
TEXT
2.9802322387695312e-08

Lebegő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 softmax

Egy 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:

mechanics.pyPYTHON
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 again
TEXT
loop 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.167

Egy 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 tt pozíció láthatná a t+1t{+}1 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 -\infty é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 -\infty-et, ne -1e9-t: ez az az érték, amit a masking jelent, float16-ra castolva -\infty-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?

Nem lehetnek puszta paraméterek. Egy tanult T×TT \times T 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 tt pozíciót a ii 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 ii pozíciót a tt pozíció számára xtxi\mathbf{x}_t \cdot \mathbf{x}_i-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ó, qt=Wqxt\mathbf{q}_t = W_q\mathbf{x}_t, a query; és mivel kínálja fel magát megtalálásra, ki=Wkxi\mathbf{k}_i = W_k\mathbf{x}_i, a key. A pontszám legyen qtki\mathbf{q}_t \cdot \mathbf{k}_i, és a szimmetria eltűnik, mert WqWkW_q \neq W_k: egy token hirdethet egy dolgot, és kereshet egy másikat.

Egy dolog még mindig hibás. A súlyozott összeg magukon a xi\mathbf{x}_i-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, vi=Wvxi\mathbf{v}_i = W_v\mathbf{x}_i, a value-t, és ezeket összegezzük.

A képlet most már könyvelés:

Attention(Q,K,V)=softmax ⁣(QKdk+M)V\mathrm{Attention}(Q, K, V) = \mathrm{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}} + M\right)V

ahol MM a causal mask, nulla az átlón és alatta, -\infty felette. Kódban harminc sor, amelyből húsz shape:

attention.pyPYTHON
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éd

A dk\sqrt{d_k} 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 q\mathbf{q} és k\mathbf{k} elemei függetlenek, nulla várható értékkel és egy varianciával, akkor minden qjkjq_j k_j szorzat varianciája egy, a független dolgok varianciái pedig összeadódnak:

Var(qk)=j=1dkVar(qjkj)=dk\mathrm{Var}(\mathbf{q}\cdot\mathbf{k}) = \sum_{j=1}^{d_k}\mathrm{Var}(q_j k_j) = d_k

Tehát a pontszámok szórása dk\sqrt{d_k}. Húszezer véletlen páron mérve:

TEXT
     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.000

Mié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:

dkd_klegnagyobb súly, osztatlanentrópiaeffektív tokeneklegnagyobb súly, osztottentrópiaeffektív tokenek
40.2052.94419.00.0813.75842.9
160.4381.6925.40.0753.84946.9
640.4890.8742.40.0853.67339.4
2560.99990.00071.00.1433.54734.7
10241.00000.00001.00.1323.64438.3

Az „effektív tokenek” az entrópia exponenciálisa: hány pozíciót átlagol a sor valójában. Osztatlanul, dk=256d_k = 256 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 tanh\tanh-en. Egyetlen elemre elkötelezett softmaxnak alig van deriváltja: Jacobi-mátrixának diagonálisa wi(1wi)w_i(1-w_i), mindkét végén nulla. Kétezer véletlen soron:

dkd_kiwi(1wi)\sum_i w_i(1-w_i) osztatlanosztotttelített sorok (legnagyobb súly 0.99 felett)
40.84270.95680.2 % → 0.0 %
640.29400.960917.9 % → 0.0 %
2560.14060.960949.1 % → 0.0 %
10240.06810.961170.4 % → 0.0 %

dk=1024d_k = 1024 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égosztatlanosztva dk\sqrt{d_k}-gyelosztva dkd_k-gyel
négy head, dk=32d_k = 3237.2938.0737.89
egy head, dk=128d_k = 12848.5146.1045.99
egy head, dk=256d_k = 25665.3747.53
egy head, dk=512d_k = 51267.0649.15
egy head, dk=1024d_k = 102476.6959.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.

dk=32d_k = 32 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:

dkd_kpontszám szórása inicializáláskor1500 lépés után, osztatlan1500 lépés után, osztotttelített sorok, osztatlanosztott
25610.49121.672.1391.9 %0.8 %
51215.13836.852.6698.7 %1.3 %
102421.155147.463.4499.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 dkd_k 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él

Egy 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 dmodel/hd_{\text{model}}/h szélességgel, fűzd össze, és keverd még egy WoW_o 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:

modellparaméterekvalidációs perplexity
egységes átlag, hozzáadva279 55260.45
egy attention head, a token helyett328 70455.47
egy attention head, hozzáadva328 70446.10
négy head egy helyett345 21643.21
plusz a feed-forward network476 92839.87
plusz LayerNorm — a teljes blokk477 69638.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égheadekattentionfeed-forwardösszesen blokkonként
128465 664 (33.2 %)131 712 (66.6 %)197 888
768122 360 064 (33.3 %)4 722 432 (66.6 %)7 085 568
40963267 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 d×dd \times d 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ölve

A 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.

block.pyPYTHON
class Block(nn.Module):
    def forward(self, x):
        x = x + self.att(self.ln1(x))     
        x = x + self.ff(self.ln2(x))      
        return x

Né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 3×1033 \times 10^{-3}:

TEXT
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.88

A 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.

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 tt vagy ii é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ókperplexity 64-nél128-nál256-nál
semmi48.7952.6357.52
tanult abszolút embeddingek38.63108.47181.94
fix szinuszok42.9695.26152.25
RoPE44.1250.5284.84
ALiBi44.9543.5142.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 tit - i-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.

A rétegben két tensor alakja n×nn \times n, ahol nn 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 nn-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.

TEXT
  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.87

A x4 oszlopok az előző sorhoz viszonyított arányok, és nn 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 hh query projekciót, de egyetlen key és value projekciót használ, amelyet minden head megoszt, így a cache-t hh-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 g=hg = h a szokásos attention, g=1g = 1 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”.

A 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, dd szélességgel és négyszeres bővítéssel: 4d2+4d4d^2 + 4d a Wq,Wk,Wv,WoW_q, W_k, W_v, W_o-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 d=768d = 768 mellett 2304-gyel kevesebb blokkonként; 8d2+5d8d^2 + 5d az MLP-hez; 4d4d két LayerNormhoz — 12d2+13d12d^2 + 13d, plusz egy V×dV \times d token tábla és abszolút pozíciókhoz nctx×dn_{\text{ctx}} \times d. A GPT-2 small alakjára — d=768d = 768, 12 blokk, 50 257-es szókészlet, 1024-es context, a kimeneti réteg megosztja az embedding súlyokat:

TEXT
  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,808

Ez 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.

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:

TEXT
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).

TEXT
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.

modellparaméterekvisszatartotta másik főnevet nevezi meg
csak aktuális token5 7965.2 %5.2 %
egységes causal átlag5 79627.9 %50.0 %
egy head tanult attention18 08435.4 %64.6 %
négy head22 24475.0 %15.6 %
egy transformer blokk55 71692.7 %4.2 %
két transformer blokk105 508100.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.

TEXT
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.25

Az 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év2. blokk az animal-öna street-ena melléknévenválasz
tired, scared, slow, weak0.0000.0001.000animal
wet, wide, busy, steep0.0000.4910.00–0.03street

Á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:

TEXT
ours vs nn.MultiheadAttention           max |diff| = 1.7881393432617188e-07
ours vs F.scaled_dot_product_attention  max |diff| = 1.7881393432617188e-07

1.8×1071.8 \times 10^{-7} olyan kimeneteken, amelyek átlagos nagysága 0,159: ugyanaz az aritmetika más sorrendben, float32 pontossággal.

Megvan 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?


Há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.

  1. Hochreiter, S. és Schmidhuber, J. Long Short-Term Memory. Neural Computation 9(8), 1735–1780. o. (1997).

  2. 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.

  3. 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.

  4. 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ó.

  5. 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 dk\sqrt{d_k}-ről, amelynek mérésére ez a fejezet egy teljes szakaszt szán.

  6. 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).

  7. 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.

  8. 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.

  9. Su, J., Lu, Y., Pan, S., Murtadha, A., Wen, B. és Liu, Y. RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864 (2021).

  10. 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.

  11. 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).

  12. Shazeer, N. Fast Transformer Decoding: One Write-Head is All You Need. arXiv:1911.02150 (2019).

  13. 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).

  14. 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.

Készen állsz, hogy a LIA válasszon helyetted?

Építs az összes AI-modellel egy helyen – kezdd el ma, ingyen.