Модуль 2. Трансформер без магии: attention и предсказание следующего токена

Цель модуля: понять механику трансформера на уровне, достаточном для инженерных решений: что делают attention-слои, откуда берутся «7B параметров», почему модель обучена «предсказывать следующий токен» и почему из этого выросло всё — от переводчика до собеседника. Без матриц большой размерности и без единой формулы производной.

Перед началом: модуль 1 (токены, эмбеддинги). Инструменты: песочница сайта, сниппет toy-attention. Трудоёмкость: ~1.5 ч (чтение 50 мин · сниппет и практика 40 мин).

🔥 Одно слово — два смысла

«Ключ лежит у серверной, спроси у дежурного» и «ключ лежит в переменной API_KEY, не коммитьте его» — для человека очевидно, что «ключ» тут две разные сущности. Эмбеддинг из модуля 1 у слова «ключ» один и тот же. Но модель никогда не путает эти фразы. Значит, между статичным эмбеддингом и ответом что-то делает вектор контекстным — учитывает соседей.

Это «что-то» — attention. За модуль мы соберём его из трёх операций (пара скалярных произведений, softmax, взвешенная сумма) и закроем последний слой магии: после этого «трансформер из 32 слоёв и 40 голов» перестанет звучать заклинанием, а фраза «дообучение меняет веса» обретёт конкретный смысл — весов вот столько, и вот какие из них трогает LoRA.

📖 2.1. Проблема: у порядка и контекста нет места в «мешке слов»

Первые языковые модели представляли текст вектором-«мешком»: просуммировали эмбеддинги слов — получили текст. «Собака укусила человека» и «человек укусил собаку» для такого мешка одинаковы. Нужен механизм, который строит представление каждого токена с учётом его соседей — и при этом работает с последовательностями длиной в тысячи токенов.

Ответ 2017 года — статья «Attention Is All You Need» и архитектура трансформер: представление каждого токена пересобирается как взвешенная смесь представлений других токенов, и веса этой смеси модель вычисляет сама по ходу дела.

📖 2.2. Одна attention-голова: запрос, ключ, значение

У каждого токена три вектора, получающихся из его эмбеддинга умножением на три матрицы весов (свои в каждом слое):

  • q (query, запрос) — «что я ищу в контексте?»;
  • k (key, ключ) — «что я могу предложить другим?»;
  • v (value, значение) — «что я передам, если на меня обратили внимание».

Шаг для одного токена: скалярное произведение его q с k каждого соседа — это баллы релевантности; баллы через softmax превращаются в веса, в сумме дающие 1; итог — взвешенная сумма v соседей. Это и есть новое, контекстное представление токена.

Аналогия из разработки: q — поисковый запрос, k — заголовки страниц в поисковой выдаче, баллы q·k — релевантность, v — содержимое страниц, а новый вектор токена — «выжимка» выдачи. Никакой рекуррентности: все токены обрабатываются одной большой матричной операцией, отсюда и обучаемость на тысячах GPU параллельно.

Одна attention-голова: q токена ищет по k соседей, из их v собирается контекстный вектор

Разбор диаграммы. Эмбеддинги токенов (модуль 1) идут в три обучаемые проекции — матрицы Wq, Wk, Wv, свои в каждом слое. Слева направо видно весь конвейер одной головы: q слова «ключ» умножается на k каждого соседа (замок, шифрование, поворачивают) — получаются баллы релевантности; softmax превращает баллы в веса, сумму которых диаграмма фиксирует как «= 1»; и уже этими весами взвешивается v соседей в один-единственный контекстный вектор. Пунктирная стрелка — судьба этого вектора: он уходит в следующий слой, и так 32 раза, пока выход верхнего слоя не станет «посылом» всей фразы. Запомните тройку Wq/Wk/Wv — в модуле 6 «target modules» LoRA-адаптера — это ровно эти матрицы.

Запустите сниппет toy-attention.py. В нём слово «ключ» с амбивалентным запросом стоит в двух контекстах — «замок поворачивают» и «шифрование взламывают». Посмотрите, как веса (softmax от баллов) распределяются по соседям и как новое представление «ключа» из физического объекта становится цифровой сущностью. Вы только что своими глазами увидели суть полисемии-в-LLM.

📖 2.3. Маска, головы, слои, параметры

Causal mask. Модель предсказывает следующий токен, поэтому при подсчёте attention токен видит только предыдущие: будущего в контексте нет. Это не оптимизация, а сама постановка задачи.

Несколько голов. Одна голова ловит одну зависимость («ключ ищет замок»), поэтому в слое их десятки: одна следит за синтаксисом, другая за «кто субъект», третья за позициями-числами. Их выходы склеиваются и снова перемножаются — детали не важны, важно, что «40 голов» = 40 параллельных взглядов на каждый токен.

Стек слоёв. Слой трансформера = attention + небольшая полносвязная сеть («FFN»), и таких слоёв десятки. Низкие слои цепляют морфологию и синтаксис, средние — смысловые отношения, высокие — задачу и стиль. Предложение проходит все слои, и на выходе верхнего вектор последнего токена «насыщен» всей фразой.

