English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

гість
1 / ?
назад до уроків

Запит, Ключ, Значення

Три лінійні відображення з одного й того ж входу

Після вбудовування (активність 4) кожна позиція несе 768-вимірний вектор x_t. Увага починається з створення трьох різних проєкцій x:


Q (запит): що ця позиція хоче знати?


K (ключ): що ця позиція пропонує іншим позиціям?


V (значення): який контент ця позиція надає, якщо на неї звертається увага?


Кожна проєкція походить з матриці вивчених ваг:


Q = x · W_Q     # Форма W_Q: (d_model, d_k)
K = x · W_K     # Форма W_K: (d_model, d_k)
V = x · W_V     # Форма W_V: (d_model, d_k)

Три матриці, всі навчаються через зворотне поширення. Модель навчається: у цій позиції, який запит найкраще витягує корисний минулий контекст? Який ключ добре рекламує вміст цієї позиції? Яке значення передається, якщо вибрано?


Масштабована увага на основі скалярного добутку


Аналогія з бібліотечним каталогом

Уявіть каталог карток бібліотеки. Ви заходите з темою на думці (ваш запит). Кожна картка містить ключові слова (ключ). Коли ваша тема збігається з ключовими словами картки, ви берете зміст книги (значення). Attention виконує це для кожного токена паралельно: кожна позиція запитує кожну іншу позицію, ранжує узгодженість та витягує зважену комбінацію векторів значень.


Розміри ANDREA-120M


КількістьЗначенняПримітки
d_model768Розмір вектора на кожній позиції
n_head12Паралельні увагові головки
d_k64Розмірність на головку (= d_model / n_head)
T1024Довжина контексту

d_k = d_model / n_head = 768 / 12 = 64. Кожна головка бачить 64-вимірний зріз повного 768-вимірного простору. Активність 6 (grow_a_language_model_multi_head) детально розглядає розподіл на головки.

Обчисліть d_k

Обчисліть d_k для двох варіантів ANDREA. (a) ANDREA-12M: d_model = 384, n_head = 12. (b) ANDREA-480M: d_model = 1536, n_head = 24. Покажіть формулу d_k = d_model / n_head для кожного.

Чому ділити на sqrt(d_k)

Матриця оцінок

Як тільки Q та K існують (кожна форма (T, d_k)), увага обчислює матрицю оцінок:


scores = Q · K^T     # shape: (T, T)

scores[i, j] = наскільки сильно запит позиції i узгоджується з ключем позиції j. Кожна пара (i, j) отримує один бал: 1024 × 1024 = 1,048,576 балів на голову уваги на один прохід вперед.


Чому ділити

Скалярні добутки двох випадкових одиничних векторів розмірності d мають величину порядку sqrt(d). Без масштабування бали зростають з d_k:


- d_k = 64: типові скалярні добутки порядку 8.

- d_k = 256: типові скалярні добутки порядку 16.

- d_k = 4096: типові скалярні добутки порядку 64.


Великі значення призводять до пікового softmax (одна позиція домінує, градієнти зникають деінде). Навчання зупиняється. Масштабування виправляє величину:


scaled_scores = (Q · K^T) / sqrt(d_k)

Для ANDREA-120M, sqrt(d_k) = sqrt(64) = 8. Кожен бал ділиться на 8. Величини залишаються приблизно на одиничному масштабі незалежно від d_k. Softmax залишається добре поведеним. Градієнти течуть.


Оригінальне обґрунтування Васвани

З Attention Is All You Need (2017): 'Для великих значень d_k скалярні добутки зростають у величині, штовхаючи функцію softmax у регіони, де у неї надзвичайно малі градієнти.' Дільник sqrt(d_k) протидіє цьому зростанню.


Вигляд коду

Усередині microgpt_cuda.cu це масштабування з'являється як буквальний поділ:


scores[i][j] = dot(Q[i], K[j]) * (1.0f / sqrtf(d_k));

Одне множення на float для кожного score. Дешево. Критично.

Масштабування при d_model = 4096

Припустімо, дослідницька команда створює ANDREA-2B з d_model = 4096 та n_head = 32. (a) Обчисліть d_k. (b) Обчисліть sqrt(d_k). (c) Поясніть в одному реченні, що станеться, якщо команда забуде розділити на sqrt(d_k) при цьому масштабі.

Чому позиція i не може бачити позицію j > i

Обмеження, народжене з генерації

