Siirry sisältöön
9/30Luku 9/30

Attention ja transformer-lohko keskiarvosta johdettuna

Aloita contextin halvimmasta tiivistelmästä, keskiarvosta, mittaa sen virheet ja anna attention-kaavan syntyä korjauksesta.

Tällä sivulla

Saavut tähän kohtaan tokenizer mukanasi luvusta 7, embedding-taulu luvusta 8 ja niihin kuuluva tavoite: kun tähänastiset tokenit on annettu, aseta todennäköisyys seuraavalle.

Puuttuva osa on keskellä. Jotta malli voi ennustaa token tt, se tarvitsee yhden vektorin, joka tiivistää kaiken sitä edeltävän, eikä mikään tähän mennessä rakennettu tuota sellaista. Token t1t-1 embedding ei ole se — se on bigram-malli, eikä se voi tietää, että lause alkoi kysymyksellä. Kaikkien aiempien embeddingien ketjutus ei sekään ole ratkaisu: niiden määrä muuttuu joka askeleella, eikä kiinteä painomatriisi voi ottaa muuttuvan pituista syötettä.

Siis: yksi kiinteän kokoinen vektori, joka tiivistää muuttuvan määrän vektoreita. Siinä on koko ongelma, ja attention on se, mitä saat ratkaisemalla sen laiskimmalla mahdollisella tavalla ja korjaamalla sitten kaksi asiaa, jotka rikkoutuvat.

Alan silloinen vastaus ja miksi emme rakenna sitä

Linkki osioon: Alan silloinen vastaus ja miksi emme rakenna sitä

Vuodesta 1997 suunnilleen vuoteen 2017 tiivistelmä oli recurrent state: pidä yllä vektoria h\mathbf{h} ja päivitä sitä jokaisella tokenilla, ht=f(ht1,xt)\mathbf{h}_t = f(\mathbf{h}_{t-1}, \mathbf{x}_t). Kiinteä koko, muuttuva syöte, täsmälleen oikea muoto.

Se epäonnistui kolmella tavalla, ja tämän luvun arkkitehtuuri vastaa niihin kaikkiin. Backpropagation TT askeleen läpi kertoo TT Jacobian-matriisia, joten gradientti katoaa tai räjähtää — sama tauti, jonka luku 5 mittasi yhden tanh\tanh-solmun sisällä. LSTM1 suunniteltiin juuri tätä vastaan ja työnsi käyttökelpoisen kantaman kymmenistä askeleista satoihin muuttamatta sitä tosiasiaa, että tieto tokenista 5 pääsee tokeniin 500 vain selviytymällä 495 peräkkäisestä päivityksestä. Koko lähteen piti mahtua yhteen vektoriin: sequence-to-sequence-käännöksessä2 encoder pakkaa syötteen lopputilaansa. Bahdanau, Cho ja Bengio nimesivät tämän pullonkaulan ja korjasivat sen vuonna 2014, kolme vuotta ennen transformeria, antamalla decoderin ottaa painotetun summan kaikista encoder-tiloista painoilla, jotka se laski itse.3 Kaikki alla oleva on tuo idea, sovellettuna sekvenssin toimesta siihen itseensä, recurrence poistettuna. Ja päivitys on rakenteensa vuoksi peräkkäinen: ht\mathbf{h}_t tarvitsee ht1\mathbf{h}_{t-1}, eikä kymmenentuhannen ytimen GPU voi tehdä sillä mitään. Voittanut arkkitehtuuri ei ole ilmeisen paljon älykkäämpi; se on se, jonka kallis vaihe on matriisikertolasku.

Toista klassista inductive biasia, convolutionia — liu’uta yhtä pientä suodatinta koko syötteen yli, jotta missä tahansa havaittu piirre havaitaan kaikkialla — ei rakenneta tässäkään; se on lähes täsmälleen oikea kuville ja jätetään konenäkökurssille. Recurrence eikä convolution palaa tämän sivun jälkeen, minkä vuoksi kumpikaan ei saa omaa lukua: luku 1 lupasi, että poisjätöt ilmoitetaan eikä piiloteta.

Ilmeisin funktio, joka ottaa muuttuvan määrän vektoreita ja palauttaa yhden vektorin, on keskiarvo:

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

Mikä tahansa määrä syötteitä, kiinteä tuloskoko, derivoituva, ilmainen. Embedding-taulu plus tämä keskiarvo plus lineaarinen kerros sanastoon on kokonainen kielimalli viidessätoista rivissä. Se on myös surkea, ja sen surkeuden tapa on koko johdanto.

Alla oleva corpus on yksi megatavu Shakespearea, 1 115 394 merkkiä, luvussa 7 rakennetun kaltaisen tavutason BPE-tokenizerin läpi sanastolla 1024: 459 760 tokenia, 2,43 merkkiä kukin, jaettuna 90/10. Jokainen malli on 128 leveä, näkee 128 tokenia ja harjoittelee 3000 AdamW-askelta arvolla 10310^{-3} ja batch-koolla 64. Perplexity mitataan sivuun jätetyllä osalla.4

