Від згортки до уваги

Вісімнадцять тем ми будували мережі на згортці. Вона несе в собі припущення, яке ми давно перестали помічати: важливо тільки сусідство. Ця тема знімає це припущення й розбирає операцію, яка приходить йому на зміну. Майже все тут доводиться алгеброю — без жодного навчання.

У кінці теми 18 ми поставили питання й лишили його без відповіді. Усі девʼять архітектур, які ми розібрали, — від AlexNet 2012 року до EfficientNet 2019-го — стоять на одному припущенні: сусідні пікселі повʼязані, далекі — ні. А що буде, якщо цю ставку зняти? Якщо дозволити кожній частині зображення дивитися одразу на будь-яку іншу, без вікна й без сусідства? Відповідь називається увага, і в цій темі ми розберемо саму операцію: звідки береться її формула, чому в ній стоїть ділення на корінь, що вона вміє задарма і за що доводиться платити.

Чим ця тема незвична. Майже все, що тут написано, можна перевірити за секунди й без жодного навчання — трьома-чотирма рядками коду. Головний факт теми доводиться взагалі алгеброю: він випливає з форми формули, а не з того, що модель чогось навчилась. Тому й усі числа нижче зняті на випадкових, ненавчених вагах — навчати тут нема чого.

СпадокЩо згортка вирішила за нас

Повернімось до теми 06. Там ми брали повнозвʼязну мережу, показували, що на зсунутих предметах вона падає до рівня вгадування, і вводили згортку як ліки. Ліки подіяли: та сама задача, у тринадцять разів менше ваг, точність на зсунутих предметах удвічі вища.

Але кожні ліки — це вибір, і за нього чимось платять. Згортка не просто «краще працює». Вона ухвалює за нас три рішення, ще до того, як мережа побачить перший приклад. Ось вони.

рішеннящо воно кажещо з нього випливає
Локальністьзначення має лише те, що лежить у вікні 3×3далекий звʼязок треба збирати з багатьох шарів
Спільні вагите саме ядро працює в кожній точці кадруознака, вивчена в кутку, працює по всьому кадру
Порядокпіксель знає, хто його лівий сусід, а хто верхнійгеометрія кадру закладена в саму операцію

Третє рішення варто розжувати, бо його майже ніколи не називають окремо. Коли ядро 3×3 множить свою верхню ліву клітинку на верхній лівий піксель вікна, воно тим самим знає, що цей піксель — верхній лівий. Це знання не вивчене, воно вбудоване в те, як записано операцію. Згортка отримує геометрію кадру безкоштовно, разом із формулою.

Три рішення разом і є та ставка, про яку йшлося в кінці теми 18. Вона виявилась блискучою — але лишається ставкою: локальність не є властивістю зображень, вона є нашим припущенням про них. У цій темі подивимось на ті самі три рішення з іншого боку — як на обмеження. Почнемо з першого.

МежаДе локальність заважає

Уяви фотографію кімнати: у лівому нижньому кутку склянка, у правому верхньому — вона ж у дзеркалі. Щоб зрозуміти, що це відображення, мережі треба звести обидва кутки в одне число. Скільки на це потрібно згорткових шарів?

У темі 07 ми вводили рецептивне поле — ділянку входу, здатну вплинути на одне число на виході. Для згортки 3×3 із кроком 1 воно росте на два пікселі за шар: перший шар бачить 3×3, другий — 5×5, третій — 7×7. Формула:

рецептивне поле після L шарів 3×3 = (2L + 1) × (2L + 1)

Слово за словом: кількість шарів L множимо на два й додаємо одиницю — це сторона квадрата вхідних пікселів, які можуть вплинути на одне число після цих шарів. Множник два — бо кожен шар додає по пікселю з кожного боку; одиниця — бо нульовий шар бачить сам себе.

Наші фігури — 28×28. Підставляємо: щоб рецептивне поле накрило 27×27, тобто майже весь кадр, треба L = 13. Тринадцять шарів згортки, щоб перший піксель нарешті «побачив» останній. Це не оцінка, а арифметика: підстав L = 13 у формулу вище й дістанеш 2·13 + 1 = 27.

згортка 3×313 шарівщоб довести рецептивне поле до 27×27 на кадрі 28×28
увага1 шаркожен із 49 патчів бачить усі 49 з першої ж операції

Проти цього — операція, яку ми зараз розберемо. Вона накриває весь кадр з першого шару, бо в неї взагалі немає поняття вікна. І це не хитрість: далі ми побачимо, скільки саме за це платять.

Чесна поправка: на практиці тринадцять шарів 3×3 поспіль ніхто не ставить — пулінг і крок 2 подвоюють рецептивне поле разом із кожним зменшенням карти. Але суть не міняється: далекий звʼязок у згортці доводиться будувати, а не брати. Він збирається через ланцюжок посередників, і на кожній ланці частина інформації розмивається.

