Přeskočit na obsah
9/30Kapitola 9 z 30

Attention a Transformer block odvozené z průměru

Začněte průměrem jako nejlevnějším shrnutím context, změřte jeho selhání a nechte z opravy vyplynout vzorec attention.

Na této stránce

Přicházíte sem s tokenizerem z Kapitoly 7, tabulkou embedding z Kapitoly 8 a cílem, který k nim patří: při daných dosavadních tokens přiřadit pravděpodobnost dalšímu.

Chybí prostředek. Aby model předpověděl token tt, potřebuje jeden vektor, který shrnuje vše před ním, a nic z toho, co jste postavili, žádný takový vektor nevytváří. Embedding token t1t-1 jím není — to je bigramový model a nemůže vědět, že věta začala otázkou. Ani konkatenace všech předchozích embeddings jím není: jejich počet se v každém kroku mění a pevná váhová matice neumí přijmout vstup proměnné délky.

Tedy: jeden vektor pevné velikosti, který shrnuje proměnný počet vektorů. To je celý problém a attention je to, co dostanete, když ho vyřešíte tím nejlínějším možným způsobem a pak opravíte dvě věci, které se rozbijí.

Odpověď, kterou obor měl, a proč ji nestavíme

Odkaz na sekci: Odpověď, kterou obor měl, a proč ji nestavíme

Od roku 1997 přibližně do roku 2017 bylo shrnutím rekurentní rozpoložení: udržujte vektor h\mathbf{h} a aktualizujte ho při každém token, ht=f(ht1,xt)\mathbf{h}_t = f(\mathbf{h}_{t-1}, \mathbf{x}_t). Pevná velikost, proměnný vstup, přesně správný tvar.

Selhalo to třemi způsoby a architektura této kapitoly odpovídá na všechny tři. Backpropagation přes TT kroků násobí TT Jacobiho matic, takže gradient mizí nebo exploduje — nemoc, kterou Kapitola 5 měřila uvnitř jediného uzlu tanh\tanh. LSTM1 byla navržena přesně proti tomu a posunula použitelný rozsah z desítek kroků na stovky, aniž změnila fakt, že informace z token 5 dorazí k token 500 jen tak, že přežije 495 sekvenčních aktualizací. Celý zdroj se musel vejít do jednoho vektoru: v sekvenčně-sekvenčním překladu2 encoder komprimuje vstup do svého finálního stavu. Bahdanau, Cho a Bengio toto hrdlo pojmenovali a opravili v roce 2014, tři roky před transformerem, tím, že decoderu dovolili vzít vážený součet všech stavů encoderu s vahami, které si spočítal sám.3 Všechno níže je táž myšlenka, aplikovaná sekvencí na sebe samu, s odstraněnou rekurencí. A aktualizace je sekvenční už z konstrukce: ht\mathbf{h}_t potřebuje ht1\mathbf{h}_{t-1} a GPU s deseti tisíci jádry s tím nic neudělá. Architektura, která vyhrála, není zjevně chytřejší; je to ta, jejíž drahý krok je násobení matic.

Druhý klasický induktivní bias, konvoluce — posouvejte jeden malý filtr po celém vstupu, takže feature detekovaná kdekoli se detekuje všude — zde také nestavíme; pro obrazy je téměř přesně správná a patří do kurzu vidění. Rekurence ani konvoluce se po této stránce znovu neobjeví, proto ani jedna nedostává kapitolu: Kapitola 1 slíbila, že vynechávky budou přiznané, ne tiché.

Nejlevnější shrnutí, jaké existuje

Odkaz na sekci: Nejlevnější shrnutí, jaké existuje

Nejzřejmější funkce proměnného počtu vektorů, která vrací jeden vektor, je průměr:

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

Libovolný počet vstupů, pevná velikost výstupu, diferencovatelné, zdarma. Tabulka embedding plus tento průměr plus lineární vrstva do slovníku je kompletní jazykový model v patnácti řádcích. Je také hrozný — a způsob, jakým je hrozný, je celá derivace.

Níže uvedený korpus je jeden megabajt Shakespeara, 1 115 394 znaků, přes byte-level BPE tokenizer typu postaveného v Kapitole 7 se slovníkem 1024: 459 760 tokens po 2,43 znacích, rozděleno 90/10. Každý model má šířku 128, vidí 128 tokens a trénuje 3000 kroků AdamW při 10310^{-3} s batchem 64. Perplexity je na odloženém splitu.4