malliparametritvalidation perplexity
vain nykyinen token, ei lainkaan contextia263 16859.71
plus kaikkien edellisten tasainen keskiarvo263 168248.07
plus opitut position embeddingit279 552245.93
tasainen keskiarvo lisättynä tokeniin sen korvaamisen sijaan263 16860.45

Lue toinen rivi kahdesti. Contextin keskiarvoistaminen ei auta vähän; se tekee mallista neljä kertaa huonomman kuin contextin täydellinen sivuuttaminen. Syitä on kaksi, ja molemmat ovat todistettavia eivätkä empiirisiä.

Keskiarvo ei näe järjestystä. Yhteenlasku on vaihdannainen, joten ikkunan sekoittaminen jättää tiivistelmän ennalleen — ei likimäärin:

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

Liukulukuääntä uudelleenjärjestetyssä summassa: kaksi tiivistelmää ovat sama vektori. Malli, jonka ainoa näkymä contextiin on keskiarvo, ei voi erottaa lausetta the dog bit the man lauseesta the man bit the dog. Kolmas rivi todistaa, ettei tätä voi korjata lisäämällä positioita syötteisiin — opittu position embedding jokaisessa tokenissa ennen keskiarvoistamista osti 2,14 pistettä 188:sta. Positiot menevät summaan, ja summa unohtaa ne.

Ja keskiarvo hukuttaa nykyhetken. Positiossa 100 nykyinen token on sadasosa tiivistelmästä. Siihen on halpa korjaus, jonka jo omistat: pidä token ja lisää tiivistelmä siihen — residual connection, luvusta 6, ja neljäs rivi näyttää mitä se tekee. Kun laimeneminen on korjattu, tasainen keskiarvo ei tuo mitään: 60.45 perustasoa 59.71 vastaan. Jokainen token on mukana, yhtä suurella painolla, ja yhtäläinen painotus on sama kuin ei informaatiota.

Ongelma ei ole keskiarvoistaminen. Ongelma on painot.

Keskiarvo on matriisikertolasku ja maski on softmax

Linkki osioon: Keskiarvo on matriisikertolasku ja maski on softmax

Kasvavan prefiksin keskiarvo näyttää silmukalta. Se on yksi kertolasku alhaalta kolmiomaisella matriisilla, jonka rivit summautuvat yhteen — ja myös, täsmälleen, 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

Kolme transformer-komponenttia on nyt ruudulla nimettyinä. Kolmio on causal mask, tavoitteen pakottama: jos positio tt voisi nähdä position t+1t{+}1, vastaus olisi syötteessä — vuoto, jonka luku 6 käski auditoida, paitsi nyt arkkitehtuurin sisällä. Softmax on tapa, jolla maski toteutetaan: kiellettyjen kohtien asettaminen arvoon -\infty lähettää ne täsmälleen nollaan ja normalisoi jäljelle jäävän, joten maskaus ja normalisointi ovat yksi operaatio. (Käytä -\infty, älä -1e9: se on arvo, jota maskaus tarkoittaa, se selviää muunnoksesta float16:een arvona -\infty, eikä sinun tarvitse päättää, onko valitsemasi vakio riittävän suuri juuri siinä vaihteluvälissä, jossa satut olemaan — mikä on luvun 2 liukulukulaatikon kysymys, johon sinun ei tarvitse vastata.) Ja scoret ovat vapaa parametri. Tasainen keskiarvo on se, mitä saat, kun jokainen sallittu score on sama luku; laita sinne mitä tahansa lukuja, ja softmax muuttaa ne kelvollisiksi painoiksi.

Tämän luvun loppu on yksi kysymys: mistä nuo luvut tulevat?

Ne eivät voi olla tavallisia parametreja. Opittu T×TT \times T-matriisi olisi sama jokaiselle lauseelle — se voisi koodata "katso neljä tokenia taaksepäin", mutta ei koskaan "katso substantiivia, johon tämä pronomini viittaa". Painon, joka yhdistää position tt positioon ii, täytyy riippua siitä, mitä molemmissa positioissa on, koska relevanssi on suhde eikä ominaisuus: sana it ei ole luontaisesti relevantti, se on relevantti jollekin.

Halvin funktio kahdesta vektorista luvuksi on luvun 1 pistetulo. Anna positiolle ii score positiota tt varten muodossa xtxi\mathbf{x}_t \cdot \mathbf{x}_i ja mekanismi toimii — huonosti, kahdella tavalla, jotka pakottavat kaiken muun. Vektorin pistetulo itsensä kanssa on sen normin neliö, joten jokainen token kiinnittäisi attentionin enimmäkseen itseensä. Ja suhde olisi symmetrinen: jos it antaa vahvan attentionin sanalle animal, myös animal antaa vahvan attentionin sanalle it, mikä ei pidä paikkaansa kielessä, jossa adjektiivi tarvitsee substantiiviaan paljon enemmän kuin substantiivi tarvitsee adjektiivia.

Anna siis jokaiselle tokenille kaksi roolia, kahtena siitä opittuna lineaarikuvauksena: mitä tämä positio etsii, qt=Wqxt\mathbf{q}_t = W_q\mathbf{x}_t, query; ja millä se tarjoutuu löydettäväksi, ki=Wkxi\mathbf{k}_i = W_k\mathbf{x}_i, key. Score on qtki\mathbf{q}_t \cdot \mathbf{k}_i, ja symmetria katoaa, koska WqWkW_q \neq W_k: token voi mainostaa yhtä asiaa ja etsiä toista.