Что такое «7B параметров». Вот эти самые матрицы: эмбеддинг-таблица (модуль 1), по три матрицы q/k/v на каждую голову каждого слоя, матрицы FFN (их больше всего), и т.д. — миллиарды чисел. Всё, что делает модель, — пропускает токены через эти числа. «Дообучение» = сдвинуть часть чисел. «7B» на этикетке = сколько чисел. Это знание — фундамент модуля 6: LoRA меняет не всё, а малую добавку к этим матрицам.

📖 2.4. Предобучение: «предскажи следующий токен» × триллион раз

Как из перемножения матриц вырос собеседник? Обучение LLM — гигантский цикл:

  1. Взять текст (интернет, книги, код, — триллионы токенов).
  2. Для каждой позиции дать модели задание: по всем предыдущим токенам предсказать следующий.
  3. Сравнить предсказание с фактом, посчитать ошибку (loss), чуть-чуть сдвинуть ВСЕ параметры против ошибки (градиентный спуск — механику без формул разберём в модуле 7).
  4. Повторить триллионы раз.

Поразительно, что для способности «предсказывать следующий токен» модель вынуждена выучить грамматику, факты, стиль, логику и код: нельзя хорошо продолжить текст, не поняв его. А «понимание» возникает как побочный эффект масштаба — данных и параметров. Эти способности называют эмерджентными: модели меньшего масштаба их не демонстрировали.

Но у base-модели после предобучения одна роль — продолжатель текста. Спросите «Как вернуть деньги за курс?» — и она может продолжить «…в соответствии с пунктом 4.2 договора» (стиль похож на FAQ) или вообще «…спрашивают тысячи пользователей». Собеседником её делает дообучение на диалогах (instruction tuning — так делали авторы модели) — то же «предскажи следующий токен», но на аккуратно собранных парах «инструкция → ответ». Ваш собственный такой цикл — модули 5 и 10: вы повторяете последний шаг индустрии на своей задаче.

📖 2.5. Компромиссы

  • Длина контекста vs цена. Каждый токен attends к каждому: память и счёт растут квадратично по длине. 128k контекст существует ценой ухищрений — и всё равно «длинный контекст» дороже короткого на каждом запросе.
  • Больше голов vs шире головы. Фиксированный бюджет параметров можно потратить на много узких голов или мало широких: узкие ловят разные зависимости, широкие — сложные. Индустрия сходится к «много средних».
  • Масштаб предобучения vs специализация. Универсальная base-модель дороже, но дообучается под что угодно; учить «с нуля» под задачу — только для больших команд и узких доменов.
  • Прозрачность vs производительность. Attention-веса можно вывести и изучать (interpretability), но полного «почту модель ответила так» они не дают — принимать инженерные решения (evals, метрики) надёжнее, чем «объяснения» модели.

💻 Практика

  1. Сниппет (15 мин). Запустите toy-attention.py. Найдите в выводе пару (score, вес) для «шифрования» в первом контексте — соседа там нет, но посмотрите, как изменились бы веса, добавь мы его: допишите его в список контекста и перезапустите.
  2. Своё слово (15 мин). Добавьте в KV-словарь слова «дескриптор» и «шифруется» с векторами по вашему разумению. Сделайте так, чтобы «ключ» в новом контексте остался «цифровым» даже с «замком» в соседях — и объясните, почему получилось.
  3. Softmax руками (10 мин). Посчитайте на бумаге softmax для баллов [2.0, 1.0, 0.1]. Сравните с тем, что даёт сниппет. Объясните, почему softmax, а не просто «взять максимум» (подсказка: вспомните градиенты и «обучаемость» — модулю 7 это ещё пригодится).
  4. Архитектурный скетч (10 мин). Возьмите описание любой открытой модели с Hugging Face (например Qwen: «32 слоя, 32 головы, скрытая размерность 4096»). Нарисуйте на бумаге один слой: attention (32 головы q/k/v) + FFN. Подпишите, где из этого берётся «7B параметров».

🧩 Quiz "Проверь себя"

1. Что делает causal mask?
2. Почему base-модель после предобучения — «продолжатель текста», а не собеседник?
3. «7B параметров» — это…
4. Зачем модели три вектора q, k, v на каждый токен?
5. Откуда у больших моделей способности, которых нет у маленьких?

✅ Итоги модуля

  • Объяснить q/k/v-механику через аналогию с поисковой выдачей.
  • Показать на сниппете, как контекст меняет представление слова.
  • Назвать, из каких матриц складываются «7B параметров».
  • Рассказать, как «предскажи следующий токен» порождает все умения модели.
  • Объяснить разницу между base-моделью и инструктивной (instruction tuning).

🔗 Мостик к Модулю 3

Модель обучена, веса заморожены. Но между «модель выдала распределение следующего токена» и «пользователь увидел ответ» стоит слой, о котором забывают чаще всего, — декодер: как именно выбирать токен за токеном. Одна и та же модель с temperature 0.2 и 1.5 — это два разных продукта; а вместе с chat template и окном контекста декодер решает половину инженерных вопросов вокруг LLM. Этим и займёмся.