Локальність проти всеосяжності

Ліворуч — рецептивне поле центрального нейрона після заданої кількості згорток 3×3. Праворуч — та сама сітка з увагою, яка накриває все з першого шару, і ціна цього під нею. Тягни повзунок і дивись, коли квадрат дістане до країв — і скільки пар за це платить сусідня панель.

рецептивне поле3×3
частка кадру1.1 %
ваг у стосі—
ціна уваги: пар2 401
Кадр 28×28, згортки 3×3 із кроком 1 і padding=1, один канал. «Ваг у стосі» — 9·L, тобто скільки ядерних чисел довелося поставити, щоб дотягнутись. Увага накриває 100 % кадру при будь-якому положенні повзунка — але рахує 49² = 2 401 пару патчів, і рахує їх заново для кожного зображення. Обидві половини правди на одній картинці: згортка платить шарами, увага — парами.

ІдеяХай кожен сам обере, з ким рахуватися

Слово «увага» тут заважає більше, ніж допомагає: воно натякає, що мережа кудись дивиться й чогось хоче. Нічого такого не відбувається. Точне формулювання вміщається в одне речення: для кожної позиції ми рахуємо зважену суму всіх позицій, і самі ваги теж рахуються з даних.

Перша половина — «зважена сума всіх позицій» — це те, що робить і згортка: множимо сусідів на числа й додаємо. Різниця в тому, що сусідів тепер не девʼять, а всі. Друга половина — і саме вона нова — ваги не фіксовані. У згортці ядро вивчається один раз, і далі те саме число множить верхнього сусіда в кожній точці кадру. В увазі ваг не існує заздалегідь: вони обчислюються щоразу заново, для конкретного зображення.

Далі — три слова, які треба ввести, бо без них не читається жоден код. Кожна позиція отримує три різні описи себе, і кожен потрібен для свого:

назвапитання, на яке відповідаєде вживається
Запит Q (query)що я шукаю?у позиції, яка збирає інформацію
Ключ K (key)що я можу запропонувати?у позиціях, які інформацію віддають
Значення V (value)що саме я віддам, якщо мене оберуть?там само

Побутова аналогія — бібліотечний каталог. Ти приходиш із запитом («книжка про мости»), у кожної картки є ключ (тема, за якою її знайдуть) і значення (сама книжка). Збіг запиту з ключем вирішує, наскільки ця картка тобі потрібна.

Де аналогія бреше. У бібліотеці ти береш одну книжку — ту, що збіглась найкраще. Увага не бере одну: вона бере всі, змішує їх у пропорції «наскільки збіглось» і віддає суміш. Навіть найдальша картка отримує ненульову частку. Правильний образ — не пошук, а усереднення з нерівними вагами.

І ще одне, важливе для наступних розділів. Три описи — запит, ключ, значення — отримують із того самого вектора позиції, помноживши його на три різні матриці ваг. Оці матриці й є те, що вчиться. Самі ваги уваги не вчаться ніколи; вчиться лише те, як їх рахувати.

Звідки взялись «позиції». Для згортки позиція — це піксель; для уваги працювати з окремими пікселями надто дорого (розділ 09), тому кадр ріжуть на квадратні патчі (patch) — у нас 4×4 пікселі, тобто 7×7 = 49 патчів на кадр 28×28. Кожен патч розпрямляють у вектор із 16 чисел і проєктують у робочу розмірність; результат називають токеном. Як це робиться в справжній мережі — тема 20.

ФормулаФормула по кроках

Ось вона повністю. Не лякайся — далі кожен символ буде розібраний, а потім ми порахуємо все руками на чотирьох числах.

Увага(Q, K, V) = softmax( Q · Kт / √d ) · V

Що є що:

Тепер по кроках. Візьмемо чотири токени по два числа — так усі числа влізуть на екран і їх можна перевірити олівцем. Матриці ваг візьмемо одиничні, тобто Q, K і V просто дорівнюють входу. Це законний окремий випадок формули, а не спрощення: справжні матриці лише повертають і розтягують ці вектори, а вся механіка нижче лишається та сама.

вхід X — чотири токени, кожен із двох чисел t1 = [ 2, 0 ] t2 = [ 0, 2 ] t3 = [ 2, 2 ] t4 = [ -2, 0 ]
крок 1 · три ролі

Q = K = V = X. Кожен токен виступає одночасно і як запит, і як ключ, і як значення. Саме тому операція зветься самоувагою (self-attention): токени дивляться самі на себе, а не на якийсь інший набір.

крок 2 · наскільки схожі