ANDREA генерує один токен за раз. Під час інференсу позиція 0 виробляє перший токен, потім позиція 1 бачить вихід позиції 0 та виробляє другий токен, і так далі. Модель ніколи не має доступу до майбутніх токенів під час генерації.


Навчання повинно відображати це. Якщо під час навчання позиція 5 могла б звертати увагу на позицію 6, модель вивчила б обхідний шлях: 'передбачити токен 6, читаючи токен 6'. Під час інференсу цей обхідний шлях зникає (токен 6 ще не існує). Поведінка моделі під час навчання та інференсу розійшлася б катастрофічно.


Маска

Казуальна маска блокує увагу з будь-якої позиції i до будь-якої позиції j > i. Реалізація: встановити scaled_scores[i][j] = -infinity всюди, де j > i. Після softmax ці елементи стають exp(-inf) = 0. Маска чисто обнуляє увагу до майбутніх позицій.


for i in range(T):
for j in range(T):
if j > i:
scaled_scores[i][j] = -1e9   # фактично -inf

Після softmax (по рядках), кожен рядок сумується до 1, але тільки елементи [0, i] несуть масу ймовірності. Позиція i змішує інформацію тільки з минулих позицій.


Візуалізація маски

Матриця оцінок форми (T, T) з застосованою маскою має вигляд нижньотрикутної структури:


scaled_scores після маски, softmax по рядках:

рядок 0:  [1.0, 0,   0,   0,   ...]   # бачить лише себе
рядок 1:  [0.4, 0.6, 0,   0,   ...]   # бачить позиції 0, 1
рядок 2:  [0.2, 0.3, 0.5, 0,   ...]   # бачить 0, 1, 2
рядок 3:  [0.1, 0.2, 0.3, 0.4, ...]   # бачить 0, 1, 2, 3
...

Строга нижньотрикутна ймовірнісна дистрибуція на рядок. Майбутнє залишається невидимим.


Чому Transformer тільки з декодером потребує цього

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

Маска та Смак

Активність 2 (вступ) охопила три смаки трансформерів: лише енкодер, енкодер-декодер, лише декодер. (a) Який смак використовує каузальну маску? (b) Скажіть в одному реченні, чому інший смак (лише енкодер, як BERT) НЕ використовував би каузальну маску. (c) На яку мету тренується немаскаваний енкодер замість цього?

Від Очків до Виводу

Softmax: Від оцінки до ймовірностей

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


A[i][j] = exp(scaled_scores[i][j]) / sum_k exp(scaled_scores[i][k])

Виникають три властивості:


- A[i][j] >= 0 для всіх (i, j).

- sum_j A[i][j] = 1 для кожного рядка i.

- Більші сирі бали виробляють більші ймовірності (монотонно).


Вектор ймовірностей рядка i каже моделі: наскільки позиція i повинна звертати увагу на кожну попередню позицію при обчисленні свого виходу?


Зважена сума V

Остаточний вихід уваги для позиції i:


output[i] = sum_j A[i][j] · V[j]

Кожен вектор значень V[j] важиться з ймовірністю уваги A[i][j], а потім підсумовується. Вихід позиції i комбінує вектори значень з кожної попередньої позиції, важені за релевантністю.


У матричній формі, усі позиції одночасно:


Attention(Q, K, V) = softmax(mask(Q · K^T / sqrt(d_k))) · V

Один рядок. Цілий механізм уваги. Vaswani et al. написали цей рядок у 2017 році; трансформери фундаментально не змінилися з того часу.


Форма виходу на голову

Вихід однієї увагової голови: форма (T, d_k). Для ANDREA-120M: (1024, 64). Усі 12 голів обчислюються паралельно; їхні виходи конкатенуються до (1024, 768) та подаються на фінальну лінійну проєкцію (W_O), а потім до MLP блоку трансформера.


Активність 6 (grow_a_language_model_multi_head) охоплює розподіл на багатоклавову увагу. Активність 7 (grow_a_language_model_transformer_block) охоплює все, що оточує увагу: залишкові з’єднання, нормалізацію шарів, MLP.

Синтезуйте конвеєр

Синтезуйте повний конвеєр уваги своїми словами. Пройдіться по тому, що відбувається з однією позицією i (наприклад, позиція 5 у послідовності) від вхідного вектора x_5 до attention output[5]. Назвіть чотири операції по порядку: (1) проєкція до Q/K/V, (2) обчислення масштабних оцінок проти всіх позицій, (3) застосування причинної маски + softmax, (4) зважена сума векторів V з ймовірностями. Один короткий абзац.