Yksi asia on yhä väärin. Painotettu summa oli itse xi\mathbf{x}_i:ien yli, mikä pakottaa kopioitavan asian olemaan sama kuin matchattava asia. Matching tarvitsee piirteitä, jotka tunnistavat tokenin; kopiointi tarvitsee piirteitä, jotka ovat hyödyllisiä myöhemmin. Opitaan siis kolmas kuvaus, vi=Wvxi\mathbf{v}_i = W_v\mathbf{x}_i, value, ja summataan niitä.

Kaava on nyt kirjanpitoa:

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

missä MM on causal mask, nolla diagonaalilla ja sen alapuolella ja -\infty yläpuolella. Koodissa se on kolmekymmentä riviä, joista kaksikymmentä on muotoja:

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, maskaa, normalisoi, sekoita. Kaikki muu on projektio.

Jakaminen neliöjuurella ja miltä se suojaa

Linkki osioon: Jakaminen neliöjuurella ja miltä se suojaa

Melkein jokainen selitys termille dk\sqrt{d_k} sanoo "jotta softmax ei saturoidu", mikä on totta eikä selitä mitään. Argumentti on kahden rivin varianssilasku luvusta 2. Jos q\mathbf{q}:n ja k\mathbf{k}:n alkiot ovat riippumattomia, odotusarvoltaan nollia ja varianssiltaan ykkösiä, jokaisella tulolla qjkjq_j k_j on varianssi yksi, ja riippumattomien asioiden varianssit summautuvat:

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

Niinpä scoreilla on keskihajonta dk\sqrt{d_k}. Mitattuna kahdenkymmenentuhannen satunnaisparin yli:

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

Miksi sillä on väliä: softmax on mittakaavaherkkä tavalla, jolla lineaarinen kerros ei ole. Lineaarisen kerroksen syötteen kaksinkertaistaminen kaksinkertaistaa sen tuloksen; scorejen kertominen kymmenellä ennen softmaxia muuttaa pehmeän sekoituksen kovaksi valinnaksi. Yksi 64 scoren rivi, jaolla ja ilman:

dkd_ksuurin paino, jakamatonentropiaeffective tokenssuurin paino, jaettuentropiaeffective 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

"Effective tokens" on entropian eksponentti: kuinka monen position yli rivi todella keskiarvoistaa. Jakamattomana kohdassa dk=256d_k = 256 juuri alustettu head antaa attentionin täsmälleen yhdelle tokenille 64:stä, täysin satunnaisarvonnan valitsemana.

Se on huono eteenpäin ja vielä pahempi taaksepäin, muodossa jonka luku 5 jo mittasi tanh\tanh:llä. Yhteen kohtaan sitoutuneella softmaxilla ei ole juuri derivaattia: sen Jacobianin diagonaali on wi(1wi)w_i(1-w_i), nolla molemmissa päissä. Kahdentuhannen satunnaisrivin yli:

dkd_kiwi(1wi)\sum_i w_i(1-w_i) jakamatonjaettusaturoituneet rivit (suurin paino yli 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 %

Kohdassa dk=1024d_k = 1024 seitsemän riviä kymmenestä on jäässä ennen harjoittelun alkua, eikä head, joka alkaa jäässä, voi oppia mihin katsoa. Jaettuna suure on tasainen 0.96 jokaisella leveydellä eikä mikään saturoitu.

Nyt osa, jota kukaan ei julkaise: muuttaako se lopullista perplexityä? Poista jako ja harjoittele neljällä head-leveydellä:

head-leveysjakamatonjaettu luvulla dk\sqrt{d_k}jaettu luvulla dkd_k
neljä headia, dk=32d_k = 3237.2938.0737.89
yksi head, dk=128d_k = 12848.5146.1045.99
yksi head, dk=256d_k = 25665.3747.53
yksi head, dk=512d_k = 51267.0649.15
yksi head, dk=1024d_k = 102476.6959.17

Kaksi ensimmäistä riviä tulevat yllä olevasta 3000 askeleen budjetista; kolme viimeistä ovat lyhyempi ajo — 1500 askelta, batch 32, yksi head, ei normalisointia ennen projektioita — molemmilla varianteilla identtisillä asetuksilla.

Kohdassa dk=32d_k = 32 jako ei ole minkään arvoinen ja ajo ilman sitä on hyvin hieman edellä. Se ei ole lupa pudottaa sitä, koska 256:ssa se on 18 perplexity-pisteen arvoinen ja 1024:ssä 17. Mekanismi näkyy scoreissa itsessään:

dkd_kscorejen std alustuksessa1500 askeleen jälkeen, jakamaton1500 askeleen jälkeen, jaettusaturoituneet rivit, jakamatonjaettu
25610.49121.672.1391.9 %0.8 %
51215.13836.852.6698.7 %1.3 %
102421.155147.463.4499.9 %16.5 %

Jakamaton head ei toivu. Se karkaa: sen scorejen keskihajonta nousee alustuksen 21:stä arvoon 5147, attention-entropia putoaa nollaan ja 99,9 % riveistä asettaa yli 0,99 painostaan yhdelle tokenille. Kun head on kova valitsin, sen gradientti on lähes nolla eikä mikään vedä sitä takaisin, joten romahdus on vakaa. Jaettu head pysyy saman harjoittelun jälkeen scorejen keskihajonnassa 3,44, mikä on pehmeä sekoitus, jota voi yhä muuttaa.

Vaswani et al. sanovat täsmälleen tämän eivätkä enempää — he epäilevät, että tulot "grow large in magnitude for large values of dkd_k" ja jakavat.5 Sana large kantaa kuorman, ja taulukot näyttävät mistä suuri alkaa: ei mitään 32:ssa, kaikki 256:een mennessä.

Useampi kuin yksi mielipide ja kaksi kolmasosaa, joista kukaan ei puhu

Linkki osioon: Useampi kuin yksi mielipide ja kaksi kolmasosaa, joista kukaan ei puhu

Yksi head on yksi softmax-rivi per positio, joten se kantaa yhden vastauksen kysymykseen "mikä on tässä relevanttia". Sanan ennustaminen sanan the jälkeen lauseessa the animal that crossed the wet street tarvitsee syntaktisen paikan, subjektin ja edellisen tokenin yhtä aikaa, eikä yksi todennäköisyysjakauma voi keskittyä kolmeen paikkaan. Aja siis useita headeja rinnakkain, kukin leveydellä dmodel/hd_{\text{model}}/h, ketjuta ja sekoita vielä yhdellä matriisilla WoW_o: olet osittanut leveyden, et lisännyt sitä.

Attention tekee myös täsmälleen yhden asian — se siirtää informaatiota positioiden välillä. Jokainen yllä olevan koodin operaatio on lineaarinen piirre-akselilla, ja luku 5 todisti mitä lineaaristen kuvausten pino on. Siksi jokaisessa lohkossa on myös pieni MLP, jota sovelletaan jokaiseen positioon itsenäisesti, leventäen nelinkertaiseksi ja palaten takaisin, keskellä GELU. Työnjako kannattaa opetella ulkoa: attention sekoittaa positioiden yli, feed-forward network laskee position sisällä.

Koko tikapuu, jokainen rivi lisää yhden palan yläpuoliseen riviin:

malliparametritvalidation perplexity
tasainen keskiarvo, lisättynä279 55260.45
yksi attention head, korvaa tokenin328 70455.47
yksi attention head, lisättynä328 70446.10
neljä headia yhden sijaan345 21643.21
plus feed-forward network476 92839.87
plus LayerNorm — kokonainen lohko477 69638.07

Opitut painot voittavat tasaiset 14 perplexity-pisteellä, mikä on tämän luvun koko argumentti yhdellä rivillä. Neljä headia ostaa vielä 3 pistettä 16 512 lisäparametrilla. Ja sama head on lisättynä 9 pistettä arvokkaampi kuin korvaavana: attention tuo informaatiota sisään, se ei päätä mikä positio on.

Nyt se, missä parametrit oikeasti sijaitsevat, mikä yllättää ne, jotka ovat nähneet vain kaavion:

leveysheaditattentionfeed-forwardyhteensä per lohko
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

Kaksi kolmasosaa jokaisesta transformer-lohkosta on feed-forward network, jokaisessa mittakaavassa, koska attentionilla on neljä d×dd \times d-matriisia ja MLP:llä vastaavuus kahdeksaan. Mitä malli sitten tietääkin, suurin osa sitä kantavista parametreista on position sisäisessä MLP:ssä.

Residualit ja LayerNorm, perittynä luvusta 6

Linkki osioon: Residualit ja LayerNorm, perittynä luvusta 6

LayerNorm rakennettiin ja mitattiin luvussa 6, ja tämä luku käyttää sitä sellaisena kuin se sinne jäi; residual connectionit nimettiin ja abloitiin siellä, ja ne rakennetaan tänne. Yllä olevat "lisätty, ei korvaava" -rivit ovat residual connectioneja, arvoltaan 188 perplexity-pistettä keskiarvolle ja 9 yhdelle headille. LayerNorm7 normalisoi jokaisen esimerkin sen piirteiden yli, ja luku 6 antoi syyt, miksi juuri se eikä BatchNorm jäi tänne — ei riippuvuutta batchista, ei juoksevia tilastoja, sama harjoittelussa ja inferenssissä, välinpitämätön sekvenssin pituudelle — ja jokainen niistä muuttuu vaatimukseksi, kun tuotat yhden tokenin kerrallaan yhdelle käyttäjälle, mihin luku 13 päätyy. Se maksaa 768 parametria ja ostaa 1,8 perplexity-pistettä.

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

Katso missä normalisointi sijaitsee: jokaisen alikerroksen syötteessä, residual-polun kulkiessa syötteestä tulokseen koskaan normalisoitumatta. Se on pre-norm. Vuoden 2017 paperi tekee päinvastoin, x = LayerNorm(x + Att(x))post-norm, joka asettaa LayerNormin itse residual-polulle.

Xiong et al. selittivät eron alustuksen gradientin kautta, joka post-norm-verkossa skaalautuu syvyyden kanssa huonosti — syy siihen, miksi alkuperäinen transformer tarvitsi learning-rate-warmupin ylipäätään harjoitellakseen.8 Kaksitoista lohkoa, 1000 askelta, 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 ilman warmupia on kahdeksan kertaa huonompi, ja post-norm warmupilla täsmää pre-normiin tarkalleen. Warmup ei ole tässä yleinen hyvä käytäntö; se on paikkaus tietylle normalisoinnin järjestelylle, ja LayerNormin siirtäminen poistaa sen tarpeen. Siksi käytännössä jokainen malli vuodesta 2019 lähtien on pre-norm, ja siksi vuoden 2017 kaaviota pitää lukea historiana eikä määrittelynä.

Poista position embeddingit ja malli harjoittelee yhä; se ei vain pysty kertomaan missä mikään on, ja se on symmetria eikä harjoittelun epäonnistuminen. Mikään attention-scoressa ei mainitse itse tt:tä tai ii:ta, joten syötteen permutointi permutoi tuloksen: self-attention on permutation-equivariant. Se on keskiarvon järjestyssokeus paremmassa valepuvussa — causal mask palauttaa jonkin verran järjestystä, koska jokainen positio näkee eri prefiksin, mutta prefiksin sisällä kaikki järjestykset ovat samanlaisia.

Neljä tapaa injektoida positio, harjoiteltuna 64 tokenin ikkunoilla ja arvioituna pituuksilla 64, 128 ja 256 — yli kaiken, mitä ne näkivät:

positiotperplexity kohdassa 64kohdassa 128kohdassa 256
ei lainkaan48.7952.6357.52
opitut absoluuttiset embeddingit38.63108.47181.94
kiinteät sinusoidit42.9695.26152.25
RoPE44.1250.5284.84
ALiBi44.9543.5142.49

Opitut absoluuttiset embeddingit — yksi vektori per positio, lisättynä tokeniin — voittavat harjoituspituudessa ja putoavat sitten jyrkänteeltä, koska positio 100 ei koskaan ollut batchissa ja sen embedding on yhä se satunnainen vektori, jona se aloitti. Sinusoidit, alkuperäinen valinta, lasketaan eikä opita, sinien ja kosinien avulla geometrisesti välistetyillä taajuuksilla; vuoden 2017 paperi toivoi sen ekstrapoloivan, ja taulukko sanoo ettei se tee niin — funktio on määritelty positiossa 200, mutta malli ei koskaan oppinut lukemaan sitä siellä. RoPE9 ei lisää mitään vaan kiertää queryn ja keyn position verrannollisella kulmalla kaksiulotteisissa viipaleissa; koska molempien puolien kiertäminen pistetulossa yhtä paljon jättää sen ennalleen, score päätyy riippumaan vain arvosta tit - i, joten positiosta tulee suhteellinen ilmaiseksi eikä taulu voi loppua kesken. Se heikkenee, mutta se heikkenee hallitusti. ALiBi10 on yksinkertaisin ja oudoin tulos tässä: lineaarinen rangaistus scoreen etäisyyden mukaan, eri kulmakertoimella per head. Sen perplexity paranee, kun ikkuna kasvaa harjoituspituuden yli, 44.95:stä 42.49:ään, koska rangaistus on määritelty millä tahansa etäisyydellä ja jokainen head jatkaa sen tekemistä, mihin se koulutettiin.

Opetus kestää taulukkoa pidempään: arkkitehtuuri, joka ei voi representoida jotakin, on eri ongelma kuin arkkitehtuuri, joka ei koskaan oppinut kyseistä aluetta, ja toinen näistä puree. Se on myös koneisto jokaisen "laajensimme contextin 128K:hon" -ilmoituksen takana — ne ovat lähes aina rotary encodingin uudelleenskaalauksia, ja siksi luku 16 sanoo, että context-raja liikkuu eikä katoa.

Dropout periytyy samalla tavalla: se esiintyy attention-painoissa softmaxin jälkeen, jokaisen alikerroksen tuloksessa ennen residual-lisäystä ja embedding-summassa, tehden täsmälleen sen, mitä luku 6 kuvasi. Suurissa pretraining-ajoissa se asetetaan usein nollaan, koska malli, joka näkee jokaisen tokenin kerran, ei juuri voi overfitata.

Kahdella kerroksen tensorilla on muoto n×nn \times n, missä nn on tokenien määrä: scoreilla ja softmaxin jälkeisillä painoilla. Kaikki muu — jokainen projektio, koko MLP — on lineaarista arvossa nn.

Yksi attention-kerros, leveys 512, 8 headia, batch yksi, float32, kannettavan GPU:lla. Lue kahden millisekuntisarakkeen suhteita vain suhteina: ne ovat seinäkellon aikaa 8 GB:n kannettavakortilla, joka throttlaa 1 785 MHz:stä alle 300 MHz:iin kuumetessaan, joten saman koodin kylmä ajo palaa seitsemästä kymmeneen kertaa nopeammin ja kiireinen ajo vielä hitaammin. Megatavusarakkeet ovat allokaattorin tavumääriä eivätkä liiku.

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

x4-sarakkeet ovat suhde yläpuoliseen riviin, ja nn:n kaksinkertaistuminen lähestyy täsmälleen arvoa 4 sekä ajassa että muistissa — 3.91 viimeisessä askeleessa teoreettista 4:ää vastaan. Projektiosarake on kontrolli: 4.0 ms 1024 tokenilla ja 40.1 ms 8192:lla, kerroin kymmenen kertoimelle kahdeksan. Lineaarinen, kuten luvattiin.

Sitten viimeinen rivi. Yksi attention-kerros, yksi sekvenssi, ei mallia ympärillä, loppuu muisti 8 GB:n GPU:lla 16 384 tokenissa — pelkkä score-matriisi olisi 8 GB, koska se on 8 headia kertaa 16 384 kertaa 16 384 kertaa 4 tavua. Ei malli; yksi välitensori yhdessä kerroksessa.

Tuo on fyysinen tosiasia kolmen myöhemmän luvun alla. Siksi context window’lla on ylipäätään raja, josta luku 16 tekee hinnan. Siksi FlashAttention on olemassa, laskemassa saman tuloksen laatoissa ilman että matriisia koskaan tallennetaan — muistioptimointi ennen kuin se on nopeusoptimointi.11 Ja se on aritmetiikka pitkän promptin hinnan takana, jonka luku 24 maksaa agent-silmukassa — erillinen asia tuon luvun toisesta löydöksestä, että malli myös käyttää pitkää contextia huonommin, minkä se mittaa eikä syytä tästä kaavasta.

Näytä lisätiedot

Kaksi cachea pienentävää varianttia, nimetty tässä ja maksettu luvussa 13.

Generointi cachettaa jo käsiteltyjen tokenien keyt ja valuet — yksi key ja yksi value per token, per head per kerros. Multi-query attention12 pitää hh query-projektiota mutta yhden kaikkien headien jakaman key- ja value-projektion, jakaen cachea luvulla hh. Grouped-query attention13 interpoloi: headit ryhmitellään, kukin ryhmä jakaa yhden keyn ja valuen, joten g=hg = h on tavallinen attention ja g=1g = 1 on multi-query. Lähes jokainen avoin malli vuodesta 2023 lähtien käyttää sitä 4 tai 8 ryhmällä. Kumpikaan ei ole olemassa laadun vuoksi; molemmat ovat olemassa tuon cachen koon vuoksi, ja luku 13 tekee aritmetiikan, joka muuttaa sen muotoon "mikä malli mahtuu GPU:hun".

Vuoden 2017 paperi kuvaa encoder-decoderin: yksi pino lukee lähteen maskaamattomalla attentionilla, toinen generoi kohteen kausaalisesti, ja keskellä on kolmas attention-laji, jossa decoderin queryt kohtaavat encoderin keyt. Se on oikein käännökselle, jossa syöte ja tulos ovat kaksi sekvenssiä.

Voittajaksi nousi decoder-only-puolikas — yksi pino, kausaalinen kaikkialla, syöte ja tulos samassa sekvenssissä — eikä syy ole eleganssi. "Ennusta seuraava token" toimii mille tahansa tekstille, joten harjoitusaineisto on internet eikä rinnakkaiscorpus, ja kaikesta tulee tuo yksi tehtävä: käännös on dokumentti, jossa on lähde ja sitten kohde, kysymys ja sen vastaus ovat dokumentti, keskustelu jossa on tool call keskellä on dokumentti. Luku 11 käsittelee, miten tuo viimeinen valmistetaan. Encoderit eivät kadonneet — sellainen näkee koko syötteen kerralla, mitä haluat, kun tehtävä on representoida tekstiä eikä jatkaa sitä, ja siksi luvun 19 retrieval embeddingit tulevat encodereista eivätkä keskustelua käyvästä mallista.

Kun lohko on määritelty, mallin koko on aritmetiikkaa. Per lohko, leveydellä dd ja nelinkertaisella laajennuksella: 4d2+4d4d^2 + 4d termille Wq,Wk,Wv,WoW_q, W_k, W_v, W_o biasien kanssa kaikissa neljässä, kuten GPT-2:ssa — yllä oleva taulukko jättää biasin pois kolmesta niistä, siitä 2 304 vähemmän per lohko arvolla d=768d = 768; 8d2+5d8d^2 + 5d MLP:lle; 4d4d kahdelle LayerNormille — 12d2+13d12d^2 + 13d, plus token-taulu V×dV \times d ja absoluuttisille positioille nctx×dn_{\text{ctx}} \times d. GPT-2 smallin muodolle — d=768d = 768, 12 lohkoa, sanasto 50 257, context 1024, output layer jakaa embedding-painot:

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

Mikä on kyseisen mallin julkaistu koko. Kaava ei ole likiarvo; se on malli. Huomaa myös, että lähes kolmannes pienestä mallista on embedding-taulu, minkä vuoksi sanaston koko on arkkitehtuuripäätös eikä esikäsittelypäätös — trade-off, jonka luku 7 asetti.

Perplexity on luku corpuksesta. Se, mitä yksi head tekee, on eri kysymys, ja megatavulla Shakespearea koulutettu malli on siihen väärä instrumentti: rehellistä 500 000 parametrin mallin attention-kartasta on sanoa, että se on enimmäkseen tulkitsematon. Siispä: kieli, jossa kysymyksellä on oikea vastaus.

Klassinen kuvitus on the animal did not cross the street because it was too tired, jossa it on animal, vasten lausetta …because it was too wet, jossa yksi sana siirtää viitekohteen streetiin. Nämä ovat Winograd-skeemoja14 — lausepareja, jotka ovat identtisiä yhtä sanaa lukuun ottamatta, ja tuo sana päättää, mihin pronomini viittaa.

Ne ovat myös ratkaistavissa huijaamalla, mikä on osa, jonka tutorialit ohittavat. Jos kaksi ehdokasta ovat eläin ja paikka, tired ja wet tunnistavat viitekohteen kategorian perusteella, ja malli, joka tietää vain mitkä sanat ovat läsnä, saa sen oikein tietämättä mitään järjestyksestä. Mitattuna tällä tehtävän versiolla, sivuun jätetyillä eläin/paikka-pareilla:

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

Bag of words voittaa transformerin. Mikä tahansa tuohon lauseeseen rakennettu demonstraatio ei todista mitään attentionista.

Sulje siis aukko: poimi molemmat ehdokkaat yhdestä kuudentoista substantiivin joukosta, joista kumpi tahansa voi esiintyä kummassa tahansa paikassa, ja jaa adjektiivit roolin eikä kategorian mukaan — neljä tekee it:stä ylittäjän (tired, scared, slow, weak), neljä tekee siitä ylitettävän (wet, wide, busy, steep).

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

Harjoittele tavallisena next-token-predictorina, scoreta yksi positio — sana kohdan so the jälkeen — ja rakenna sivuun jätetty joukko substantiivipareista, joiden käänteinen järjestys oli harjoittelussa, joten minkä tahansa joka tietää läsnä olevat kaksi substantiivia mutta ei kumpi tuli ensin, täytyy vastata takaperin.

malliparametritheld-outnimeää toisen substantiivin
vain nykyinen token5 7965.2 %5.2 %
tasainen causal-keskiarvo5 79627.9 %50.0 %
yksi learned attention -head18 08435.4 %64.6 %
neljä headia22 24475.0 %15.6 %
yksi transformer-lohko55 71692.7 %4.2 %
kaksi transformer-lohkoa105 508100.0 %0.0 %

Sattuma kahden läsnä olevan substantiivin välillä on 50 %. Tasainen keskiarvo päätyy 27,9 %:iin ja vastaa parin väärällä substantiivilla täsmälleen puolet ajasta — tunnusmerkki asiasta, joka tietää mitkä sanat ovat paikalla eikä mitään niiden järjestyksestä, kuten sekoitustesti ennusti kolme osiota sitten.

Nyt kartta: attention positiossa, jonka täytyy nimetä viitekohde, keskiarvoistettuna kunkin lohkon neljän headin yli, kahdelle lauseelle, jotka eroavat yhdellä sanalla. Tasainen keskiarvo asettaisi 0.067 jokaiselle viidestätoista näkyvästä tokenista.

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

Lohko 1 on identtinen molemmissa lauseissa — 0.70 ensimmäisessä substantiivissa riippumatta adjektiivista. Se ei ole epäonnistuminen vaan todiste: ensimmäisessä kerroksessa position query on funktio position omasta tokenista ja indeksistä, ja the positiossa 14 on sama token molemmissa lauseissa. Ensimmäisen kerroksen head ei voi ehdollistua sanaan, jota se ei ole vielä hakenut. Siksi lohko 1 tekee ainoan hyödyllisen asian, joka sille on saatavilla, ja vetää ensimmäisen substantiivin eteenpäin.

Lohko 2 on kohta, jossa lauseet erkanevat, ja sama rivi kaikkien kahdeksan adjektiivin yli näyttää säännön, jonka malli löysi:

adjektiivilohko 2 sanassa animalsanassa streetadjektiivissavastaus
tired, scared, slow, weak0.0000.0001.000animal
wet, wide, busy, steep0.0000.4910.00–0.03street

Ylittäjä-adjektiivilla toinen lohko käyttää koko painonsa adjektiiviin, koska vastaus on jo residual streamissa — lohko 1 laittoi sen sinne — ja se tarvitsee vain vahvistuksen. Ylitettävä-adjektiivilla se hakee toisen substantiivin sen sijaan. Se on kahden hypyn piiri: yksi head siirtää ehdokkaan eteenpäin, myöhemmän kerroksen head lukee tokenin, joka päättää pidetäänkö se. Kerrosten välinen kompositio on mekanismi, ja siksi yksi lohko pääsi 92,7 %:iin ja kaksi 100 %:iin.

Se on myös parhaiten dokumentoidun todellisten mallien piirin muoto. Induction heads — previous-token head, joka syöttää seuraavan kerroksen headia, joka täydentää kuvion [A][B] … [A] → [B] — ovat se, minkä Anthropicin interpretability-työ tunnistaa suuren osan in-context learningista taustalla, ja ne muodostuvat tunnistettavalla hetkellä pretrainingin aikana. Tämä luku ei yritä sitä analyysiä: se delegoidaan, molemmat paperit lähteissä, koska piirien lukeminen todellisesta mallista on tutkimusala eikä osio.

Lopuksi toteutus. Yllä olevat kolmekymmentä riviä, painot kopioituina PyTorchin omista:

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} tuloksissa, joiden keskimääräinen magnitudi on 0.159: sama aritmetiikka eri järjestyksessä, float32-tarkkuudella.

