Машинное обучение

Трансформеры и механизм Attention

В 2017 году восемь исследователей из Google опубликовали статью с дерзким названием - Attention Is All You Need. Они предложили полностью отказаться от рекуррентных сетей и свёрток, заменив их одним механизмом - attention. Научное сообщество было скептично: как один механизм может заменить проверенные годами архитектуры? Прошло несколько лет - и эта одна статья перевернула всю область. GPT, BERT, ChatGPT, DALL-E, Stable Diffusion, Claude, Gemini, LLaMA - все построены на архитектуре Transformer. Одна идея, 8 авторов, 15 страниц - и весь современный AI.

  • **GPT-4 и ChatGPT** - decoder-only Transformer, генерирующий текст токен за токеном через masked self-attention. Сотни миллиардов параметров, обученные на триллионах токенов текста, но в основе - тот самый механизм attention из статьи 2017 года
  • **Машинный перевод (Google Translate)** - encoder-decoder Transformer кодирует исходное предложение через encoder, а decoder генерирует перевод, используя cross-attention к закодированному входу. Качество выросло настолько, что для многих языковых пар приблизилось к человеческому
  • **DALL-E и Stable Diffusion** - Transformer обрабатывает текстовый промпт через attention, создавая представление, которое направляет генерацию изображений. Cross-attention связывает текстовые токены с пространственными регионами картинки, позволяя генерировать конкретные объекты в конкретных местах

Предварительные знания

  • Recurrent Networks: RNN, LSTM, GRU

Внимание - это всё, что нужно

В 2017 году команда под руководством Ашиша Васвани из Google опубликовала статью с дерзким названием "Attention Is All You Need". До этого модели последовательностей опирались на рекуррентность или свёртку для учёта порядка слов и обрабатывали токены один за другим. Трансформер отказался от этого и оставил только механизм внимания, позволив каждому токену смотреть на все остальные параллельно. Это сделало обучение намного быстрее на современном железе и убрало узкое место RNN с памятью на длинных дистанциях. Архитектура оказалась прекрасно масштабируемой, и за несколько лет она стала основой BERT, GPT и почти всех последующих больших языковых моделей.

Self-Attention: что на что смотрит

Рассмотрим предложение: *The animal didn't cross the street because it was too tired*. На что ссылается слово "it"? Человек сразу понимает - на "animal". Но для модели это задача: нужно понять, какие слова в предложении **связаны** друг с другом. Self-attention решает именно эту задачу: каждый токен (слово) "смотрит" на все остальные токены и решает, на какие из них обращать больше внимания. Слово "it" научится смотреть на "animal", потому что контекст "was too tired" указывает на живое существо, а не на улицу.

Как это работает технически? Каждый токен представляется тремя векторами: **Query** ("что я ищу?"), **Key** ("что я содержу?") и **Value** ("какую информацию я передаю?"). Эти три вектора получаются умножением embedding токена на три обучаемые матрицы W_Q, W_K, W_V. Интуиция: Query - это вопрос, Key - это ответ на вопрос "подхожу ли я?", Value - сама информация, которую нужно передать.

Формула self-attention: **Attention(Q, K, V) = softmax(Q @ K^T / sqrt(d_k)) @ V**. Здесь Q @ K^T - матрица скалярных произведений всех Query со всеми Key (размер: seq_len x seq_len). Деление на sqrt(d_k) - масштабирование, где d_k - размерность Key-вектора. Softmax превращает scores в вероятности (сумма = 1 для каждой строки). Умножение на V дает взвешенную сумму Value-векторов.

**Зачем деление на sqrt(d_k)?** Без масштабирования скалярные произведения Q @ K^T растут пропорционально размерности d_k. При d_k = 512 значения scores могут достигать сотен. Softmax от таких больших чисел дает почти one-hot вектор (одна позиция ~1.0, остальные ~0.0), и градиенты становятся почти нулевыми - обучение останавливается. Деление на sqrt(d_k) нормализует дисперсию scores до ~1.0 независимо от размерности. Это позволяет softmax работать в "мягком" режиме, распределяя внимание между несколькими токенами, а не фиксируясь на одном.