modelparametryvalidační perplexity
pouze aktuální token, vůbec žádný context263,16859.71
plus rovnoměrný průměr všeho před ním263,168248.07
plus naučené poziční embeddings279,552245.93
rovnoměrný průměr přičtený k token místo jeho nahrazení263,16860.45

Přečtěte si druhý řádek dvakrát. Průměrování context nepomůže trochu; udělá model čtyřikrát horším než úplné ignorování context. Dva důvody, oba dokazatelné, ne empirické.

Průměr nevidí pořadí. Sčítání je komutativní, takže promíchání okna nechá shrnutí nezměněné — ne přibližně:

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

Šum floating-point při přeřazeném součtu: obě shrnutí jsou tentýž vektor. Model, jehož jediným pohledem na context je průměr, nedokáže rozlišit pes kousl muže od muž kousl psa. Třetí řádek dokazuje, že to nelze opravit přidáním pozic do vstupů — naučený poziční embedding na každém token před průměrováním získal 2,14 bodu ze 188. Pozice vstoupí do součtu a součet je zapomene.

A průměr utopí přítomnost. Na pozici 100 je aktuální token jednou setinou shrnutí. To má levnou opravu, kterou už vlastníte: ponechte token a shrnutí k němu přičtěte — reziduální spojení z Kapitoly 6, a čtvrtý řádek ukazuje, co udělá. Po opravě ředění nepřispívá rovnoměrný průměr vůbec ničím: 60,45 proti baseline 59,71. Každý token tam je, všechny mají stejnou váhu, a stejné vážení je totéž jako žádná informace.

Problém není průměrování. Jsou to váhy.

Průměr je násobení matic a maska je softmax

Odkaz na sekci: Průměr je násobení matic a maska je softmax

Průměrování přes rostoucí prefix vypadá jako smyčka. Je to jedno násobení dolní trojúhelníkovou maticí, jejíž řádky se sčítají na jednu — a zároveň přesně 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

Tři pojmenované komponenty transformeru jsou teď na obrazovce. Trojúhelník je kauzální maska, vynucená cílem: kdyby pozice tt mohla vidět pozici t+1t{+}1, odpověď by byla ve vstupu — leak, který vám Kapitola 6 řekla auditovat, jen uvnitř architektury. Softmax je způsob implementace masky: nastavení zakázaných položek na -\infty je pošle přesně na nulu a znormalizuje zbytek, takže maskování a normalizace jsou jedna operace. (Použijte -\infty, ne -1e9: je to hodnota, kterou maskování znamená, přežije cast na float16 jako -\infty a ušetří vám rozhodování, zda je vybraná konstanta dost velká pro rozsah, ve kterém zrovna jste — což je floating-point rámeček z Kapitoly 2, který pokládá otázku, na niž nemusíte odpovídat.) A scores jsou volný parametr. Rovnoměrný průměr je to, co dostanete, když je každý povolený score stejné číslo; dejte tam libovolná čísla a softmax je převede na platné váhy.

Zbytek této kapitoly je jedna otázka: odkud ta čísla pocházejí?

Nemohou to být prosté parametry. Naučená matice T×TT \times T by byla totožná pro každou větu — mohla by kódovat „podívej se čtyři tokens zpět“, ale nikdy „podívej se na podstatné jméno, k němuž se toto zájmeno vztahuje“. Váha spojující pozici tt s pozicí ii musí záviset na tom, co je na obou pozicích, protože relevance je vztah, ne vlastnost: slovo it není relevantní samo o sobě, je relevantní k něčemu.

Nejlevnější funkce dvou vektorů vracející číslo je skalární součin z Kapitoly 1. Oscoreujte pozici ii pro pozici tt jako xtxi\mathbf{x}_t \cdot \mathbf{x}_i a mechanismus funguje — špatně, dvěma způsoby, které vynutí všechno ostatní. Skalární součin vektoru se sebou samým je jeho kvadratická norma, takže každý token by attendoval převážně sám na sebe. A vztah by byl symetrický: pokud it silně attenduje na animal, pak animal silně attenduje na it, což u jazyka není pravda, protože přídavné jméno potřebuje své podstatné jméno mnohem víc než podstatné jméno potřebuje přídavné.

Dejte tedy každému token dvě role jako dvě naučená lineární zobrazení: co tato pozice hledá, qt=Wqxt\mathbf{q}_t = W_q\mathbf{x}_t, query; a čím nabízí, že bude nalezena, ki=Wkxi\mathbf{k}_i = W_k\mathbf{x}_i, key. Score qtki\mathbf{q}_t \cdot \mathbf{k}_i a symetrie je pryč, protože WqWkW_q \neq W_k: token může inzerovat jednu věc a hledat jinou.