Множимо Q на K набік. Клітинка (i, j) — це скалярний добуток токена i на токен j: перемножили перші числа, перемножили другі, склали. Наприклад, t1·t3 = 2·2 + 0·2 = 4. Що більший добуток, то краще збіглись напрямки.

QKᵀ — сирі оцінки збігу t1 t2 t3 t4 t1 [ 4 0 4 -4 ] t2 [ 0 4 4 0 ] t3 [ 4 4 8 -4 ] t4 [ -4 0 -4 4 ]

Рядок t1 каже, наскільки перший токен збігається з кожним із чотирьох. Найкраще — із собою й із t3 (по 4), найгірше — із t4 (мінус 4: вони дивляться в протилежні боки).

крок 3 · ділення на корінь

Розмірність d = 2, отже √2 ≈ 1.414. Ділимо кожну клітинку на це число. Навіщо — цілий наступний розділ; поки просто зроби.

QKᵀ / √2 t1 t2 t3 t4 t1 [ 2.828 0.000 2.828 -2.828 ] t2 [ 0.000 2.828 2.828 0.000 ] t3 [ 2.828 2.828 5.657 -2.828 ] t4 [-2.828 0.000 -2.828 2.828 ]
крок 4 · softmax по рядках

Кожен рядок окремо перетворюємо на частки. Для рядка t1: підносимо e (число 2.718…) до степеня кожного елемента — виходить 16.92 · 1.00 · 16.92 · 0.059 — і ділимо кожне на їхню суму 34.90.

матриця уваги — кожен рядок у сумі дає рівно 1 t1 t2 t3 t4 сума t1 [ 0.485 0.029 0.485 0.002 ] 1.000 t2 [ 0.028 0.472 0.472 0.028 ] 1.000 t3 [ 0.053 0.053 0.894 0.000 ] 1.000 t4 [ 0.003 0.055 0.003 0.938 ] 1.000

Оце і є матриця уваги. Рядок t1 читається так: «збираючи свій новий опис, перший токен візьме 48.5 % від себе, 48.5 % від t3, 2.9 % від t2 і майже нічого від t4». Зверни увагу на рядок t4: він майже цілком складається з самого себе (93.8 %) — бо ні з ким не збігся.

крок 5 · зважена сума значень

Тепер множимо матрицю уваги на V. Кожен новий токен — це суміш усіх старих у щойно порахованих пропорціях. Для t1:

0.485·[2,0] + 0.029·[0,2] + 0.485·[2,2] + 0.002·[-2,0] = [0.970 + 0 + 0.970 − 0.003, 0 + 0.057 + 0.970 + 0] = [1.936, 1.027]
вихід уваги t1 = [ 1.936 1.027 ] було [ 2 0 ] t2 = [ 0.944 1.888 ] було [ 0 2 ] t3 = [ 1.894 1.894 ] було [ 2 2 ] t4 = [ -1.863 0.117 ] було [ -2 0 ]

В останній таблиці видно всю ідею. Токен t1 був [2, 0], а став [1.94, 1.03] — його підтягнуло до t3, з яким він збігся. Токен t4 не збігся ні з ким і майже не змінився. Ніхто нічого не вчив: усі ці числа вийшли з самого входу, за один прохід.

Що змінюють справжні матриці ваг. У робочій мережі Q = X·Wq, K = X·Wk, V = X·Wv, і три матриці різні. Це дозволяє шукати не подібність: токен «око» може мати запит, який збігається з ключем токена «око з іншого боку обличчя», хоч самі вектори не схожі. З одиничними матрицями увага вміє тільки «шукай схоже на себе» — саме тому їх і вчать.

Увага по кроках, усі числа на екрані

Той самий приклад: чотири токени по два числа. Тисни «крок» і проходь усі пʼять етапів формули. Повзунок рухає четвертий токен від −2 (як у тексті вище) до +2, де він стає копією першого. Дивись, що від цього робиться з першим рядком матриці уваги.

етап
Q = K = V = X
S = Q · K.T
S = S / sqrt(2)
A = softmax(S)
out = A · V
t1 бере від t4—
t1 бере від себе—
Матриці ваг одиничні, тому Q = K = V = X — той самий окремий випадок, що в тексті. При t4 = [−2, 0] числа на екрані збігаються з розібраними вище до третього знака. Обчислення живе, у подвійній точності.

А тепер те саме на справжніх даних: наша фігура 28×28, порізана на 49 патчів 4×4, і матриця уваги 49×49 — вона теж уміщається на екран.

Матриця уваги: хто в кого бере інформацію

Ліворуч — сітка 7×7 патчів фігури, праворуч — матриця уваги 49×49: рядок i показує, звідки бере інформацію патч i. Наведи мишу на рядок матриці або на патч ліворуч. Повзунок міняє дільник у формулі.