В механизме self-attention каждый токен представляется тремя векторами Q, K, V. Что именно вычисляет матрица Q @ K^T?

Multi-Head Attention: параллельные точки зрения

Одна голова self-attention учится фокусироваться на определённом типе связей. Но в языке существует множество типов зависимостей одновременно: синтаксические (подлежащее-сказуемое), семантические (синонимы, антонимы), кореференции ("it" ссылается на "animal"), временные (последовательность событий). Одна голова не может уловить все типы связей сразу. Решение - **запустить несколько голов параллельно**, каждая со своими матрицами W_Q, W_K, W_V.

Как устроен multi-head attention: вместо одного набора {W_Q, W_K, W_V} размерности d_model x d_model, мы создаем h наборов {W_Q_i, W_K_i, W_V_i} размерности d_model x d_k, где d_k = d_model / h. Каждая голова работает с вектором меньшей размерности, но зато голов несколько. В оригинальном Transformer: d_model = 512, h = 8 голов, d_k = 512 / 8 = 64 на голову.

**Количество параметров multi-head attention:** Для одной головы: 3 матрицы (W_Q, W_K, W_V) размера d_model x d_k = 512 x 64 = 32 768 параметров x 3 = 98 304. Для h = 8 голов: 98 304 x 8 = 786 432 параметра. Плюс финальная проекция W_O размера d_model x d_model = 512 x 512 = 262 144. **Итого: ~1 048 576 параметров (1M)** на один слой multi-head attention. Важно: количество параметров **одинаковое**, независимо от того, используем мы 1 голову с d_k = 512 или 8 голов с d_k = 64. Но 8 голов учат разные типы зависимостей параллельно!

Исследования показали, что разные головы действительно специализируются. В обученных моделях можно наблюдать: одни головы отслеживают синтаксические зависимости (подлежащее-сказуемое), другие - позиционные паттерны ("смотрю на предыдущий токен"), третьи - редкие, но важные семантические связи. При этом часть голов оказывается избыточной - эксперименты по "pruning" (обрезке) голов показывают, что можно удалить 20-40% голов без значительной потери качества.

В Transformer с d_model=512 и 8 головами, какова размерность Q, K, V для каждой отдельной головы?

Positional Encoding: добавляем порядок

У self-attention есть фундаментальная проблема: он **не знает о порядке токенов**. Если перемешать слова в предложении, attention-веса изменятся (потому что embedding слов разные), но механизм self-attention сам по себе не содержит информации о *позициях*. Для него "кошка ест рыбу" и "рыбу ест кошка" - это одно и то же, если embedding каждого слова одинаковый. RNN решала эту проблему автоматически - она обрабатывала токены последовательно, один за другим. Transformer обрабатывает все токены параллельно, поэтому информацию о позициях нужно **добавить явно**.

В оригинальной статье "Attention Is All You Need" используется **sinusoidal positional encoding**: для каждой позиции и каждого измерения embedding вычисляется значение через sin и cos с разными частотами. Формула: PE(pos, 2i) = sin(pos / 10000^(2i/d_model)), PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model)). Здесь pos - позиция токена, i - индекс измерения. Каждое измерение использует свою частоту, от быстрой (2*pi) до медленной (2*pi*10000).

**Три подхода к positional encoding:** 1. **Sinusoidal (оригинальный Transformer):** фиксированный, не обучается. Плюс: может экстраполировать на длины, которых не было в обучении. Минус: не адаптируется под задачу. 2. **Learned embeddings (BERT, GPT):** обучаемый вектор для каждой позиции. Плюс: адаптируется под данные, обычно чуть лучше по качеству. Минус: фиксированная максимальная длина (BERT = 512, GPT-2 = 1024). 3. **Relative positional (T5, ALiBi):** кодирует не абсолютную позицию, а расстояние между токенами. Плюс: лучше обобщается на длинные последовательности. ALiBi добавляет штраф к attention scores пропорционально расстоянию: чем дальше токены друг от друга, тем ниже score.

