EssayAI
Блог
Блог
Математика и алгоритмы

Архитектура трансформер: из чего собран Transformer

19 июня 2026Время чтения: 7 минут
#трансформер#transformer#энкодер#декодер#self-attention
Архитектура трансформер: из чего собран Transformer

Архитектура трансформер (Transformer) - это нейросеть из 2017 года, которая полностью отказалась от рекуррентности и свёрток и собрала обработку последовательности на одном механизме: внимании. Сегодня на ней построены почти все большие языковые модели, и понимать её устройство нужно и на собеседовании, и в курсовой по глубокому обучению. Ниже разберём архитектуру по кирпичам: чем энкодер отличается от декодера, что внутри одного блока, как данные проходят насквозь и зачем каждому подслою нужны residual-связь и нормализация. Чтобы сразу увидеть, как меняется размер сети при разном числе слоёв и голов, соберите свой расчёт в инструменте ниже.

Что такое трансформер и зачем он появился

До трансформера последовательности обрабатывали рекуррентные сети (RNN, LSTM): скрытое состояние передавалось от токена к токену по цепочке. Это создавало два узких места - сигнал между далёкими словами размывался по пути, а вычисления нельзя было распараллелить, потому что сотый токен зависел от девяносто девятого. Статья «Attention Is All You Need» предложила убрать рекуррентность целиком и связать любые две позиции последовательности напрямую - через механизм внимания attention.

Получилась архитектура, где каждый слой видит всю последовательность сразу. Это дало два эффекта: путь между любой парой токенов стал равен единице (дальние зависимости больше не теряются), а все позиции считаются параллельно как одно перемножение матриц, идеально ложащееся на GPU. Именно поэтому трансформеры удалось масштабировать до миллиардов параметров - обучение перестало быть последовательным.

Сравнение цепочки RNN и трансформера: слева сигнал идёт по шагам, справа все токены связаны напрямую через слой внимания
Сравнение цепочки RNN и трансформера: слева сигнал идёт по шагам, справа все токены связаны напрямую через слой внимания

Энкодер и декодер: две половины

В оригинальной архитектуре трансформер состоит из двух стеков - энкодера и декодера, по N=6N=6 одинаковых блоков в каждом.

Энкодер читает весь вход целиком и строит его контекстное представление. Каждый его блок содержит два подслоя: multi-head self-attention (токены смотрят друг на друга без ограничений) и позиционный полносвязный слой (FFN). Внимание здесь двунаправленное - слово видит и левых, и правых соседей.

Декодер генерирует выход по одному токену и содержит уже три подслоя: маскированное self-attention (чтобы при генерации позиция не подсматривала будущие токены), cross-attention (через него декодер «читает» выход энкодера) и тот же FFN. Маска - это добавление -\infty в матрицу весов справа от текущей позиции, чтобы после softmax они занулились.

На этой схеме держатся три семейства моделей. Чисто энкодерные (BERT) хороши для понимания текста, чисто декодерные (GPT) - для генерации, полные энкодер-декодеры (T5, оригинальный Transformer) - для перевода и задач «вход → выход».

Два стека блоков трансформера: слева энкодер с двунаправленным вниманием, справа декодер с маской и cross-attention
Два стека блоков трансформера: слева энкодер с двунаправленным вниманием, справа декодер с маской и cross-attention

Multi-head self-attention внутри блока

Сердце каждого блока - внимание с несколькими головами. Базовый расчёт - scaled dot-product: из входа XX линейными проекциями получают запросы, ключи и значения, а затем взвешивают значения по сходству запросов и ключей:

Attention(Q,K,V)=softmax ⁣(QKdk)V\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V

Масштаб 1/dk1/\sqrt{d_k} обязателен: без него при больших dkd_k скалярные произведения раздуваются, softmax вырождается в почти one-hot, и градиент перестаёт течь. Подробнее механика одного слоя разобрана в материале про self-attention механизм.

«Multi-head» означает, что этот расчёт делают параллельно hh раз с разными проекциями, а результаты склеивают:

MultiHead(X)=Concat(head1,,headh)WO,\text{MultiHead}(X) = \text{Concat}(\text{head}_1, \dots, \text{head}_h)\,W_O,

где каждая headi=Attention(XWQi,XWKi,XWVi)\text{head}_i = \text{Attention}(XW_Q^i, XW_K^i, XW_V^i) работает в подпространстве размерности dk=dmodel/hd_k = d_{\text{model}}/h. Зачем несколько голов? Каждая учится своему типу связи: одна ловит синтаксис (подлежащее - сказуемое), другая кореференцию (местоимение - его антецедент), третья позиционную близость. Одна голова усреднила бы всё в одну размытую связь.

Позиционное кодирование

У self-attention есть неочевидное свойство: он инвариантен к перестановке токенов. В формуле нет ни одного слагаемого, зависящего от того, где стоит токен, - переставьте слова, и выходные векторы просто переставятся, не изменив содержимого. Для модели «собака укусила человека» и «человека укусила собака» без дополнительной информации одинаковы.

Поэтому к эмбеддингам перед первым блоком добавляют позиционное кодирование - вектор, кодирующий номер позиции:

PE(pos,2i)=sin ⁣(pos100002i/dmodel),PE(pos,2i+1)=cos ⁣(pos100002i/dmodel)PE_{(pos,\,2i)} = \sin\!\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right), \quad PE_{(pos,\,2i+1)} = \cos\!\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right)

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

FFN, residual и нормализация

Между блоками внимания стоит позиционный FFN - два линейных слоя с нелинейностью, применяемые к каждой позиции независимо:

FFN(x)=max(0,xW1+b1)W2+b2\text{FFN}(x) = \max(0,\, xW_1 + b_1)\,W_2 + b_2

Внутренняя размерность обычно вчетверо больше: dff=4dmodeld_{ff} = 4\,d_{\text{model}}. Если внимание перемешивает информацию между токенами, то FFN нелинейно перерабатывает её внутри каждой позиции - это основной «склад» знаний модели по числу параметров.

Каждый из подслоёв обёрнут в два приёма, без которых глубокая сеть не обучилась бы. Residual-связь x+Sublayer(x)x + \text{Sublayer}(x) пропускает вход в обход подслоя - это даёт градиенту короткий путь и спасает от затухания при десятках слоёв. LayerNorm нормирует активации по признакам, удерживая их в стабильном масштабе. Вместе они образуют шаблон LayerNorm(x+Sublayer(x))\text{LayerNorm}(x + \text{Sublayer}(x)) (post-norm в оригинале; в современных моделях чаще pre-norm - норма до подслоя, она устойчивее при обучении).

Как данные проходят насквозь

Соберём путь одного входа в энкодере по шагам:

  1. Токены превращаются в эмбеддинги размерности dmodeld_{\text{model}} (в оригинале 512).
  2. К ним прибавляется позиционное кодирование PEPE.
  3. Multi-head self-attention пересобирает каждый вектор из контекста; результат идёт через residual и LayerNorm.
  4. FFN нелинейно перерабатывает каждую позицию; снова residual и LayerNorm.
  5. Шаги 3–4 повторяются NN раз - это и есть «стек блоков».

В декодере добавляется маскированное внимание в начале и cross-attention в середине, а на самом верху - линейная проекция в словарь и softmax, дающий распределение вероятностей следующего токена. Платой за всю эту мощь служит квадратичная сложность: матрица QKQK^{\top} имеет размер n×nn \times n, поэтому память и время растут как O(n2)O(n^2) по длине последовательности - именно этот квадрат ограничивает длину контекстного окна.

Частые ошибки

  • Путать энкодер и декодер. Энкодер видит весь вход двунаправленно, декодер маскирует будущее и читает энкодер через cross-attention. BERT - энкодер, GPT - декодер.
  • Забыть позиционное кодирование. Без него трансформер инвариантен к перестановке и теряет порядок слов. Добавлять нужно до первого блока.
  • Игнорировать масштаб 1/dk1/\sqrt{d_k}. Без него softmax насыщается и градиент перестаёт течь.
  • Считать, что головы независимы и взаимозаменяемы. Каждая учится своей роли; одна голова на dmodeld_{\text{model}} работает заметно хуже, чем hh голов меньшей размерности.
  • Недооценивать O(n2)O(n^2). Длинный контекст в наивной реализации упирается в квадратичную память задолго до конца точности - отсюда FlashAttention и разреженное внимание.

FAQ

Чем энкодер трансформера отличается от декодера? Энкодер строит контекстное представление входа и использует двунаправленное self-attention - каждый токен видит всех соседей. Декодер генерирует выход по одному токену, поэтому его self-attention маскировано (нельзя смотреть в будущее), и в нём есть дополнительный cross-attention к выходу энкодера. Поэтому декодерный блок содержит три подслоя, а энкодерный - два.

Зачем в трансформере несколько голов внимания? Одна голова усреднила бы все типы связей в одну размытую матрицу. Несколько голов работают в разных подпространствах и параллельно ловят разные зависимости: синтаксические, кореферентные, позиционные. Затраты те же, потому что размерность каждой головы равна dmodel/hd_{\text{model}}/h, а выходы склеиваются обратно.

Почему трансформер обучается быстрее RNN? RNN обрабатывает токены строго по порядку - сотый зависит от девяносто девятого, распараллелить нельзя. Трансформер считает все позиции одновременно одним перемножением матриц, что идеально ложится на GPU, а путь между любыми двумя токенами равен единице, поэтому дальние зависимости не размываются.

Коротко

Архитектура трансформер собрана из стека одинаковых блоков, где каждый держится на multi-head self-attention и позиционном FFN, обёрнутых в residual-связь и LayerNorm. Энкодер двунаправленно кодирует вход, декодер маскированно генерирует выход и читает энкодер через cross-attention. Порядок слов возвращает позиционное кодирование, добавляемое к эмбеддингам перед первым блоком. Отказ от рекуррентности дал прямой путь между любыми токенами и полный параллелизм, а ценой стала квадратичная по длине сложность O(n2)O(n^2).

Доверьте текст нейросети EssayAI

Открыть EssayAI

Бесплатно, на русском языке и без VPN

Читайте также