Jedna věc je pořád špatně. Vážený součet byl přes samotná xi\mathbf{x}_i, což nutí, aby věc, která se kopíruje, byla zároveň věcí, podle níž se matchuje. Matching chce features, které token identifikují; kopírování chce features užitečné downstream. Naučte se tedy třetí mapu, vi=Wvxi\mathbf{v}_i = W_v\mathbf{x}_i, value, a sčítejte ty.

Vzorec je teď účetnictví:

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

kde MM je kauzální maska, nula na diagonále a pod ní a -\infty nad ní. V kódu je to třicet řádků, z nichž dvacet jsou tvary:

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                                                  

Score, maska, normalizace, mix. Všechno ostatní je projekce.

Dělení odmocninou a proti čemu chrání

Odkaz na sekci: Dělení odmocninou a proti čemu chrání

Téměř každé vysvětlení dk\sqrt{d_k} říká „aby softmax nesaturoval“, což je pravda a nic to nevysvětluje. Argument jsou dva řádky rozptylu z Kapitoly 2. Pokud jsou položky q\mathbf{q} a k\mathbf{k} nezávislé se střední hodnotou nula a rozptylem jedna, každý součin qjkjq_j k_j má rozptyl jedna a rozptyly nezávislých věcí se sčítají:

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

Scores tedy mají směrodatnou odchylku dk\sqrt{d_k}. Měřeno na dvaceti tisících náhodných dvojic:

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

Proč na tom záleží: softmax je citlivý na měřítko způsobem, jakým lineární vrstva není. Zdvojnásobení vstupu lineární vrstvy zdvojnásobí její výstup; vynásobení scores deseti před softmax změní měkkou směs v tvrdou volbu. Jeden řádek 64 scores, s dělením a bez něj:

dkd_knejvětší váha, nedělenoentropieefektivní tokensnejvětší váha, dělenoentropieefektivní tokens
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

„Efektivní tokens“ je exponenciála entropie: přes kolik pozic řádek ve skutečnosti průměruje. Neděleně, při dk=256d_k = 256, čerstvě inicializovaná hlava attenduje přesně na jeden token ze 64, vybraný ničím jiným než náhodným tahem.

To je špatné dopředně a ještě horší zpětně, ve tvaru, který Kapitola 5 už měřila na tanh\tanh. Softmax zavázaný jedné položce má téměř nulovou derivaci: diagonála jeho Jacobiho matice je wi(1wi)w_i(1-w_i), nula na obou koncích. Přes dva tisíce náhodných řádků:

dkd_kiwi(1wi)\sum_i w_i(1-w_i) nedělenodělenosaturované řádky (největší váha nad 0,99)
40.84270.95680.2 % → 0.0 %
640.29400.960917.9 % → 0.0 %
2560.14060.960949.1 % → 0.0 %
10240.06810.961170.4 % → 0.0 %

Při dk=1024d_k = 1024 je sedm řádků z deseti zamrzlých ještě před začátkem tréninku a hlava, která začne zamrzlá, se nemůže naučit, na co se dívat. Po dělení je veličina plochá na 0,96 při každé šířce a nic nesaturuje.

Teď část, kterou nikdo nepublikuje: změní to finální perplexity? Smažte dělení a trénujte při čtyřech šířkách hlavy:

šířka hlavynedělenoděleno dk\sqrt{d_k}děleno dkd_k
čtyři hlavy, dk=32d_k = 3237.2938.0737.89
jedna hlava, dk=128d_k = 12848.5146.1045.99
jedna hlava, dk=256d_k = 25665.3747.53
jedna hlava, dk=512d_k = 51267.0649.15
jedna hlava, dk=1024d_k = 102476.6959.17

První dva řádky pocházejí z rozpočtu 3000 kroků výše; poslední tři jsou kratší běh — 1500 kroků, batch 32, jedna hlava, bez normalizace před projekcemi — s oběma variantami ve shodných nastaveních.

Při dk=32d_k = 32 nemá dělení žádnou hodnotu a běh bez něj je velmi mírně napřed. To není licence ho zahodit, protože při 256 má hodnotu 18 bodů perplexity a při 1024 hodnotu 17. Mechanismus je vidět v samotných scores:

dkd_kstd score při initpo 1500 krocích, nedělenopo 1500 krocích, dělenosaturované řádky, nedělenoděleno
25610.49121.672.1391.9 %0.8 %
51215.13836.852.6698.7 %1.3 %
102421.155147.463.4499.9 %16.5 %