фігура
рядок під мишею—
максимум у рядку—
ентропія цього рядка—
середній максимум—
Токен = патч 4×4, розпрямлений у 16 чисел і нормалізований до нульового середнього й одиничного розкиду (те саме робить LayerNorm у справжній мережі). Q = K = V = сам патч, тобто матриці ваг одиничні й нічого не навчено. Ентропія рядка міряє, наскільки увага розмазана: 3.892 — рівномірно по всіх 49, нуль — увесь вміст узято з одного патча. Рівномірна вага для 49 патчів — 0.0204; «середній максимум» — найбільша вага в рядку, усереднена по всіх 49 рядках. √d тут дорівнює 4.

Навіть без жодного навчання видно головне: рядок патча, що лежить на фігурі, підсвічує інші патчі фігури — по всьому кадру, зокрема ті, що на протилежному боці. Ніякого вікна тут немає. Це та сама всеосяжність із розділу 02, тільки тепер її видно.

МасштабНавіщо ділити на корінь із d

У формулі стоїть / √d, і в кроці 3 ми його просто зробили. Тепер розберемось, звідки він, — бо це один із тих випадків, коли крихітна деталь вирішує, працюватиме навчання взагалі чи ні.

Беремо два випадкові вектори довжини d — кожне число незалежне, із середнім нуль і одиничним розкидом (саме так виглядають ваги на початку навчання). Скалярний добуток — це сума d поелементних добутків. Середнє такої суми нуль, а дисперсія — міра розкиду — дорівнює рівно d: розкид суми незалежних доданків дорівнює сумі їхніх розкидів, кожен дає одиницю, доданків d штук. Отже, типовий розмір добутку росте як √d: при d = 4 це приблизно 2, при d = 256 — приблизно 16.

А softmax підносить e до степеня кожного числа. Різниця у входах на 16 перетворюється на різницю у виходах у e16 ≈ 9 мільйонів разів: один елемент забирає майже всю вагу.

Це і поміряно. Девʼять тисяч вісімсот випадкових рядків по 49 елементів, чотири розмірності:

dдисперсія QKᵀмакс. вага без діленняз діленняментропія безз діленням
43.990.3000.1232.5993.442
1616.060.5990.1261.2843.427
6463.960.7980.1260.5553.427
256255.500.9030.1270.2493.425

Друга колонка підтверджує теорію до другого знака: дисперсія дорівнює d. Третя — головна: без ділення при d = 256 один елемент забирає 90 % ваги рядка з 49. Увага перестає бути зваженою сумою й вироджується у вибір одного. Четверта показує, що ділення тримає максимум коло 0.12–0.13 при будь-якій розмірності.

Ентропія в останніх колонках міряє «розмазаність» розподілу: 3.892 — ідеально рівномірно по 49 позиціях, нуль — уся вага в одному. Без ділення при d = 256 вона падає до 0.249.

І чому це вбиває навчання

Виродження не просто негарне — воно зупиняє навчання. Щоб градієнт пройшов крізь softmax, зміна входу має міняти вихід. Наскільки — показує сума p(1−p) по рядку: якщо всі частки коло нуля або коло одиниці, цей добуток теж коло нуля, і сигнал не проходить.

dсума p(1−p) без діленняз діленняму скільки разів гірше
40.8270.9481.1
160.5340.9491.8
640.2810.9503.4
2560.1380.9506.9

Кожне збільшення розмірності вчетверо приблизно вдвічі зменшує здатність softmax пропускати градієнт. З діленням на √d ця величина стоїть на 0.95 при будь-якій розмірності — рівно тому, що дисперсія після ділення завжди одиниця. У цьому й уся ідея: ділення робить масштаб оцінок незалежним від розмірності.

Не переплутай із температурою. √d — не гіперпараметр, який добирають, а поправка на відомий заздалегідь ефект розмірності. Менший дільник дає ті самі проблеми, що й одиниця; значно більший розмазує увагу в рівномірне середнє. Обидва краї видно в інтерактиві 3 вище.

Що робить ділення на корінь

Дві криві: як росте типовий максимум у рядку softmax зі зростанням розмірності — без ділення й із діленням на √d. Числа рахуються тут-таки, у браузері, на випадкових векторах. Тягни повзунок розмірності й дивись, коли увага перестає бути сумою.

що показати
дисперсія без—
дисперсія з—
макс. вага без—
макс. вага з—
Рядок із 49 елементів, 60 випадкових рядків на кожну розмірність, генератор детермінований — числа однакові в усіх читачів. Рядків тут менше, ніж у таблиці вище (там 9 800), тому третій знак трохи інший — це та сама величина, заміряна на меншій вибірці. Рівномірна вага для 49 елементів — 0.0204.

ГоловиКілька голів