Важное свойство sinusoidal encoding: скалярное произведение PE(pos) и PE(pos + k) зависит только от сдвига k, а не от абсолютной позиции pos. Это значит, что расстояние между позициями 5 и 8 "выглядит" так же, как расстояние между позициями 100 и 103. Модель может учить паттерны вроде "следующее слово" или "через два слова" независимо от абсолютной позиции в предложении.

Зачем Transformer нужен positional encoding, если attention и так вычисляет взаимодействия между всеми парами токенов?

Архитектура Encoder-Decoder: собираем Transformer

Теперь у нас есть все кирпичики: self-attention, multi-head attention, positional encoding. Пора собрать полный Transformer. Оригинальная архитектура (2017) состоит из двух стеков: **Encoder** кодирует входную последовательность в непрерывное представление, а **Decoder** генерирует выходную последовательность токен за токеном, используя это представление. Encoder и Decoder состоят из одинаковых блоков, повторенных N раз (в оригинальной статье N = 6).

Каждый блок Encoder содержит два подслоя: 1. multi-head self-attention и (2) feed-forward network (два линейных слоя с ReLU: FFN(x) = max(0, x @ W1 + b1) @ W2 + b2, размерности d_model=512 -> d_ff=2048 -> d_model=512). Каждый блок Decoder содержит три подслоя: 1. **masked** multi-head self-attention (маскирование будущих позиций) 2. **cross-attention** (Key и Value из Encoder, Query из Decoder) 3. feed-forward network. Вокруг каждого подслоя - **residual connection + Layer Normalization**: output = LayerNorm(x + Sublayer(x)).

**Три типа attention в Transformer:** 1. **Encoder self-attention:** каждый входной токен смотрит на ВСЕ входные токены. Без масок - полная видимость. 2. **Masked decoder self-attention:** каждый выходной токен смотрит только на ПРЕДЫДУЩИЕ выходные токены. Будущие позиции замаскированы значением -inf (после softmax = 0). Это нужно, чтобы при генерации модель не "подсматривала" ответ. 3. **Cross-attention (encoder-decoder):** Query из decoder, Key и Value из encoder. Decoder "задает вопросы" закодированному входу. Например, при переводе "I love cats" decoder на шаге генерации слова "люблю" через cross-attention фокусируется на "love" из encoder.

**Residual connections** (остаточные связи) - output = x + Sublayer(x) - решают проблему затухающих градиентов при глубоком стеке (6+ слоев). Градиент может течь напрямую через сложение (skip connection) мимо слоя. **Layer Normalization** нормализует активации по последнему измерению (d_model), стабилизируя обучение. Комбинация Add & LayerNorm после каждого подслоя - критический компонент, без которого глубокие Transformer не обучаются.

Почему Transformer победил RNN? Три причины. 1. **Параллелизм**: RNN обрабатывает токены последовательно (каждый зависит от предыдущего), Transformer - все параллельно. Обучение на GPU ускоряется в десятки раз. 2. **Длинные зависимости**: в RNN информация от далекого токена должна "протечь" через все промежуточные шаги, затухая. В Transformer любые два токена связаны напрямую через attention (расстояние = 1 слой). 3. **Масштабируемость**: увеличение модели (больше слоев, голов, d_model) дает предсказуемый рост качества - scaling laws, открытые командой OpenAI.

Transformer полностью заменил все предыдущие архитектуры - CNN и RNN больше не нужны

CNN до сих пор эффективнее для задач обработки изображений фиксированного размера на ограниченных ресурсах, а RNN/LSTM остаются лучшим выбором для потоковых данных на edge-устройствах с жесткими ограничениями по памяти и задержке