Nedělená hlava se nevzpamatuje. Ujede: směrodatná odchylka jejích scores vzroste z 21 při inicializaci na 5147, entropie attention spadne na nulu a 99,9 % řádků dá více než 0,99 své váhy na jediný token. Jakmile je hlava tvrdý selektor, její gradient je téměř nulový a nic ji netáhne zpět, takže kolaps je stabilní. Dělená hlava po stejném tréninku sedí na směrodatné odchylce score 3,44, což je měkká směs, kterou lze pořád měnit.

Vaswani et al. říkají přesně toto a nic víc — mají podezření, že součiny „rostou ve velikosti pro velké hodnoty dkd_k“, a dělí.5 Slovo velké nese váhu a tabulky říkají, kde velké začíná: nic při 32, všechno při 256.

Více než jeden názor a dvě třetiny, o kterých nikdo nemluví

Odkaz na sekci: Více než jeden názor a dvě třetiny, o kterých nikdo nemluví

Jedna hlava je jeden řádek softmax na pozici, takže drží jednu odpověď na otázku „co je zde relevantní“. Předpovědět slovo po the ve větě the animal that crossed the wet street potřebuje syntaktický slot, subjekt i předchozí token zároveň, a jedno rozdělení pravděpodobnosti nemůže být koncentrované na třech místech. Spusťte tedy několik hlav paralelně, každou o šířce dmodel/hd_{\text{model}}/h, konkatenovat a promíchat ještě jednou maticí WoW_o: šířku jste rozdělili, nepřidali k ní.

Attention také dělá přesně jednu věc — přesouvá informaci mezi pozicemi. Každá operace v kódu výše je lineární podél osy features a Kapitola 5 dokázala, čím je zásobník lineárních map. Každý block tedy nese také malé MLP aplikované na každou pozici nezávisle, rozšiřující šířku čtyřikrát a vracející se zpět, s GELU uprostřed. Dělba práce stojí za zapamatování: attention míchá napříč pozicemi, feed-forward network počítá uvnitř pozice.

Celý žebřík, každý řádek přidává jeden díl k řádku nad ním:

modelparametryvalidační perplexity
rovnoměrný průměr, přičtený279,55260.45
jedna attention hlava, nahrazuje token328,70455.47
jedna attention hlava, přičtená328,70446.10
čtyři hlavy místo jedné345,21643.21
plus feed-forward network476,92839.87
plus LayerNorm — kompletní block477,69638.07

Naučené váhy porážejí rovnoměrné o 14 bodů perplexity, což je celý argument této kapitoly v jednom řádku. Čtyři hlavy koupí další 3 body za 16 512 parametrů navíc. A stejná hlava má o 9 bodů větší hodnotu přičtená než nahrazující: attention přináší informaci dovnitř, nerozhoduje, čím pozice je.

Teď kde parametry skutečně sedí, což překvapuje lidi, kteří viděli jen diagram:

šířkahlavyattentionfeed-forwardcelkem na block
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

Dvě třetiny každého transformer block tvoří feed-forward network, v každém měřítku, protože attention má čtyři matice d×dd \times d a MLP má ekvivalent osmi. Ať model ví cokoli, většina parametrů, které to drží, je v pozičním MLP.

Residuals a LayerNorm, zděděné z Kapitoly 6

Odkaz na sekci: Residuals a LayerNorm, zděděné z Kapitoly 6

LayerNorm byla postavena a měřena v Kapitole 6 a tato kapitola ji používá tak, jak tam zůstala; reziduální spojení tam byla pojmenována a ablována a zde se staví. Řádky „přičtené, ne nahrazující“ výše jsou reziduální spojení, v hodnotě 188 bodů perplexity pro průměr a 9 pro jednu hlavu. LayerNorm7 normalizuje každý příklad napříč jeho features a Kapitola 6 uvedla důvody, proč zde přežila ona a ne BatchNorm — žádná závislost na batch, žádné běžící statistiky, totožná při tréninku a inference, lhostejná k délce sekvence — a každý z nich se stává požadavkem, když generujete jeden token po druhém pro jednoho uživatele, kam dospěje Kapitola 13. Stojí 768 parametrů a kupuje 1,8 bodu perplexity.

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

Podívejte se, kde normalizace sedí: na vstupu každé sub-layer, přičemž reziduální cesta od vstupu k výstupu není nikdy normalizovaná. To je pre-norm. Článek z roku 2017 dělá opak, x = LayerNorm(x + Att(x))post-norm, což dává LayerNorm na samotnou reziduální cestu.

Xiong et al. vysvětlili rozdíl přes gradient při inicializaci, který je v post-norm síti špatně škálovaný s hloubkou — důvod, proč původní transformer vůbec potřeboval learning-rate warmup, aby se trénoval.8 Dvanáct blocků, 1000 kroků, learning rate 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