У розібраній формулі є мовчазне обмеження. Матриця уваги одна на всі числа опису. Якщо токен вирішив узяти 48 % від сусіда, то він бере 48 % від усіх тридцяти двох чисел цього сусіда. Взяти колір звідси, а форму звідти не можна: пропорція одна на весь вектор.

Ліки прості: поріж опис на шматки й порахуй увагу в кожному окремо. Було 32 числа й одна матриця уваги — стало чотири шматки по 8 чисел і чотири незалежні матриці. Кожен шматок називають головою (head), а конструкцію — багатоголовою увагою (multi-head attention). Результати склеюють назад у 32 числа й проганяють через одну вихідну матрицю.

Тепер найцікавіше — скільки це коштує. Порахуємо параметри руками. Матриць чотири: три вхідні (Wq, Wk, Wv) і одна вихідна, кожна розміром d×d, і в кожної є зсув на d чисел:

параметрів = 4·d·d + 4·d

Підставляємо d = 32: 4·1024 + 128 = 4224. А тепер той самий рахунок для восьми голів. Кожна голова має свої матриці розміром d×(d/8)… але їх вісім, і 8 · d · (d/8) = d·d. Те саме число. Заміряно на nn.MultiheadAttention:

dголіврозмір головиручний рахунокsum(p.numel())
321324 2244 224
32484 2244 224
32844 2244 224
76817682 362 3682 362 368
76812642 362 3682 362 368

Це й є відповідь на питання «чи не те саме одна велика голова?». Ні, і не тому, що параметрів більше — їх рівно стільки ж. Різниця в операції: одна голова рахує одну зважену суму, вісім голів — вісім різних. За ті самі ваги отримуємо вісім незалежних поглядів замість одного.

Це видно навіть на випадкових вагах. При чотирьох головах і розмірності 32 кожен токен має в середньому 3.94 різних цілі з чотирьох можливих, а взаємна кореляція матриць уваги — −0.012, тобто фактично нуль. Голови незалежні за побудовою, ще до навчання. (В інтерактиві 5 нижче та сама величина виходить меншою — 3.49 з 4, — бо там опис патча вдвічі коротший, 16 чисел замість 32, і на голову лишається по чотири. Це не суперечність, а той самий ефект, з якого починається наступна врізка.)

Межа, яку легко проґавити. Ділити можна не нескінченно. При 16 головах на 32 числа кожна голова отримує два числа, і скалярний добуток двовимірних векторів уже майже нічого не розрізняє: там просто мало інформації. Заміряно на тому самому наборі — при 16 головах кількість різних цілей перестає рости пропорційно (12.29 замість 16), бо голови починають випадково збігатися. У справжніх мережах розмір голови тримають коло 64 — це не традиція, а той розмір, при якому скалярний добуток ще щось означає.

Кілька голів дивляться в різні місця

Один обраний патч (тягни повзунок) і те, куди він дивиться кожною зі своїх голів. Перемикай кількість голів і стеж за лічильником параметрів: він не міняється.

голів
розмір голови—
параметрів—
різних цілей у середньому—
матриць уваги—
Опис патча — 16 чисел, поділених між головами порівну. Хрестик — куди дивиться голова найсильніше. Параметри рахуються за формулою 4d² + 4d для d = 16, тобто 1 088 при будь-якій кількості голів.

ПорядокУвага не бачить порядку

Тепер головне відкриття теми. Воно доводиться в три рядки, без навчання, і з нього випливає все, що буде далі.

Подивись іще раз на формулу. Де в ній сказано, що токен №1 стоїть перед токеном №2? Ніде. Скалярний добуток не знає, звідки взялися вектори; softmax працює по рядку; значення підсумовуються — а сума не залежить від порядку додавання.

Звідси випливає точне твердження. Переставмо токени на вході в будь-якому порядку. Тоді вихід переставиться рівно так само, і більше не зміниться нічого. Ця властивість зветься еквіваріантністю щодо перестановки (permutation equivariance).

Еквіваріантність, а не інваріантність. Слова схожі, означають різне, і плутають їх постійно. Інваріантність — вихід не змінюється взагалі: перемішав вхід і дістав той самий результат. Еквіваріантність — вихід змінюється так само, як вхід: перемішав вхід — вихід перемішався тим самим чином. Увага еквіваріантна. Але щойно поверх неї поставити усереднення по всіх токенах (а саме так роблять перед класифікатором), еквіваріантність перетворюється на інваріантність — і модель стає повністю сліпою до розташування.

Перевіримо. Беремо 49 токенів нашої фігури, беремо nn.MultiheadAttention зі щойно створеними випадковими вагами й рахуємо два числа: вихід від перемішаного входу і перемішаний вихід від нормального входу. Якщо твердження правильне, вони мають збігтися.