Sinulla on nyt arkkitehtuuri, josta jokainen tämän kurssin loppuosan malli on rakennettu, ja se on mainettaan pienempi: painotettu keskiarvo, jonka painot opitaan, per-position MLP joka kantaa kaksi kolmasosaa parametreista, kaksi normalisointia ja kaksi lisäystä, pinottuna.

Sinulla ei ole mallia, joka tietää mitään, eikä pinoaminen korjaa sitä itsestään. Kaksi lohkoa tällä corpuksella saavuttaa training perplexityn 14.49 ja validation perplexityn 40.57, yhden lohkon arvoja 18.77 ja 38.07 vastaan — enemmän kapasiteettia, parempi siinä mitä se on nähnyt, huonompi siinä mitä se ei ole nähnyt, eli luvun 6 taulukko transformer sisällään. Etäisyys tämän mallin ja niiden välillä, joille luvut 14–30 puhuvat, ei ole arkkitehtoninen. Se on sama lohko, toistettuna useammin, valtavasti suuremman tekstimäärän yli.

Siitä tulee kirjanpito-ongelma, ja kirjanpito on oudompaa kuin miltä näyttää. Kuinka paljon tekstiä, ja mistä sitä kukaan saa? Kuinka paljon aritmetiikkaa, ja miten arvioit sen ennen kuin raha on käytetty? Kiinteällä budjetilla, onko parempi tehdä mallista suurempi vai näyttää sille enemmän dataa — ja onko olemassa oikea vastaus vai vain muoti? Luku 10 vastaa kaikkiin kolmeen mittaamalla ja asettaa hinnan kysymyksen halvimmalle hyödylliselle muodolle: mitä maksaa tänään kouluttaa GPT-2:n kaltainen malli tyhjästä?