Post-norm bez warmup je osmkrát horší a post-norm s warmup přesně odpovídá pre-norm. Warmup zde není obecně dobrá praxe; je to záplata pro konkrétní uspořádání normalizace a přesunutí LayerNorm potřebu záplaty odstraňuje. Proto je prakticky každý model od roku 2019 pre-norm a diagram z roku 2017 se má číst jako historie, ne jako specifikace.

Smažte poziční embeddings a model stále trénuje; prostě nedokáže říct, kde cokoli je, a to je symetrie, ne tréninkové selhání. Nic ve score attention nezmiňuje samotná tt ani ii, takže permutace vstupu permutuje výstup: self-attention je permutation-equivariant. Je to slepota průměru k pořadí v lepším převleku — kauzální maska obnovuje část pořadí, protože každá pozice vidí jiný prefix, ale uvnitř prefixu jsou všechna pořadí stejná.

Čtyři způsoby, jak injektovat pozici, trénované na 64-token oknech a vyhodnocené při 64, 128 a 256 — za jakoukoli délku, kterou viděly:

poziceperplexity při 64při 128při 256
vůbec žádné48.7952.6357.52
naučené absolutní embeddings38.63108.47181.94
pevné sinusoidy42.9695.26152.25
RoPE44.1250.5284.84
ALiBi44.9543.5142.49

Naučené absolutní embeddings — jeden vektor na pozici, přičtený k token — vítězí na trénované délce a pak spadnou z útesu, protože pozice 100 nikdy nebyla v batch a její embedding je pořád náhodný vektor, kterým začal. Sinusoidy, původní volba, se počítají místo toho, aby se učily, ze sinů a cosinů na geometricky rozmístěných frekvencích; článek z roku 2017 doufal, že to bude extrapolovat, a tabulka říká, že ne — funkce je definována na pozici 200, ale model se ji tam nikdy nenaučil číst. RoPE9 nic nepřidává a místo toho rotuje query a key o úhel úměrný pozici, ve dvourozměrných řezech; protože stejná rotace obou stran skalárního součinu ho nechá beze změny, score nakonec závisí jen na tit - i, takže pozice se stane relativní zdarma a neexistuje žádná tabulka, která by doběhla. Degraduje, ale degraduje postupně. ALiBi10 je zde nejjednodušší a nejpodivnější výsledek: lineární penalizace score úměrná vzdálenosti, s jiným sklonem na hlavu. Jeho perplexity se zlepšuje, jak okno roste za trénovanou délku, z 44,95 na 42,49, protože penalizace je definována pro libovolnou vzdálenost a každá hlava dál dělá to, k čemu byla trénována.

Ponaučení přežije tabulku: architektura, která něco neumí reprezentovat, je jiný problém než architektura, která se daný rozsah nikdy nenaučila, a kouše ten druhý. Je to také mechanismus za každým oznámením „rozšířili jsme context na 128K“ — téměř vždy jde o přeškálování rotary encoding, a proto Kapitola 16 říká, že limit context se posouvá, ne mizí.

Dropout je zděděn stejně: objevuje se na vahách attention po softmax, na výstupu každé sub-layer před reziduálním přičtením a na součtu embedding, a dělá přesně to, co popsala Kapitola 6. Ve velkých pretraining bězích je často nastaven na nulu, protože model, který vidí každý token jednou, není v pozici, aby overfitoval.

Dva tenzory ve vrstvě mají tvar n×nn \times n, kde nn je počet tokens: scores a váhy po softmax. Všechno ostatní — každá projekce, celé MLP — je lineární v nn.

Jedna attention vrstva, šířka 512, 8 hlav, batch jedna, float32, na GPU v laptopu. Dva sloupce v milisekundách čtěte jen pro jejich poměry: jsou to wall clock časy na 8GB kartě v laptopu, která při zahřátí throttluje z 1 785 MHz pod 300 MHz, takže studený běh téhož kódu se vrátí sedmkrát až desetkrát rychleji a vytížený ještě pomaleji. Sloupce v megabajtech jsou počty bytů alokátoru a nehýbou se.

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

Sloupce x4 jsou poměr k řádku nad nimi a zdvojnásobení nn konverguje přesně ke 4 pro čas i paměť — 3,91 v posledním kroku proti teoretickým 4. Sloupec projekcí je kontrola: 4,0 ms při 1024 tokens na 40,1 ms při 8192, faktor deset pro faktor osm. Lineární, jak bylo slíbeno.