операціянайбільша різницящо це означає
увага без позиційного1.8·10⁻⁷нуль із точністю float32
увага з позиційним0.135порядок тепер видно
згортка Conv1d(3)1.700порядок було видно завжди

Перший рядок — і є доказ. 1.8·10⁻⁷ — не «мала різниця», а арифметичний шум float32 при виході масштабу 0.82: відносна похибка дві десятимільйонні. Увага не «майже не помічає» перестановку — вона не помічає її взагалі.

Третій рядок для контрасту: та сама перевірка на згортці дає 1.700 — величину порядку самого сигналу. Згортка ловить перестановку негайно.

Чому це руйнує класифікацію

Ось наслідок, який робить абстракцію відчутною. Візьмемо два зображення: маленька фігура у верхньому лівому куті та вона ж у нижньому правому. Друге отримано з першого чистою перестановкою патчів — жоден піксель не змінився, змінилися лише їхні місця. Пропускаємо обидва через увагу, усереднюємо 49 виходів і подаємо в лінійний класифікатор:

без позиційного кодування6·10⁻⁸найбільша різниця логітів — тобто нуль. Модель фізично не може розрізнити ці дві картинки
з позиційним кодуванням4.3·10⁻²різниця зʼявилась. Тепер є що вчити

Це не результат навчання й не питання кількості даних. Мережа без позиційного кодування ніколи не навчиться відрізняти «фігура вгорі» від «фігура внизу», скільки їй прикладів не показуй. Вихід у неї буквально той самий.

Перестановка: головна демонстрація теми

Зліва — фігура, порізана на 49 патчів. Тисни «перемішати» і дивись на число внизу: наскільки вихід перемішаного відрізняється від перемішаного виходу. Перемкни позиційне кодування — і число ожине.

позиційне кодування
вихід(перемішаного) − перемішаний(виходу)—
та сама перевірка на згортці—
масштаб самого виходу—
Обчислення живе в браузері, у подвійній точності — тому «нуль» тут навіть менший, ніж заміряний у torch (там float32 і 1.8·10⁻⁷). Згортка по токенах — фіксоване ядро з трьох чисел.

ГеометріяПозиційне кодування

Раз увага не знає порядку, порядок треба їй сказати. Спосіб, який виявився робочим, дивовижно грубий: до кожного токена просто додають вектор, який залежить від його номера. Не множать, не приклеюють збоку — додають, число до числа.

токенi ← токенi + позиціяi

Тобто якщо токен описується 32 числами, то вектор позиції теж має 32 числа, і вони додаються поелементно. Після цього два патчі з однаковим вмістом, але з різних місць кадру, стають різними векторами — і скалярний добуток нарешті може їх розрізнити.

Додавання спочатку виглядає підозріло: ми ж псуємо вміст! Відповідь така: розмірність 32 (а в справжніх мережах 768) — це багато місця. Мережа може відвести частину напрямків під «що це» і частину під «де це» й навчитися читати їх окремо. Ніхто їй цього не наказує — вона просто має таку можливість.

Два способи взяти вектор позиції

навчуванесинусоїдальне
Що цетаблиця «номер → вектор», ініціалізована випадково й навчена разом з усімвектор, порахований формулою з синусів і косинусів різної частоти
Параметрівкількість позицій × dнуль
Нові довжинине працює: для позиції 200 рядка немаєпрацює: формула визначена для будь-якого номера
Де вживаютьViT і майже всі трансформери зорупочатковий Transformer, частина мовних моделей

Синусоїдальний варіант виглядає елегантніше, але в зорі переміг навчуваний: кількість патчів фіксована розміром входу, розтягуватись нікуди не треба. Скільки за нього платять — порахуємо на справжній моделі. Беремо vit_b_16 із torchvision, збираємо з weights=None (нічого не завантажується) і рахуємо:

усього ваг у ViT-B/1686 567 656повна модель, зібрана офлайн
позиційне кодування151 296197 позицій × 768 чисел = 0.175 % моделі

Сто пʼятдесят одна тисяча ваг із вісімдесяти шести мільйонів. Дві тисячні частки моделі. І це вся геометрія, яку модель має — усе, що вона знає про те, що ліворуч, а що праворуч, сидить у цих 0.175 %. Порівняй зі згорткою, де геометрія роздана безкоштовно в кожному з мільйонів ядерних чисел.

Чи потрібне позиційне кодування завжди? Правило просте й випливає з розділу 07: воно допомагає рівно тоді, коли положення має значення. Якщо клас предмета не залежить від того, де предмет лежить у кадрі, кодування додає ваги, які нема чому вчити, — і на малих даних це може навіть заважати. Але щойно задача починає залежати від розташування — «фігура вгорі проти фігури внизу» з попереднього розділу — без кодування модель не працює взагалі, а не «гірше».

ЦінаЦіна квадратична

