Глава 2.5 — Полносвязный слой
Содержание
- Подслой, который все пропускают
- Что вычисляет FFN и какую долю модели он составляет
- От ReLU к GELU: сглаживание вентиля
- Gated Linear Units: третья матрица вместо более удачной кривой
- SwiGLU и правило двух третей
- Взгляд с точки зрения собеседования
- Вопросы для самопроверки
- Источники
1. Подслой, который все пропускают
Каждая глава части II до сих пор была про внимание или про то, что вниманию нужно, чтобы работать: позиционная информация — потому что внимание инвариантно к перестановкам (глава 2.2), выбор формы стека — потому что внимание можно маскировать, а можно нет (глава 2.3), нормализация — потому что глубокие остаточные стеки из подслоёв внимания иначе не обучаются (глава 2.4). Между тем второй подслой в каждом блоке Transformer — позиционный полносвязный слой — появлялся в этой книге примерно десяток раз в виде одной и той же проходной фразы: «небольшой двухслойный MLP с нелинейностью посередине, применяемый токен за токеном». Фраза верная. Она же в модели вроде LLaMA-2 70B описывает примерно две трети параметров.
Это по-настоящему распространённая слепая зона, и интервьюеры об этом знают. Кандидат, который выводит масштабирующий множитель $\sqrt{d_k}$ из первых принципов, но не может сказать, какая функция активации стоит в FFN его продакшн-модели и почему скрытая размерность равна $11008$, а не круглому числу, выучил эффектную половину архитектуры. Эта глава заполняет вторую: что FFN на самом деле делает, почему область перешла от ReLU к GELU, а затем к вентильным вариантам, и как конкретное проектное решение — какая активация, при какой ширине — выглядит, когда конфигурируешь модель сам. Это ещё и последняя деталь блока: после этой главы каждый компонент современного слоя Transformer будет разобран, и часть III сможет заняться масштабированием этого слоя.
2. Что вычисляет FFN и какую долю модели он составляет
Исходная формулировка из Vaswani et al. — это две линейные проекции с нелинейностью между ними, применяемые независимо к вектору каждой позиции: $$\text{FFN}(x) = \max(0,\, xW_1 + b_1)\,W_2 + b_2$$ где $x \in \mathbb{R}^{d}$ — представление одного токена, $W_1 \in \mathbb{R}^{d \times d_{ff}}$ проецирует его вверх в более широкое промежуточное пространство, там применяется нелинейность (ReLU в исходной статье), а $W_2 \in \mathbb{R}^{d_{ff} \times d}$ проецирует обратно в размерность модели, чтобы результат можно было прибавить к остаточному потоку. Исходный Transformer использовал $d = 512$ и $d_{ff} = 2048$, задав соглашение $d_{ff} = 4d$, которое продержалось практически неизменным годы. Слово «позиционный» здесь несёт нагрузку: одни и те же $W_1$ и $W_2$ применяются к каждому токену независимо, вообще без какого-либо смешивания между позициями. Вся коммуникация между токенами происходит в подслое внимания; FFN — это место, где каждый токен по отдельности вычисляет что-то над тем, что только что собрал.
Это разделение труда — самый чистый способ думать о блоке Transformer, и оно делает подсчёт параметров стоящим того, чтобы провести его явно. Подслой внимания держит четыре матрицы $d \times d$ — $W_Q$, $W_K$, $W_V$, $W_O$ — то есть $4d^2$ параметров. FFN держит $d \times 4d$ и $4d \times d$, то есть $8d^2$. Значит, FFN вдвое больше подслоя внимания, или две трети каждого блока; и поскольку FFN точно так же применяется в каждой позиции, на него приходится примерно та же доля в две трети от FLOPs прямого прохода при небольших длинах контекста (квадратичный член внимания обгоняет его только на длинных последовательностях — ровно та точка пересечения, о которой глава 3.1). Любое утверждение о том, «где находятся параметры» в плотной LLM, — это в основном утверждение про FFN.
Geva et al. дали этому подслою куда более конкретную интерпретацию в 2021 году, показав, что полносвязные слои Transformer работают как память ключ-значение: каждый столбец $W_1$ действует как ключ, срабатывающий на определённый входной паттерн (их анализ находит отдельные столбцы, активирующиеся на узнаваемые текстовые паттерны — от поверхностных n-грамм в ранних слоях до семантических тем в поздних), а соответствующая строка $W_2$ — это значение, то есть вектор, который этот столбец записывает в остаточный поток при срабатывании. При таком прочтении FFN — не абстрактный блок «дополнительной ёмкости», а ассоциативная память с $d_{ff}$ ячейками, к которой подслой внимания обращается косвенно, собирая нужный входной паттерн. Эта интерпретация ещё и концептуальный мост к главе 3.3: Mixture of Experts заменяет один плотный FFN на множество и направляет каждый токен лишь к нескольким из них — что имеет смысл как проектное решение, только если вы уже считаете FFN хранилищем множества специализированных, индивидуально адресуемых кусочков знания, а не одной монолитной функцией.
Эта же рамка отвечает и на вопрос, на который стоит уметь дать содержательный ответ: если нужна модель с бóльшей ёмкостью, почему расширять именно этот подслой ($d_{ff}$), а не просто наращивать число слоёв? Эти два рычага не взаимозаменяемы по цене. Глубина по своей природе последовательна: каждый дополнительный слой — это ещё один переход, через который представление токена должно пройти, прежде чем сможет начаться следующий слой, так что глубина напрямую увеличивает задержку инференса и усложняет ландшафт оптимизации (всё обсуждение Pre-LN и нормализации в главе 2.4 — это, по сути, укрощение трудности, возникающей именно из-за глубины). Ширина же, напротив, параллельна: расширение $d_{ff}$ просто увеличивает размер двух матричных умножений внутри одного вызова FFN, что современные ускорители поглощают, не добавляя ни единого дополнительного последовательного шага, — прямой проход токена через этот один более широкий FFN по-прежнему происходит за тот же самый один переход через блок. В свете прочтения Geva et al. про память ключ-значение выше это тоже имеет конкретный смысл: расширение $d_{ff}$ просто добавляет больше ячеек ключ-значение в ту же самую одну память, к которой токен обращается один раз за слой, тогда как добавление целого дополнительного слоя вставляет ещё одно полное вычисление внимание-затем-FFN, через которое представление токена приходится последовательно проталкивать, вдобавок ко всей стоимости целого лишнего слоя в параметрах для внимания. Для чистой ёмкости хранения в смысле, который описывают Geva et al., больше ячеек в одной памяти — более дешёвый, более параллельный способ купить то же самое, чем ещё один целый переход последовательного вычисления, — именно поэтому $d_{ff}$, а не глубина, оказывается тем рычагом, за который реальные конфигурации моделей тянут сильнее всего ради ёмкости, если разумный минимум глубины уже заложен.
3. От ReLU к GELU: сглаживание вентиля
ReLU, $\max(0, x)$, — это жёсткий вентиль: вход либо пропускается без изменений, либо обнуляется, причём решение принимает разрывный переключатель в нуле. Gaussian Error Linear Unit авторства Hendrycks и Gimpel переформулирует этот вентиль вероятностно. Вместо того чтобы открывать вентиль по знаку $x$, стоит открывать его по тому, насколько $x$ велик относительно распределения активаций, умножив вход на вероятность того, что стандартная нормальная величина окажется ниже него: $$\text{GELU}(x) = x \cdot \Phi(x)$$ где $\Phi$ — функция распределения стандартного нормального закона. Получается гладкая кривая, ведущая себя как ReLU вдали от нуля (при больших положительных $x$ имеем $\Phi(x) \approx 1$ и GELU$(x) \approx x$; при больших отрицательных $\Phi(x) \approx 0$ и выход исчезает), но переходящая через начало координат постепенно — и, что примечательно, немонотонная: она слегка уходит в минус на малых отрицательных входах, прежде чем вернуться к нулю, вместо того чтобы плоско зажаться, как ReLU.
Эмпирическому преимуществу GELU обычно приписывают два свойства. Первое — она дифференцируема всюду, без излома в начале координат, что даёт градиентному спуску лучше обусловленную поверхность, чем разрывная производная ReLU. Второе — точное обнуление всех отрицательных входов у ReLU порождает по-настоящему мёртвые нейроны: нейрон, у которого предактивация отрицательна на каждом входе из данных, вообще не получает градиента и уже не может восстановиться, тогда как небольшой отрицательный хвост GELU сохраняет градиентный сигнал и на отрицательной стороне. GELU была принята в BERT и во всей линейке GPT вплоть до GPT-3 и остаётся вполне разумным выбором по умолчанию; на практике реализации часто используют tanh-приближение $\text{GELU}(x) \approx 0.5x\left(1 + \tanh\left[\sqrt{2/\pi}\,(x + 0.044715x^3)\right]\right)$, которое дешевле вычисления настоящей CDF и численно неотличимо в обученной сети.
Ramachandran, Zoph и Le пришли к очень похожей функции совсем с другой стороны, запустив автоматизированный поиск по пространству функций активации и обнаружив, что лучший найденный поиском вариант — это $\text{Swish}(x) = x \cdot \sigma(\beta x)$, вход, умноженный на сигмоиду от себя же. При $\beta = 1$ это часто называют SiLU, и его форма почти идентична GELU: гладкая, немонотонная, ReLU-подобная в хвостах. То, что две независимые линии работ — одна аналитическая, другая автоматизированный поиск — сошлись по сути на одной кривой, служит неплохим свидетельством, что важна именно форма, а не конкретный вывод. Впрочем, держать это стоит не слишком крепко: измеренные разрывы между ReLU, GELU и Swish в хорошо настроенной большой модели реальны, но малы, и ни одно из этих изменений не преображает модель. Следующее — более структурное.
4. Gated Linear Units: третья матрица вместо более удачной кривой
Каждая функция из предыдущего раздела — это поточечное перегибание одной и той же величины: взять $xW_1$, согнуть через какую-то кривую, спроецировать обратно вниз. Dauphin et al., работая над свёрточными языковыми моделями в 2017 году, предложили категорически иное: вместо того чтобы подбирать более удачную кривую для одной проекции, вычислить две проекции и позволить одной мультипликативно управлять другой: $$\text{GLU}(x) = (xW + b) \odot \sigma(xV + c)$$ где $\odot$ — поэлементное умножение. Первая ветвь несёт содержимое; вторая, сжатая сигмоидой в $[0,1]$, решает, какая доля каждого измерения содержимого выживет. Вентиль теперь — обучаемая, зависящая от входа функция, вычисляемая собственной матрицей весов, а не фиксированная кривая, применённая к самому содержимому.
Различие значит больше, чем кажется. Поточечная активация, как бы хитро она ни была изогнута, вычисляет каждую выходную координату ровно из одной входной — функция $\mathbb{R} \to \mathbb{R}$ одна и та же для каждого нейрона и каждого токена. Вентильный юнит вычисляет каждую выходную координату как произведение двух разных линейных функций всего входного вектора, что делает выход слоя квадратичным по $x$, а не «линейным-и-согнутым». Это мультипликативное взаимодействие — по-настоящему более богатый примитив: сеть может выучить вентиль, подавляющий один признак именно тогда, когда присутствует какой-то другой, никак с ним не связанный, — а этого никакая поточечная нелинейность не выражает вовсе. Это та же структурная идея, что заставила работать вентили LSTM в главе 1.4 — мультипликативное, зависящее от данных управление потоком информации, — вновь появившаяся в полносвязном контексте.
Заметка Шазира 2020 года GLU Variants Improve Transformer перенесла идею в FFN трансформера и попутно определила семейство, которым современные модели реально пользуются. Ход состоит в том, чтобы заменить сигмоиду в GLU на любую понравившуюся активацию, что даёт по именованному варианту на каждый выбор: $$\begin{aligned}\text{ReGLU}(x) &= \max(0,\,xW) \odot xV \ \text{GEGLU}(x) &= \text{GELU}(xW) \odot xV \ \text{SwiGLU}(x) &= \text{Swish}(xW) \odot xV\end{aligned}$$ после чего FFN завершается как и раньше — проекцией провентилированного результата обратно вниз через третью матрицу $W_2$. Шазир оценил их как drop-in замены в постановке предобучения T5 на заполнение спанов и обнаружил, что вентильные варианты бьют и чистый ReLU, и чистый GELU как по лоссу предобучения, так и на дообучении, причём GEGLU и SwiGLU идут примерно вровень впереди. Статья освежающе честна в том, что это эмпирический результат без механистического объяснения, и закрывается фразой, процитированной затем во множестве работ: авторы не предлагают объяснения, почему эти архитектуры работают, и приписывают их успех, как и всё прочее, божественной благосклонности.
5. SwiGLU и правило двух третей
В предыдущем разделе есть проблема учёта, которую надо решить, прежде чем всё это станет честным сравнением. У стандартного FFN две матрицы, $W_1$ и $W_2$, то есть $2 \cdot d \cdot d_{ff}$ параметров. У вентильного FFN их три — $W$, $V$ и $W_2$ — то есть $3 \cdot d \cdot d_{ff}$. При одинаковом $d_{ff}$ вентильная версия на 50% больше, а «слой побольше работает получше» — не интересный вывод. Эксперименты Шазира контролировали это, сжимая скрытую размерность в $2/3$ раза, чтобы $3 \cdot d \cdot \frac{2}{3}d_{ff} = 2 \cdot d \cdot d_{ff}$ и количество параметров совпало в точности. При обычной отправной точке $d_{ff} = 4d$ это даёт правило, которое вы и видите в современных конфигах: $$d_{ff} = \tfrac{2}{3} \cdot 4d = \tfrac{8}{3}d$$ Вентильные варианты выигрывают при равном числе параметров и равных FLOPs — вот что делает результат достойным применения.
Именно поэтому у конфигов открытых моделей такие странные на вид ширины FFN. У LLaMA-7B $d = 4096$; $\frac{8}{3} \cdot 4096 = 10922.67$, что LLaMA округляет вверх до $11008$ — кратного $256$, выбранного потому, что и аппаратные ядра, и тензорный параллелизм (глава 4.4) предпочитают размерности, делящиеся начисто. Если вы когда-нибудь смотрели в конфиг и удивлялись, почему intermediate_size не просто вчетверо больше hidden_size, — вот весь ответ: это $8/3$, округлённое до чего-то, что нравится GPU. Современные реализации к тому же обычно полностью убирают смещения $b_1, b_2$ — PaLM и другие обнаружили, что удаление смещений из всех плотных слоёв улучшает стабильность обучения в масштабе без потерь качества, — так что продакшн-FFN обычно представляет собой три матрицы без смещений и вентиль Swish.
SwiGLU сейчас почти универсален в больших моделях «только декодер»: LLaMA и её многочисленные потомки, PaLM, Mistral, Qwen и большая часть открытого поля используют именно его, тогда как более старая конфигурация «GELU при $4d$» выживает главным образом в моделях, происходящих от линии GPT-2/GPT-3, и в семействе энкодер-моделей BERT. GEGLU, несмотря на то что в собственных цифрах Шазира она идёт примерно вровень со SwiGLU, применяется на практике заметно реже — самый заметный продакшен-пользователь — семейство Gemma от Google, что отражает скорее то, что SwiGLU стал выбором по умолчанию для всей области, чем какой-либо измеренный разрыв в качестве между ними. Стоит трезво оценивать размер эффекта: это улучшение лосса при фиксированном компьюте на уровне единиц процентов, а не скачок, и держится оно потому, что достаётся бесплатно — те же параметры, те же FLOPs, одно лишнее поэлементное умножение. Это характерная форма улучшения в зрелой архитектуре, и она полезно контрастирует с тем, чем занимается дальше часть III, где выигрыш приходит от изменения асимптотической стоимости вычисления, а не от подбора чуть более удачной функции внутри фиксированного бюджета.
На этом часть II собрала полный современный блок Transformer: внимание, чтобы перемещать информацию между позициями, позиционное кодирование, чтобы сообщить ему, где эти позиции находятся, форму стека «только декодер», нормализацию, размещённую так, чтобы остаточный путь оставался чистым, и вентильный полносвязный подслой, держащий большинство параметров. Всё дальнейшее — про масштаб: как удешевить этот блок на длинных последовательностях, как дать ему гораздо больше параметров, чем он может позволить себе использовать плотно, и как обслуживать его для реальных пользователей — ровно то, чем и занимается часть III, «Масштабирование архитектуры».
6. Взгляд с точки зрения собеседования
Собеседование на senior-позицию по LLM редко спросит «что такое полносвязный слой» в лоб, но обязательно проверит, знаете ли вы, куда на самом деле уходят параметры и FLOPs модели, — обычно вопросами вроде:
- «Какая примерно доля параметров плотного трансформера лежит в подслоях FFN и почему?» Сильный ответ считает арифметику на месте: внимание — это четыре проекции $d \times d$, то есть $4d^2$; FFN при $d_{ff} = 4d$ — это две матрицы $d \times 4d$, то есть $8d^2$; значит, FFN составляет две трети каждого блока. Сильный ответ также отметит, что это делает FFN примерно двумя третями FLOPs на токен при коротком контексте, а квадратичный член внимания доминирует лишь на больших длинах, и свяжет это с тем, почему MoE (глава 3.3) целится именно в FFN, а не во внимание.
- «Почему скрытая размерность FFN в LLaMA равна $11008$, а не $16384$?» Ожидаемый ответ — правило $2/3$: SwiGLU использует три матрицы вместо двух, поэтому скрытая размерность умножается на $2/3$, чтобы сохранить параметры и FLOPs, давая $\frac{8}{3}d$; $\frac{8}{3} \cdot 4096 \approx 10923$, округлённое вверх до $11008$ ради удобной для железа делимости. Правильный ответ здесь сигнализирует, что вы читали реальный конфиг и поняли его, а не только статью.
- «Что даёт вентильная активация такого, чего не может дать более удачная поточечная нелинейность?» Ответ должен быть именно про мультипликативное взаимодействие: поточечная функция отображает каждую координату независимо через фиксированную кривую, тогда как вентиль — это вторая обучаемая линейная функция всего входного вектора, умножающая первую, что позволяет слою подавлять признак условно на других, не связанных с ним признаках. Названная параллель с вентилями LSTM показывает, что вы видите в этом ту же идею, а не новый трюк, а честное замечание, что эмпирический выигрыш мал и механистически не объяснён, — довод в вашу пользу, а не против.
- «Почему область ушла от ReLU?» Сильный ответ называет оба свойства — дифференцируемость всюду против излома в нуле и небольшой отрицательный хвост, позволяющий избежать навсегда мёртвых нейронов ReLU, — и опознаёт GELU и Swish как почти идентичные кривые, полученные независимыми путями (аналитическим аргументом про вероятностное вентилирование и автоматизированным поиском функций), что и служит доводом в пользу того, что важна форма, а не конкретный вывод.
Сквозная линия, которую проверяют интервьюеры, — является ли вашей ментальной моделью трансформера весь блок или только схема внимания. Про $QK^\top$ может рассказать любой, кто прочитал статью про внимание; и лишь тот, кто реально конфигурировал, профилировал или обучал модель, знает, что большинство параметров, за которые он платил, сидело в подслое, который никто не рисует.
7. Вопросы для самопроверки
- Выпишите исходную формулу FFN и объясните, что механически означает «позиционный», — что сломалось бы, если бы FFN смешивал информацию между позициями?
- Выведите количество параметров подслоёв внимания и полносвязного через $d$ и используйте это, чтобы назвать долю параметров плотного блока, приходящуюся на FFN. Как изменится эта доля, если $d_{ff} = 4d$ станет $d_{ff} = 8d$?
- Объясните интерпретацию FFN как памяти ключ-значение и почему она делает Mixture of Experts естественным следующим шагом, а не произвольным.
- Какими двумя свойствами обладает GELU, которых нет у ReLU, и какой конкретный режим отказа ReLU адресует второе из них?
- Объясните точно, почему вентильный юнит выразительнее любой поточечной активации — в терминах того, что каждый из них может вычислить из входного вектора.
- Коллега сравнивает SwiGLU с GELU при одинаковом $d_{ff}$ и сообщает, что SwiGLU лучше. Что не так с этим сравнением и что вы посоветуете изменить?
- Оглядываясь на часть II, назовите одну проблему, которую решает центральный механизм каждой главы, и объясните, почему роль FFN обретает смысл только после того, как вы знаете, что внимание делает, а чего не делает.
8. Источники
- Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, Ł., & Polosukhin, I. (2017). Attention Is All You Need. NeurIPS 2017. arXiv:1706.03762. https://arxiv.org/abs/1706.03762
- Hendrycks, D., & Gimpel, K. (2016). Gaussian Error Linear Units (GELUs). arXiv:1606.08415. https://arxiv.org/abs/1606.08415
- Ramachandran, P., Zoph, B., & Le, Q. V. (2017). Searching for Activation Functions. arXiv:1710.05941. https://arxiv.org/abs/1710.05941
- Dauphin, Y. N., Fan, A., Auli, M., & Grangier, D. (2017). Language Modeling with Gated Convolutional Networks. ICML 2017. arXiv:1612.08083. https://arxiv.org/abs/1612.08083
- Shazeer, N. (2020). GLU Variants Improve Transformer. arXiv:2002.05202. https://arxiv.org/abs/2002.05202
- Geva, M., Schuster, R., Berant, J., & Levy, O. (2021). Transformer Feed-Forward Layers Are Key-Value Memories. EMNLP 2021. arXiv:2012.14913. https://arxiv.org/abs/2012.14913
- Touvron, H., Lavril, T., Izacard, G., Martinet, X., Lachaux, M.-A., Lacroix, T., Rozière, B., Goyal, N., Hambro, E., Azhar, F., Rodriguez, A., Joulin, A., Grave, E., & Lample, G. (2023). LLaMA: Open and Efficient Foundation Language Models. arXiv:2302.13971. https://arxiv.org/abs/2302.13971
- Chowdhery, A., Narang, S., Devlin, J., et al. (2022). PaLM: Scaling Language Modeling with Pathways. arXiv:2204.02311. https://arxiv.org/abs/2204.02311