Pak poslední řádek. Jedna attention vrstva, jedna sekvence, bez modelu okolo, dojde na 8GB GPU paměť při 16 384 tokens — samotná matice scores by měla 8 GB, protože je to 8 hlav krát 16 384 krát 16 384 krát 4 byty. Ne model; jeden mezilehlý tenzor v jedné vrstvě.

To je fyzický fakt pod třemi pozdějšími kapitolami. Proto má context window vůbec limit, který Kapitola 16 promění v cenu. Proto existuje FlashAttention, počítající stejný výsledek po dlaždicích, aniž kdy uloží matici — paměťová optimalizace dřív než rychlostní.11 A je to aritmetika za cenou dlouhého prompt, kterou Kapitola 24 platí ve smyčce agent — oddělená věc od dalšího zjištění té kapitoly, že model dlouhý context také používá hůř, což změří a odmítne svést na tento vzorec.

Zobrazit podrobnosti

Dvě varianty zmenšující cache, pojmenované zde a zaplacené v Kapitole 13.

Generování cachuje keys a values už zpracovaných tokens — jeden key a jedna value na token, na hlavu a vrstvu. Multi-query attention12 ponechává hh query projekcí, ale jedinou key a value projekci sdílenou všemi hlavami, čímž tuto cache dělí hh. Grouped-query attention13 interpoluje: hlavy jsou seskupené, každá skupina sdílí jeden key a value, takže g=hg = h je běžná attention a g=1g = 1 je multi-query. Téměř každý otevřený model od roku 2023 ji používá se 4 nebo 8 skupinami. Ani jedna neexistuje kvůli kvalitě; obě existují kvůli velikosti této cache a Kapitola 13 dělá aritmetiku, která to převádí na „který model se vejde do vaší GPU“.

Článek z roku 2017 popisuje encoder-decoder: jeden stack čte zdroj s nemaskovanou attention, druhý kauzálně generuje cíl a uprostřed je třetí druh attention, kde se query decoderu potkávají s keys encoderu. To je správně pro překlad, kde vstup a výstup jsou dvě sekvence.

Vyhrála decoder-only polovina — jeden stack, kauzální skrz naskrz, vstup a výstup ve stejné sekvenci — a důvodem není elegance. „Předpověz další token“ běží na libovolném textu, takže tréninková množina je internet místo paralelního korpusu a všechno se stane touto jednou úlohou: překlad je dokument obsahující zdroj a pak cíl, otázka a její odpověď jsou dokument, konverzace s tool calling uprostřed je dokument. Kapitola 11 je o tom, jak se ta poslední vyrábí. Encoders nezmizely — jeden vidí celý vstup najednou, což chcete, když úkolem je text reprezentovat, ne v něm pokračovat, a proto retrieval embeddings v Kapitole 19 pocházejí z encoders, ne z modelu, který chatuje.

Když je block definován, velikost modelu je aritmetika. Na block, se šířkou dd a čtyřnásobnou expanzí: 4d2+4d4d^2 + 4d pro Wq,Wk,Wv,WoW_q, W_k, W_v, W_o s biasy na všech čtyřech, jak je má GPT-2 — tabulka výše nechává bias u tří z nich pryč, proto o 2 304 méně na block při d=768d = 768; 8d2+5d8d^2 + 5d pro MLP; 4d4d pro dvě LayerNorms — 12d2+13d12d^2 + 13d, plus token tabulka V×dV \times d a pro absolutní pozice nctx×dn_{\text{ctx}} \times d. Pro tvar GPT-2 small — d=768d = 768, 12 blocků, slovník 50 257, context 1024, výstupní vrstva sdílí váhy embedding:

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

Což je publikovaná velikost tohoto modelu. Vzorec není aproximace; je to model. Všimněte si také, že téměř třetina malého modelu je tabulka embedding, a proto je velikost slovníku architektonické rozhodnutí, ne preprocessingové — trade-off, který připravila Kapitola 7.

Perplexity je číslo o korpusu. Co dělá jedna hlava, je jiná otázka, a model trénovaný na megabajtu Shakespeara je na ni špatný nástroj: poctivé tvrzení o attention mapě 500 000parametrového modelu je, že je většinou neinterpretovatelná. Tedy: jazyk, v němž má otázka správnou odpověď.

Klasická ilustrace je the animal did not cross the street because it was too tired, kde it je animal, oproti …because it was too wet, kde jedno slovo přesune referent na street. To jsou Winograd schemas14 — dvojice vět totožné až na jedno slovo, kde toto slovo rozhoduje, k čemu se zájmeno vztahuje.