Тепер рахунок, який визначає все проєктування трансформерів зору. Матриця уваги має розмір «токенів × токенів». При n токенах у ній n² клітинок, і кожну треба порахувати. Подвоїв кількість токенів — учетверо збільшив роботу.

Для кадру 28×28 усе залежить від одного числа — розміру патча:

патчтокенівпар увагимножень у матрицімножень у проєкціях
14×144161 02416 384
7×71625616 38465 536
4×4492 401153 664200 704
2×219638 4162 458 624802 816

Розмір патча зменшився в сім разів — з 14 до 2, — а кількість пар зросла з 16 до 38 416, тобто в 2 401 раз. Ось за що платять дрібними патчами.

Дві останні колонки варто прочитати окремо, бо в них є перелом. «Множення в проєкціях» — вартість трьох матриць Q, K, V і однієї вихідної; вона росте лінійно за кількістю токенів. «Множення в матриці» ростуть квадратично. При 4 токенах проєкції коштують у 16 разів більше, а при 196 токенах — уже втричі менше. Точка рівноваги:

2·n²·d = 4·n·d² ⟹ n = 2·d

Тобто при розмірності 32 матриця уваги стає дорожчою за проєкції, коли токенів більше 64. До цієї межі квадратичність нікого не турбує; після неї вона починає визначати все.

Час на реальній машині це підтверджує — і показує, де саме починається квадратичний режим. Прямий прохід nn.MultiheadAttention, розмірність 64, один потік CPU:

токенівпарчас, мсчас × від 49пар × від 49
492 4010.1211.01
19638 4160.5224.316
784614 6565.93048.9256
1 5682 458 62441.592342.81 024
3 1369 834 496195.7761 613.74 096

Абсолютні мілісекунди в тебе будуть інші — вони залежать від того, чим ще зайнята машина. Стале тут співвідношення, і воно каже ось що. На малих числах час росте повільніше за кількість пар: від 49 до 196 токенів пар стало в 16 разів більше, а часу — лише в 4.3. Квадратичність не зникла: на таких розмірах помітну частку зʼїдають накладні витрати виклику, а не множення. Зате від 784 токенів іде чистий квадратичний режим — подвоєння токенів учетверо збільшує кількість пар і в пʼять-сім разів час. На 3 136 токенах один прохід уваги займає вже пʼяту частину секунди.

Куди це веде. ViT-B/16 ділить кадр 224×224 на патчі 16×16 і отримує 196 токенів (плюс один службовий, звідси 197 у розділі 08). Зменшити патч до 8×8 — і токенів стане 784, а пар уваги вчетверо більше. Саме тому 16 стало стандартом: це компроміс, а не природна константа. Обійти квадратичність, не збільшуючи патч, — окрема інженерна задача, і їй присвячена тема 21.

Ціна: розмір патча як головна ручка

Два повзунки: розмір патча (він задає кількість токенів) і робоча розмірність. Стовпчики показують, куди йдуть множення — у матрицю уваги чи в проєкції. Знайди положення, де вони міняються місцями.

токенів—
пар уваги—
множень: матриця—
множень: проєкції—
Кадр 28×28. Множень у матриці — 2·n²·d (оцінки збігу плюс зважена сума значень), у проєкціях — 4·n·d². Порівнюються самі множення, без накладних витрат: саме тому таблиця часу вище на малих розмірах виглядає інакше.

ПорівнянняУвага проти згортки: чесне порівняння

Тепер можна покласти дві операції поруч. Головне питання не «яка краща», а що кожна дає задарма, а що доводиться вчити.

згорткаувага
Локальністьзадарма: вікно 3×3 вбудованетреба вивчити з даних, якщо вона потрібна
Далекий звʼязоктреба будувати: 13 шарів на кадр 28×28задарма з першого шару
Порядок і геометріязадарма: закладений у форму операціїтреба додати окремо, коштує 0.175 % ваг
Спільні ваги по кадрузадарма: те саме ядро скрізьзадарма: ті самі матриці для всіх токенів
Ваги залежать від входуні: ядро те саме для всіх зображеньтак: матриця уваги рахується заново щоразу
Ціна від розміру входулінійнаквадратична за кількістю токенів

Перший і третій рядки — це і є відповідь на питання, чому трансформерам потрібно більше даних. Згортка приходить із двома готовими правилами про світ: «важливе поруч» і «ось де ліворуч». Ці правила не безкоштовні в іншому сенсі — вони обмежують, — але вони правильні для зображень, і мережа отримує їх задарма, ще до першого прикладу.

Увага не приходить ні з чим. Вона починає з чистого аркуша, на якому всі позиції рівноправні, і мусить вивести локальність із даних — тобто самотужки дійти до того, що сусідні патчі корисніші за далекі. Це можливо, але за це платять прикладами: правило, яке згортці подарували, трансформер має відкрити. Наскільки більше прикладів для цього треба й що буває, коли їх бракує, — із заміряними числами в темі 20.