Итоги

  • **Self-attention:** каждый токен вычисляет три вектора (Query, Key, Value), матрица Q @ K^T дает scores совместимости, softmax с масштабированием на sqrt(d_k) превращает их в веса, а умножение на V выдает контекстно-обогащенное представление каждого токена
  • **Multi-head attention:** вместо одной большой головы - h параллельных голов с уменьшенной размерностью d_k = d_model / h, каждая специализируется на своем типе зависимостей (синтаксис, семантика, кореференции), результаты конкатенируются и проецируются обратно
  • **Positional encoding:** self-attention инвариантен к порядку токенов, поэтому информация о позициях добавляется явно - через sinusoidal функции (фиксированные), обучаемые embeddings (BERT/GPT) или относительные кодировки (ALiBi/T5)
  • **Encoder-Decoder:** encoder кодирует вход через self-attention + FFN (N раз), decoder генерирует выход через masked self-attention + cross-attention к encoder + FFN (N раз), с residual connections и LayerNorm вокруг каждого подслоя
  • **Один механизм - весь современный AI:** те самые 8 авторов из Google в 2017 году были правы - attention действительно оказался всем, что нужно. GPT, BERT, Claude, DALL-E - все стоят на фундаменте Transformer, отличаясь лишь тем, какую часть архитектуры используют и на каких данных обучены

Связанные темы

Transformer вырос из идей рекуррентных сетей и породил целое семейство моделей, определяющих современный AI:

  • BERT и GPT — Две главные ветви Transformer: BERT использует только encoder (двунаправленный контекст) для задач понимания текста, GPT использует только decoder (авторегрессивная генерация) для генерации текста. Оба механизма подробно разбираются в следующем уроке
  • RNN и LSTM — Предшественники Transformer для обработки последовательностей: RNN обрабатывала токены последовательно и страдала от затухающих градиентов, LSTM решала эту проблему через gates. Transformer заменил последовательную обработку параллельным attention, решив обе проблемы

Вопросы для размышления

  • Transformer имеет квадратичную сложность O(n^2) по длине последовательности из-за матрицы attention. Какие подходы могут решить эту проблему для длинных текстов (книг, кодовых баз), и какие компромиссы они вносят?
  • Decoder-only модели (GPT, LLaMA, Claude) доминируют в 2024-2026, хотя изначально Transformer был encoder-decoder. Почему decoder-only оказался достаточным для большинства задач, и для каких задач encoder-decoder всё ещё предпочтительнее?
  • Positional encoding добавляет информацию о позиции, но при этом ограничивает максимальную длину контекста. Как модели вроде GPT-4 или Claude работают с контекстами в сотни тысяч токенов, если обучались на меньших длинах?

Связанные уроки

  • ml-30-rnn-lstm — Трансформеры снимают узкое место RNN
  • ml-37-bert-gpt — BERT и GPT построены на трансформерах
  • ml-36-seq2seq — Attention обобщил декодер seq2seq
  • la-07-matrix-multiply — Attention - это масштабированное скалярное произведение
  • la-13-eigenvectors — Веса attention проецируют на подпространства значений
  • aie-03-llm-fundamentals
  • aie-13-advanced-rag
Трансформеры и механизм Attention

0

1

Войти

Transformer доминирует в NLP и все больше в computer vision (ViT), но его квадратичная сложность по длине O(n^2) делает его дорогим для длинных последовательностей. MobileNet (CNN) на телефоне классифицирует изображения за 5 мс, тогда как Vision Transformer требует в 10 раз больше вычислений. LSTM на микроконтроллере обрабатывает аудио-поток с задержкой 1 мс, Transformer потребует накопить батч. Выбор архитектуры зависит от задачи, данных и ограничений, а не от даты публикации статьи.

Зачем decoder в Transformer использует маскирование (masked attention) при обучении?