Attention i blok transformer wyprowadzone ze średniej
Zacznij od najtańszego podsumowania kontekstu — średniej — zobacz, gdzie zawodzi, i wyprowadź wzór attention z naprawy.
Na tej stronie
Trafiasz tu z tokenizerem z rozdziału 7, tabelą embedding z rozdziału 8 i celem, który im towarzyszy: mając dotychczasowe tokens, przypisać prawdopodobieństwo następnemu.
Brakuje środka. Aby przewidzieć token , model potrzebuje jednego wektora podsumowującego wszystko, co było wcześniej, a nic z tego, co zbudowałeś, takiego wektora nie daje. Embedding token nim nie jest — to model bigramowy i nie może wiedzieć, że zdanie zaczęło się od pytania. Konkatenacja wszystkich poprzednich embeddings też nim nie jest: ich liczba zmienia się na każdym kroku, a stała macierz wag nie może przyjąć wejścia o zmiennej długości.
A więc: jeden wektor o stałym rozmiarze, podsumowujący zmienną liczbę wektorów. To cały problem, a attention jest tym, co dostajesz, rozwiązując go w możliwie najbardziej leniwy sposób, a potem naprawiając dwie rzeczy, które się psują.
Odpowiedź, którą miała dziedzina, i dlaczego jej tu nie budujemy
Link do sekcji: Odpowiedź, którą miała dziedzina, i dlaczego jej tu nie budujemyOd 1997 do około 2017 roku podsumowaniem był stan rekurencyjny: utrzymuj wektor i aktualizuj go przy każdym token, . Stały rozmiar, zmienne wejście, dokładnie właściwy kształt.
Zawiódł na trzy sposoby, a architektura z tego rozdziału odpowiada na wszystkie trzy. Backpropagation przez kroków mnoży jakobianów, więc gradient zanika albo eksploduje — choroba, którą rozdział 5 mierzył wewnątrz pojedynczego węzła . LSTM1 zaprojektowano dokładnie przeciw temu i przesunął użyteczny zakres z dziesiątek kroków do setek, nie zmieniając faktu, że informacja z token 5 dociera do token 500 tylko wtedy, gdy przetrwa 495 sekwencyjnych aktualizacji. Całe źródło musiało zmieścić się w jednym wektorze: w tłumaczeniu sequence-to-sequence2 encoder kompresuje wejście do swojego stanu końcowego. Bahdanau, Cho i Bengio nazwali to wąskie gardło i naprawili je w 2014 roku, trzy lata przed transformer, pozwalając decoderowi brać ważoną sumę wszystkich stanów encodera z wagami, które sam obliczał.3 Wszystko poniżej to ta idea zastosowana przez sekwencję do samej siebie, z usuniętą rekurencją. I aktualizacja jest sekwencyjna z konstrukcji: potrzebuje , a GPU z dziesięcioma tysiącami rdzeni nic z tym nie zrobi. Architektura, która wygrała, nie jest oczywiście mądrzejsza; jest tą, której kosztownym krokiem jest mnożenie macierzy.
Drugi klasyczny bias indukcyjny, konwolucja — przesuwanie jednego małego filtra po całym wejściu, aby cecha wykryta gdziekolwiek była wykryta wszędzie — też nie jest tu budowany; jest niemal dokładnie właściwy dla obrazów i zostaje przekazany kursowi o widzeniu. Ani rekurencja, ani konwolucja nie wracają po tej stronie, dlatego żadna z nich nie dostaje rozdziału: rozdział 1 obiecał, że pominięcia będą deklarowane, a nie przemilczane.
Najtańsze możliwe podsumowanie
Link do sekcji: Najtańsze możliwe podsumowanieNajbardziej oczywistą funkcją, która z dowolnej liczby wektorów zwraca jeden wektor, jest średnia:
Dowolna liczba wejść, stały rozmiar wyjścia, różniczkowalne, darmowe. Tabela embedding plus ta średnia plus warstwa liniowa do słownika to kompletny model językowy w piętnastu liniach. Jest też fatalny, a sposób, w jaki jest fatalny, stanowi całe wyprowadzenie.
Poniższy korpus to jeden megabajt Szekspira, 1 115 394 znaków, przepuszczony przez byte-level BPE tokenizer typu zbudowanego w rozdziale 7, ze słownikiem 1024: 459 760 tokens po 2,43 znaku każdy, podział 90/10. Każdy model ma szerokość 128, widzi 128 tokens i trenuje przez 3000 kroków AdamW przy z batchem 64. Perplexity podano na zbiorze walidacyjnym.4
| model | parametry | validation perplexity |
|---|---|---|
| tylko bieżący token, bez żadnego kontekstu | 263 168 | 59.71 |
| plus jednolita średnia wszystkiego przed nim | 263 168 | 248.07 |
| plus wyuczone embeddings pozycji | 279 552 | 245.93 |
| jednolita średnia dodana do token zamiast go zastępować | 263 168 | 60.45 |
Przeczytaj drugi wiersz dwa razy. Uśrednianie kontekstu nie pomaga trochę; sprawia, że model jest cztery razy gorszy niż ignorowanie kontekstu całkowicie. Są dwa powody, oba możliwe do udowodnienia, a nie tylko empiryczne.
Średnia nie widzi kolejności. Dodawanie jest przemienne, więc przetasowanie okna zostawia podsumowanie bez zmian — nie w przybliżeniu:
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-08Szum zmiennoprzecinkowy na sumie o zmienionej kolejności: oba podsumowania są tym samym wektorem. Model, którego jedynym widokiem kontekstu jest średnia, nie odróżni pies ugryzł człowieka od człowiek ugryzł psa. Trzeci wiersz dowodzi, że nie da się tego naprawić przez dodanie pozycji do wejść — wyuczony embedding pozycji na każdym token przed uśrednieniem dał 2,14 punktu ze 188. Pozycje trafiają do sumy, a suma je zapomina.
I średnia topi teraźniejszość. Na pozycji 100 bieżący token stanowi jedną setną podsumowania. To ma tanią naprawę, którą już masz: zachowaj token i dodaj do niego podsumowanie — residual connection z rozdziału 6, a czwarty wiersz pokazuje, co robi. Po naprawieniu rozcieńczenia jednolita średnia nie wnosi niczego: 60.45 wobec baseline 59.71. Każdy token tam jest, ważony równo, a równe ważenie jest tym samym co brak informacji.
Problemem nie jest uśrednianie. Problemem są wagi.
Średnia to mnożenie macierzy, a maska to softmax
Link do sekcji: Średnia to mnożenie macierzy, a maska to softmaxUśrednianie po rosnącym prefiksie wygląda jak pętla. Jest jednym mnożeniem przez dolnotrójkątną macierz, której wiersze sumują się do jednego — i także, dokładnie, 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.167Trzy nazwane komponenty transformer są teraz na ekranie. Trójkąt to causal mask, wymuszona przez cel: gdyby pozycja mogła widzieć pozycję , odpowiedź byłaby w wejściu — przeciek, który rozdział 6 kazał ci audytować, tylko wewnątrz architektury. Softmax to sposób implementacji maski: ustawienie zakazanych wpisów na wysyła je dokładnie do zera i normalizuje to, co zostaje, więc maskowanie i normalizacja są jedną operacją. (Użyj , nie -1e9: to wartość, którą maskowanie oznacza, przetrwa rzutowanie do float16 jako i oszczędza ci decyzji, czy wybrana stała jest dość duża dla zakresu, w którym akurat jesteś — a to pudełko zmiennoprzecinkowe z rozdziału 2 zadaje pytanie, na które nie musisz odpowiadać.) A scores są wolnym parametrem. Jednolita średnia jest tym, co dostajesz, gdy każdy dozwolony score jest tą samą liczbą; wpisz tam dowolne liczby, a softmax zamieni je w prawidłowe wagi.
Reszta tego rozdziału to jedno pytanie: skąd biorą się te liczby?
Query, key, value
Link do sekcji: Query, key, valueNie mogą być zwykłymi parametrami. Wyuczona macierz byłaby identyczna dla każdego zdania — mogłaby zakodować „spójrz cztery tokens wstecz”, ale nigdy „spójrz na rzeczownik, do którego odnosi się ten zaimek”. Waga łącząca pozycję z pozycją musi zależeć od tego, co jest na obu pozycjach, bo relewantność jest relacją, nie własnością: słowo to nie jest samo w sobie relewantne, jest relewantne dla czegoś.
Najtańszą funkcją dwóch wektorów zwracającą liczbę jest iloczyn skalarny z rozdziału 1. Oceń pozycję dla pozycji jako i mechanizm działa — źle, na dwa sposoby, które wymuszają całą resztę. Iloczyn skalarny wektora z samym sobą jest jego normą do kwadratu, więc każdy token attendowałby głównie do siebie. A relacja byłaby symetryczna: jeśli to attenduje mocno do zwierzę, wtedy zwierzę attenduje mocno do to, co jest fałszywe w języku, gdzie przymiotnik potrzebuje rzeczownika znacznie bardziej niż rzeczownik potrzebuje przymiotnika.
Daj więc każdemu token dwie role, jako dwie wyuczone liniowe mapy: czego ta pozycja szuka, , czyli query; oraz czym oferuje, że da się ją znaleźć, , czyli key. Score i symetria znika, bo : token może reklamować jedno, a szukać czegoś innego.
Jedna rzecz nadal jest zła. Ważona suma była po samych , co zmusza rzecz, która zostaje skopiowana, by była tą samą rzeczą, która zostaje dopasowana. Dopasowanie chce cech identyfikujących token; kopiowanie chce cech użytecznych dalej. Naucz więc trzecią mapę, , czyli value, i sumuj je.
Wzór jest teraz księgowością:
z jako causal mask, zerem na przekątnej i pod nią oraz powyżej. W kodzie to trzydzieści linii, z czego dwadzieścia to kształty:
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, maskuj, normalizuj, mieszaj. Cała reszta to projekcja.
Dzielenie przez pierwiastek kwadratowy i przed czym broni
Link do sekcji: Dzielenie przez pierwiastek kwadratowy i przed czym broniPrawie każde wyjaśnienie mówi „żeby softmax się nie nasycał”, co jest prawdą i niczego nie wyjaśnia. Argument to dwie linie wariancji z rozdziału 2. Jeśli wpisy i są niezależne, mają średnią zero i wariancję jeden, każdy iloczyn ma wariancję jeden, a wariancje rzeczy niezależnych się dodają:
Więc scores mają odchylenie standardowe . Zmierzone na dwudziestu tysiącach losowych par:
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.000Dlaczego to ma znaczenie: softmax jest wrażliwy na skalę w sposób, w jaki warstwa liniowa nie jest. Podwojenie wejścia warstwy liniowej podwaja jej wyjście; pomnożenie scores przez dziesięć przed softmax zamienia miękką mieszankę w twardy wybór. Jeden wiersz 64 scores, z dzieleniem i bez niego:
| największa waga, bez dzielenia | entropia | effective tokens | największa waga, z dzieleniem | entropia | effective 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 |
„Effective tokens” to wykładnik entropii: po ilu pozycjach wiersz naprawdę uśrednia. Bez dzielenia, przy , świeżo zainicjalizowana head attenduje do dokładnie jednego token z 64, wybranego wyłącznie przez losowanie.
To złe w przód i jeszcze gorsze w tył, w kształcie, który rozdział 5 już mierzył na . Softmax przywiązany do jednego wpisu ma prawie zerową pochodną: przekątna jego jakobianu to , zero na obu krańcach. Na dwóch tysiącach losowych wierszy:
| bez dzielenia | z dzieleniem | wiersze nasycone (największa waga powyżej 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 % |
Przy siedem wierszy na dziesięć jest zamrożonych, zanim zacznie się trening, a head, która startuje zamrożona, nie może nauczyć się, na co patrzeć. Po dzieleniu ta wielkość jest płaska na 0.96 przy każdej szerokości i nic się nie nasyca.
Teraz część, której nikt nie publikuje: czy to zmienia końcowe perplexity? Usuń dzielenie i trenuj przy czterech szerokościach head:
| szerokość head | bez dzielenia | dzielone przez | dzielone przez |
|---|---|---|---|
| cztery heads, | 37.29 | 38.07 | 37.89 |
| jedna head, | 48.51 | 46.10 | 45.99 |
| jedna head, | 65.37 | 47.53 | — |
| jedna head, | 67.06 | 49.15 | — |
| jedna head, | 76.69 | 59.17 | — |
Pierwsze dwa wiersze pochodzą z budżetu 3000 kroków powyżej; ostatnie trzy to krótszy run — 1500 kroków, batch 32, jedna head, bez normalizacji przed projekcjami — z obiema wersjami w identycznych ustawieniach.
Przy dzielenie nie jest nic warte, a run bez niego jest minimalnie z przodu. To nie licencja, by je wyrzucić, bo przy 256 jest warte 18 punktów perplexity, a przy 1024 — 17. Mechanizm widać w samych scores:
| std score przy init | po 1500 krokach, bez dzielenia | po 1500 krokach, z dzieleniem | wiersze nasycone, bez dzielenia | z dzieleniem | |
|---|---|---|---|---|---|
| 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 % |
Head bez dzielenia się nie regeneruje. Ucieka: odchylenie standardowe jej scores rośnie z 21 przy inicjalizacji do 5147, entropia attention spada do zera, a 99,9 % wierszy kładzie ponad 0,99 swojej wagi na jeden token. Gdy head staje się twardym selektorem, jej gradient jest prawie zerowy i nic jej nie cofa, więc załamanie jest stabilne. Head z dzieleniem siedzi po tym samym treningu przy odchyleniu standardowym score 3,44, czyli przy miękkiej mieszance, którą nadal można zmienić.
Vaswani i in. mówią dokładnie to i nic więcej — podejrzewają, że iloczyny „rosną co do wartości bezwzględnej dla dużych wartości ” i dzielą.5 Słowo duże niesie ciężar, a tabele mówią, gdzie duże się zaczyna: nic przy 32, wszystko do 256.
Więcej niż jedna opinia i dwie trzecie, o których nikt nie mówi
Link do sekcji: Więcej niż jedna opinia i dwie trzecie, o których nikt nie mówiJedna head to jeden wiersz softmax na pozycję, więc zawiera jedną odpowiedź na pytanie „co jest tu relewantne”. Przewidzenie słowa po the w the animal that crossed the wet street wymaga jednocześnie slotu składniowego, podmiotu i poprzedniego token, a jeden rozkład prawdopodobieństwa nie może być skoncentrowany w trzech miejscach. Uruchom więc kilka heads równolegle, każdą o szerokości , skonkatenowuj i wymieszaj jeszcze jedną macierzą : podzieliłeś szerokość, nie dodałeś do niej.
Attention robi też dokładnie jedną rzecz — przenosi informację między pozycjami. Każda operacja w kodzie powyżej jest liniowa wzdłuż osi cech, a rozdział 5 udowodnił, czym jest stos map liniowych. Dlatego każdy blok niesie też mały MLP stosowany do każdej pozycji niezależnie, rozszerzający szerokość czterokrotnie i wracający, z GELU pośrodku. Podział pracy warto zapamiętać: attention miesza między pozycjami, feed-forward network liczy wewnątrz pozycji.
Pełna drabina, każdy wiersz dodaje jeden element do wiersza nad nim:
| model | parametry | validation perplexity |
|---|---|---|
| jednolita średnia, dodana | 279 552 | 60.45 |
| jedna attention head, zastępująca token | 328 704 | 55.47 |
| jedna attention head, dodana | 328 704 | 46.10 |
| cztery heads zamiast jednej | 345 216 | 43.21 |
| plus feed-forward network | 476 928 | 39.87 |
| plus LayerNorm — kompletny blok | 477 696 | 38.07 |
Wyuczone wagi biją jednolite o 14 punktów perplexity, co jest całym argumentem tego rozdziału w jednym wierszu. Cztery heads kupują kolejne 3 za 16 512 dodatkowych parametrów. A ta sama head jest warta o 9 punktów więcej dodana niż zastępująca: attention wnosi informację, nie decyduje, czym jest pozycja.
Teraz gdzie naprawdę siedzą parametry, co zaskakuje ludzi, którzy widzieli tylko diagram:
| szerokość | heads | attention | feed-forward | łącznie na blok |
|---|---|---|---|---|
| 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 |
Dwie trzecie każdego transformer block to feed-forward network, w każdej skali, bo attention ma cztery macierze , a MLP ma odpowiednik ośmiu. Cokolwiek model wie, większość parametrów, które to trzymają, znajduje się w MLP per pozycja.
Residuals i LayerNorm, odziedziczone z rozdziału 6
Link do sekcji: Residuals i LayerNorm, odziedziczone z rozdziału 6LayerNorm zbudowano i zmierzono w rozdziale 6, a ten rozdział używa go tak, jak tam został zostawiony; residual connections nazwano i ablatowano tam, a tu są wbudowane. Wiersze „dodane, nie zastępujące” powyżej to residual connections, warte 188 punktów perplexity dla średniej i 9 dla jednej head. LayerNorm7 normalizuje każdy przykład po jego cechach, a rozdział 6 podał powody, dla których to on, a nie BatchNorm, przetrwał tutaj — brak zależności od batcha, brak statystyk kroczących, identyczność w treningu i inference, obojętność na długość sekwencji — i każdy z nich staje się wymaganiem, gdy generujesz jeden token naraz dla jednego użytkownika, dokąd prowadzi rozdział 13. Kosztuje 768 parametrów i kupuje 1,8 punktu perplexity.
class Block(nn.Module):
def forward(self, x):
x = x + self.att(self.ln1(x))
x = x + self.ff(self.ln2(x))
return xSpójrz, gdzie siedzi normalizacja: na wejściu każdej podwarstwy, z residual path od wejścia do wyjścia nigdy nienormalizowaną. To jest pre-norm. Artykuł z 2017 roku robi odwrotnie, x = LayerNorm(x + Att(x)) — post-norm, który umieszcza LayerNorm na samej residual path.
Xiong i in. wyjaśnili różnicę przez gradient przy inicjalizacji, który w sieci post-norm jest źle skalowany z głębokością — to powód, dla którego oryginalny transformer potrzebował warmup learning rate, by w ogóle trenować.8 Dwanaście bloków, 1000 kroków, 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 jest osiem razy gorszy, a post-norm z warmup dorównuje pre-norm dokładnie. Warmup nie jest tu ogólnie dobrą praktyką; jest łatą na konkretny układ normalizacji, a przesunięcie LayerNorm usuwa potrzebę tej łaty. Dlatego zasadniczo każdy model od 2019 roku jest pre-norm i dlatego diagram z 2017 roku należy czytać jako historię, nie jako specyfikację.
Gdzie jest token?
Link do sekcji: Gdzie jest token?Usuń embeddings pozycji, a model nadal trenuje; po prostu nie potrafi powiedzieć, gdzie cokolwiek jest, i to jest symetria, a nie porażka treningu. Nic w attention score nie wspomina samych ani , więc permutacja wejścia permutuje wyjście: self-attention jest permutation-equivariant. To ślepota średniej na kolejność w lepszym przebraniu — causal mask przywraca część porządku, bo każda pozycja widzi inny prefiks, ale wewnątrz prefiksu wszystkie uporządkowania wyglądają tak samo.
Cztery sposoby wstrzyknięcia pozycji, trenowane na oknach 64-tokenowych i oceniane przy 64, 128 i 256 — poza jakąkolwiek długością, którą widziały:
| pozycje | perplexity przy 64 | przy 128 | przy 256 |
|---|---|---|---|
| żadnych | 48.79 | 52.63 | 57.52 |
| wyuczone absolutne embeddings | 38.63 | 108.47 | 181.94 |
| stałe sinusoidy | 42.96 | 95.26 | 152.25 |
| RoPE | 44.12 | 50.52 | 84.84 |
| ALiBi | 44.95 | 43.51 | 42.49 |
Wyuczone absolutne embeddings — jeden wektor na pozycję, dodany do token — wygrywają przy długości treningowej, a potem spadają z klifu, bo pozycja 100 nigdy nie była w batchu i jej embedding nadal jest losowym wektorem, od którego zaczynała. Sinusoidy, oryginalny wybór, są liczone, a nie uczone, z sinusów i cosinusów o geometrycznie rozmieszczonych częstotliwościach; artykuł z 2017 roku miał nadzieję, że to będzie ekstrapolować, a tabela mówi, że nie — funkcja jest zdefiniowana na pozycji 200, ale model nigdy nie nauczył się jej tam czytać. RoPE9 niczego nie dodaje, tylko obraca query i key o kąt proporcjonalny do pozycji, w dwuwymiarowych wycinkach; ponieważ równy obrót obu stron iloczynu skalarnego zostawia go bez zmian, score zależy ostatecznie tylko od , więc pozycja staje się relatywna za darmo i nie ma tabeli, która mogłaby się skończyć. Degraduje się, ale się degraduje. ALiBi10 to najprostszy i najdziwniejszy wynik tutaj: liniowa kara na score proporcjonalna do odległości, z innym nachyleniem na head. Jego perplexity poprawia się, gdy okno rośnie poza długość treningową, z 44.95 do 42.49, bo kara jest zdefiniowana dla dowolnej odległości i każda head dalej robi to, do czego była trenowana.
Lekcja przeżywa tabelę: architektura, która nie potrafi czegoś reprezentować, to inny problem niż taka, która nigdy nie nauczyła się tego zakresu, a gryzie ten drugi. To także mechanika za każdym ogłoszeniem „rozszerzyliśmy context do 128K” — prawie zawsze są to przeskalowania kodowania rotary i dlatego rozdział 16 mówi, że limit context przesuwa się, a nie znika.
Dropout jest dziedziczony tak samo: pojawia się na wagach attention po softmax, na wyjściu każdej podwarstwy przed dodaniem residual oraz na sumie embedding, robiąc dokładnie to, co opisał rozdział 6. W dużych runach pretraining często ustawia się go na zero, bo model, który widzi każdy token raz, nie jest w pozycji do overfit.
Ile to kosztuje
Link do sekcji: Ile to kosztujeDwa tensory w warstwie mają kształt , gdzie to liczba tokens: scores i wagi po softmax. Wszystko inne — każda projekcja, cały MLP — jest liniowe względem .
Jedna warstwa attention, szerokość 512, 8 heads, batch jeden, float32, na GPU w laptopie. Czytaj dwie kolumny milisekund tylko jako stosunki: to wall clock na karcie laptopowej 8 GB, która dławi się z 1785 MHz do poniżej 300 MHz, gdy robi się gorąca, więc zimny run tego samego kodu wraca siedem do dziesięciu razy szybciej, a zajęty jeszcze wolniej. Kolumny megabajtów to liczniki bajtów alokatora i się nie ruszają.
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.87Kolumny x4 to stosunek do wiersza powyżej, a podwojenie zbiega dokładnie do 4 zarówno dla czasu, jak i pamięci — 3.91 w ostatnim kroku wobec teoretycznych 4. Kolumna projekcji jest kontrolą: 4.0 ms przy 1024 tokens do 40.1 ms przy 8192, czynnik dziesięć dla czynnika osiem. Liniowo, zgodnie z zapowiedzią.
Potem ostatni wiersz. Jedna warstwa attention, jedna sekwencja, bez modelu wokół niej, kończy pamięć na GPU 8 GB przy 16 384 tokens — sama macierz score miałaby 8 GB, bo to 8 heads razy 16 384 razy 16 384 razy 4 bajty. Nie model; jeden tensor pośredni w jednej warstwie.
To fizyczny fakt pod trzema późniejszymi rozdziałami. Dlatego context window w ogóle ma limit, który rozdział 16 zamienia w cenę. Dlatego istnieje FlashAttention, liczące ten sam wynik w kaflach bez kiedykolwiek przechowywania macierzy — optymalizacja pamięci, zanim jest optymalizacją szybkości.11 I to arytmetyka za ceną długiego prompt, którą rozdział 24 płaci w pętli agent — osobna sprawa od innego odkrycia tamtego rozdziału, że model także gorzej używa długiego context, co mierzy i odmawia zrzucenia winy na ten wzór.
Pokaż szczegóły
Dwa warianty zmniejszające cache, nazwane tutaj i opłacone w rozdziale 13.
Generowanie cache'uje keys i values tokens już przetworzonych — jeden key i jedna value per token, per head per layer. Multi-query attention12 zachowuje projekcji query, ale pojedynczą projekcję key i value współdzieloną przez wszystkie heads, dzieląc ten cache przez . Grouped-query attention13 interpoluje: heads są grupowane, każda grupa współdzieli jeden key i value, więc to zwykłe attention, a to multi-query. Prawie każdy otwarty model od 2023 roku używa tego z 4 lub 8 grupami. Żadne z nich nie istnieje dla jakości; oba istnieją dla rozmiaru tego cache, a rozdział 13 robi arytmetykę, która zamienia to w „który model mieści się w twoim GPU”.
Dwa kształty i rozmiar jednego
Link do sekcji: Dwa kształty i rozmiar jednegoArtykuł z 2017 roku opisuje encoder-decoder: jeden stos czyta źródło z niemaskowanym attention, drugi generuje cel causalnie, a trzeci rodzaj attention pośrodku to miejsce, gdzie queries decodera spotykają keys encodera. To właściwe dla tłumaczenia, gdzie wejście i wyjście są dwiema sekwencjami.
Wygrała połowa decoder-only — jeden stos, causal wszędzie, wejście i wyjście w tej samej sekwencji — a powodem nie jest elegancja. „Przewiduj następny token” działa na dowolnym tekście, więc zbiorem treningowym jest internet zamiast korpusu równoległego, a wszystko staje się tym jednym zadaniem: tłumaczenie to dokument zawierający źródło, potem cel; pytanie i odpowiedź są dokumentem; rozmowa z tool call pośrodku jest dokumentem. Rozdział 11 jest o tym, jak wytwarza się to ostatnie. Encodery nie zniknęły — jeden widzi całe wejście naraz, czego chcesz, gdy zadaniem jest reprezentować tekst, a nie go kontynuować, i dlatego retrieval embeddings z rozdziału 19 pochodzą z encoderów, a nie z modelu, który czatuje.
Gdy blok jest zdefiniowany, rozmiar modelu to arytmetyka. Na blok, przy szerokości i czterokrotnym rozszerzeniu: dla z biasami na wszystkich czterech, jak ma GPT-2 — tabela powyżej zostawia bias poza trzema z nich, stąd 2304 mniej na blok przy ; dla MLP; dla dwóch LayerNorm — , plus tabela token i, dla pozycji absolutnych, . Dla kształtu GPT-2 small — , 12 bloków, słownik 50 257, context 1024, warstwa wyjściowa współdzieląca wagi 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 jest opublikowanym rozmiarem tego modelu. Wzór nie jest przybliżeniem; jest modelem. Zauważ też, że prawie jedna trzecia małego modelu to tabela embedding, dlatego rozmiar słownika jest decyzją architektoniczną, a nie preprocessingiem — trade-off ustawiony w rozdziale 7.
Na co naprawdę patrzy head
Link do sekcji: Na co naprawdę patrzy headPerplexity to liczba o korpusie. To, co robi jedna head, jest innym pytaniem, a model trenowany na megabajcie Szekspira jest złym instrumentem do jego zadawania: uczciwie o attention map modelu z 500 000 parametrów można powiedzieć, że w większości nie jest interpretowalna. Więc: język, w którym pytanie ma poprawną odpowiedź.
Klasyczna ilustracja to the animal did not cross the street because it was too tired, gdzie it to animal, w kontraście do …because it was too wet, gdzie jedno słowo przenosi referenta na street. To są schematy Winograda14 — pary zdań identyczne poza jednym słowem, gdzie to słowo decyduje, do czego odnosi się zaimek.
Są też rozwiązywalne oszustwem, i tę część tutoriale pomijają. Jeśli dwaj kandydaci to zwierzę i miejsce, tired i wet identyfikują referenta przez kategorię, a model, który wie tylko, jakie słowa są obecne, odpowiada poprawnie, nie wiedząc nic o kolejności. Zmierzone na tej wersji zadania, z odłożonymi parami zwierzę/miejsce:
uniform causal average held-out referent accuracy 100.0 %
one transformer block held-out referent accuracy 91.7 %Bag of words bije transformer. Każda demonstracja zbudowana na tym zdaniu niczego nie dowodzi o attention.
Zamknij więc dziurę: losuj obu kandydatów z jednej puli szesnastu rzeczowników, z których każdy może pojawić się w dowolnym slocie, i podziel przymiotniki według roli zamiast kategorii — cztery czyniące it tym, który przekracza (tired, scared, slow, weak), cztery czyniące go tym, co przekraczane (wet, wide, busy, steep).
the {x} did not cross the {y} because it was too {adj} , so the {ref} waited .Trenuj jako zwykły next-token predictor, oceniaj jedną pozycję — słowo po so the — i zbuduj zbiór odłożony z par rzeczowników, których odwrócona kolejność była w treningu, więc wszystko, co wie, które dwa rzeczowniki są obecne, ale nie wie, który był pierwszy, musi odpowiedzieć odwrotnie.
| model | parametry | held-out | nazywa drugi rzeczownik |
|---|---|---|---|
| tylko bieżący token | 5796 | 5.2 % | 5.2 % |
| jednolita causal average | 5796 | 27.9 % | 50.0 % |
| jedna head wyuczonego attention | 18 084 | 35.4 % | 64.6 % |
| cztery heads | 22 244 | 75.0 % | 15.6 % |
| jeden transformer block | 55 716 | 92.7 % | 4.2 % |
| dwa transformer blocks | 105 508 | 100.0 % | 0.0 % |
Szansa spośród dwóch obecnych rzeczowników to 50 %. Jednolita średnia ląduje na 27.9 % i odpowiada złym rzeczownikiem z pary dokładnie połowę czasu — sygnatura czegoś, co wie, jakie słowa tam są, i nic o ich kolejności, zgodnie z testem tasowania sprzed trzech sekcji.
Teraz mapa: attention na pozycji, która musi nazwać referenta, uśrednione po czterech heads każdego bloku, dla dwóch zdań różniących się jednym słowem. Jednolita średnia położyłaby 0.067 na każdym z piętnastu widocznych 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.25Blok 1 jest identyczny w obu zdaniach — 0.70 na pierwszym rzeczowniku, niezależnie od przymiotnika. To nie porażka, tylko dowód: w pierwszej warstwie query na pozycji jest funkcją własnego token i indeksu tej pozycji, a the na pozycji 14 jest tym samym token w obu zdaniach. Head pierwszej warstwy nie może warunkować się słowem, którego jeszcze nie pobrała. Dlatego blok 1 robi jedyną użyteczną rzecz dostępną dla siebie i przeciąga pierwszy rzeczownik do przodu.
Blok 2 jest miejscem, gdzie zdania się rozchodzą, a ten sam wiersz przez wszystkie osiem przymiotników pokazuje regułę, którą znalazł model:
| przymiotnik | blok 2 na animal | na street | na przymiotniku | odpowiedź |
|---|---|---|---|---|
| tired, scared, slow, weak | 0.000 | 0.000 | 1.000 | animal |
| wet, wide, busy, steep | 0.000 | 0.491 | 0.00–0.03 | street |
Dla przymiotnika crosser druga warstwa kładzie całą wagę na przymiotnik, bo odpowiedź już jest w residual stream — blok 1 ją tam włożył — i potrzebuje tylko potwierdzenia. Dla przymiotnika crossed idzie i pobiera drugi rzeczownik. To obwód dwuskokowy: jedna head przesuwa kandydata do przodu, head w późniejszej warstwie czyta token, który decyduje, czy go zachować. Kompozycja przez warstwy jest mechanizmem i dlatego jeden blok osiągnął 92.7 %, a dwa — 100 %.
To także kształt najlepiej udokumentowanego obwodu w prawdziwych modelach. Induction heads — previous-token head karmiąca head w następnej warstwie, która domyka wzorzec [A][B] … [A] → [B] — są tym, co prace Anthropic o interpretowalności identyfikują za dużą częścią in-context learning, i tworzą się w rozpoznawalnym momencie podczas pretraining. Ten rozdział nie próbuje tej analizy: jest oddelegowana, z obiema pracami w bibliografii, bo czytanie obwodów z prawdziwego modelu to dziedzina badań, nie sekcja.
Na koniec implementacja. Trzydzieści linii powyżej, z wagami skopiowanymi z własnych wag PyTorch:
ours vs nn.MultiheadAttention max |diff| = 1.7881393432617188e-07
ours vs F.scaled_dot_product_attention max |diff| = 1.7881393432617188e-07na wyjściach, których średnia wielkość to 0.159: ta sama arytmetyka w innej kolejności, przy precyzji float32.
Dokąd to prowadzi
Link do sekcji: Dokąd to prowadziMasz architekturę, z której zbudowany jest każdy model w reszcie tego kursu, i jest mniejsza niż jej reputacja: ważona średnia, której wagi są uczone, MLP per pozycja trzymający dwie trzecie parametrów, dwie normalizacje i dwa dodania, ułożone w stos.
Nie masz modelu, który cokolwiek wie, a samo dokładanie stosu tego nie naprawi. Dwa bloki na tym korpusie osiągają training perplexity 14.49 i validation perplexity 40.57, wobec 18.77 i 38.07 dla jednego bloku — więcej pojemności, lepiej na tym, co widział, gorzej na tym, czego nie widział, czyli tabela z rozdziału 6 z transformer w środku. Odległość między tym modelem a tymi, z którymi rozmawiają rozdziały 14–30, nie jest architektoniczna. To ten sam blok, powtórzony więcej razy, nad ogromnie większą ilością tekstu.
To czyni sprawę problemem księgowości, a ta księgowość jest dziwniejsza, niż wygląda. Ile tekstu i skąd ktokolwiek go bierze? Ile arytmetyki i jak oszacować ją zanim pieniądze zostaną wydane? Przy stałym budżecie lepiej powiększyć model czy pokazać mu więcej danych — i czy istnieje poprawna odpowiedź, czy tylko moda? Rozdział 10 odpowiada na wszystkie trzy pytania pomiarami i wycenia najtańszą użyteczną formę pytania: ile dziś kosztuje wytrenowanie modelu takiego jak GPT-2 od zera?
Źródła i metoda
Link do sekcji: Źródła i metodaTrzy wyjaśnienia tego materiału są lepsze od tego w tym, do czego służą, a ten rozdział napisano do czytania obok nich. The Illustrated Transformer Jaya Alammara to najlepszy rysunek przepływu danych, jaki kiedykolwiek powstał. The Annotated Transformer Harvard NLP to artykuł z 2017 roku z działającym kodem przeplatanym linia po linii. Let's build GPT: from scratch, in code, spelled out Andreja Karpathy'ego buduje ten sam model na żywo w dwie godziny, a drabina ablations powyżej jest tym samym kręgosłupem zmierzonym na innym korpusie. Dla pytania o interpretowalność, którego ten rozdział tylko dotyka, źródłami podstawowymi są Elhage i in., A Mathematical Framework for Transformer Circuits (2021) oraz Olsson i in., In-context Learning and Induction Heads (2022), oba z grupy interpretowalności Anthropic.
Przypisy
Link do sekcji: Przypisy-
Hochreiter, S. and Schmidhuber, J. Long Short-Term Memory. Neural Computation 9(8), pp. 1735–1780 (1997). ↩
-
Sutskever, I., Vinyals, O. and Le, Q. V. Sequence to Sequence Learning with Neural Networks. arXiv:1409.3215 (2014). Encoder-decoder, którego pojedynczy wektor kontekstu jest wąskim gardłem. ↩
-
Bahdanau, D., Cho, K. and Bengio, Y. Neural Machine Translation by Jointly Learning to Align and Translate. arXiv:1409.0473 (2014). Attention, trzy lata przed transformer. ↩
-
Perplexity to wykładnik średniej cross-entropy per token, z rozdziału 8. Każda liczba tutaj używa tego samego tokenizera i tego samego podziału walidacyjnego, co jest jedynym warunkiem, pod którym dwie wartości perplexity w ogóle można porównywać. ↩
-
Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł. and Polosukhin, I. Attention Is All You Need. arXiv:1706.03762 (2017). Sekcja 3.2.1 to jedno zdanie o , którego pomiarom ten rozdział poświęca sekcję. ↩
-
Shazeer, N., Mirhoseini, A., Maziarz, K., Davis, A., Le, Q., Hinton, G. and Dean, J. Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer. arXiv:1701.06538 (2017). ↩
-
Ba, J. L., Kiros, J. R. and Hinton, G. E. Layer Normalization. arXiv:1607.06450 (2016). Wprowadzone i zmierzone w rozdziale 6; użyte tutaj bez zmian. ↩
-
Xiong, R., Yang, Y., He, D., Zheng, K., Zheng, S., Xing, C., Zhang, H., Lan, Y., Wang, L. and Liu, T.-Y. On Layer Normalization in the Transformer Architecture. arXiv:2002.04745 (2020). Analiza gradientu stojąca za pre-norm i argument, że warmup jest symptomem. ↩
-
Su, J., Lu, Y., Pan, S., Murtadha, A., Wen, B. and Liu, Y. RoFormer: Enhanced Transformer with Rotary Position Embedding. arXiv:2104.09864 (2021). ↩
-
Press, O., Smith, N. A. and Lewis, M. Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation. arXiv:2108.12409 (2021). Wynik ekstrapolacji odtworzony powyżej. ↩
-
Dao, T., Fu, D. Y., Ermon, S., Rudra, A. and 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. and Sanghai, S. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245 (2023). ↩
-
Levesque, H. J., Davis, E. and Morgenstern, L. The Winograd Schema Challenge. KR (2012). Konstrukcja stojąca za zdaniem animal / street, którego używa każdy tutorial o attention. ↩