Jsou také řešitelné podvodem, což je část, kterou návody přeskakují. Pokud jsou dva kandidáti zvíře a místo, tired a wet identifikují referent podle kategorie, a model, který ví jen to, která slova jsou přítomna, to trefí bez jakékoli znalosti pořadí. Měřeno na této verzi úlohy s odloženými dvojicemi zvíře/místo:

TEXT
uniform causal average           held-out referent accuracy 100.0 %
one transformer block            held-out referent accuracy  91.7 %

Bag of words poráží transformer. Jakákoli demonstrace postavená na této větě nedokazuje nic o attention.

Zavřete tedy díru: vezměte oba kandidáty z jedné množiny šestnácti podstatných jmen, z nichž kterékoli se může objevit v kterémkoli slotu, a rozdělte přídavná jména podle role místo kategorie — čtyři dělající z it toho, kdo přechází (tired, scared, slow, weak), čtyři dělající z něj to, co se přechází (wet, wide, busy, steep).

TEXT
the {x} did not cross the {y} because it was too {adj} , so the {ref} waited .

Trénujte jako běžný next-token predictor, scoreujte jednu pozici — slovo po so the — a postavte odloženou množinu z dvojic podstatných jmen, jejichž obrácené pořadí bylo v tréninku, takže cokoli, co ví, která dvě podstatná jména jsou přítomna, ale neví, které bylo první, musí odpovědět obráceně.

modelparametryodloženéjmenuje druhé podstatné jméno
pouze aktuální token5,7965.2 %5.2 %
rovnoměrný kauzální průměr5,79627.9 %50.0 %
jedna hlava naučené attention18,08435.4 %64.6 %
čtyři hlavy22,24475.0 %15.6 %
jeden transformer block55,71692.7 %4.2 %
dva transformer blocky105,508100.0 %0.0 %

Náhoda mezi dvěma přítomnými podstatnými jmény je 50 %. Rovnoměrný průměr končí na 27,9 % a odpovídá špatným podstatným jménem dvojice přesně v polovině případů — podpis něčeho, co ví, která slova tam jsou, a nic o jejich pořadí, jak předpověděl shuffle test před třemi sekcemi.

Teď mapa: attention na pozici, která musí pojmenovat referent, zprůměrovaná přes čtyři hlavy každého block, pro dvě věty lišící se jedním slovem. Rovnoměrný průměr by dal 0,067 na každý z patnácti viditelných tokens.

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

Block 1 je v obou větách totožný — 0,70 na prvním podstatném jméně bez ohledu na přídavné jméno. To není selhání, ale důkaz: v první vrstvě je query na pozici funkcí vlastního token a indexu této pozice a the na pozici 14 je tentýž token v obou větách. Hlava první vrstvy nemůže podmiňovat na slově, které si ještě nepřitáhla. Block 1 tedy udělá jedinou užitečnou věc, kterou má k dispozici, a přitáhne první podstatné jméno dopředu.

Block 2 je místo, kde se věty rozdělí, a stejný řádek přes všech osm přídavných jmen ukazuje pravidlo, které model našel:

přídavné jménoblock 2 na animalna streetna přídavném jméněodpověď
tired, scared, slow, weak0.0000.0001.000animal
wet, wide, busy, steep0.0000.4910.00–0.03street

U přídavného jména pro toho, kdo přechází, druhý block utratí celou váhu na přídavné jméno, protože odpověď už je v residual stream — block 1 ji tam vložil — a potřebuje jen potvrzení. U přídavného jména pro to, co se přechází, si místo toho jde vyzvednout druhé podstatné jméno. To je dvouskokový obvod: jedna hlava posune kandidáta dopředu, hlava v pozdější vrstvě čte token, který rozhoduje, zda ho ponechat. Kompozice napříč vrstvami je mechanismus, a proto jeden block dosáhl 92,7 % a dva dosáhly 100 %.

Je to také tvar nejlépe zdokumentovaného obvodu ve skutečných modelech. Induction heads — hlava předchozího token krmící hlavu v další vrstvě, která dokončí pattern [A][B] … [A] → [B] — jsou tím, co interpretační práce Anthropic identifikuje za velkou částí in-context learning, a tvoří se v identifikovatelném okamžiku během pretraining. Tato kapitola se o tuto analýzu nepokouší: je delegována, s oběma články v referencích, protože čtení obvodů ze skutečného modelu je výzkumný obor, ne sekce.

Nakonec implementace. Třicet řádků výše, s váhami zkopírovanými z vlastního PyTorch:

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} na výstupech, jejichž střední velikost je 0,159: stejná aritmetika v jiném pořadí, při přesnosti float32.

