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 , 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 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ímeOd roku 1997 přibližně do roku 2017 bylo shrnutím rekurentní rozpoložení: udržujte vektor a aktualizujte ho při každém token, . 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 kroků násobí Jacobiho matic, takže gradient mizí nebo exploduje — nemoc, kterou Kapitola 5 měřila uvnitř jediného uzlu . 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: potřebuje 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é existujeNejzřejmější funkce proměnného počtu vektorů, která vrací jeden vektor, je průměr:
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 s batchem 64. Perplexity je na odloženém splitu.4
| model | parametry | validační perplexity |
|---|---|---|
| pouze aktuální token, vůbec žádný context | 263,168 | 59.71 |
| plus rovnoměrný průměr všeho před ním | 263,168 | 248.07 |
| plus naučené poziční embeddings | 279,552 | 245.93 |
| rovnoměrný průměr přičtený k token místo jeho nahrazení | 263,168 | 60.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ě:
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-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 softmaxPrů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:
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.167Tři pojmenované komponenty transformeru jsou teď na obrazovce. Trojúhelník je kauzální maska, vynucená cílem: kdyby pozice mohla vidět pozici , 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 je pošle přesně na nulu a znormalizuje zbytek, takže maskování a normalizace jsou jedna operace. (Použijte , ne -1e9: je to hodnota, kterou maskování znamená, přežije cast na float16 jako 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í?
Query, key, value
Odkaz na sekci: Query, key, valueNemohou to být prosté parametry. Naučená matice 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 s pozicí 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 pro pozici jako 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á, , query; a čím nabízí, že bude nalezena, , key. Score a symetrie je pryč, protože : 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á , 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, , value, a sčítejte ty.
Vzorec je teď účetnictví:
kde je kauzální maska, nula na diagonále a pod ní a nad ní. V kódu je to třicet řádků, z nichž dvacet jsou tvary:
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í říká „aby softmax nesaturoval“, což je pravda a nic to nevysvětluje. Argument jsou dva řádky rozptylu z Kapitoly 2. Pokud jsou položky a nezávislé se střední hodnotou nula a rozptylem jedna, každý součin má rozptyl jedna a rozptyly nezávislých věcí se sčítají:
Scores tedy mají směrodatnou odchylku . Měřeno na dvaceti tisících náhodných dvojic:
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.000Proč 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:
| největší váha, neděleno | entropie | efektivní tokens | největší váha, děleno | entropie | efektivní tokens | |
|---|---|---|---|---|---|---|
| 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 |
„Efektivní tokens“ je exponenciála entropie: přes kolik pozic řádek ve skutečnosti průměruje. Neděleně, při , č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 . Softmax zavázaný jedné položce má téměř nulovou derivaci: diagonála jeho Jacobiho matice je , nula na obou koncích. Přes dva tisíce náhodných řádků:
| neděleno | děleno | saturované řádky (největší váha nad 0,99) | |
|---|---|---|---|
| 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 % |
Při 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 hlavy | neděleno | děleno | děleno |
|---|---|---|---|
| čtyři hlavy, | 37.29 | 38.07 | 37.89 |
| jedna hlava, | 48.51 | 46.10 | 45.99 |
| jedna hlava, | 65.37 | 47.53 | — |
| jedna hlava, | 67.06 | 49.15 | — |
| jedna hlava, | 76.69 | 59.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 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:
| std score při init | po 1500 krocích, neděleno | po 1500 krocích, děleno | saturované řádky, neděleno | děleno | |
|---|---|---|---|---|---|
| 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 % |
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 “, 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 , konkatenovat a promíchat ještě jednou maticí : šíř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:
| model | parametry | validační perplexity |
|---|---|---|
| rovnoměrný průměr, přičtený | 279,552 | 60.45 |
| jedna attention hlava, nahrazuje token | 328,704 | 55.47 |
| jedna attention hlava, přičtená | 328,704 | 46.10 |
| čtyři hlavy místo jedné | 345,216 | 43.21 |
| plus feed-forward network | 476,928 | 39.87 |
| plus LayerNorm — kompletní block | 477,696 | 38.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:
| šířka | hlavy | attention | feed-forward | celkem na block |
|---|---|---|---|---|
| 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 |
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 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 6LayerNorm 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.
class Block(nn.Module):
def forward(self, x):
x = x + self.att(self.ln1(x))
x = x + self.ff(self.ln2(x))
return xPodí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 :
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.88Post-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.
Kde je token?
Odkaz na sekci: Kde je token?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á ani , 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:
| pozice | perplexity při 64 | při 128 | při 256 |
|---|---|---|---|
| vůbec žádné | 48.79 | 52.63 | 57.52 |
| naučené absolutní embeddings | 38.63 | 108.47 | 181.94 |
| pevné sinusoidy | 42.96 | 95.26 | 152.25 |
| RoPE | 44.12 | 50.52 | 84.84 |
| ALiBi | 44.95 | 43.51 | 42.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 , 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.
Co to stojí
Odkaz na sekci: Co to stojíDva tenzory ve vrstvě mají tvar , kde je počet tokens: scores a váhy po softmax. Všechno ostatní — každá projekce, celé MLP — je lineární v .
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.
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.87Sloupce x4 jsou poměr k řádku nad nimi a zdvojnásobení 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á query projekcí, ale jedinou key a value projekci sdílenou všemi hlavami, čímž tuto cache dělí . Grouped-query attention13 interpoluje: hlavy jsou seskupené, každá skupina sdílí jeden key a value, takže je běžná attention a 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“.
Dva tvary a velikost jednoho
Odkaz na sekci: Dva tvary a velikost jednohoČ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 a čtyřnásobnou expanzí: pro 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 ; pro MLP; pro dvě LayerNorms — , plus token tabulka a pro absolutní pozice . Pro tvar GPT-2 small — , 12 blocků, slovník 50 257, context 1024, výstupní vrstva sdílí váhy embedding:
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,808Což 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.
Na co se hlava skutečně dívá
Odkaz na sekci: Na co se hlava skutečně dívá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:
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).
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ě.
| model | parametry | odložené | jmenuje druhé podstatné jméno |
|---|---|---|---|
| pouze aktuální token | 5,796 | 5.2 % | 5.2 % |
| rovnoměrný kauzální průměr | 5,796 | 27.9 % | 50.0 % |
| jedna hlava naučené attention | 18,084 | 35.4 % | 64.6 % |
| čtyři hlavy | 22,244 | 75.0 % | 15.6 % |
| jeden transformer block | 55,716 | 92.7 % | 4.2 % |
| dva transformer blocky | 105,508 | 100.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.
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.25Block 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éno | block 2 na animal | na street | na přídavném jméně | odpověď |
|---|---|---|---|---|
| tired, scared, slow, weak | 0.000 | 0.000 | 1.000 | animal |
| wet, wide, busy, steep | 0.000 | 0.491 | 0.00–0.03 | street |
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:
ours vs nn.MultiheadAttention max |diff| = 1.7881393432617188e-07
ours vs F.scaled_dot_product_attention max |diff| = 1.7881393432617188e-07na výstupech, jejichž střední velikost je 0,159: stejná aritmetika v jiném pořadí, při přesnosti float32.
Kam to vede dál
Odkaz na sekci: Kam to vede dálMá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?
Zdroje a metoda
Odkaz na sekci: Zdroje a metodaTř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.
Reference
Odkaz na sekci: Reference-
Hochreiter, S. a Schmidhuber, J. Long Short-Term Memory. Neural Computation 9(8), s. 1735–1780 (1997). ↩
-
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. ↩
-
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. ↩
-
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. ↩
-
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 , jejímuž měření tato kapitola věnuje celou sekci. ↩
-
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). ↩
-
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. ↩
-
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. ↩
-
Su, J., Lu, Y., Pan, S., Murtadha, A., Wen, B. a Liu, Y. RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864 (2021). ↩
-
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. ↩
-
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). ↩
-
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. a Sanghai, S. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245 (2023). ↩
-
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. ↩