Останній рядок таблиці — «ваги залежать від входу» — те, чого згортка не вміє взагалі. Ядро після навчання застигає: воно однакове для котика й для креслення. Матриця уваги перераховується для кожного зображення окремо, і в цьому її сила, яку ніяким збільшенням глибини не заміниш.

ІсторіяУвага не нова для зору

Легко подумати, що увага прийшла в зір із трансформерів у 2020 році. Насправді вона працювала всередині згорткових мереж на кілька років раніше — просто скромніше й під іншими назвами.

SE-блок (squeeze-and-excitation, 2017) — найпростіший із них. Після згорткового шару він стискає кожну карту ознак в одне число, проганяє їх через крихітну мережу й отримує по коефіцієнту на канал, на який цю карту множить. Це увага по каналах: мережа вирішує, які ознаки зараз важливі, і робить це залежно від конкретного зображення. Той самий SE-блок стоїть усередині EfficientNet і MobileNet-v3 із теми 15 — ти вже з ним працював, просто ми не називали це увагою.

Non-local блок (2018) — уже майже те, що ми розібрали: повна матриця «кожна позиція з кожною» всередині згорткової мережі. Її ставили одним-двома блоками в глибині, де карта ознак уже маленька й квадратична ціна терпима.

Тобто ідея визріла всередині згорткового світу як доповнення. Питання, яке поставив 2020 рік, було іншим і значно різкішим: а якщо згортки прибрати зовсім? Відповідь — наступна тема.

ПідсумокПідсумок і що далі

Операцію розібрано до останнього символу. Що варто винести:

  1. Увага — зважена сума всіх позицій, де ваги рахуються з самих даних. Запит, ключ і значення — три описи того самого токена. Вчаться матриці, якими їх отримують; самі ваги уваги не вчаться ніколи.
  2. Ділення на √d — не гіперпараметр. Дисперсія скалярних добутків дорівнює d, і без поправки softmax при d = 256 віддає 90 % ваги одному елементу, а здатність пропускати градієнт падає всемеро.
  3. Кілька голів нічого не коштують у параметрах — 4d² + 4d при будь-якій їх кількості. Вони дають не більше ваг, а більше різних зважених сум за ті самі ваги.
  4. Увага еквіваріантна щодо перестановки. Це не властивість навченої моделі, а наслідок форми формули: 1.8·10⁻⁷ проти 1.700 у згортки. Із цього випливає, що геометрію треба додавати окремо.
  5. Позиційне кодування — уся геометрія моделі, і коштує вона 0.175 % ваг ViT-B/16.
  6. Ціна квадратична за кількістю токенів. Патч 2×2 на кадрі 28×28 дає 38 416 пар замість 16. Розмір патча — головна ручка вартості.

І головне про метод. Усі шість пунктів вище перевіряються без жодного навчання — випадковими вагами, за секунди. Це рідкість: більшість тверджень про мережі доводиться перевіряти прогонами, розкидом від зерна й трьома повтореннями, як у темі 18. Якщо твердження про архітектуру можна перевірити алгеброю — перевіряй алгеброю; це дешевше й надійніше за будь-який експеримент.

Останнє перед наступною темою: матриця уваги на ненавчених вагах майже рівномірна. Заміряно на нашій фігурі з випадковими матрицями Q, K, V — такими, які стоять у щойно створеному nn.MultiheadAttention: ентропія рядка 3.863 із максимальних 3.892, тобто 99.3 % від ідеально рівномірного розподілу, а найбільша вага 0.034 проти рівномірних 0.020. Красиві карти уваги зі статей — результат навчання, а не властивість операції.

Не сплутай це з інтерактивом 3: там матриці ваг одиничні, тобто патчі порівнюються самі з собою напряму, і розподіл виходить помітно гострішим: на кільці при дільнику 4.00 ентропія рядка № 10 — 2.718, а найбільша вага в рядку, усереднена по всіх 49 рядках, — 0.3700. Випадкова матриця перемішує вміст патча й тим згладжує збіги; одинична лишає їх як є. Конфігурація тут важить не менше за саму операцію, тож числа двох замірів порівнювати між собою не можна.

Місток до теми 20

Наступний крок очевидний: зібрати з операції цілу мережу — порізати зображення на патчі, додати позиційне кодування, покласти дюжину шарів уваги поспіль. Саме це зробили автори Vision Transformer, і саме це розбирає тема 20.

А вийде там несподіване. Мережа справді працює — але на наших даних програє згортковій, яка в рази менша, і розрив із кількістю прикладів не зменшується, а росте. Чому так — там, із числами.