Máte architekturu, z níž je postaven každý model ve zbytku tohoto kurzu, a je menší než její pověst: vážený průměr, jehož váhy jsou naučené, poziční MLP držící dvě třetiny parametrů, dvě normalizace a dvě přičtení, naskládané na sebe.

Nemáte ale model, který něco ví, a samotné skládání to neopraví. Dva blocky na tomto korpusu dosáhnou tréninkové perplexity 14,49 a validační perplexity 40,57, proti 18,77 a 38,07 u jednoho block — větší kapacita, lepší na tom, co viděl, horší na tom, co neviděl, což je tabulka z Kapitoly 6 s transformerem uvnitř. Vzdálenost mezi tímto modelem a těmi, se kterými mluví Kapitoly 14 až 30, není architektonická. Je to stejný block, opakovaný vícekrát, nad nesrovnatelně větším množstvím textu.

Což z toho dělá účetní problém, a účetnictví je podivnější, než vypadá. Kolik textu a odkud ho kdo vezme? Kolik aritmetiky a jak ji odhadnete dřív, než utratíte peníze? Při pevném rozpočtu je lepší udělat model větší, nebo mu ukázat více dat — a existuje správná odpověď, nebo jen móda? Kapitola 10 odpoví na všechny tři měřením a ocení nejlevnější užitečnou podobu otázky: co dnes stojí vytrénovat model jako GPT-2 od nuly?


Tři vysvětlení tohoto materiálu jsou lepší než toto v tom, k čemu jsou určena, a tato kapitola je psaná tak, aby se četla spolu s nimi. The Illustrated Transformer od Jaye Alammara je nejlepší obrázek toku dat, jaký kdy vznikl. The Annotated Transformer od Harvard NLP je článek z roku 2017 s běžícím kódem vkládaným řádek po řádku. Let's build GPT: from scratch, in code, spelled out od Andreje Karpathyho staví tentýž model živě za dvě hodiny a žebřík ablations výše je tatáž páteř měřená na jiném korpusu. Pro otázku interpretability, které se tato kapitola jen dotýká, jsou primárními zdroji Elhage et al., A Mathematical Framework for Transformer Circuits (2021) a Olsson et al., In-context Learning and Induction Heads (2022), oba od interpretability skupiny Anthropic.

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

  2. Sutskever, I., Vinyals, O. a Le, Q. V. Sequence to Sequence Learning with Neural Networks. arXiv:1409.3215 (2014). Encoder-decoder, jehož jednovektorový context je hrdlem.

  3. Bahdanau, D., Cho, K. a Bengio, Y. Neural Machine Translation by Jointly Learning to Align and Translate. arXiv:1409.0473 (2014). Attention, tři roky před transformerem.

  4. Perplexity je exponenciála střední cross-entropy na token z Kapitoly 8. Každé číslo zde používá stejný tokenizer a stejný validační split, což je jediná podmínka, za níž lze dvě perplexity vůbec porovnat.

  5. Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł. a Polosukhin, I. Attention Is All You Need. arXiv:1706.03762 (2017). Sekce 3.2.1 je ona jedna věta o dk\sqrt{d_k}, jejímuž měření tato kapitola věnuje celou sekci.

  6. Shazeer, N., Mirhoseini, A., Maziarz, K., Davis, A., Le, Q., Hinton, G. a Dean, J. Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. arXiv:1701.06538 (2017).

  7. Ba, J. L., Kiros, J. R. a Hinton, G. E. Layer Normalization. arXiv:1607.06450 (2016). Zavedeno a měřeno v Kapitole 6; zde použito beze změny.

  8. Xiong, R., Yang, Y., He, D., Zheng, K., Zheng, S., Xing, C., Zhang, H., Lan, Y., Wang, L. a Liu, T.-Y. On Layer Normalization in the Transformer Architecture. arXiv:2002.04745 (2020). Gradientová analýza za pre-norm a argument, že warmup je symptom.

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

  10. Press, O., Smith, N. A. a Lewis, M. Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation. arXiv:2108.12409 (2021). Výše reprodukovaný extrapolační výsledek.

  11. Dao, T., Fu, D. Y., Ermon, S., Rudra, A. a 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. a Sanghai, S. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245 (2023).

  14. Levesque, H. J., Davis, E. a Morgenstern, L. The Winograd Schema Challenge. KR (2012). Konstrukce za větou animal / street, kterou používá každý tutorial attention.

Necháte výběr modelu na LIA?

Tvořte se všemi modely AI na jednom místě – začněte ještě dnes zdarma.