Attention і transformer block, виведені із середнього
Почніть із найдешевшого підсумку context — середнього — виміряйте його провал і отримайте формулу attention з виправлення.
На цій сторінці
Ви приходите сюди з tokenizer із розділу 7, таблицею embedding з розділу 8 і відповідною ціллю: маючи tokens дотепер, поставити ймовірність на наступний.
Бракує середини. Щоб передбачити token , моделі потрібен один vector, який підсумовує все перед ним, а ніщо з уже побудованого такого vector не дає. Embedding token — не він: це біграмна модель, і вона не може знати, що речення почалося із запитання. Конкатенація всіх попередніх embeddings теж не підходить: їхня кількість змінюється на кожному кроці, а фіксована матриця ваг не може приймати вхід змінної довжини.
Отже: один vector фіксованого розміру, який підсумовує змінну кількість vectors. Це вся задача, а attention — те, що ви отримуєте, коли розв’язуєте її найлінивішим можливим способом, а потім ремонтуєте дві речі, які ламаються.
Відповідь, яку вже мала галузь, і чому ми її не будуємо
Посилання на розділ: Відповідь, яку вже мала галузь, і чому ми її не будуємоЗ 1997-го приблизно до 2017-го підсумком був рекурентний стан: тримати vector і оновлювати його на кожному token, . Фіксований розмір, змінний вхід, саме потрібна форма.
Він провалився трьома способами, і архітектура цього розділу відповідає на всі три. Backpropagation через кроків множить якобіани, тому gradient зникає або вибухає — це та сама хвороба, яку розділ 5 вимірював усередині одного вузла . LSTM1 була спроєктована саме проти цього й розширила корисний діапазон із десятків кроків до сотень, не змінюючи факту, що інформація з token 5 доходить до token 500 лише якщо переживе 495 послідовних оновлень. Усе джерело мало вміститися в одному vector: у перекладі sequence-to-sequence2 encoder стискає вхід у свій фінальний стан. Bahdanau, Cho і Bengio назвали це вузьке місце й виправили його у 2014 році, за три роки до transformer, дозволивши decoder брати зважену суму всіх станів encoder з вагами, які він обчислював сам.3 Усе нижче — та сама ідея, застосована послідовністю до самої себе, з видаленою рекурентністю. І оновлення послідовне за конструкцією: потребує , і GPU з десятьма тисячами ядер нічого не може з цим зробити. Архітектура, яка перемогла, не очевидно розумніша; це та, чий дорогий крок є множенням матриць.
Інший класичний індуктивний ухил, згортка — ковзати одним малим фільтром по всьому входу, щоб ознака, виявлена будь-де, виявлялася всюди, — ми тут теж не будуємо; він майже точно підходить для зображень і делегований курсу з комп’ютерного зору. Ні рекурентність, ні згортка після цієї сторінки не повертаються, тому жодна не отримує розділу: розділ 1 обіцяв, що пропуски будуть оголошені, а не замовчані.
Найдешевший підсумок, який існує
Посилання на розділ: Найдешевший підсумок, який існуєНайочевидніша функція від змінної кількості vectors, що повертає один vector, — це середнє:
Будь-яка кількість входів, фіксований розмір виходу, диференційовність, безкоштовно. Таблиця embedding плюс це середнє плюс лінійний шар до словника — повна мовна модель у п’ятнадцять рядків. Вона ще й жахлива, а те, як саме вона жахлива, і є всім виведенням.
Корпус нижче — один мегабайт Shakespeare, 1 115 394 символи, через byte-level BPE tokenizer того типу, який будувався в розділі 7, зі словником 1024: 459 760 tokens по 2,43 символа кожен, поділ 90/10. Кожна модель має ширину 128, бачить 128 tokens і тренується 3000 кроків AdamW при з batch 64. Perplexity виміряна на відкладеній частині.4
| model | parameters | validation perplexity |
|---|---|---|
| лише поточний token, взагалі без context | 263,168 | 59.71 |
| плюс рівномірне середнє всього перед ним | 263,168 | 248.07 |
| плюс learned position embeddings | 279,552 | 245.93 |
| рівномірне середнє додане до token замість заміни ним | 263,168 | 60.45 |
Прочитайте другий рядок двічі. Усереднення context не допомагає трохи; воно робить модель у чотири рази гіршою, ніж повне ігнорування context. Є дві причини, обидві доводяться, а не просто спостерігаються емпірично.
Середнє не бачить порядку. Додавання комутативне, тому перемішування window лишає підсумок незмінним — не приблизно:
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Шум floating-point у перевпорядкованій сумі: два підсумки — той самий vector. Модель, чий єдиний погляд на context є середнім, не може відрізнити the dog bit the man від the man bit the dog. Третій рядок доводить, що це не виправляється додаванням позицій до входів — learned position embedding на кожному token перед усередненням дав 2,14 пункта з 188. Позиції входять у суму, і сума їх забуває.
І середнє топить теперішнє. На позиції 100 поточний token становить одну соту підсумку. У цього є дешеве виправлення, яке ви вже маєте: зберегти token і додати до нього підсумок — residual connection із розділу 6, і четвертий рядок показує, що вона робить. Коли розбавлення виправлене, рівномірне середнє не додає нічого: 60.45 проти baseline 59.71. Кожен token там є, з однаковою вагою, а однакова вага — те саме, що відсутність інформації.
Проблема не в усередненні. Вона у вагах.
Середнє — це множення матриць, а маска — це softmax
Посилання на розділ: Середнє — це множення матриць, а маска — це softmaxУсереднення по зростаючому префіксу виглядає як цикл. Насправді це одне множення на нижньотрикутну матрицю, рядки якої сумуються до одиниці, — і також, точно, 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.167Три названі компоненти transformer вже на екрані. Трикутник — це causal mask, продиктована ціллю: якби позиція могла бачити позицію , відповідь була б у вході — той витік, який розділ 6 просив вас перевіряти, тільки всередині архітектури. Softmax — це спосіб реалізувати маску: встановлення заборонених елементів у відправляє їх точно в нуль і нормалізує те, що лишилося, тож маскування й нормалізація є однією операцією. (Використовуйте , а не -1e9: це значення, яке маскування означає, воно переживає приведення до float16 як і позбавляє вас рішення, чи константа, яку ви вибрали, достатньо велика для діапазону, в якому ви опинилися, — це скринька floating-point із розділу 2, що ставить питання, на яке вам не потрібно відповідати.) А scores — це вільний параметр. Рівномірне середнє — те, що ви отримуєте, коли кожен дозволений score є тим самим числом; поставте там будь-які числа, і softmax перетворить їх на допустимі ваги.
Решта цього розділу — одне питання: звідки беруться ці числа?
Query, key, value
Посилання на розділ: Query, key, valueВони не можуть бути простими параметрами. Learned матриця була б однаковою для кожного речення — вона могла б закодувати «дивись на чотири tokens назад», але ніколи «дивись на іменник, до якого належить цей займенник». Вага, що зв’язує позицію із позицією , має залежати від того, що стоїть в обох позиціях, бо релевантність — це відношення, а не властивість: слово it не є релевантним саме по собі, воно релевантне до чогось.
Найдешевша функція двох vectors, що повертає число, — dot product із розділу 1. Оцініть позицію для позиції як , і механізм працює — погано, двома способами, що змушують з’явитися все інше. Dot product vector із самим собою — це квадрат його норми, тож кожен token здебільшого звертав би attention на себе. І відношення було б симетричним: якщо it сильно звертає attention на animal, тоді animal сильно звертає attention на it, що неправда для мови, де прикметнику його іменник потрібен значно більше, ніж іменнику прикметник.
Тому дайте кожному token дві ролі як дві learned лінійні карти від нього: що ця позиція шукає, , query; і що вона пропонує для знаходження, , key. Score , і симетрія зникає, бо : token може рекламувати одне, а шукати інше.
Одна річ усе ще неправильна. Зважена сума була по самих , що змушує те, що копіюється, бути тим самим, що зіставляється. Зіставленню потрібні ознаки, які ідентифікують token; копіюванню потрібні ознаки, корисні нижче за потоком. Тому вивчаємо третю карту, , value, і сумуємо їх.
Формула тепер — бухгалтерія:
де — causal mask, нуль на діагоналі й нижче та вище. У коді це тридцять рядків, із яких двадцять — форми:
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, mask, normalise, mix. Усе інше — projection.
Ділення на квадратний корінь і від чого воно захищає
Посилання на розділ: Ділення на квадратний корінь і від чого воно захищаєМайже кожне пояснення каже «щоб softmax не насичувався», що правда й нічого не пояснює. Аргумент — два рядки дисперсії з розділу 2. Якщо елементи і незалежні, із нульовим середнім і дисперсією один, кожен добуток має дисперсію один, а дисперсії незалежних величин додаються:
Отже, scores мають стандартне відхилення . Виміряно на двадцяти тисячах випадкових пар:
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Чому це важливо: softmax чутливий до масштабу так, як лінійний шар — ні. Подвоєння входу лінійного шару подвоює його вихід; множення scores на десять перед softmax перетворює м’яку суміш на жорсткий вибір. Один рядок із 64 scores, із діленням і без:
| largest weight, undivided | entropy | effective tokens | largest weight, divided | entropy | 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» — це експонента entropy: скільки позицій рядок справді усереднює. Без ділення, при , щойно ініціалізована head звертає attention рівно на один token із 64, вибраний нічим, крім випадкового жереба.
Це погано в forward і ще гірше в backward, у формі, яку розділ 5 уже виміряв на . Softmax, що зафіксувався на одному елементі, має майже нульову похідну: діагональ його якобіана — , нуль на обох кінцях. На двох тисячах випадкових рядків:
| undivided | divided | rows saturated (largest weight above 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 % |
При сім рядків із десяти заморожені ще до початку навчання, а head, що стартує замороженою, не може навчитися, куди дивитися. З діленням ця величина рівна 0.96 на кожній ширині, і нічого не насичується.
Тепер частина, яку ніхто не публікує: чи змінює це фінальну perplexity? Видаліть ділення й навчіть, на чотирьох ширинах head:
| head width | undivided | divided by | divided by |
|---|---|---|---|
| four heads, | 37.29 | 38.07 | 37.89 |
| one head, | 48.51 | 46.10 | 45.99 |
| one head, | 65.37 | 47.53 | — |
| one head, | 67.06 | 49.15 | — |
| one head, | 76.69 | 59.17 | — |
Перші два рядки походять із бюджету 3000 кроків вище; останні три — коротший запуск: 1500 кроків, batch 32, одна head, без нормалізації перед projections, з обома варіантами в ідентичних налаштуваннях.
При ділення не варте нічого, і запуск без нього трохи попереду. Це не ліцензія його викидати, бо при 256 воно варте 18 пунктів perplexity, а при 1024 — 17. Механізм видно в самих scores:
| score std at init | after 1500 steps, undivided | after 1500 steps, divided | rows saturated, undivided | divided | |
|---|---|---|---|---|---|
| 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 без ділення не відновлюється. Вона тікає в рознос: стандартне відхилення її scores зростає з 21 при ініціалізації до 5147, entropy attention падає до нуля, і 99,9 % рядків кладуть понад 0.99 своєї ваги на один token. Коли head стає жорстким selector, її gradient майже нульовий і ніщо не тягне її назад, тож колапс стабільний. Head із діленням після того самого навчання сидить на стандартному відхиленні scores 3.44, тобто це м’яка суміш, яку ще можна змінювати.
Vaswani et al. кажуть саме це й не більше — вони підозрюють, що добутки «стають великими за модулем для великих значень », і ділять.5 Слово великими несе навантаження, і таблиці кажуть, де починається велике: нічого при 32, усе при 256.
Більше ніж одна думка і дві третини, про які ніхто не говорить
Посилання на розділ: Більше ніж одна думка і дві третини, про які ніхто не говоритьОдна head — це один рядок softmax на позицію, тож вона тримає одну відповідь на «що тут релевантне». Передбачити слово після the у the animal that crossed the wet street потребує синтаксичного слота, підмета й попереднього token одночасно, а один розподіл імовірностей не може бути сконцентрований у трьох місцях. Тому запускаємо кілька heads паралельно, кожну ширини , конкатенуємо й змішуємо ще однією матрицею : ви поділили ширину, а не додали до неї.
Attention також робить рівно одну річ — переносить інформацію між позиціями. Кожна операція в коді вище лінійна вздовж осі ознак, а розділ 5 довів, чим є стек лінійних карт. Тому кожен block також містить малий MLP, застосований до кожної позиції незалежно, який розширює ширину вчетверо й повертає назад, із GELU посередині. Поділ праці варто запам’ятати: attention змішує між позиціями, feed-forward network обчислює всередині позиції.
Повна драбина, де кожен рядок додає одну частину до рядка над ним:
| model | parameters | validation perplexity |
|---|---|---|
| uniform average, added | 279,552 | 60.45 |
| one attention head, replacing the token | 328,704 | 55.47 |
| one attention head, added | 328,704 | 46.10 |
| four heads instead of one | 345,216 | 43.21 |
| plus the feed-forward network | 476,928 | 39.87 |
| plus LayerNorm — the complete block | 477,696 | 38.07 |
Learned ваги перемагають рівномірні на 14 пунктів perplexity — це весь аргумент розділу в одному рядку. Чотири heads купують ще 3 за 16 512 додаткових параметрів. І та сама head варта на 9 пунктів більше, коли вона додається, ніж коли замінює: attention приносить інформацію всередину, а не вирішує, чим є позиція.
Тепер де насправді сидять параметри — це дивує людей, які бачили лише діаграму:
| width | heads | attention | feed-forward | total per 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 |
Дві третини кожного transformer block — це feed-forward network, на кожному масштабі, бо attention має чотири матриці , а MLP має еквівалент восьми. Що б модель не знала, більшість параметрів, які це тримають, перебувають у per-position MLP.
Residuals і LayerNorm, успадковані з розділу 6
Посилання на розділ: Residuals і LayerNorm, успадковані з розділу 6LayerNorm був побудований і виміряний у розділі 6, і цей розділ використовує його таким, яким він там залишився; residual connections були названі й абльовані там, і тут вони вбудовані. Рядки «added, not replacing» вище — це residual connections, варті 188 пунктів perplexity для середнього й 9 для однієї head. LayerNorm7 нормалізує кожен приклад по його ознаках, а розділ 6 дав причини, чому саме він, а не BatchNorm, вижив тут — відсутність залежності від batch, відсутність running statistics, однакова поведінка в training та inference, байдужість до довжини послідовності, — і кожна з них стає вимогою, коли ви генеруєте один token за раз для одного користувача, куди зрештою приходить розділ 13. Він коштує 768 параметрів і купує 1,8 пункта perplexity.
class Block(nn.Module):
def forward(self, x):
x = x + self.att(self.ln1(x))
x = x + self.ff(self.ln2(x))
return xПодивіться, де стоїть нормалізація: на вході кожного sub-layer, а residual path від входу до виходу ніколи не нормалізується. Це pre-norm. Стаття 2017 року робить навпаки, x = LayerNorm(x + Att(x)) — post-norm, що ставить LayerNorm на сам residual path.
Xiong et al. пояснили різницю через gradient при ініціалізації, який у post-norm мережі погано масштабується з глибиною — причина, чому оригінальному transformer взагалі потрібен був learning-rate warmup, щоб навчатися.8 Дванадцять blocks, 1000 кроків, 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 без warmup у вісім разів гірший, а post-norm із warmup точно збігається з pre-norm. Warmup тут не загальна добра практика; це латка для конкретного розташування нормалізації, і перенесення LayerNorm прибирає потребу в ній. Саме тому практично кожна модель після 2019 року є pre-norm, а діаграму 2017 року слід читати як історію, а не як специфікацію.
Де перебуває token?
Посилання на розділ: Де перебуває token?Видаліть position embeddings, і модель усе ще тренується; вона просто не може сказати, де що є, і це симетрія, а не провал навчання. Ніщо в score attention не згадує самі або , тому перестановка входу переставляє вихід: self-attention є permutation-equivariant. Це сліпота середнього до порядку в кращому маскуванні — causal mask відновлює частину порядку, бо кожна позиція бачить інший префікс, але всередині префікса всі порядки однакові.
Чотири способи ін’єктувати позицію, навчені на 64-token windows і оцінені на 64, 128 і 256 — за межами будь-якої довжини, яку вони бачили:
| positions | perplexity at 64 | at 128 | at 256 |
|---|---|---|---|
| none at all | 48.79 | 52.63 | 57.52 |
| learned absolute embeddings | 38.63 | 108.47 | 181.94 |
| fixed sinusoids | 42.96 | 95.26 | 152.25 |
| RoPE | 44.12 | 50.52 | 84.84 |
| ALiBi | 44.95 | 43.51 | 42.49 |
Learned absolute embeddings — один vector на позицію, доданий до token, — перемагають на навченій довжині, а потім падають зі скелі, бо позиція 100 ніколи не була в batch, і її embedding усе ще той випадковий vector, з якого вона почалася. Sinusoids, початковий вибір, обчислюються, а не вивчаються, із синусів і косинусів на геометрично рознесених частотах; стаття 2017 року сподівалася, що це екстраполюватиме, а таблиця каже, що ні — функція визначена в позиції 200, але модель ніколи не навчилася читати її там. RoPE9 нічого не додає, а натомість обертає query і key на кут, пропорційний позиції, у двовимірних зрізах; оскільки однаковий поворот обох сторін dot product лишає його незмінним, score зрештою залежить тільки від , тож позиція безкоштовно стає відносною, і немає таблиці, яка може закінчитися. Він деградує, але деградує. ALiBi10 — найпростіший і найдивніший результат тут: лінійний штраф на score, пропорційний відстані, з різним нахилом для кожної head. Його perplexity покращується, коли window зростає за межі навчальної довжини, з 44.95 до 42.49, бо штраф визначений на будь-якій відстані, і кожна head продовжує робити те, чого її навчали.
Урок живе довше за таблицю: архітектура, яка не може представити щось, — інша проблема, ніж та, що просто ніколи не вивчила цей діапазон, і кусає саме друга. Це також механіка за кожним оголошенням «ми розширили context до 128K» — майже завжди це re-scaling rotary encoding, і саме тому розділ 16 каже, що межа context рухається, а не зникає.
Dropout успадкований так само: він з’являється на вагах attention після softmax, на виході кожного sub-layer перед residual addition і на сумі embeddings, роблячи саме те, що описував розділ 6. У великих pretraining-запусках його часто ставлять у нуль, бо модель, яка бачить кожен token один раз, не в позиції overfit.
Скільки це коштує
Посилання на розділ: Скільки це коштуєДва tensors у шарі мають форму , де — кількість tokens: scores і ваги після softmax. Усе інше — кожна projection, весь MLP — лінійне за .
Один attention layer, ширина 512, 8 heads, batch один, float32, на GPU ноутбука. Читайте дві мілісекундні колонки лише за їхніми співвідношеннями: це wall clock на 8 GB ноутбучній карті, яка throttles із 1 785 MHz до менш ніж 300 MHz, коли нагрівається, тому холодний запуск того самого коду повертається у сім-десять разів швидше, а зайнятий — ще повільніше. Колонки megabyte — це byte counts allocator, і вони не рухаються.
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 — це відношення до рядка вище, і подвоєння сходиться рівно до 4 і для часу, і для пам’яті — 3.91 на останньому кроці проти теоретичних 4. Колонка projections — контроль: 4.0 ms на 1024 tokens до 40.1 ms на 8192, фактор десять для фактора вісім. Лінійно, як і обіцяно.
Потім останній рядок. Один attention layer, одна послідовність, без моделі навколо нього, вичерпує пам’ять на 8 GB GPU при 16 384 tokens — сама матриця scores була б 8 GB: 8 heads × 16 384 × 16 384 × 4 bytes. Не модель; один проміжний tensor в одному шарі.
Це фізичний факт під трьома наступними розділами. Саме тому context window взагалі має межу, яку розділ 16 перетворює на ціну. Саме тому існує FlashAttention, що обчислює той самий результат плитками, ніколи не зберігаючи матрицю, — оптимізація пам’яті до того, як вона є оптимізацією швидкості.11 І це арифметика за ціною довгого prompt, яку розділ 24 платить в agent loop, — окрема справа від іншого висновку того розділу: що модель ще й гірше використовує довгий context, що він вимірює й відмовляється звинувачувати в цій формулі.
Показати подробиці
Два варіанти зменшення cache, названі тут і оплачені в розділі 13.
Generation кешує keys і values уже оброблених tokens — один key і один value на token, на head на layer. Multi-query attention12 тримає query projections, але одну key і value projection, спільну для всіх heads, ділячи цей cache на . Grouped-query attention13 інтерполює: heads групуються, кожна група ділить один key і value, тож — звичайний attention, а — multi-query. Майже кожна відкрита модель із 2023 року використовує це з 4 або 8 групами. Жодне не існує заради якості; обидва існують заради розміру цього cache, і розділ 13 робить арифметику, яка перетворює це на «яка модель вміщується у ваш GPU».
Дві форми й розмір однієї
Посилання на розділ: Дві форми й розмір однієїСтаття 2017 року описує encoder-decoder: один стек читає джерело з unmasked attention, другий генерує ціль causal, а посередині третій вид attention, де queries decoder зустрічаються з keys encoder. Це правильно для перекладу, де вхід і вихід — дві послідовності.
Перемогла decoder-only половина — один стек, causal всюди, вхід і вихід в одній послідовності, — і причина не в елегантності. «Передбачити наступний token» працює на будь-якому тексті, тож training set — інтернет, а не паралельний корпус, і все стає одним завданням: переклад — це документ, що містить джерело, потім ціль; питання та відповідь — документ; розмова з tool call посередині — документ. Розділ 11 про те, як виготовляють останнє. Encoders не зникли — один бачить увесь вхід одразу, що й потрібно, коли задача — представити текст, а не продовжити його; тому retrieval embeddings у розділі 19 походять з encoders, а не з моделі, яка чатиться.
Коли block визначений, розмір моделі — арифметика. На block, із шириною і чотириразовим розширенням: для з biases на всіх чотирьох, як у GPT-2, — таблиця вище лишає bias вимкненим на трьох із них, тому на 2 304 менше на block при ; для MLP; для двох LayerNorms — , плюс таблиця tokens і, для absolute positions, . Для форми GPT-2 small — , 12 blocks, словник 50 257, context 1024, output layer ділить ваги з 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,808Це опублікований розмір цієї моделі. Формула не наближення; це модель. Також зауважте, що майже третина малої моделі — це embedding table, тому розмір словника є архітектурним рішенням, а не preprocessing — trade-off, який підготував розділ 7.
На що насправді дивиться head
Посилання на розділ: На що насправді дивиться headPerplexity — число про корпус. Що робить одна head — інше питання, і модель, навчена на мегабайті Shakespeare, — неправильний інструмент для нього: чесно про attention map моделі на 500 000 параметрів можна сказати, що вона здебільшого неінтерпретована. Тож: мова, де питання має правильну відповідь.
Класична ілюстрація — the animal did not cross the street because it was too tired, де it — це animal, на противагу …because it was too wet, де одне слово переносить референт на street. Це Winograd schemas14 — пари речень, ідентичні, крім одного слова, де це слово вирішує, до чого належить займенник.
Вони також розв’язні шахрайством, і це частина, яку tutorials пропускають. Якщо два кандидати — тварина й місце, tired і wet ідентифікують референт за категорією, і модель, що знає лише, які слова присутні, відповідає правильно, нічого не знаючи про порядок. Виміряно на цій версії задачі, з відкладеними парами animal/place:
uniform causal average held-out referent accuracy 100.0 %
one transformer block held-out referent accuracy 91.7 %Bag of words перемагає transformer. Будь-яка демонстрація, побудована на цьому реченні, нічого не доводить про attention.
Тож закриймо діру: беремо обох кандидатів з одного пулу шістнадцяти іменників, кожен із яких може з’явитися в будь-якому слоті, і ділимо прикметники за роллю, а не категорією — чотири роблять it тим, хто перетинає (tired, scared, slow, weak), чотири — тим, що перетинають (wet, wide, busy, steep).
the {x} did not cross the {y} because it was too {adj} , so the {ref} waited .Навчайте як звичайний next-token predictor, оцінюйте одну позицію — слово після so the — і будуйте held-out set із пар іменників, чий зворотний порядок був у training, тож усе, що знає, які два іменники присутні, але не знає, який був першим, має відповісти навпаки.
| model | parameters | held-out | names the other noun |
|---|---|---|---|
| current token only | 5,796 | 5.2 % | 5.2 % |
| uniform causal average | 5,796 | 27.9 % | 50.0 % |
| one head of learned attention | 18,084 | 35.4 % | 64.6 % |
| four heads | 22,244 | 75.0 % | 15.6 % |
| one transformer block | 55,716 | 92.7 % | 4.2 % |
| two transformer blocks | 105,508 | 100.0 % | 0.0 % |
Випадковий вибір серед двох присутніх іменників — 50 %. Рівномірне середнє доходить до 27.9 % і відповідає неправильним іменником із пари рівно в половині випадків — підпис чогось, що знає, які слова є, і нічого про їхній порядок, як shuffle test передбачив три секції тому.
Тепер карта: attention у позиції, яка має назвати референт, усереднений по чотирьох heads кожного block, для двох речень, що відрізняються одним словом. Рівномірне середнє поставило б 0.067 на кожен із п’ятнадцяти видимих 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 ідентичний в обох реченнях — 0.70 на першому іменнику, яким би не був прикметник. Це не провал, а доказ: у першому layer query у позиції є функцією власного token та індексу цієї позиції, а the у позиції 14 — той самий token в обох реченнях. Head першого layer не може залежати від слова, якого вона ще не витягла. Тому block 1 робить єдине корисне, що доступне, і тягне перший іменник уперед.
Block 2 — місце, де речення розходяться, і той самий рядок на всіх восьми прикметниках показує правило, яке знайшла модель:
| adjective | block 2 on animal | on street | on the adjective | answer |
|---|---|---|---|---|
| tired, scared, slow, weak | 0.000 | 0.000 | 1.000 | animal |
| wet, wide, busy, steep | 0.000 | 0.491 | 0.00–0.03 | street |
Для прикметника crosser другий block витрачає всю вагу на прикметник, бо відповідь уже в residual stream — block 1 її туди поклав, — і все, що потрібно, це підтвердження. Для прикметника crossed він іде й витягає інший іменник. Це двострибковий circuit: одна head переносить кандидата вперед, head у пізнішому layer читає token, який вирішує, чи залишити його. Композиція між layers — механізм, і саме тому один block досяг 92.7 %, а два — 100 %.
Це також форма найкраще задокументованого circuit у реальних моделях. Induction heads — previous-token head, що живить head у наступному layer, яка завершує патерн [A][B] … [A] → [B], — це те, що робота Anthropic з interpretability ідентифікує за великою частиною in-context learning, і вони формуються в упізнаваний момент під час pretraining. Цей розділ не намагається виконати такий аналіз: він делегований, із двома статтями в джерелах, бо читання circuits із реальної моделі — дослідницька галузь, а не секція.
Нарешті, реалізація. Тридцять рядків вище, з вагами, скопійованими з власних ваг PyTorch:
ours vs nn.MultiheadAttention max |diff| = 1.7881393432617188e-07
ours vs F.scaled_dot_product_attention max |diff| = 1.7881393432617188e-07на виходах, чия середня величина 0.159: та сама арифметика в іншому порядку, з точністю float32.
Куди це веде далі
Посилання на розділ: Куди це веде даліУ вас є архітектура, з якої побудована кожна модель у решті курсу, і вона менша за свою репутацію: зважене середнє, чиї ваги learned, per-position MLP, що тримає дві третини параметрів, дві нормалізації й два додавання, складені в стек.
Чого у вас немає — це моделі, яка щось знає, і саме стекування цього не виправить. Два blocks на цьому корпусі досягають training perplexity 14.49 і validation perplexity 40.57 проти 18.77 і 38.07 для одного block — більше capacity, краще на тому, що вона бачила, гірше на тому, чого не бачила; це таблиця розділу 6 із transformer усередині. Відстань між цією моделлю і тими, з якими говорять розділи 14–30, не архітектурна. Це той самий block, повторений більше разів, на незрівнянно більшій кількості тексту.
А отже, це бухгалтерська задача, і бухгалтерія дивніша, ніж здається. Скільки тексту, і звідки хтось його бере? Скільки арифметики, і як оцінити її до того, як витрачені гроші? За фіксованого бюджету краще зробити модель більшою чи показати їй більше даних — і чи є правильна відповідь, або лише мода? Розділ 10 відповідає на всі три вимірюванням і ставить ціну на найдешевшу корисну форму питання: скільки сьогодні коштує навчити модель на кшталт GPT-2 з нуля?
Джерела й метод
Посилання на розділ: Джерела й методТри пояснення цього матеріалу кращі за це у своїх завданнях, і цей розділ написаний, щоб читатися поруч із ними. The Illustrated Transformer Jay Alammar — найкраща картина потоку даних із будь-коли намальованих. The Annotated Transformer Harvard NLP — це стаття 2017 року з робочим кодом, вставленим рядок за рядком. Let's build GPT: from scratch, in code, spelled out Andrej Karpathy будує ту саму модель наживо за дві години, а драбина ablations вище — той самий хребет, виміряний на іншому корпусі. Для питання interpretability, якого цей розділ лише торкається, первинні джерела — Elhage et al., A Mathematical Framework for Transformer Circuits (2021) і Olsson et al., In-context Learning and Induction Heads (2022), обидва від групи interpretability Anthropic.
Примітки
Посилання на розділ: Примітки-
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, чий єдиний context vector є вузьким місцем. ↩
-
Bahdanau, D., Cho, K. and Bengio, Y. Neural Machine Translation by Jointly Learning to Align and Translate. arXiv:1409.0473 (2014). Attention, за три роки до transformer. ↩
-
Perplexity — це експонента середньої cross-entropy на token, з розділу 8. Кожне число тут використовує той самий tokenizer і той самий validation split, що є єдиною умовою, за якої дві perplexities взагалі можна порівнювати. ↩
-
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). Section 3.2.1 — це одне речення про , яке цей розділ витрачає секцію, щоб виміряти. ↩
-
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). Введено й виміряно в розділі 6; тут використовується без змін. ↩
-
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). Gradient analysis за pre-norm і аргумент, що warmup — симптом. ↩
-
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). Результат екстраполяції, відтворений вище. ↩
-
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). Конструкція за реченням animal / street, яке використовує кожен tutorial про attention. ↩