Kolme tämän materiaalin selitystä ovat parempia kuin tämä siinä, mitä varten ne on tehty, ja tämä luku on kirjoitettu luettavaksi niiden rinnalla. Jay Alammarin The Illustrated Transformer on paras koskaan piirretty kuva datavirroista. Harvard NLP:n The Annotated Transformer on vuoden 2017 paperi, jonka väliin on punottu ajettava koodi rivi riviltä. Andrej Karpathyn Let's build GPT: from scratch, in code, spelled out rakentaa saman mallin livenä kahdessa tunnissa, ja yllä oleva ablaatiotikapuu on sama runko mitattuna eri corpuksella. Interpretability-kysymykseen, jota tämä luku vain koskettaa, ensisijaiset lähteet ovat Elhage et al., A Mathematical Framework for Transformer Circuits (2021) ja Olsson et al., In-context Learning and Induction Heads (2022), molemmat Anthropicin interpretability-ryhmältä.

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

  2. Sutskever, I., Vinyals, O. and Le, Q. V. Sequence to Sequence Learning with Neural Networks. arXiv:1409.3215 (2014). Encoder-decoder, jonka yksittäinen context-vektori on pullonkaula.

  3. Bahdanau, D., Cho, K. and Bengio, Y. Neural Machine Translation by Jointly Learning to Align and Translate. arXiv:1409.0473 (2014). Attention, kolme vuotta ennen transformeria.

  4. Perplexity on keskimääräisen cross-entropyn eksponentti per token, luvusta 8. Jokainen tässä oleva luku käyttää samaa tokenizeria ja samaa validation-jakoa, mikä on ainoa ehto, jonka alla kahta perplexityä voi ylipäätään verrata.

  5. 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). Osio 3.2.1 on se yksi lause aiheesta dk\sqrt{d_k}, jonka mittaamiseen tämä luku käyttää kokonaisen osion.

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

  7. Ba, J. L., Kiros, J. R. and Hinton, G. E. Layer Normalization. arXiv:1607.06450 (2016). Esiteltiin ja mitattiin luvussa 6; käytetään tässä muuttumattomana.

  8. 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). Gradienttianalyysi pre-normin takana ja argumentti siitä, että warmup on oire.

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

  10. Press, O., Smith, N. A. and Lewis, M. Train Short, Test Long: Attention with Linear Biases Enables Input Length Extrapolation. arXiv:2108.12409 (2021). Yllä toistettu ekstrapolaatiotulos.

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

  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. and Sanghai, S. GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints. arXiv:2305.13245 (2023).

  14. Levesque, H. J., Davis, E. and Morgenstern, L. The Winograd Schema Challenge. KR (2012). Rakenne animal / street -lauseen takana, jota jokainen attention-tutorial käyttää.

Valmis antamaan LIA:n valita puolestasi?

Rakenna kaikilla tekoälymalleilla yhdessä paikassa — aloita ilmaiseksi jo tänään.