Архитектура Трансформеров: Под капотом LLM

Глубокое погружение в математическую и логическую основу архитектуры Transformer. Вы детально изучите механизм внутреннего внимания (self-attention), работу энкодеров и декодеров, а также алгоритмы обработки контекста.

1. От рекуррентных сетей к вниманию: Проблема долгосрочной памяти

В первой части нашего курса мы выяснили, что большие языковые модели (LLM) по своей сути занимаются предсказанием следующего слова. Однако для того, чтобы это предсказание было точным, модель должна глубоко понимать контекст всего сказанного ранее. Если вы читаете детектив, концовка имеет смысл только в том случае, если вы помните улики из первой главы.

До 2017 года нейросети читали текст примерно так же, как человек с тяжелой формой амнезии: они помнили последние несколько слов, но безнадежно забывали то, что было в начале абзаца. Этот фундаментальный барьер не позволял создавать по-настоящему умные языковые модели. Решение этой проблемы привело к созданию архитектуры Transformer — двигателя всех современных LLM.

Эпоха до Трансформеров: Рекуррентные нейронные сети

Чтобы понять гениальность Трансформеров, нужно сначала разобраться, как работали их предшественники — рекуррентные нейронные сети (RNN, Recurrent Neural Networks).

Долгое время RNN были золотым стандартом для работы с последовательностями: текстом, речью, временными рядами. Их главная особенность заключалась в последовательной обработке данных. RNN читала текст строго слово за словом, слева направо.

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

В архитектуре RNN этот «стикер» называется скрытым состоянием (hidden state).

Математически шаг работы RNN можно описать следующей формулой:

Где:

  • — новое скрытое состояние (ваш новый стикер) на текущем шаге .
  • — функция активации (математический фильтр, который решает, какую информацию пропустить дальше).
  • и — веса модели (настройки, которые нейросеть выучила во время тренировки).
  • — предыдущее скрытое состояние (ваш старый стикер с прошлого шага).
  • — текущее слово, которое модель читает прямо сейчас.
  • Каждый раз, когда RNN читает новое слово, она обновляет свое скрытое состояние. К концу предложения это скрытое состояние должно, в теории, содержать смысл всего прочитанного текста.

    Проблема долгосрочной памяти и «узкое горлышко»

    Логика RNN звучит разумно, но на практике она столкнулась с фатальной проблемой, известной как затухание градиента (vanishing gradient).

    Вернемся к аналогии со стикером. Размер вашего стикера строго ограничен. Когда вы читаете первое предложение, вы легко умещаете его смысл на бумажке. Но когда вы доходите до сотой страницы, вам приходится сжимать информацию всё сильнее и сильнее. Вы начинаете выкидывать детали, оставляя только самую суть. К двухсотой странице вы можете забыть имя второстепенного персонажа, который внезапно становится главным злодеем.

    В нейросетях этот эффект называется информационным узким горлышком (information bottleneck). Вектор скрытого состояния имеет фиксированный размер (например, массив из 512 чисел). Нейросеть вынуждена «впихивать» смысл текста любой длины — будь то три слова или три тысячи слов — в эти 512 чисел.

    !Схема проблемы "узкого горлышка" в классических нейросетях

    Рассмотрим классический пример, на котором ломались старые модели: > «Я вырос во Франции, в маленьком живописном городке на юге, где каждое утро пахло свежими круассанами... [еще 50 слов описания природы и архитектуры] ... поэтому я свободно говорю по-_____»

    Любой человек мгновенно вставит слово «французски». Мы легко связываем слово «Франции» в начале текста с пропуском в конце. Но для RNN слово «Франции» осталось на стикере 50 шагов назад. За это время стикер перезаписывался 50 раз, наполняясь информацией о круассанах, природе и архитектуре. Сигнал от слова «Франции» затух, растворился в шуме новых данных. Модель с высокой вероятностью предскажет неверное слово.

    Попытки ремонта: LSTM и GRU

    Инженеры пытались спасти рекуррентные сети. Были созданы усложненные версии RNN, такие как LSTM (Long Short-Term Memory — долгая краткосрочная память) и GRU (Gated Recurrent Unit).

    Они добавили в архитектуру математические «вентили» (gates). Эти вентили работали как умные фильтры: они могли принимать решение: «Слово 'круассан' — это просто декорация, не будем записывать его на стикер, а вот слово 'Франция' — это важно, сохраним его в отдельный сейф памяти».

    LSTM действительно улучшили ситуацию. Модели смогли помнить контекст на протяжении 100–200 слов. Но фундаментальные проблемы остались:

  • Ограниченная емкость: Сейф памяти всё равно имел фиксированный размер.
  • Последовательность (отсутствие параллелизма): Чтобы прочитать 100-е слово, LSTM обязана была сначала прочитать предыдущие 99. Это делало обучение невыносимо медленным. Современные видеокарты (GPU) созданы для того, чтобы делать тысячи вычислений одновременно, но RNN заставляли их работать в однопоточном режиме, ожидая завершения каждого предыдущего шага.
  • Индустрии требовался радикально новый подход.

    Сдвиг парадигмы: Механизм внимания

    В 2017 году исследователи из Google опубликовали статью с провокационным названием «Attention Is All You Need» (Внимание — это всё, что вам нужно). Они предложили полностью отказаться от рекуррентных сетей и стикеров с краткой выжимкой.

    Вместо того чтобы пытаться запомнить весь прошлый текст в одном векторе, почему бы не дать модели доступ ко всем предыдущим словам одновременно, позволив ей самой решать, на какие слова обращать внимание прямо сейчас?

    Этот подход получил название Механизм внутреннего внимания (Self-Attention).

    Представьте детектива, расследующего сложное дело. Подход RNN — это чтение линейного отчета, где каждая новая страница заставляет забывать предыдущую. Подход Self-Attention — это пробковая доска на стене, к которой приколоты все улики, фотографии и показания свидетелей. Детектив стоит перед доской и протягивает красные нити между связанными фактами. Он видит всю картину целиком и одновременно.

    !Визуализация проблемы долгосрочной памяти и механизма внимания

    В механизме внимания каждое слово в предложении напрямую связывается с каждым другим словом. Расстояние между словами больше не имеет значения. Слово на 1-й позиции и слово на 1000-й позиции находятся на расстоянии всего одного математического шага друг от друга.

    Как слова понимают свой контекст

    Возьмем слово «замок». Вне контекста это просто набор букв.

  • В предложении «Старый замок возвышался над горой» — это строение.
  • В предложении «Дверной замок заклинило» — это механизм.
  • Механизм Self-Attention позволяет слову «замок» посмотреть на своих соседей, чтобы понять свою суть. В первом случае слово «замок» обратит сильное внимание на слова «старый», «возвышался» и «горой». Во втором случае — на «дверной» и «заклинило».

    В результате работы механизма внимания изначальное «пустое» слово обогащается контекстом. Оно превращается в сложный математический вектор, который содержит в себе не только словарное значение, но и смысл всего окружающего предложения.

    Математика внимания: Query, Key, Value

    Как именно нейросеть вычисляет, какие слова важны друг для друга? Для этого создатели Трансформеров позаимствовали концепцию из систем баз данных: Запрос (Query), Ключ (Key) и Значение (Value).

    Чтобы понять эту концепцию, представим поход в библиотеку:

  • Вы подходите к библиотекарю и говорите: «Мне нужна книга про квантовую физику для начинающих». Это ваш Query (Запрос) — то, что вы ищете.
  • Библиотекарь смотрит в каталог, где у каждой книги есть название, автор и теги. Это Keys (Ключи) — описания того, что содержится в книгах.
  • Библиотекарь сравнивает ваш Запрос с Ключами всех книг. Найдя лучшее совпадение, он выдает вам саму книгу. Текст внутри книги — это Value (Значение).
  • В механизме Self-Attention каждое слово в тексте одновременно играет все три роли. Для каждого слова нейросеть создает три вектора (массива чисел): вектор , вектор и вектор .

    Давайте разберем процесс пошагово на примере фразы: «Умная собака лает».

    Шаг 1. Формирование запросов и ключей Мы хотим понять контекст слова «лает». Слово «лает» формирует свой Запрос (): «Я глагол, обозначающий звук животного. Кто здесь может издавать этот звук?»

    Остальные слова выставляют свои Ключи ():

  • «Умная» выставляет ключ: «Я прилагательное, описываю интеллект».
  • «Собака» выставляет ключ: «Я существительное, животное, питомец».
  • Шаг 2. Вычисление оценок внимания (Attention Scores) Нейросеть берет Запрос слова «лает» и математически сравнивает его с Ключами всех слов в предложении (включая само себя). Сравнение происходит с помощью операции скалярного произведения векторов.

    Если векторы похожи (направлены в одну сторону), результат умножения будет большим числом. Если не похожи — маленьким или отрицательным.

    Допустим, мы получили следующие сырые оценки для слова «лает»:

  • Совпадение с «Умная»: 2
  • Совпадение с «собака»: 15
  • Совпадение с «лает» (с самим собой): 10
  • Шаг 3. Нормализация (Softmax) Сырые числа неудобны для работы. Нейросеть пропускает их через функцию Softmax, которая превращает их в проценты (веса), сумма которых всегда равна 100% (или 1.0).

    После Softmax веса внимания для слова «лает» могут выглядеть так:

  • На «Умная»: 0.01 (1%)
  • На «собака»: 0.85 (85%)
  • На «лает»: 0.14 (14%)
  • Шаг 4. Сборка итогового значения Теперь мы берем векторы Значений () всех слов и умножаем их на полученные проценты.

    Итоговый контекстный вектор для слова «лает» = (0.01 × ) + (0.85 × ) + (0.14 × )

    Слово «лает» впитало в себя 85% смысла слова «собака». Теперь нейросеть точно знает, кто именно издает звук в этом контексте.

    Главная формула Трансформеров

    Весь этот элегантный процесс описывается одной из самых важных формул в современном искусственном интеллекте:

    Разберем её элементы:

  • , , — матрицы Запросов, Ключей и Значений для всех слов сразу.
  • — скалярное произведение Запросов на Ключи (поиск совпадений, Шаг 2).
  • — математический стабилизатор. — это размерность вектора ключа. Деление на корень из этого числа не дает сырым оценкам стать слишком огромными, что сломало бы функцию Softmax.
  • — превращение оценок в проценты от 0 до 1 (Шаг 3).
  • Умножение на — сборка итоговых контекстных векторов (Шаг 4).
  • Триумф параллелизма

    Механизм внимания решил проблему долгосрочной памяти: расстояние между словами больше не приводило к потере информации. Но у Трансформеров оказалось еще одно, возможно, даже более важное преимущество.

    Посмотрите на формулу внимания еще раз. В ней нет зависимости от времени или предыдущего состояния .

    В RNN мы не могли обработать слово №50, пока не обработали слово №49. В Трансформерах матричное умножение вычисляет связи между всеми словами одновременно.

    Если у вас есть предложение из 1000 слов, Трансформер не читает его слово за словом. Он загружает все 1000 слов в память видеокарты и за одну гигантскую математическую операцию вычисляет миллион связей (1000 × 1000) между ними.

    Это свойство называется параллелизацией вычислений. Именно оно позволило исследователям начать обучать модели на терабайтах текста. То, на что у RNN ушли бы десятилетия, Трансформеры на кластерах GPU обрабатывают за недели.

    Переход от рекуррентных сетей к механизму внимания можно сравнить с переходом от конвейерной сборки, где каждый рабочий ждет деталь от предыдущего, к магии, где миллион рабочих одновременно собирают весь автомобиль за долю секунды. Этот архитектурный прорыв снял ограничения на размер контекста и скорость обучения, открыв двери в эру Больших Языковых Моделей.

    10. Сборка Энкодера (Encoder): Блок извлечения признаков

    Сборка Энкодера (Encoder): Блок извлечения признаков

    На предыдущих этапах мы разобрали Трансформер на мельчайшие детали. Мы изучили, как слова превращаются в числа (Embeddings), как они получают координаты в пространстве (Positional Encoding), как обмениваются смыслами (Self-Attention) и как нейросеть обрабатывает их индивидуально (Feed-Forward Networks). Мы также выяснили, как стабилизировать этот процесс с помощью остаточных связей и нормализации (Add & Norm).

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

    Роль Энкодера: От словаря к контексту

    Энкодер не генерирует новый текст. Его единственная цель — прочитать входные данные и создать для них идеальную математическую репрезентацию.

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

    На входе в Энкодер поступают статические векторы слов (эмбеддинги). В них слово «замок» всегда имеет одни и те же координаты, независимо от того, идет ли речь о средневековой крепости или о дверном механизме. На выходе Энкодер выдает контекстуализированные эмбеддинги. В них вектор слова «замок» кардинально меняется в зависимости от соседних слов.

    Анатомия одного блока Энкодера

    Энкодер состоит из одинаковых структурных единиц — слоев или блоков. Давайте проследим путь данных через один такой блок. Он состоит из двух главных подслоев (sub-layers).

    Подслой 1: Обмен информацией

    Сначала матрица входных токенов попадает в механизм многоголового внутреннего внимания (Multi-Head Self-Attention). Здесь токены «смотрят» друг на друга. Местоимение «он» выясняет, к какому существительному оно относится. Прилагательное «красный» связывается с объектом, который оно описывает. Модель параллельно вычисляет грамматические, семантические и логические связи с помощью разных «голов» внимания.

    Сразу после этого результат проходит через блок Add & Norm:

  • Add (Остаточная связь): К результату внимания прибавляется оригинальный входной вектор. Это гарантирует, что изначальный смысл слова не потеряется в процессе обмена контекстом.
  • Norm (Layer Normalization): Полученная сумма нормализуется, чтобы масштаб чисел не вышел из-под контроля.
  • Математически первый подслой выглядит так:

    Подслой 2: Индивидуальное осмысление

    Векторы, обогащенные контекстом других слов, поступают в полносвязную нейронную сеть (Feed-Forward Network, FFN). Если на предыдущем этапе токены общались между собой, то здесь каждый токен обрабатывается строго индивидуально. FFN работает как фильтр и банк памяти: она применяет нелинейные преобразования (например, функцию активации ReLU или GELU), чтобы выявить сложные паттерны и закрепить новые смыслы.

    Затем снова применяется блок Add & Norm:

    !Схема архитектуры одного блока Энкодера Трансформера

    > Блок Энкодера можно сравнить с рабочим днем в офисе. Сначала все сотрудники собираются на планерку, чтобы обменяться новостями и синхронизировать задачи (Self-Attention). Затем каждый возвращается за свой стол и индивидуально переваривает полученную информацию, выполняя свою часть работы (Feed-Forward Network).

    Зачем наслаивать Энкодеры?

    В оригинальной статье «Attention Is All You Need» Энкодер состоял из одинаковых блоков, поставленных друг на друга. В современных моделях их количество может достигать 96 и более.

    Почему одного блока недостаточно? Ответ кроется в концепции иерархического извлечения признаков (Hierarchical Feature Extraction).

    Один слой внимания способен уловить только прямые, очевидные связи между словами. Но человеческий язык устроен сложнее. Наслаивание блоков позволяет модели понимать текст на все более глубоких уровнях абстракции:

    * Нижние слои (1-2): Фокусируются на локальном синтаксисе. Они связывают соседние слова, определяют части речи (где существительное, а где глагол) и находят базовые словосочетания. * Средние слои (3-4): Начинают улавливать семантику. Они разрешают неоднозначности (тот самый «замок») и связывают местоимения с объектами через половину предложения. * Верхние слои (5-6+): Формируют прагматику и логику. Они понимают общую тональность текста, скрытый смысл, иронию и сложные причинно-следственные связи.

    Каждый следующий слой принимает на вход не оригинальные слова, а уже частично обработанные концепты от предыдущего слоя.

    Что получается на выходе?

    Важнейшее свойство Энкодера — он сохраняет размерность данных. Если на вход поступило предложение из 10 токенов, каждый из которых представлен вектором из 512 чисел, то на выходе из последнего (шестого) слоя мы получим ровно такую же матрицу размером .

    Разница заключается в качестве информации внутри этих чисел.

    | Характеристика | Входные данные (Embeddings) | Выходные данные Энкодера | | :--- | :--- | :--- | | Зависимость от контекста | Нулевая. Вектор слова берется из статического словаря. | Абсолютная. Вектор слова содержит информацию обо всем предложении. | | Уникальность | Слово «коса» всегда имеет один и тот же вектор. | Вектор слова «коса» (инструмент) и «коса» (прическа) кардинально отличаются. | | Информационная плотность | Содержит только базовый смысл самого слова. | Содержит смысл слова + его грамматическую роль + его отношение к другим токенам. |

    Эта финальная матрица — вершина понимания текста машиной. Она представляет собой идеальный слепок смысла, готовый для дальнейшего использования.

    Жизнь Энкодера вне генерации текста (BERT)

    Хотя Энкодер был придуман как часть системы машинного перевода (где он передавал свои знания Декодеру для генерации текста), исследователи быстро поняли, что этот блок обладает колоссальной самостоятельной ценностью.

    В 2018 году компания Google представила модель BERT (Bidirectional Encoder Representations from Transformers). Архитектурно BERT — это просто стопка Энкодеров (12 или 24 слоя), без Декодера вообще.

    Поскольку Энкодеру не нужно генерировать текст слово за словом, он может смотреть на предложение двунаправленно (bidirectional) — то есть каждый токен одновременно анализирует и левый, и правый контекст.

    Модели, состоящие только из Энкодера (семейство BERT), стали золотым стандартом для задач, где нужно понять текст, а не написать его:

  • Поисковые системы: Google использует BERT для понимания сложных поисковых запросов, где важен порядок слов и предлоги.
  • Классификация текстов: Определение тональности отзывов (позитивный/негативный), фильтрация спама.
  • Извлечение сущностей (NER): Поиск в тексте имен, названий компаний, дат и адресов.
  • Энкодер берет хаос человеческого языка и превращает его в строгую, математически выверенную структуру признаков. На следующем этапе мы рассмотрим вторую половину архитектуры — Декодер, который берет эту структуру и использует её для генерации осмысленного текста.

    11. Маскированное внимание (Masked Self-Attention): Предотвращение заглядывания в будущее

    Маскированное внимание (Masked Self-Attention): Предотвращение заглядывания в будущее

    В предыдущей статье мы собрали Энкодер — левую половину классического Трансформера. Его задача — прочитать весь текст целиком, проанализировать связи между словами во всех направлениях и создать идеальный математический слепок смысла. Энкодер видит текст как единую картину, где каждое слово знает о существовании всех остальных.

    Но когда мы переходим к генерации текста (задаче, которую выполняют современные LLM вроде GPT-4 или LLaMA), правила игры кардинально меняются. Модель не может видеть текст целиком, потому что этого текста еще не существует. Она должна создавать его шаг за шагом.

    Этот процесс называется авторегрессионной генерацией. Модель предсказывает следующее слово, опираясь только на те слова, которые уже были сгенерированы (или поданы на вход в качестве промпта).

    Чтобы обучить нейросеть такому последовательному мышлению, сохраняя при этом главное преимущество Трансформеров — параллельную обработку данных, — инженерам пришлось модифицировать базовый механизм внимания. Так появилось маскированное внутреннее внимание (Masked Self-Attention).

    Проблема «шпаргалки» при обучении

    Представьте, что вы учите ребенка писать сочинение. Вы даете ему начало фразы: «Утром я проснулся, умылся и пошел на...», и просите угадать следующее слово (например, «кухню» или «работу»). Ребенок должен использовать логику и контекст предыдущих слов.

    Обучение языковых моделей происходит похожим образом. У нас есть гигантские массивы готовых текстов. Мы берем предложение, например, «Кот сидит на пушистом коврике», и заставляем модель предсказывать каждое следующее слово:

  • Дано: [START] Предскажи: Кот
  • Дано: [START] Кот Предскажи: сидит
  • Дано: [START] Кот сидит Предскажи: на
  • Дано: [START] Кот сидит на Предскажи: пушистом
  • Если использовать для этой задачи рекуррентные нейросети (RNN), они будут обрабатывать слова именно так — строго по одному, медленно и печально.

    Трансформеры совершили революцию благодаря тому, что они обрабатывают всю последовательность целиком и параллельно. Во время обучения мы загружаем в модель сразу все предложение «Кот сидит на пушистом коврике».

    Но здесь возникает критическая проблема. Обычный механизм Self-Attention (который мы разбирали ранее) позволяет каждому токену обмениваться информацией со всеми остальными токенами в предложении. Если мы попросим модель предсказать слово, идущее после «сидит», механизм внимания позволит слову «сидит» заглянуть вперед и увидеть слова «на», «пушистом» и «коврике».

    > Это эквивалентно тому, чтобы дать студенту тест, где правильные ответы написаны прямо под вопросами. Студент (модель) не научится думать, он просто скопирует ответ. Нейросеть идеально выучит тренировочные данные, но полностью провалится в реальном мире, где будущего контекста нет.

    Нам нужен способ загружать в модель все слова одновременно (для скорости), но при этом математически запретить словам «смотреть» вправо, на будущие токены.

    Анатомия маски: Как спрятать будущее

    Решение этой проблемы кроется в элегантной математической операции, которая применяется внутри формулы внимания.

    Давайте вспомним базовую формулу Scaled Dot-Product Attention:

    Ключевой элемент здесь — матрица (результат умножения Запросов на Ключи). Это квадратная таблица, где строки — это слова, которые «спрашивают» (Запросы), а столбцы — слова, которые «отвечают» (Ключи). Числа в этой таблице показывают сырую силу связи между каждой парой слов.

    Для предложения из 4 слов («Кот сидит на коврике») матрица будет иметь размер . В обычном (двунаправленном) внимании матрица заполнена числами полностью.

    Чтобы превратить это в маскированное внимание, мы вводим дополнительный шаг перед применением функции Softmax. Мы накладываем на матрицу Look-Ahead Mask (маску заглядывания вперед).

    !Схема авторегрессионной генерации: модель предсказывает следующее слово на основе предыдущих

    Шаг 1: Создание маски

    Маска представляет собой такую же квадратную матрицу . Она разделена по диагонали: * Нижний левый треугольник (включая главную диагональ) заполнен нулями (). Это разрешенная зона — прошлое и настоящее. * Верхний правый треугольник заполнен отрицательной бесконечностью (). Это запретная зона — будущее.

    Шаг 2: Наложение маски

    Мы поэлементно складываем сырую матрицу с нашей маской.

    Там, где в маске стоят нули, оригинальные числа (оценки связи) остаются без изменений. Там, где стоит , любое число превращается в .

    Давайте посмотрим, как это выглядит для слова «сидит» (вторая строка матрицы): Связь с «Кот»* (прошлое): Связь с «сидит»* (настоящее): Связь с «на»* (будущее): Связь с «коврике»* (будущее):

    Шаг 3: Магия Softmax

    Почему мы используем именно минус бесконечность, а не просто умножаем запрещенные ячейки на ноль? Ответ кроется в том, как работает функция Softmax.

    Задача Softmax — превратить любые сырые числа в проценты (вероятности), сумма которых равна 100% (или 1.0). Формула Softmax использует экспоненту ().

    Если бы мы просто поставили в запрещенные ячейки, Softmax возвел бы и получил бы . Это означало бы, что запрещенное слово все равно получило бы какой-то вес внимания. Модель бы «подглядывала».

    Но математическое свойство экспоненты таково, что стремится к абсолютному, математическому нулю ().

    Когда Softmax обрабатывает строку с минус бесконечностями, эти ячейки получают ровно внимания. Оставшиеся 100% распределяются только между разрешенными словами (прошлым и настоящим).

    !Интерактивная матрица маскированного внимания

    Как это выглядит на практике

    После применения маски и Softmax, наша матрица весов внимания для фразы «Кот сидит на коврике» приобретает строгий треугольный вид:

    | Запрос (Слово) | Кот (Ключ) | сидит (Ключ) | на (Ключ) | коврике (Ключ) | | :--- | :--- | :--- | :--- | :--- | | Кот | 100% | 0% | 0% | 0% | | сидит | 40% | 60% | 0% | 0% | | на | 20% | 30% | 50% | 0% | | коврике | 10% | 20% | 30% | 40% |

    Давайте расшифруем эту таблицу: * Когда модель обрабатывает токен «Кот», она может использовать информацию только от самого слова «Кот». Будущее скрыто. Когда модель обрабатывает токен «сидит», она распределяет свое внимание между «Кот» (40%) и «сидит» (60%). Она понимает, кто сидит, но не знает, где*. * Когда модель доходит до «коврике», ей доступен весь предыдущий контекст. Только на этом этапе формируется полное понимание сцены.

    Благодаря этому трюку, мы можем загрузить в Трансформер текст из 4000 токенов и обучать модель предсказывать следующее слово для каждой из 4000 позиций одновременно, на видеокартах (GPU), не боясь, что модель сжульничает.

    Обучение (Training) против Использования (Inference)

    Важно понимать фундаментальную разницу в том, как маскированное внимание работает на разных этапах жизни LLM.

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

    На этапе использования (Inference / Генерация): Когда вы пишете запрос в ChatGPT, маска в ее классическом матричном виде фактически не нужна. Почему? Потому что будущего физически не существует.

    Когда модель сгенерировала слово «сидит», слов «на коврике» еще нет в памяти видеокарты. Модели просто некуда заглядывать. На этапе генерации Трансформер работает как классическая авторегрессионная модель: он берет текущий контекст, прогоняет его через слои внимания, предсказывает одно новое слово, добавляет его в конец контекста и повторяет цикл.

    > Чтобы не пересчитывать внимание для всех предыдущих слов на каждом шаге генерации (что было бы катастрофически медленно), современные LLM используют механизм KV Cache (Кэш Ключей и Значений), который мы упоминали в статье про многоголовое внимание. Модель просто запоминает векторы и для уже сгенерированных слов и вычисляет внимание только для самого нового токена.

    Место маскированного внимания в архитектуре

    В оригинальной архитектуре Трансформера (из статьи «Attention Is All You Need») маскированное внимание является первым подслоем в блоке Декодера.

    Декодер принимает на вход то, что он уже успел сгенерировать, пропускает это через Masked Multi-Head Attention, чтобы токены обменялись контекстом (не заглядывая в будущее), а затем передает результат в следующий слой, где сгенерированный текст будет сравниваться с информацией, полученной от Энкодера.

    Однако в современных генеративных моделях (таких как GPT-3, GPT-4, LLaMA, Claude) архитектура была упрощена. Инженеры полностью отказались от Энкодера.

    Современная LLM — это, по сути, просто стопка Декодеров, состоящих исключительно из слоев Маскированного Внимания и Полносвязных сетей (FFN). Вся магия ChatGPT, его способность писать код, сочинять стихи и вести диалог, базируется на этом строгом правиле: анализируй прошлое, чтобы предсказать будущее, шаг за шагом.

    12. Перекрестное внимание (Cross-Attention): Связь Энкодера и Декодера

    Перекрестное внимание (Cross-Attention): Связь Энкодера и Декодера

    В предыдущих статьях мы разобрали две изолированные вселенные. С одной стороны, у нас есть Энкодер (Encoder) с его двунаправленным внутренним вниманием, который читает текст целиком и создает идеальный математический слепок смысла. С другой стороны — Декодер (Decoder) с маскированным вниманием, который умеет генерировать текст шаг за шагом, опираясь только на прошлое.

    Но если мы решаем задачу перевода текста, суммаризации или ответов на вопросы, эти две вселенные должны как-то общаться. Декодер не может генерировать перевод из пустоты — ему нужно постоянно сверяться с оригинальным текстом, который прочитал Энкодер.

    Механизм, который служит мостом между пониманием (Энкодером) и генерацией (Декодером), называется перекрестным вниманием (Cross-Attention). Это архитектурное решение, которое позволило оригинальному Трансформеру совершить революцию в машинном переводе.

    Аналогия: Синхронный переводчик и докладчик

    Чтобы понять суть Cross-Attention, представим работу синхронного переводчика на международной конференции.

    Докладчик произносит фразу на французском языке: «Le chat noir dort sur la table» (Черный кот спит на столе).

  • Работа Энкодера: Мозг переводчика (Энкодер) слушает всю фразу, анализирует грамматику, связи между словами и формирует в памяти целостную смысловую картину.
  • Работа Декодера: Переводчик начинает говорить на английском. Он произносит первое слово: «The».
  • Перекрестное внимание: Чтобы произнести следующее слово, переводчик задает себе внутренний вопрос (Запрос): «Какое существительное шло после артикля в оригинальной фразе?». Он обращается к своей памяти о французской фразе (Ключи и Значения), находит слово «chat» (кот), понимает, что к нему относится прилагательное «noir» (черный), и генерирует английское слово «black».
  • В механизме Cross-Attention Декодер выступает в роли активного генератора вопросов, а Энкодер — в роли пассивной базы знаний, которая хранит контекст оригинального текста.

    Анатомия Cross-Attention: Разделение ролей

    Вспомним базовую концепцию механизма внимания. Он всегда оперирует тремя матрицами: Запросами (Query, Q), Ключами (Key, K) и Значениями (Value, V).

    В обычном Self-Attention (внутреннем внимании) все три матрицы создаются из одного и того же источника — текущего предложения. Слова ищут связи между собой.

    В Cross-Attention источники матриц разделяются:

    Запросы (Q) приходят из Декодера. Это текущее состояние генерируемого текста. Декодер как бы говорит: «Я только что сгенерировал слово 'The', что мне нужно перевести дальше?»*. Ключи (K) и Значения (V) приходят из Энкодера. Это финальный выходной вектор Энкодера, содержащий глубоко переработанный смысл исходного текста. Энкодер отвечает: «Вот все слова оригинала и их смысловые связи, ищи совпадения»*.

    !Схема перекрестного внимания: Запросы идут от Декодера, а Ключи и Значения от Энкодера

    Математика моста

    Математическая формула перекрестного внимания абсолютно идентична классическому Scaled Dot-Product Attention, меняются только индексы происхождения данных:

    Где: * — матрица Запросов от Декодера. * — матрица Ключей от Энкодера. * — матрица Значений от Энкодера. * — размерность вектора Ключа (используется для масштабирования).

    Давайте разберем процесс пошагово на примере перевода фразы «Le chat noir» «The black cat».

  • Подготовка базы знаний: Энкодер обрабатывает «Le chat noir» и выдает матрицы и . Они остаются неизменными на протяжении всей генерации перевода.
  • Генерация первого слова: Декодер получает стартовый токен [START]. Он формирует из него Запрос и умножает его на Ключи Энкодера ().
  • Распределение внимания: Функция Softmax превращает результаты умножения в проценты. Декодер понимает, что для начала фразы нужно обратить 90% внимания на французское слово «Le».
  • Извлечение смысла: Веса внимания умножаются на Значения (). Декодер получает вектор, содержащий смысл слова «Le», и генерирует английское «The».
  • Следующий шаг: На следующем цикле Декодер берет уже сгенерированное «The», формирует новый Запрос . При умножении на Ключи Энкодера максимальный вес внимания (например, 85%) получает слово «noir» (потому что в английском прилагательное идет перед существительным). Декодер генерирует «black».
  • !Интерактивная матрица весов перекрестного внимания при переводе

    > Важное свойство: В Cross-Attention не используется маскирование будущего (Look-Ahead Mask). Декодеру разрешено и даже необходимо видеть весь оригинальный текст Энкодера целиком. Маскирование применяется только во внутреннем внимании самого Декодера, чтобы он не видел свои собственные будущие сгенерированные слова.

    Сравнение механизмов внимания

    Чтобы окончательно структурировать знания, сравним три типа внимания, которые используются в классическом Трансформере:

    | Характеристика | Self-Attention (Энкодер) | Masked Self-Attention (Декодер) | Cross-Attention (Связь) | | :--- | :--- | :--- | :--- | | Источник Q | Входной текст | Сгенерированный текст | Сгенерированный текст (Декодер) | | Источник K, V | Входной текст | Сгенерированный текст | Исходный текст (Энкодер) | | Маскирование будущего | Нет (видит весь текст) | Да (видит только прошлое) | Нет (видит весь исходный текст) | | Главная задача | Понять контекст оригинала | Связать сгенерированные слова | Найти нужную информацию в оригинале |

    Эволюция: Куда исчез Cross-Attention в современных LLM?

    Если вы посмотрите на архитектуру современных текстовых гигантов вроде GPT-4, LLaMA или Claude, вы обнаружите удивительный факт: в них нет Энкодера, а значит, нет и классического Cross-Attention.

    Оригинальный Трансформер создавался для задачи перевода (Sequence-to-Sequence), где есть четкое разделение на «исходный текст» и «результат». Но современные LLM работают по принципу продолжения текста (Text Continuation).

    Инженеры OpenAI (создатели архитектуры GPT — Generative Pre-trained Transformer) поняли, что можно упростить архитектуру, оставив только Декодер.

    Как же GPT понимает промпт пользователя без Энкодера и Cross-Attention?

    Модель просто склеивает ваш промпт и свой ответ в одну длинную строку. Если вы пишете: «Переведи на английский: кот», модель видит это как единую последовательность: [Переведи] [на] [английский:] [кот] [->] [cat].

    Вместо того чтобы перекидывать информацию из Энкодера в Декодер через Cross-Attention, GPT использует обычное маскированное внутреннее внимание (Masked Self-Attention) ко всей этой строке. Когда модель генерирует слово «cat», ее механизм внимания просто оглядывается назад на токены промпта, которые уже находятся в ее контекстном окне.

    Отказ от Энкодера и Cross-Attention сделал архитектуру однородной, что радикально упростило масштабирование моделей и их обучение на тысячах GPU.

    Возрождение Cross-Attention: Мультимодальность

    Означает ли это, что Cross-Attention устарел? Абсолютно нет. Он переживает второе рождение в мультимодальных нейросетях — моделях, которые работают с разными типами данных одновременно (текст, аудио, изображения).

    Когда данные имеют принципиально разную природу, их нельзя просто «склеить» в одну строку, как это делает GPT с текстом. Здесь классическая архитектура Энкодер-Декодер с перекрестным вниманием становится незаменимой.

    Пример 1: Распознавание речи (Whisper)

    Модель Whisper от OpenAI переводит аудио в текст. * Аудио-Энкодер слушает звуковую волну и превращает ее в векторы (Ключи и Значения), представляющие фонемы и интонации. * Текстовый Декодер генерирует слова (Запросы). * Cross-Attention позволяет Декодеру на каждом шаге генерации текста фокусироваться на конкретном миллисекундном отрезке звуковой волны.

    Пример 2: Генерация изображений (Stable Diffusion / Midjourney)

    Когда вы пишете промпт «Киберпанк город под дождем», работает обратный процесс: * Текстовый Энкодер (часто это модель CLIP) читает ваш промпт и создает векторы смысла (Ключи и Значения). * Декодер изображений (U-Net или Diffusion Transformer) начинает рисовать пиксели из шума. На каждом этапе отрисовки он отправляет Запросы. Cross-Attention гарантирует, что когда Декодер рисует капли воды, он смотрит на вектор слова «дождь» из Энкодера, а когда рисует неоновые вывески — на вектор слова «киберпанк»*.

    Таким образом, Cross-Attention — это универсальный математический интерфейс. Это способ заставить одну нейросеть (или часть нейросети) задавать точные вопросы другой нейросети и получать взвешенные, контекстно-зависимые ответы, независимо от того, на каком «языке» (текст, звук, пиксели) они изначально говорили.

    13. Сборка Декодера (Decoder): Блок авторегрессионной генерации

    Сборка Декодера (Decoder): Блок авторегрессионной генерации

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

    Теперь пришло время собрать вторую половину оригинального Трансформера — Декодер (Decoder). Если Энкодер — это читатель, то Декодер — это «писатель». Именно этот блок отвечает за создание нового текста, и именно его эволюция привела к появлению современных Больших Языковых Моделей (LLM), таких как GPT-4, Claude и LLaMA.

    Суть авторегрессии: Шаг за шагом

    Главная особенность Декодера заключается в том, что он работает по принципу авторегрессии (Autoregression).

    В статистике и машинном обучении авторегрессионная модель — это модель, которая предсказывает будущее значение на основе своих же прошлых предсказаний. В контексте генерации текста это означает простое, но строгое правило: модель генерирует текст строго по одному токену (слову) за раз, слева направо.

    Математически это выражается через условную вероятность:

    Где: * — вероятность появления конкретного слова. * — токен, который модель должна сгенерировать на текущем шаге . — все токены, которые модель уже* сгенерировала на предыдущих шагах. * — исходный контекст (например, промпт пользователя или выход Энкодера).

    > Авторегрессия похожа на движение по темному коридору с фонариком. Вы делаете шаг (генерируете слово), освещаете пространство чуть дальше, оцениваете новую обстановку с учетом сделанного шага, и только потом делаете следующий. Вы не можете сделать пятый шаг, не сделав первые четыре.

    Если мы хотим сгенерировать фразу «Кот спит на столе», процесс выглядит так:

  • Вход: [START] Выход: «Кот»
  • Вход: [START] Кот Выход: «спит»
  • Вход: [START] Кот спит Выход: «на»
  • Вход: [START] Кот спит на Выход: «столе»
  • Вход: [START] Кот спит на столе Выход: [END]
  • Этот процесс продолжается до тех пор, пока Декодер не сгенерирует специальный токен остановки [END] (или [EOS]End of Sequence), сигнализирующий о завершении мысли.

    Анатомия классического блока Декодера

    Давайте заглянем внутрь одного слоя Декодера в классической архитектуре (например, в модели для перевода). Он очень похож на блок Энкодера, но имеет три существенных отличия, продиктованных необходимостью генерировать текст.

    !Схема архитектуры блока Декодера с тремя подслоями: маскированное внимание, перекрестное внимание и полносвязная сеть

    Пайплайн обработки данных внутри одного блока Декодера состоит из трех подслоев:

    1. Маскированное внутреннее внимание (Masked Multi-Head Self-Attention)

    Как мы помним из предыдущих статей, во время обучения Трансформер обрабатывает всю последовательность параллельно. Но если мы дадим Декодеру фразу «Кот спит на столе» целиком, он сможет «подсмотреть» будущее слово «спит» при попытке предсказать его после слова «Кот».

    Чтобы предотвратить это читерство, используется маскирование. На верхний правый треугольник матрицы весов внимания накладывается маска из минус бесконечностей (). После применения функции Softmax эти значения превращаются в строгие нули.

    В результате каждое слово в Декодере может обращать внимание (вычислять связи) только на себя и на слова, стоящие слева от него. Прошлое известно, будущее скрыто.

    2. Перекрестное внимание (Cross-Attention)

    Сразу после маскированного внимания идет слой связи с Энкодером.

    Сгенерированный на данный момент текст (выход из предыдущего подслоя) выступает в роли Запросов (Query). Декодер спрашивает: «Учитывая то, что я уже сказал, на что мне нужно обратить внимание в оригинальном тексте?».

    Оригинальный текст, обработанный Энкодером, предоставляется в виде Ключей (Key) и Значений (Value). Здесь маскирование не применяется — Декодер имеет право видеть весь исходный текст целиком, чтобы сделать правильный перевод или выжимку.

    3. Полносвязная нейронная сеть (Feed-Forward Network)

    Как и в Энкодере, после обмена контекстом каждый токен проходит через индивидуальную полносвязную сеть (FFN). Здесь происходит нелинейная трансформация вектора: модель применяет усвоенные во время обучения факты, правила грамматики и логику.

    Каждый из этих трех подслоев обернут в механизм остаточных связей (Residual Connections) и нормализации (Layer Normalization) — блок Add & Norm, который предотвращает затухание градиента и стабилизирует обучение.

    Финальный аккорд: От векторов к словам

    Представим, что наш токен прошел через 6, 12 или даже 96 таких блоков Декодера (как в GPT-3). На выходе из последнего слоя мы получаем плотный вектор чисел (например, размерностью 4096).

    Но пользователю нужны слова, а не векторы. Как Декодер переводит математику обратно в человеческий язык? Для этого используется финальный блок, состоящий из линейного слоя и функции Softmax.

    Линейная проекция (Linear Layer)

    Задача линейного слоя — растянуть наш вектор размерности 4096 до размера всего словаря модели. Если словарь модели содержит 50 000 уникальных токенов, линейный слой превращает вектор [1 × 4096] в вектор [1 × 50 000].

    Каждое число в этом огромном векторе (они называются логитамиlogits) представляет собой «сырую» оценку того, насколько сильно модель хочет выбрать соответствующее слово из словаря.

    Преобразование в вероятности (Softmax)

    Сырые логиты могут быть любыми числами: 15.2, -3.8, 114.1. Чтобы превратить их в понятные проценты, применяется функция Softmax.

    Где: * — логит конкретного слова. * — размер словаря. * — экспонента (основание натурального логарифма).

    Softmax делает две вещи: избавляется от отрицательных значений (экспонента всегда положительна) и нормализует сумму всех значений до 1 (или 100%).

    Пример распределения вероятностей на выходе: * «столе» 85% * «ковре» 10% * «диване» 4% * «сингулярности» 0.0001%

    Модель выбирает слово с наибольшей вероятностью (или использует алгоритмы сэмплирования для разнообразия, о которых мы поговорим в будущих статьях), выводит его пользователю, и... цикл начинается заново.

    Проблема производительности: Зачем нужен KV Cache

    Если вы внимательно следили за процессом авторегрессии, вы могли заметить огромную вычислительную проблему на этапе генерации (Inference).

    Допустим, мы сгенерировали 1000 слов и хотим сгенерировать 1001-е. По правилам авторегрессии, мы должны подать на вход Декодера все 1000 слов. Декодер прогонит их через все слои внимания. Но постойте! Векторы для первых 999 слов уже были вычислены на предыдущих шагах. Зачем нам заново вычислять их Ключи (Keys) и Значения (Values) для механизма внимания?

    Пересчет всего контекста на каждом шаге делает генерацию длинных текстов невыносимо медленной. Сложность растет квадратично с каждым новым словом.

    Решение этой проблемы — KV Cache (Кэш Ключей и Значений).

    !Интерактивная визуализация работы авторегрессии и заполнения KV Cache шаг за шагом

    Вместо того чтобы пересчитывать всё заново, современные LLM сохраняют в оперативную память (VRAM видеокарты) матрицы Ключей () и Значений () для каждого уже обработанного токена на каждом слое.

    Когда приходит время сгенерировать 1001-е слово:

  • На вход подается только одно новое (1000-е) слово.
  • Для него вычисляется Запрос (), Ключ () и Значение ().
  • Его и добавляются в сохраненный KV Cache.
  • Его Запрос () умножается на весь исторический KV Cache, чтобы понять контекст.
  • Генерируется новое слово.
  • > Практический нюанс: KV Cache — это главная причина, почему LLM требуют так много видеопамяти. Если сама модель (веса) занимает 16 ГБ, то при генерации текста с контекстом в 32 000 токенов для нескольких пользователей одновременно, размер KV Cache может легко превысить размер самой модели и потребовать дополнительных десятков гигабайт памяти.

    Обучение vs Генерация (Training vs Inference)

    Важно четко понимать разницу в том, как Декодер работает в лаборатории (при обучении) и в реальном мире (при генерации).

    | Характеристика | Обучение (Training) | Генерация (Inference) | | :--- | :--- | :--- | | Входные данные | Весь текст подается целиком (параллельно) | Текст подается по одному токену (последовательно) | | Маскирование | Критически важно (чтобы не видеть будущее) | Не нужно (будущего еще физически не существует) | | Скорость | Очень высокая (благодаря матричным вычислениям на GPU) | Относительно низкая (ограничена авторегрессией) | | KV Cache | Не используется | Жизненно необходим для скорости | | Ошибки | Используется Teacher Forcing (модели всегда дают правильный контекст, даже если она ошиблась на прошлом шаге) | Ошибка накапливается (если модель сгенерировала бред, она будет опираться на него дальше) |

    Эволюция: Переход к Decoder-Only архитектуре (GPT)

    Классический Трансформер, который мы только что собрали, состоял из Энкодера и Декодера. Эта архитектура идеально подходит для задач Sequence-to-Sequence (последовательность в последовательность), таких как машинный перевод.

    Но в 2018 году исследователи из OpenAI задались вопросом: а нужен ли нам Энкодер вообще, если мы хотим создать универсальную языковую модель?

    Они создали архитектуру GPT (Generative Pre-trained Transformer), которая совершила революцию, отбросив половину оригинального дизайна. GPT — это модель Decoder-Only (только Декодер).

    Как GPT работает без Энкодера?

    Вместо того чтобы разделять текст на «исходный» (для Энкодера) и «целевой» (для Декодера), GPT объединяет их в одну непрерывную последовательность.

    Если вы даете промпт: «Столица Франции — это», модель воспринимает это просто как начало текста, который нужно продолжить.

    Поскольку Энкодера больше нет, из архитектуры Декодера полностью удаляется слой перекрестного внимания (Cross-Attention). Остается только маскированное внутреннее внимание (Masked Self-Attention) и полносвязные сети (FFN).

    Преимущества подхода Decoder-Only:

  • Однородность: Архитектура стала проще. Нет сложных мостов между двумя разными блоками.
  • Масштабируемость: Простую архитектуру гораздо легче масштабировать. Можно просто добавлять больше слоев и увеличивать размерность векторов. Именно так появились гиганты вроде GPT-3 и GPT-4.
  • Универсальность: Оказалось, что если обучить огромный Декодер предсказывать следующее слово на терабайтах текста из интернета, он автоматически учится переводить языки, писать код, решать логические задачи и отвечать на вопросы. Ему не нужна специализированная архитектура для каждой задачи.
  • Сегодня подавляющее большинство текстовых LLM (семейства GPT, LLaMA, Mistral, Qwen) используют именно архитектуру Decoder-Only. Классическая связка Энкодер-Декодер (как в модели T5) или чистые Энкодеры (как BERT) используются для более узких специфических задач.

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

    14. Семейство Encoder-only: Как работает архитектура BERT

    Семейство Encoder-only: Как работает архитектура BERT

    В предыдущей статье мы собрали Декодер и увидели, как архитектура Decoder-only (на примере семейства GPT) совершила революцию в генерации текста. Декодер работает по принципу авторегрессии: он читает текст слева направо и предсказывает следующее слово, опираясь только на прошлое. Это делает его идеальным «писателем».

    Но что, если наша задача — не написать новый текст, а глубоко понять уже существующий? Например, определить тональность отзыва, найти в договоре имена и суммы или понять, отвечает ли абзац на заданный вопрос. Для таких задач авторегрессия (чтение строго слева направо) становится искусственным ограничением.

    Чтобы понять смысл слова в предложении, нам часто нужно знать не только то, что было до него, но и то, что идет после.

    Сила двунаправленного контекста

    Представьте, что вы читаете предложение по одному слову, закрывая остальную часть листа бумаги. Вы видите слово: «Коса».

    Что оно означает? Это сельскохозяйственный инструмент? Прическа? Или песчаная отмель в море? Имея только одно слово, ответить невозможно.

    Теперь добавим левый контекст (как это делает GPT): «Девушка заплела длинную косу».

    Смысл стал понятен. Но что, если предложение построено иначе? «Острая коса...»

    Мы все еще не знаем точного значения. Это может быть «Острая коса легко срезала траву» (инструмент) или «Острая коса врезалась в море» (география). Только прочитав слова, идущие после целевого слова, мы можем однозначно определить его смысл.

    Именно эту проблему решает BERT (Bidirectional Encoder Representations from Transformers) — модель, представленная исследователями Google в 2018 году. BERT относится к семейству Encoder-only (только Энкодер).

    В отличие от Декодера, в Энкодере нет маскирования будущего. Механизм внутреннего внимания (Self-Attention) позволяет каждому слову устанавливать связи со всеми остальными словами в предложении одновременно — как слева, так и справа.

    Архитектура: Возвращение к истокам

    С точки зрения архитектуры, BERT — это просто стопка блоков Энкодера, которые мы подробно разбирали ранее.

    Пайплайн обработки внутри BERT выглядит так:

  • Текст разбивается на токены и превращается во входные векторы (Embeddings).
  • К векторам добавляется позиционное кодирование (Positional Encoding), чтобы модель знала порядок слов.
  • Данные проходят через слоев Энкодера (в базовой версии BERT их 12, в большой — 24).
  • Внутри каждого слоя работает Multi-Head Self-Attention, где каждое слово обменивается информацией со всем предложением целиком.
  • Затем каждый вектор проходит через полносвязную сеть (FFN).
  • На выходе мы получаем векторы той же размерности, что и на входе, но теперь они содержат глубокий, двунаправленный контекст всего предложения.
  • !Схема двунаправленного внимания в BERT при решении задачи Masked Language Modeling.

    Но если архитектура так проста и известна, в чем заключался прорыв BERT? Секрет кроется не в строении нейросети, а в том, как именно ее обучали.

    Проблема обучения: Как не дать модели списать?

    Языковые модели обучаются на огромных массивах текста из интернета. Декодеры (GPT) обучать легко: мы просто просим модель предсказать следующее слово. Поскольку Декодер не видит будущего (из-за маски в матрице внимания), он вынужден честно угадывать.

    Но Энкодер видит всё предложение сразу. Если мы попросим Энкодер предсказать слово «срезала» в предложении «Острая коса срезала траву», он просто посмотрит на это же слово в своих входных данных. Это как дать студенту тест, где ответы написаны прямо в вопросах. Модель мгновенно достигнет 100% точности, ничему не научившись.

    Чтобы заставить двунаправленную модель учиться, создатели BERT придумали гениальный подход, состоящий из двух задач предварительного обучения (Pre-training).

    Задача 1: Masked Language Modeling (MLM)

    Вместо того чтобы предсказывать следующее слово, BERT решает задачу заполнения пропусков. Это похоже на школьный тест, где в тексте замазаны некоторые слова (Cloze test).

    Алгоритм MLM работает следующим образом:

  • Модель берет реальное предложение из обучающего корпуса.
  • Случайным образом выбирается токенов в предложении.
  • Выбранные токены заменяются на специальный токен [MASK].
  • Задача модели — проанализировать контекст вокруг маски (слева и справа) и предсказать, какое оригинальное слово там находилось.
  • > Пример: > Исходный текст: «Мужчина зашел в магазин, чтобы купить хлеб и молоко.» > Вход для BERT: «Мужчина зашел в [MASK], чтобы купить хлеб и [MASK]

    Поскольку модель не видит самих слов под маской, ей приходится глубоко анализировать грамматику и семантику окружающих слов, чтобы сделать правильное предсказание.

    !Интерактивная симуляция Masked Language Modeling (MLM) — посмотрите, как контекст слева и справа влияет на предсказание скрытого слова.

    #### Хитрый нюанс с маскированием Если всегда заменять слов на [MASK], возникнет проблема: при реальном использовании (после обучения) модель никогда не увидит токен [MASK], так как пользователи отправляют обычный текст. Это создаст несоответствие между условиями обучения и реальной работой.

    Чтобы решить это, создатели BERT добавили элемент неопределенности. Из тех слов, которые выбраны для изменения: * В случаев слово заменяется на [MASK] (стандартное поведение). В случаев слово заменяется на случайное слово из словаря (например, «Мужчина зашел в яблоко...»*). Это заставляет модель всегда быть начеку и проверять, подходит ли текущее слово по смыслу, или это ошибка, которую нужно исправить. * В оставшихся случаев слово остается без изменений. Это показывает модели, что иногда входные данные уже правильные, и нужно просто подтвердить их.

    Задача 2: Next Sentence Prediction (NSP)

    Понимания отдельных предложений недостаточно. Многие задачи (например, ответы на вопросы) требуют понимания логической связи между разными предложениями.

    Для этого BERT обучали второй задаче — предсказанию следующего предложения (NSP). Модели дают два предложения (A и B) и спрашивают: является ли предложение B логичным продолжением предложения A в оригинальном тексте?

    Для этой задачи были введены два новых специальных токена: * [SEP] (Separator) — разделитель, который ставится между двумя предложениями. * [CLS] (Classification) — токен, который всегда ставится в самое начало входных данных.

    Формат входа выглядит так: [CLS] Предложение A [SEP] Предложение B [SEP]

    Обучающая выборка формируется так: * В случаев предложение B действительно идет сразу после A (метка IsNext). * В случаев предложение B берется случайно из другого документа (метка NotNext).

    Роль токена [CLS]: Поскольку механизм внимания позволяет каждому токену смотреть на все остальные, вектор токена [CLS] на самом последнем слое нейросети впитывает в себя смысл всей последовательности целиком. Именно этот вектор используется для бинарной классификации (Да/Нет) в задаче NSP.

    Тонкая настройка (Fine-Tuning): Как использовать BERT

    После того как BERT прошел предварительное обучение (Pre-training) на миллиардах слов, решая задачи MLM и NSP, он становится экспертом в понимании языка. Но сам по себе он не умеет решать конкретные бизнес-задачи.

    Чтобы заставить BERT делать то, что нам нужно, применяется тонкая настройка (Fine-Tuning). Это процесс дообучения модели на небольшом размеченном датасете под конкретную задачу.

    Прелесть BERT в том, что для большинства задач достаточно добавить всего один простой линейный слой поверх готовой архитектуры.

    Сценарий 1: Классификация текста (Анализ тональности)

    Задача: определить, позитивный или негативный отзыв оставил клиент.
  • Подаем текст в BERT: [CLS] Отличный телефон, батарея держит долго! [SEP]
  • Прогоняем через все слои Энкодера.
  • Берем вектор, соответствующий токену [CLS] на самом верхнем слое (он содержит агрегированный смысл всего отзыва).
  • Пропускаем этот вектор через простой слой классификации, который выдает вероятность: позитив, негатив.
  • Сценарий 2: Распознавание именованных сущностей (NER)

    Задача: найти в тексте имена людей, названия компаний и локации.
  • Подаем текст: [CLS] Илон Маск купил акции Twitter [SEP]
  • Прогоняем через BERT.
  • Здесь нам нужен не общий смысл, а понимание каждого отдельного слова. Поэтому мы берем выходные векторы каждого токена.
  • Каждый вектор пропускается через классификатор, который присваивает ярлык: «Илон» (Персона), «Маск» (Персона), «купил» (Обычное слово), «Twitter» (Организация).
  • Сравнение парадигм: BERT против GPT

    Чтобы окончательно закрепить понимание, давайте сравним две главные архитектуры современных языковых моделей.

    | Характеристика | Семейство BERT (Encoder-only) | Семейство GPT (Decoder-only) | | :--- | :--- | :--- | | Архитектура | Только Энкодер | Только Декодер | | Механизм внимания | Двунаправленный (видит всё) | Однонаправленный (маскирует будущее) | | Главная задача обучения | Заполнение пропусков (MLM) | Предсказание следующего слова (Авторегрессия) | | Сильные стороны | Понимание контекста, классификация, поиск, извлечение фактов | Генерация связного текста, диалоги, написание кода | | Аналогия из жизни | Внимательный аналитик / Читатель | Креативный писатель / Оратор |

    Эволюция и наследие BERT

    После выхода оригинального BERT в 2018 году, исследовательское сообщество начало активно улучшать архитектуру, создав целое семейство моделей:

    * RoBERTa (от Facebook/Meta): Исследователи поняли, что оригинальный BERT был недообучен. Они убрали задачу NSP (оказалось, она не так полезна), увеличили объем данных и время обучения, получив значительный прирост качества. * ALBERT (A Lite BERT): Оптимизированная версия, которая использует общие веса для всех слоев Энкодера, что радикально уменьшает размер модели в памяти при сохранении высокой точности. * DistilBERT: Уменьшенная версия, созданная методом дистилляции знаний. Она на меньше и на быстрее оригинала, но сохраняет его понимания языка.

    Сегодня, в эпоху доминирования генеративных моделей (ChatGPT, Claude), может показаться, что модели класса BERT устарели. Но это иллюзия.

    В то время как GPT пишет для вас стихи и код, именно модели архитектуры Encoder-only работают под капотом поисковых систем (включая Google Search), анализируют миллионы банковских транзакций, фильтруют спам и маршрутизируют обращения в службу поддержки. Там, где требуется мгновенное, дешевое и абсолютно точное понимание текста без необходимости его генерировать, BERT и его потомки остаются непревзойденным стандартом индустрии.

    15. Семейство Decoder-only: Фундамент архитектуры GPT

    Семейство Decoder-only: Фундамент архитектуры GPT

    В предыдущей статье мы разобрали архитектуру BERT, которая опирается исключительно на Энкодер. BERT читает текст в обоих направлениях одновременно, что делает его великолепным аналитиком, способным извлекать факты, определять тональность и классифицировать документы. Однако двунаправленность имеет свою цену: BERT не умеет писать. Он может заполнить пропуск в середине предложения, но не способен сгенерировать связный рассказ с нуля.

    Если наша цель — создание искусственного интеллекта, способного вести диалог, писать код, сочинять стихи и рассуждать шаг за шагом, нам нужен принципиально иной подход. Нам нужен «писатель», а не «читатель».

    Именно эту задачу решает семейство моделей GPT (Generative Pre-trained Transformer), созданное компанией OpenAI. В основе GPT лежит архитектура Decoder-only (только Декодер). Эта архитектура отказалась от Энкодера и перекрестного внимания, сделав ставку на один фундаментальный принцип — предсказание следующего слова.

    Авторегрессия: Искусство предсказания будущего

    Главный принцип работы Декодера называется авторегрессией. Это процесс пошаговой генерации данных, где каждый новый шаг опирается на результаты всех предыдущих шагов.

    В контексте языковых моделей авторегрессия означает, что модель читает последовательность слов слева направо и пытается угадать, какое слово будет следующим. Сгенерировав новое слово, модель добавляет его к исходному тексту и повторяет процесс снова и снова.

    Математически задача языковой модели сводится к вычислению условной вероятности следующего токена при условии всех предыдущих токенов от до :

    Где — вероятность, — целевой токен (слово), а — уже известный контекст.

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

    Цикл генерации текста выглядит так:

  • Вход: «Утром я налил в чашку горячий»
  • Модель предсказывает: «кофе»
  • Новый вход: «Утром я налил в чашку горячий кофе»
  • Модель предсказывает: «и»
  • Новый вход: «Утром я налил в чашку горячий кофе и»
  • Этот цикл продолжается до тех пор, пока модель не сгенерирует специальный токен остановки [EOS] (End of Sequence) или не достигнет лимита длины.

    Анатомия блока Decoder-only

    Давайте заглянем под капот GPT и посмотрим, как устроен один слой этой нейросети. Если вы помните классическую архитектуру Transformer (с Энкодером и Декодером), то заметите, что архитектура Decoder-only выглядит как ее упрощенная версия.

    !Схема архитектуры Decoder-only: данные проходят через маскированное внимание, затем через полносвязную сеть, с применением остаточных связей на каждом этапе.

    Пайплайн обработки внутри одного блока GPT состоит из следующих этапов:

    1. Входные данные: Эмбеддинги и Позиции

    Как и в любой языковой модели, текст сначала разбивается на токены. Каждый токен превращается в плотный вектор чисел (Embedding). Поскольку Трансформер обрабатывает данные параллельно, к каждому вектору прибавляется позиционное кодирование (Positional Encoding), чтобы модель знала, на каком месте стоит слово.

    2. Маскированное внутреннее внимание (Masked Multi-Head Self-Attention)

    Это сердце Декодера. В отличие от Энкодера, который позволяет словам смотреть в обе стороны, Декодер строго ограничен направлением времени (слева направо).

    Чтобы реализовать это ограничение, используется маска. При вычислении матрицы внимания (когда Запросы умножаются на Ключи), все ячейки, соответствующие будущим токенам, заполняются значением (минус бесконечность).

    Когда к этой матрице применяется функция Softmax (превращающая сырые числа в проценты от до ), превращается в абсолютный . Таким образом, вес внимания текущего слова к любому будущему слову становится равен нулю. Модель физически не может «подсмотреть» вперед.

    3. Остаточная связь и Нормализация (Add & Norm)

    Вектор, вышедший из слоя внимания, складывается с оригинальным входным вектором (Residual Connection). Это создает «скоростное шоссе» для градиентов, предотвращая их затухание при обучении глубоких сетей. Затем результат нормализуется (Layer Normalization), чтобы стабилизировать значения чисел и ускорить обучение.

    4. Полносвязная нейросеть (Feed-Forward Network)

    Далее каждый вектор обрабатывается индивидуально. Механизм внимания собрал контекст (связи между словами), а слой FFN работает как «банк памяти». Он пропускает вектор через нелинейные функции активации (например, GELU), извлекая сложные паттерны и факты, заложенные в весах модели.

    5. Снова Add & Norm

    Процесс завершается еще одной остаточной связью и нормализацией.

    В современных моделях (GPT-3, LLaMA) таких блоков может быть 96 и более, поставленных друг на друга. Вектор проходит сквозь них, становясь все более абстрактным и контекстуально богатым, пока на самом верхнем слое не превратится в распределение вероятностей для следующего слова.

    Куда исчезло перекрестное внимание (Cross-Attention)?

    В оригинальной статье «Attention Is All You Need» Декодер имел дополнительный слой — Cross-Attention. В этом слое Декодер генерировал Запросы (Query), а Ключи (Key) и Значения (Value) приходили из Энкодера. Это было необходимо для задачи машинного перевода: Энкодер читал текст на английском, а Декодер писал на французском, постоянно «оглядываясь» на английский оригинал.

    Создатели GPT задались вопросом: а нужен ли нам Энкодер вообще?

    Оказалось, что если объединить исходный текст (промпт) и генерируемый текст (ответ) в одну непрерывную последовательность, то слой Cross-Attention становится лишним.

    > Смена парадигмы: > Вместо того чтобы передавать вопрос в Энкодер, а ответ генерировать в Декодере, мы просто подаем вопрос в Декодер и заставляем его продолжить текст.

    Например, задача перевода в парадигме Decoder-only выглядит так: Вход (Промпт): Translate to French: Hello world => Генерация: Bonjour le monde

    Модель обрабатывает промпт с помощью обычного маскированного Self-Attention. Каждое новое генерируемое слово просто смотрит на все предыдущие слова (включая сам промпт), используя один и тот же механизм. Это радикально упростило архитектуру, сделав ее однородной и легко масштабируемой.

    Обучение против Генерации (Teacher Forcing)

    Важно понимать фундаментальную разницу между тем, как GPT обучается, и тем, как он работает у конечного пользователя (Inference).

    Этап обучения: Параллелизм

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

    Благодаря маскированному вниманию, нам не нужно прогонять текст через модель слово за словом. Мы подаем всё предложение целиком за один проход.

    Маска гарантирует, что при обработке слова «Кошка» модель не видит «спит», а при обработке «спит» не видит «на». На выходе модель выдает предсказания для каждой позиции одновременно. Мы сравниваем эти предсказания с реальными следующими словами и обновляем веса. Этот метод называется Teacher Forcing (Принуждение учителя). Он позволяет эффективно использовать графические процессоры (GPU), обрабатывая миллионы слов параллельно.

    Этап генерации (Inference): Узкое горлышко

    Когда вы пишете запрос в ChatGPT, будущего текста еще не существует. Модель вынуждена работать строго последовательно, генерируя по одному токену за раз.

    И здесь возникает серьезная вычислительная проблема.

    Допустим, модель сгенерировала 100 слов. Чтобы сгенерировать 101-е слово, ей нужно вычислить внимание (Attention) между этим новым словом и всеми 100 предыдущими. Для этого нужно знать Ключи (Keys) и Значения (Values) всех 100 прошлых токенов.

    Наивный подход: пропустить все 100 слов через нейросеть заново, чтобы вычислить их Ключи и Значения, а затем сгенерировать 101-е. На следующем шаге пропустить 101 слово заново... Это приводит к квадратичной сложности вычислений . Генерация длинных текстов стала бы невыносимо медленной.

    Спасение производительности: Механизм KV Cache

    Чтобы решить проблему перевычислений, инженеры внедрили механизм KV Cache (Кэш Ключей и Значений). Это одна из самых важных оптимизаций в современных LLM.

    Суть KV Cache проста: поскольку прошлые слова уже не изменятся (мы ведь генерируем текст строго слева направо), их Ключи () и Значения () на каждом слое нейросети тоже остаются неизменными.

    Вместо того чтобы вычислять их заново на каждом шаге, модель сохраняет их в оперативную память (VRAM) видеокарты.

    !Интерактивная визуализация авторегрессии и работы KV Cache. Посмотрите, как модель сохраняет вычисленные векторы прошлых слов, чтобы не тратить ресурсы на их повторную обработку при генерации нового токена.

    Как работает генерация с KV Cache:

  • Обработка промпта (Prefill phase): Пользователь отправляет промпт из 50 токенов. Модель обрабатывает их все параллельно (как при обучении), вычисляет для них матрицы и на всех слоях и сохраняет их в кэш. Генерируется 51-й токен.
  • Генерация (Decode phase): На следующем шаге в модель подается только один новый 51-й токен. Модель вычисляет для него Запрос (), Ключ () и Значение ().
  • Новый и добавляются в существующий кэш.
  • Запрос () текущего токена умножается на весь закэшированный массив Ключей (чтобы понять, на какие прошлые слова обратить внимание), а затем результат умножается на закэшированный массив Значений.
  • Генерируется 52-й токен. Процесс повторяется.
  • Цена оптимизации: KV Cache экономит колоссальное количество вычислительной мощности (FLOPS), превращая сложность из квадратичной в линейную. Однако он требует огромного объема оперативной памяти. Чем длиннее контекст (например, 128 тысяч токенов в GPT-4 Turbo), тем больше гигабайт видеопамяти уходит просто на хранение KV Cache для одного пользователя. Именно поэтому современные исследования (такие как Multi-Query Attention, о котором мы говорили ранее) направлены на сжатие этого кэша.

    Масштабирование и Эмерджентные свойства

    Архитектура Decoder-only оказалась невероятно масштабируемой. Исследователи OpenAI обнаружили эмпирический закон: качество предсказания следующего слова предсказуемо улучшается при увеличении трех параметров:

  • Количества параметров модели (размер нейросети).
  • Объема обучающих данных.
  • Вычислительной мощности (Compute), затраченной на обучение.
  • Эволюция семейства GPT наглядно это демонстрирует: * GPT-1 (2018): 117 миллионов параметров. Доказала жизнеспособность концепции. * GPT-2 (2019): 1.5 миллиарда параметров. Начала генерировать пугающе связные тексты, из-за чего OpenAI изначально отказалась публиковать полную версию модели. * GPT-3 (2020): 175 миллиардов параметров. Произошел качественный скачок.

    При переходе к масштабам GPT-3 исследователи обнаружили так называемые эмерджентные свойства (Emergent Abilities) — способности, которым модель никто явно не обучал, но они возникли сами по себе из-за глубокого понимания структуры языка.

    Главным таким свойством стало In-context learning (Обучение в контексте). Оказалось, что модель не нужно дообучать (Fine-tune) под каждую новую задачу, меняя ее веса. Достаточно просто показать ей примеры прямо в текстовом промпте.

    Типы In-context learning:

    * Zero-shot (Без примеров): Мы просто даем инструкцию. Промпт: Переведи на французский: сыр => Ответ: fromage * One-shot (Один пример): Мы показываем паттерн один раз. Промпт: Яблоко => Apple. Собака => Ответ: Dog * Few-shot (Несколько примеров): Мы задаем сложную логику через серию примеров. Промпт: Отзыв: Ужасный сервис! -> Негатив Отзыв: Быстрая доставка -> Позитив Отзыв: Батарея держит нормально, но экран тусклый -> Ответ: Нейтрально

    Модель не меняет свои внутренние нейронные связи при обработке этих промптов. Она использует механизм внутреннего внимания, чтобы на лету уловить закономерность в предоставленном контексте (закэшированном в KV Cache) и применить ее для предсказания следующего слова.

    Сравнение архитектур: Итоги

    Чтобы структурировать знания, давайте сравним три главных подхода в мире Трансформеров, которые мы изучили.

    | Характеристика | Original Transformer (Encoder-Decoder) | Семейство BERT (Encoder-only) | Семейство GPT (Decoder-only) | | :--- | :--- | :--- | :--- | | Направление внимания | Двунаправленное + Однонаправленное | Двунаправленное (видит всё) | Однонаправленное (слева направо) | | Наличие маски | Только в Декодере | Нет | Да (строгое маскирование будущего) | | Главная задача | Перевод (Sequence-to-Sequence) | Понимание текста, классификация, поиск | Генерация текста, диалоги, рассуждения | | Примеры моделей | T5, BART, Whisper | BERT, RoBERTa, ALBERT | GPT-3, GPT-4, LLaMA, Claude |

    Архитектура Decoder-only победила в гонке за создание универсального искусственного интеллекта (AGI). Оказалось, что задача «предсказать следующее слово» настолько сложна, что для ее идеального решения модели необходимо выучить грамматику, логику, факты о мире, математику и даже программирование.

    Сведя все возможные задачи к единому формату «Промпт + Продолжение», архитектура GPT заложила фундамент для революции больших языковых моделей, плодами которой мы пользуемся сегодня.

    16. Вычислительная сложность: Квадратичная зависимость от длины контекста

    Вычислительная сложность: Квадратичная зависимость от длины контекста

    В предыдущих статьях мы разобрали, как Трансформеры обрабатывают текст, превращая слова в векторы и позволяя им обмениваться контекстом через механизм внутреннего внимания (Self-Attention). Мы также выяснили, что современные LLM генерируют текст авторегрессионно — токен за токеном, опираясь на весь предыдущий контекст.

    Но по мере того как пользователи начали загружать в нейросети целые книги, юридические контракты и тысячи строк программного кода, архитектура Трансформеров столкнулась с фундаментальной математической стеной. Эта стена называется квадратичной вычислительной сложностью.

    Чтобы понять, почему увеличение длины промпта в 10 раз замедляет работу модели не в 10, а в 100 раз, нам нужно заглянуть в самое сердце математики Self-Attention и разобраться, как алгоритмы взаимодействуют с физическим «железом» видеокарт.

    Нотация «О» большое: Линейный и квадратичный рост

    В информатике для оценки того, как потребление ресурсов (времени или памяти) зависит от объема входных данных, используется нотация (О большое). В контексте языковых моделей входными данными является длина последовательности токенов, которую мы обозначаем буквой .

    Если алгоритм имеет сложность (линейная сложность), это значит, что при увеличении объема данных в 2 раза, время работы тоже увеличится в 2 раза. Чтение книги человеком — это процесс со сложностью . Прочитать 200 страниц займет в два раза больше времени, чем 100 страниц.

    Однако механизм Self-Attention имеет сложность — квадратичную сложность.

    > Аналогия с рукопожатиями: > Представьте, что вы заходите в комнату и должны пожать руку каждому присутствующему. Если в комнате 5 человек, вы сделаете 5 рукопожатий. Если 50 человек — 50 рукопожатий. Это линейный рост . > > А теперь представьте правило Self-Attention: каждый человек в комнате должен пожать руку каждому другому человеку. > При 5 людях это взаимодействий. > При 50 людях это уже взаимодействий. > Увеличение количества людей в 10 раз привело к увеличению количества рукопожатий в 100 раз.

    Именно это происходит внутри Трансформера. Каждое слово в предложении должно «посмотреть» на каждое другое слово, чтобы вычислить степень смысловой связи (веса внимания).

    Математический корень проблемы

    Давайте вспомним главную формулу механизма внимания, которую мы подробно разбирали ранее:

    Где:

  • — матрица Запросов (Query)
  • — транспонированная матрица Ключей (Key)
  • — матрица Значений (Value)
  • — размерность вектора ключа
  • Проблема скрывается в самой первой операции: умножении матрицы на матрицу .

    Допустим, мы подали в модель текст длиной токенов. Каждое слово представлено вектором размерности . Матрица имеет размер (каждая строка — это запрос от одного токена). Матрица имеет размер (каждый столбец — это ключ одного токена).

    По правилам линейной алгебры, при умножении матрицы размером на матрицу размером , мы получаем новую матрицу размером .

    Эта новая матрица размером называется матрицей оценок внимания (Attention Scores). В ней хранятся числа, показывающие, насколько сильно токен №1 связан с токеном №1, токен №1 с токеном №2, и так далее для всех возможных пар.

    !Сравнение линейного и квадратичного роста: как увеличивается матрица внимания при добавлении новых токенов.

    Анатомия катастрофы: Считаем гигабайты

    Давайте переведем абстрактную математику в реальные цифры и гигабайты видеопамяти (VRAM), чтобы оценить масштаб проблемы.

    Предположим, мы хотим обработать промпт длиной 100 000 токенов (это примерно объем романа «Гарри Поттер и философский камень»). .

  • Матрица внимания будет иметь размер ячеек.
  • Это (10 миллиардов) элементов.
  • В современных нейросетях каждое число обычно хранится в формате 16-битного числа с плавающей запятой (FP16 или BF16), что занимает 2 байта памяти.
  • Умножаем 10 миллиардов на 2 байта = байт, или примерно 20 Гигабайт.
  • Кажется, что 20 ГБ — это много, но современные видеокарты (например, NVIDIA H100) имеют 80 ГБ памяти. Вроде бы помещается?

    Нет. Мы посчитали память только для одной головы внимания (Attention Head) на одном слое нейросети.

    Возьмем архитектуру, похожую на LLaMA-3 70B:

  • Количество голов внимания: 64
  • Количество слоев (блоков Трансформера): 80
  • Если модель попытается вычислить и сохранить все матрицы внимания одновременно, ей потребуется: .

    Ни один суперкомпьютер в мире не способен выделить 100 терабайт оперативной памяти для обработки одного запроса от одного пользователя. Квадратичная сложность делает наивную реализацию Трансформера абсолютно непригодной для длинных текстов.

    !Интерактивный калькулятор сложности Self-Attention — посмотрите, как длина текста влияет на количество вычислений.

    Узкое горлышко памяти (Memory Wall)

    Чтобы понять, как инженеры решают эту проблему, нужно сделать небольшое отступление в архитектуру графических процессоров (GPU).

    Внутри видеокарты есть два главных компонента:

  • Вычислительные ядра (ALU): Они выполняют математические операции (сложение, умножение). Их скорость измеряется в FLOPS (операций с плавающей запятой в секунду). Современные GPU невероятно быстры и могут выполнять сотни триллионов операций в секунду.
  • Память (VRAM / HBM): Место, где хранятся данные.
  • Проблема современных чипов в том, что вычислительные ядра работают намного быстрее, чем память успевает поставлять им данные. Это явление называется Memory Wall (Стена памяти).

    Внутри GPU есть иерархия памяти:

  • HBM (High Bandwidth Memory): Основная видеопамять (те самые 80 ГБ). Она огромная, но относительно медленная.
  • SRAM (Static RAM): Кэш-память, расположенная прямо на вычислительном чипе. Она микроскопическая (около 50 Мегабайт), но работает с фантастической скоростью.
  • При стандартном вычислении Self-Attention происходит следующее:

  • GPU загружает матрицы и из медленной HBM в быстрый SRAM.
  • Ядра перемножают их, создавая огромную матрицу .
  • Поскольку матрица не помещается в 50 МБ SRAM, GPU вынужден записывать ее обратно в медленную HBM.
  • Затем GPU снова читает эту огромную матрицу из HBM, чтобы применить функцию Softmax.
  • Результат снова записывается в HBM.
  • Наконец, матрица читается в третий раз, чтобы умножить ее на .
  • Большую часть времени видеокарта не считает математику, а просто перекладывает гигантские объемы данных туда-сюда. Это не только долго, но и требует огромного количества электроэнергии.

    Спасение: Алгоритм FlashAttention

    В 2022 году исследователи из Стэнфорда представили алгоритм FlashAttention, который произвел революцию в мире LLM и позволил увеличить контекст моделей с жалких 2-4 тысяч токенов до сотен тысяч.

    FlashAttention не меняет математику Трансформера. Результат вычислений получается абсолютно идентичным (exact attention). Инновация заключается в том, как именно алгоритм использует память видеокарты.

    Главная идея FlashAttention — Tiling (Разбиение на плитки) и Fusion (Слияние операций).

    Вместо того чтобы вычислять всю матрицу целиком, FlashAttention разбивает матрицы , и на небольшие блоки (плитки), которые гарантированно помещаются в сверхбыстрый кэш SRAM (те самые 50 МБ).

    Процесс выглядит так:

  • Блок запросов и блок ключей загружаются в SRAM.
  • Вычисляется маленький кусочек матрицы внимания.
  • Ключевой момент: Алгоритм сразу же, не выгружая данные в медленную память, применяет к этому кусочку функцию Softmax и умножает на соответствующий блок значений .
  • В медленную память HBM выгружается только финальный результат (вектор размерности ), а промежуточная матрица никогда не создается и не сохраняется целиком.
  • > Аналогия из жизни: > Представьте, что вам нужно перевести книгу с английского на русский. > Стандартный Attention: Вы читаете всю книгу, выписываете каждое английское слово на отдельные карточки (создаете огромную кучу макулатуры), затем переводите каждую карточку, а потом собираете из них русский текст. > FlashAttention: Вы читаете одно предложение, сразу переводите его в уме и записываете готовый русский текст в тетрадь. Никаких промежуточных карточек не создается.

    FlashAttention ускорил работу моделей в 2-4 раза и снизил потребление памяти с квадратичного до линейного . Именно благодаря этой оптимизации стали возможны модели вроде GPT-4 Turbo (128K контекста) и Claude 3 (200K контекста).

    Фаза Prefill и Фаза Decode: Разная сложность

    Важно четко разделять два этапа работы языковой модели, так как вычислительная сложность на них проявляется по-разному.

    1. Фаза Prefill (Чтение промпта)

    Когда вы отправляете модели длинный документ и просите сделать краткую выжимку, модель должна обработать весь этот текст за один проход. Здесь в полной мере работает механизм Self-Attention, и именно здесь возникает квадратичная сложность вычислений . FlashAttention спасает ситуацию, позволяя вычислить связи между всеми словами промпта без переполнения памяти.

    2. Фаза Decode (Генерация ответа)

    Как мы обсуждали в предыдущей статье, генерация текста происходит авторегрессионно — по одному токену за шаг. На этом этапе модель использует KV Cache. Она уже вычислила и сохранила Ключи () и Значения () для всех слов из промпта.

    Когда генерируется новое слово, модели нужно вычислить Запрос () только для этого одного нового слова. Матрица имеет размер . Умножение на закэшированную матрицу размером дает вектор размером .

    Вычислительная сложность генерации одного токена — линейная , а не квадратичная!

    Однако здесь возникает другая проблема — емкость KV Cache. Хотя вычисления линейны, сам кэш занимает физическое место в видеопамяти. Для контекста в 1 миллион токенов (как у Gemini 1.5 Pro) KV Cache для одного пользователя может занимать десятки гигабайт. Если сервисом одновременно пользуются тысячи людей, серверам требуются петабайты оперативной памяти просто для хранения контекста бесед.

    Альтернативные подходы к длинному контексту

    Даже с FlashAttention квадратичный рост количества математических операций (FLOPS) никуда не исчезает. При контексте в 1 миллион токенов вычисления становятся настолько тяжелыми, что исследователи разрабатывают архитектурные изменения, отказываясь от «идеального» внимания ко всем словам.

    Разреженное внимание (Sparse Attention)

    Идея заключается в том, что слову не обязательно смотреть на все остальные слова в книге.
  • Локальное окно (Sliding Window): Токен обращает внимание только на соседних токенов (например, на 4000 слов слева от себя). Это снижает сложность до . Этот подход используется в моделях семейства Mistral.
  • Глобальные токены: Выделяются специальные токены (например, начало абзацев), которые видят весь текст, а остальные токены видят только локальных соседей.
  • Кольцевое внимание (Ring Attention)

    Если матрица вычислений не помещается на одну видеокарту, почему бы не разделить ее на несколько? Алгоритм Ring Attention разбивает длинную последовательность на блоки и распределяет их по кольцевой сети из множества GPU. Карты вычисляют свои локальные блоки внимания и передают промежуточные результаты соседу по кольцу. Это позволяет масштабировать контекст практически бесконечно, если у вас есть достаточное количество связанных видеокарт.

    Отказ от Трансформеров (Mamba и SSM)

    Проблема настолько фундаментальна для Трансформеров, что сейчас активно развиваются альтернативные архитектуры, такие как State Space Models (SSM), ярким представителем которых является архитектура Mamba. Они сжимают весь прошлый контекст в единое скрытое состояние фиксированного размера (подобно старым RNN, но без проблемы затухания градиента). Их сложность строго линейна , и они вообще не требуют KV Cache, что делает их главными кандидатами на замену Трансформерам в будущем.

    Понимание вычислительной сложности объясняет, почему работа с длинными текстами в LLM стоит так дорого и требует передовых инженерных решений. В следующей статье мы перейдем от архитектуры к данным и узнаем, как именно модели приобретают свои знания на этапе предварительного обучения (Pre-training).

    17. Оптимизация генерации: Механика работы KV-кэша (KV-Cache)

    Оптимизация генерации: Механика работы KV-кэша (KV-Cache)

    В предыдущей статье мы столкнулись с фундаментальной математической стеной Трансформеров — квадратичной вычислительной сложностью . Мы выяснили, что алгоритм FlashAttention элегантно решает эту проблему на этапе чтения длинного промпта, оптимизируя работу с памятью видеокарты.

    Однако чтение промпта — это лишь половина дела. Настоящая магия больших языковых моделей (LLM) заключается в генерации нового текста. И здесь архитектура сталкивается с совершенно иным типом узкого горлышка.

    В этой статье мы разберем KV-кэш (KV-Cache) — самую важную инженерную оптимизацию этапа генерации (Inference), без которой ChatGPT отвечал бы на ваши вопросы часами, а не секундами.

    Анатомия авторегрессии: Проблема «золотой рыбки»

    Чтобы понять, зачем нужен KV-кэш, давайте вспомним, как именно LLM создает текст. Этот процесс называется авторегрессией — модель генерирует текст строго по одному токену (слову или части слова) слева направо.

    Представьте, что вы попросили модель продолжить фразу: «Столица Франции — это...»

    В наивной, неоптимизированной реализации Трансформера процесс выглядит так:

  • Шаг 1: Модель получает на вход 4 токена: [Столица] [Франции] [—] [это]. Она прогоняет их через все слои внимания, вычисляет матрицы Запросов (), Ключей () и Значений () для каждого слова, перемножает их и предсказывает следующий токен: [Париж].
  • Шаг 2: Теперь у нас 5 токенов: [Столица] [Франции] [—] [это] [Париж]. Модель берет всю эту новую последовательность целиком и снова прогоняет через всю нейросеть с самого начала. Она заново вычисляет , и для слова «Столица», заново для слова «Франции» и так далее, чтобы предсказать точку [.].
  • Шаг 3: Для генерации следующего слова модель берет уже 6 токенов и снова делает полный перерасчет всего контекста.
  • > Аналогия из жизни: > Представьте, что вы пишете конспект лекции. Вы написали первое предложение. Чтобы написать второе, вы стираете себе память, заново перечитываете всю лекцию с первого слова, заново осмысливаете первое предложение, и только потом пишете второе. Для третьего предложения вы снова читаете всё с самого начала.

    Такой подход катастрофически неэффективен. На каждом шаге генерации модель выполняет колоссальный объем избыточных вычислений. Векторные представления слов [Столица] и [Франции] никак не меняются от того, что в конце предложения появилось слово [Париж]. Их смысл в данном контексте уже зафиксирован.

    Математически, если мы генерируем новых токенов для промпта длиной , наивный подход потребует операций. Это делает генерацию длинных ответов практически невозможной.

    Что такое KV-кэш и почему именно K и V?

    Инженеры задались логичным вопросом: если результаты вычислений для прошлых токенов не меняются, почему бы просто не сохранить их в оперативную память видеокарты (VRAM) и не использовать повторно?

    Этот сохраненный массив данных и называется KV-кэшем.

    Давайте вспомним главную формулу механизма внутреннего внимания (Self-Attention):

    Где:

  • (Query / Запрос) — то, что токен ищет в контексте.
  • (Key / Ключ) — ярлык токена, описывающий, какую информацию он содержит.
  • (Value / Значение) — само смысловое содержимое токена.
  • Почему кэш называется KV, а не QKV? Почему мы не сохраняем Запросы ()?

    Ответ кроется в механике маскированного внимания (Masked Self-Attention), которое используется в Декодерах. При генерации нового (текущего) токена, этому токену нужно «посмотреть» на все предыдущие слова, чтобы понять контекст. Для этого он генерирует свой Запрос () и сравнивает его с Ключами () всех прошлых слов, а затем суммирует их Значения ().

    Но прошлым словам не нужно смотреть на новый токен. Их контекст уже сформирован. Их Запросы () отработали в прошлом и больше никогда не понадобятся.

    Поэтому для каждого сгенерированного токена модель сохраняет в память только его векторы и .

    !Схема работы KV-кэша: новый токен генерирует Q, K, V. Его Q взаимодействует с сохраненными в памяти K прошлых токенов, а новые K и V добавляются в кэш для будущих шагов.

    Пошаговый разбор генерации с KV-кэшем

    Давайте разделим работу LLM на две фундаментально разные фазы, чтобы увидеть кэш в действии.

    Фаза 1: Prefill (Заполнение кэша)

    Этап обработки пользовательского промпта. Допустим, вы отправили промпт из 1000 токенов.
  • Модель обрабатывает все 1000 токенов параллельно за один проход (здесь работает FlashAttention).
  • Для каждого из 1000 токенов вычисляются матрицы , и .
  • Модель вычисляет внимание, генерирует первый новый токен (токен №1001).
  • Критический момент: Векторы и для всех 1000 токенов промпта аккуратно складываются в VRAM видеокарты. Это наш стартовый KV-кэш.
  • Фаза 2: Decode (Авторегрессионная генерация)

    Этап пословного создания ответа.
  • Генерация токена №1002: На вход модели подается только один токен (№1001). Модель вычисляет для него , и .
  • Запрос умножается на матрицу Ключей из кэша (в которой 1000 записей).
  • Полученные веса внимания умножаются на матрицу Значений из кэша.
  • Модель предсказывает токен №1002.
  • Векторы и добавляются в кэш. Теперь размер кэша — 1001 запись.
  • Генерация токена №1003: На вход подается только токен №1002. Его единственный Запрос обращается к кэшу из 1001 Ключа.
  • Благодаря KV-кэшу вычислительная сложность генерации одного токена падает с квадратичной до линейной . Модели больше не нужно пересчитывать прошлое — она просто обращается к нему как к базе данных.

    !Интерактивная визуализация авторегрессионной генерации с KV-кэшем. Наблюдайте, как при добавлении новых слов их векторы K и V сохраняются в таблице памяти, а новый Запрос (Q) обращается к уже накопленному контексту.

    Стена памяти (Memory Wall): Цена оптимизации

    В информатике чудес не бывает. Мы обменяли время (вычисления) на пространство (память). KV-кэш решает проблему скорости, но создает колоссальную проблему потребления VRAM.

    Давайте посчитаем, сколько физической памяти занимает KV-кэш, на примере популярной модели LLaMA-2 7B (относительно небольшой модели на 7 миллиардов параметров).

    Формула объема KV-кэша для одного токена выглядит так:

    Где:

  • — потому что мы храним две матрицы: и .
  • — количество байт для хранения одного числа в формате FP16 (16-битная плавающая запятая).
  • — количество слоев Трансформера (у LLaMA-2 7B их 32).
  • — количество голов внимания (у LLaMA-2 7B их 32).
  • — размерность одной головы (у LLaMA-2 7B это 128).
  • Считаем: (примерно 0.5 Мегабайта).

    Кажется, что полмегабайта — это мелочь. Но это размер кэша для одного единственного слова.

    Если пользователь загрузил документ на 4000 токенов (около 10 страниц текста), кэш для этого промпта займет: .

    А теперь представьте, что вы — компания OpenAI или Anthropic. На вашем сервере с одной видеокартой (например, NVIDIA A100 на 80 ГБ) одновременно обрабатываются запросы от 30 пользователей. .

    Почти вся память видеокарты уходит не на саму нейросеть (веса модели), а на хранение контекста бесед! Это явление называется Memory Wall (Стена памяти). Из-за огромного размера KV-кэша мы не можем обслуживать много пользователей одновременно (ограничен размер батча), что делает эксплуатацию LLM невероятно дорогой.

    Архитектурные спасательные круги: MQA и GQA

    Чтобы пробить «Стену памяти», исследователям пришлось вмешаться в саму архитектуру многоголового внимания (Multi-Head Attention, MHA).

    В классическом Трансформере каждая «голова» внимания имеет свои собственные независимые матрицы , и . Если у модели 32 головы, она создает 32 уникальных Запроса, 32 уникальных Ключа и 32 уникальных Значения для каждого слова.

    Инженеры задались вопросом: обязательно ли хранить так много Ключей и Значений?

    Multi-Query Attention (MQA)

    В 2019 году был предложен радикальный подход — MQA. Идея: давайте оставим 32 разные головы для Запросов (), но заставим их все использовать только одну общую голову для Ключей () и Значений ().

    > Аналогия: > Классический подход (MHA): В библиотеке 32 читателя (Запросы), и к каждому приставлен свой личный библиотекарь (Ключ/Значение). > Подход MQA: В библиотеке 32 читателя, но обслуживает их всех один единственный библиотекарь.

    Результат? Размер KV-кэша сокращается ровно в 32 раза! Вместо 2 ГБ контекст занимает всего 60 МБ. Однако у MQA есть минус: качество генерации и понимания сложных текстов немного падает, так как один набор и не всегда способен передать все тонкости семантики для 32 разных Запросов.

    Grouped-Query Attention (GQA)

    Золотой серединой стал алгоритм GQA, который сегодня является стандартом индустрии и используется в моделях LLaMA-3, Mistral и многих других.

    Вместо одной головы на всех, GQA разбивает Запросы на группы. Например, 32 головы Запросов делятся на 8 групп (по 4 Запроса в каждой). Каждой группе выделяется своя пара и .

    > Аналогия: > Подход GQA: В библиотеке 32 читателя, они разделены на 8 тематических столов, и каждый стол обслуживает свой библиотекарь.

    GQA сокращает размер KV-кэша в 4-8 раз (в зависимости от настроек), при этом качество ответов модели остается практически неотличимым от классического, тяжелого Multi-Head Attention.

    Системная оптимизация: PagedAttention (vLLM)

    Даже с внедрением GQA управление памятью оставалось головной болью.

    До 2023 года фреймворки для запуска LLM выделяли память под KV-кэш сплошным куском (contiguous memory). Проблема в том, что когда модель начинает генерировать ответ, мы не знаем, какой длины он будет — 10 слов или 1000. Система резервировала память «с запасом» (например, сразу под 2048 токенов). Если модель отвечала коротко («Привет!»), зарезервированная память просто простаивала. Это приводило к фрагментации памяти — до 60% VRAM тратилось впустую.

    Революцию совершила библиотека vLLM с алгоритмом PagedAttention.

    Инженеры позаимствовали идею из классических операционных систем (Windows, Linux). PagedAttention разбивает KV-кэш на небольшие блоки фиксированного размера (например, по 16 токенов) — «страницы» (pages).

    Теперь память не резервируется заранее огромным куском. Когда модель генерирует текст, она заполняет один блок из 16 токенов. Как только он заполнен, система динамически выделяет следующий блок в любом свободном месте VRAM, связывая их таблицей указателей (Block Table).

    Это полностью устранило внутреннюю фрагментацию памяти. Благодаря PagedAttention пропускная способность серверов (количество обрабатываемых токенов в секунду) выросла в 2-4 раза на том же самом оборудовании.

    Резюме этапа генерации

    Подводя черту под механикой генерации, мы видим, что работа LLM — это постоянный поиск баланса между математикой и физическими ограничениями «железа»:

  • Авторегрессия заставляет модель генерировать текст по одному слову, что грозит квадратичным ростом вычислений.
  • KV-кэш спасает процессоры от лишней работы, сохраняя контекст прошлых слов, но мгновенно забивает оперативную память видеокарт (Memory Wall).
  • GQA меняет архитектуру нейросети, заставляя разные головы внимания делить между собой Ключи и Значения, чтобы сжать размер кэша.
  • PagedAttention оптимизирует работу на уровне операционной системы, устраняя пустые дыры в памяти.
  • Понимание этих механизмов критически важно для любого специалиста, который планирует разворачивать локальные LLM или оптимизировать затраты на облачные API.

    Теперь, когда мы полностью разобрали архитектуру Трансформера — от эмбеддингов до KV-кэша — мы готовы перейти к следующему большому этапу. В следующей статье мы узнаем, как именно эти пустые математические структуры наполняются знаниями обо всем мире на этапе предварительного обучения (Pre-training).

    18. Современные модификации: FlashAttention и разреженное внимание

    Современные модификации: FlashAttention и разреженное внимание

    В предыдущих материалах мы столкнулись с суровой математической реальностью архитектуры Transformer. Механизм внутреннего внимания (Self-Attention) требует, чтобы каждый токен в последовательности сравнил себя с каждым другим токеном. Это создает матрицу размером , где — длина текста.

    Когда мы генерируем текст по одному слову, нас спасает KV-кэш, который предотвращает повторные вычисления. Но что происходит на этапе обучения модели или в момент, когда вы отправляете в нейросеть документ на 100 000 слов (этап Prefill)? Модель должна обработать весь этот массив данных одновременно.

    Квадратичная сложность приводит к тому, что при увеличении текста в 10 раз, требования к вычислениям и памяти растут в 100 раз. Долгое время это считалось непреодолимым барьером, из-за которого ранние модели (например, BERT) ограничивались контекстом всего в 512 токенов.

    Сегодня современные LLM способны читать целые книги за секунды. Это стало возможным благодаря двум революционным подходам: аппаратно-ориентированному алгоритму FlashAttention и архитектурным изменениям в виде разреженного внимания (Sparse Attention).

    Стена памяти: Почему видеокарты «голодают»

    Чтобы понять гениальность современных оптимизаций, нам нужно спуститься на уровень «железа» — туда, где физически происходят вычисления.

    Графический процессор (GPU), на котором работают нейросети, обладает колоссальной вычислительной мощностью. Современные чипы могут выполнять триллионы операций умножения в секунду. Однако у них есть уязвимое место — иерархия памяти.

    Память внутри GPU делится на два основных типа:

    | Характеристика | HBM (High Bandwidth Memory) | SRAM (Static RAM) | | :--- | :--- | :--- | | Роль | Основная видеопамять (VRAM) | Сверхбыстрый кэш вычислительных ядер | | Объем | Огромный (40–80 Гигабайт) | Крошечный (около 20–40 Мегабайт на весь чип) | | Скорость доступа | Медленная (относительно ядер) | Мгновенная | | Аналогия | Огромный склад на окраине города | Рабочий стол прямо перед вами |

    Проблема классического алгоритма внимания заключается в том, что он ограничен пропускной способностью памяти (Memory-bound), а не скоростью вычислений (Compute-bound).

    Давайте проследим, как классический Трансформер вычисляет внимание:

  • Читает матрицы Запросов () и Ключей () из медленной HBM в быстрый SRAM.
  • Перемножает их, получая огромную матрицу оценок .
  • Записывает эту огромную матрицу обратно в медленную HBM.
  • Снова читает ее из HBM, чтобы применить функцию Softmax.
  • Записывает результат Softmax обратно в HBM.
  • Снова читает результат и матрицу Значений (), чтобы умножить их.
  • Записывает финальный результат в HBM.
  • > Вычислительные ядра GPU большую часть времени просто простаивают, ожидая, пока данные приедут со «склада» (HBM) и уедут обратно. При длине контекста в 8000 токенов промежуточная матрица становится настолько огромной, что постоянное ее копирование туда-сюда убивает всю производительность.

    FlashAttention: Революция на уровне железа

    В 2022 году исследователи из Стэнфорда задали простой вопрос: «Можем ли мы вычислить точное внимание, вообще не сохраняя промежуточную матрицу в медленную память?»

    Ответом стал алгоритм FlashAttention. Это не изменение архитектуры нейросети. Математически FlashAttention выдает абсолютно тот же самый результат, что и классическое внимание. Разница лишь в том, как этот результат достигается на уровне управления памятью GPU.

    FlashAttention опирается на два ключевых принципа: тайлинг и перевычисление.

    Принцип 1: Тайлинг (Блочное вычисление)

    Вместо того чтобы пытаться загрузить все Запросы и Ключи разом, FlashAttention разбивает матрицы , и на небольшие блоки (tiles), которые гарантированно помещаются в крошечный, но сверхбыстрый кэш SRAM.

    Алгоритм загружает один блок Запросов и один блок Ключей в SRAM, перемножает их, тут же применяет к ним блок Значений () и сохраняет в медленную память только финальный, компактный результат. Огромная промежуточная матрица просто никогда не материализуется в HBM.

    Проблема функции Softmax Звучит просто, но на пути тайлинга стояла серьезная математическая преграда — функция Softmax, которая превращает сырые оценки в проценты (веса внимания от 0 до 1).

    Формула Softmax требует знания суммы экспонент всех элементов в строке. Вы не можете вычислить итоговый процент для одного слова, пока не посмотрите на оценки всех остальных слов в предложении. Как же вычислить Softmax по блокам, если в SRAM находится только часть данных?

    FlashAttention использует математический трюк под названием Online Softmax. Алгоритм поддерживает «бегущий максимум» и «бегущую сумму». Когда в SRAM загружается новый блок данных, алгоритм пересчитывает локальный Softmax и корректирует предыдущие результаты с учетом новых значений.

    > Аналогия из жизни: > Представьте, что вам нужно найти долю каждого студента в общем фонде баллов всего университета. > Классический подход: выписать баллы всех 10 000 студентов на гигантскую доску (HBM), сложить их все вместе, а затем поделить балл каждого на общую сумму. > Подход FlashAttention: вы берете группу из 20 студентов в маленькую аудиторию (SRAM), считаете их локальную сумму. Затем берете следующую группу, обновляете глобальную сумму в блокноте и слегка корректируете доли предыдущих студентов. Вам никогда не нужна гигантская доска.

    Принцип 2: Перевычисление (Recomputation) при обучении

    При обучении нейросети методом обратного распространения ошибки (Backpropagation) модели нужно знать промежуточные значения внимания, чтобы обновить веса. Классический Трансформер сохранял гигантскую матрицу в памяти специально для этого шага.

    FlashAttention делает парадоксальную вещь: он не сохраняет эти данные, а заново вычисляет их на лету во время обратного прохода.

    Кажется, что делать двойную работу — это медленно. Но парадокс современной архитектуры GPU заключается в том, что выполнить миллиард математических операций в SRAM быстрее, чем один раз прочитать гигантский файл из HBM.

    Итоги внедрения FlashAttention

    Внедрение FlashAttention (и его последующих версий FlashAttention-2 и 3) стало тектоническим сдвигом в индустрии: * Потребление памяти упало с квадратичного до линейного . * Скорость обучения и генерации выросла в 2–4 раза. * Стандартный размер контекста LLM мгновенно вырос с 2 000 до 32 000 токенов и выше.

    Сегодня FlashAttention встроен во все популярные фреймворки (PyTorch, Hugging Face) и используется по умолчанию в моделях LLaMA, GPT-4, Claude и Mistral.

    Разреженное внимание (Sparse Attention): Алгоритмические хитрости

    FlashAttention решил проблему работы с памятью, но он не отменил саму математику: процессору все еще нужно выполнить операций умножения. Если мы захотим подать в модель контекст длиной в 1 миллион токенов (как в Gemini 1.5 Pro), даже FlashAttention упрется в физический предел вычислительных ядер.

    Здесь на сцену выходит разреженное внимание (Sparse Attention). Это уже не аппаратный трюк, а изменение самой логики Трансформера.

    Идея радикальна: а что, если словам вообще не нужно смотреть на все остальные слова?

    В естественном языке связи между словами обычно локальны. В предложении «Кот сидит на коврике» слову «сидит» очень важно слово «кот», но ему совершенно не важно 85-е слово на предыдущей странице текста. Заставляя модель вычислять внимание между абсолютно всеми парами слов, мы тратим 90% ресурсов на умножение чисел, которые в итоге превратятся в нули после применения Softmax.

    Разреженное внимание искусственно ограничивает то, куда может «смотреть» каждый токен, создавая специфические паттерны связей.

    !Паттерны разреженного внимания: локальное, глобальное и случайное

    1. Локальное внимание (Sliding Window Attention)

    Самый популярный паттерн. Каждый токен имеет право смотреть только на токенов слева и токенов справа от себя. Образуется «скользящее окно».

    Если длина текста , а размер окна , то вместо связей модель вычисляет всего около . Вычислительная сложность падает с до , что фактически является линейной зависимостью.

    Как же тогда модель понимает весь текст? Секрет кроется в глубине нейросети. Трансформер состоит из множества слоев (например, 32 слоя). * На 1-м слое слово №1000 видит только слова с 900 по 1100. * На 2-м слое слово №1100 (которое уже впитало информацию от слова №1200) передает эту информацию слову №1000. * К 32-му слою «рецептивное поле» (зона видимости) каждого токена расширяется на весь документ, подобно тому, как круги расходятся по воде.

    Этот подход блестяще реализован в модели Mistral 7B, что позволило ей обрабатывать длинные тексты гораздо эффективнее конкурентов.

    2. Глобальные токены (Global Attention)

    У локального внимания есть минус: если нужно быстро сопоставить факт из первого абзаца с выводом на последней странице, передача сигнала через 32 слоя «из рук в руки» может привести к искажению смысла.

    Поэтому к скользящему окну добавляют глобальные токены. Модель назначает несколько специальных токенов (например, первый токен каждого абзаца или специальный токен [CLS]), которые работают как «менеджеры». * Глобальный токен имеет право смотреть на все слова в тексте. * Все слова в тексте имеют право смотреть на глобальный токен.

    Таким образом, любое слово может передать информацию любому другому слову максимум за два шага: сначала отдать смысл глобальному токену, а тот передаст его адресату.

    3. Случайное или разреженное с шагом (Strided Attention)

    В этом паттерне токен смотрит на своих ближайших соседей, а затем на каждый -й токен в тексте (например, на каждое 10-е или 50-е слово). Это позволяет улавливать периодические паттерны и поддерживать связь с далеким контекстом без необходимости вычислять внимание для каждого промежуточного слова.

    Модели вроде Longformer и BigBird комбинируют все три подхода: они используют локальное окно для понимания синтаксиса, глобальные токены для удержания главной темы и случайные связи для неожиданных логических скачков.

    Сравнение подходов: Кто победил?

    Важно понимать, что FlashAttention и Sparse Attention — это не взаимоисключающие технологии. Они решают проблему с разных сторон.

    | Характеристика | FlashAttention | Разреженное внимание (Sparse) | | :--- | :--- | :--- | | Тип оптимизации | Аппаратная (работа с памятью GPU) | Алгоритмическая (изменение математики) | | Точность | 100% точная (Exact Attention). Результат идентичен классическому | Приближенная (Approximate). Модель теряет часть слабых связей | | Сложность вычислений | — математики столько же, но она выполняется быстрее | — реальное сокращение количества математических операций | | Применение | Стандарт индустрии для контекстов до 128k токенов | Используется для экстремальных контекстов (от 100k до 1M+ токенов) |

    Долгое время исследователи активно развивали разреженное внимание, так как считали приговором. Но появление FlashAttention доказало, что современные GPU способны «переварить» квадратичную сложность для текстов длиной до 100 000 токенов, если правильно управлять памятью.

    Поскольку FlashAttention не теряет ни капли информации (в отличие от разреженного внимания, которое искусственно обрубает связи), индустрия сделала выбор в пользу точного внимания для большинства повседневных задач.

    Однако сейчас, когда пользователи требуют от моделей анализа целых кодовых баз на миллионы строк или часовых видеороликов, гибридные подходы (FlashAttention + Sliding Window) становятся единственным путем вперед.

    Резюме архитектурного блока

    На этом мы завершаем глубокое погружение в архитектуру Трансформеров. Давайте оглянемся на пройденный путь:

  • Мы превратили слова в числа (Embeddings) и добавили им координаты времени (Positional Encoding).
  • Мы позволили словам общаться друг с другом, выявляя контекст через Запросы, Ключи и Значения (Self-Attention).
  • Мы добавили нелинейность и фактологические знания через полносвязные сети (FFN).
  • Мы стабилизировали обучение глубоких слоев с помощью Residual Connections и LayerNorm.
  • Мы решили проблему генерации текста с помощью KV-Cache.
  • И, наконец, мы пробили стену памяти с помощью FlashAttention и Sparse Attention, позволив моделям читать целые книги.
  • Мы изучили идеальный математический двигатель. Но сам по себе этот двигатель пуст. Он не знает ни русского языка, ни квантовой физики, ни рецепта шарлотки. В следующем модуле курса мы узнаем, как именно в эту архитектуру «заливают» знания всего человечества на этапе предварительного обучения (Pre-training).

    2. Векторные представления (Embeddings): Входные данные Трансформера

    Векторные представления (Embeddings): Входные данные Трансформера

    В предыдущей части нашего курса мы разобрали механизм внутреннего внимания (Self-Attention). Мы увидели, как Трансформер работает подобно детективу перед доской с уликами, связывая каждое слово с каждым другим словом в предложении одновременно. Это решило проблему долгосрочной памяти и позволило распараллелить вычисления.

    Но здесь возникает фундаментальный вопрос. Детектив читает слова, написанные на бумаге. А как читает нейросеть? Компьютеры не понимают букв, смыслов, иронии или контекста. Процессоры и видеокарты умеют делать только одно: складывать и умножать числа.

    Чтобы магия механизма внимания сработала, нам нужно перевести человеческий язык в математический. Нам нужно превратить слова в числа так, чтобы при этом не потерять их смысл. Этот процесс трансформации текста в многомерные массивы чисел называется созданием векторных представлений или эмбеддингов (embeddings).

    Шаг 1. Токенизация: Дробление текста

    Прежде чем превращать слова в числа, текст нужно правильно нарезать. Этот процесс называется токенизацией (tokenization).

    Самый очевидный подход — разбить текст по пробелам на отдельные слова. Но языки слишком сложны для такого простого правила. Что делать со знаками препинания? Считать ли «кот», «кота» и «коту» тремя разными словами? Если да, то словарь нашей модели раздуется до миллионов слов, большинство из которых будут просто формами одного и того же корня.

    Другая крайность — разбить текст по буквам. Словарь станет крошечным (около 33 букв для русского языка плюс спецсимволы). Но буква «к» сама по себе не несет никакого смысла. Модели придется тратить огромные вычислительные ресурсы просто на то, чтобы понять, что «к-о-т» — это животное.

    Современные Большие Языковые Модели (LLM) используют золотую середину — субсловную токенизацию (subword tokenization), чаще всего алгоритм Byte-Pair Encoding (BPE).

    Алгоритм BPE анализирует огромные массивы текста и находит самые частые сочетания букв.

  • Частые слова остаются целыми: «собака», «привет», «я».
  • Редкие или сложные слова разбиваются на смысловые кусочки (токены).
  • Рассмотрим пример со словом «невероятно»: > Модель может разбить его на три токена: [«не», «вероят», «но»].

    Каждый из этих кусочков имеет свой собственный смысл. Приставка «не» меняет смысл на противоположный, корень «вероят» связан с верой и вероятностью, суффикс/окончание «но» указывает на наречие.

    В словаре современной LLM (например, GPT-4) содержится около 100 000 уникальных токенов. Каждому токену присваивается свой уникальный порядковый номер (ID).

    Например:

  • «я» = 1456
  • «люблю» = 8921
  • «котов» = 45112
  • Теперь предложение «Я люблю котов» выглядит для компьютера как массив чисел: [1456, 8921, 45112].

    Но это еще не векторные представления. Это просто порядковые номера в словаре, как номера страниц в каталоге. Число 8921 не в 6 раз «больше» или «лучше», чем число 1456. Математические операции над этими ID бессмысленны. Нам нужен следующий шаг.

    Шаг 2. Наивный подход: One-Hot Encoding

    Как превратить порядковый номер в математический объект, с которым нейросеть сможет работать? Исторически первым решением был метод унитарного кодирования (One-Hot Encoding).

    Представьте гигантскую таблицу, где количество столбцов равно размеру нашего словаря (например, 100 000 столбцов). Чтобы закодировать токен №1456 («я»), мы создаем вектор (строку) из 100 000 чисел. В этой строке 99 999 нулей, и только в столбце под номером 1456 стоит единица.

    Этот метод работает для простых задач, но для LLM он оказался катастрофически неэффективным по двум причинам:

  • Огромный размер и пустота: Векторы получаются гигантскими и почти полностью состоят из нулей. Это пустая трата памяти видеокарты.
  • Отсутствие смысла (семантики): В математике расстояние между любыми двумя One-Hot векторами абсолютно одинаково. Для компьютера вектор слова «кошка» находится на таком же расстоянии от вектора «собака», как и от вектора «синхрофазотрон». Модель не видит, что кошка и собака — это родственные понятия.
  • Индустрии требовался способ сжать эти 100 000 нулей и единиц в компактный формат, который при этом отражал бы смысл слова.

    Шаг 3. Эмбеддинги: Смысл, зашитый в координаты

    Прорыв произошел с появлением плотных векторных представлений (dense word embeddings).

    Вместо того чтобы выделять каждому слову отдельный столбец, исследователи предложили оценивать слова по набору скрытых характеристик.

    Давайте построим упрощенную модель. Представьте, что мы оцениваем слова всего по трем параметрам (измерениям) по шкале от 0 до 1:

  • Насколько это связано с королевской властью?
  • Насколько это связано с мужским полом?
  • Насколько это связано с возрастом (0 - ребенок, 1 - взрослый)?
  • Закодируем несколько слов в этом трехмерном пространстве:

    | Слово | Власть | Мужской пол | Возраст | | :--- | :--- | :--- | :--- | | Мальчик | 0.01 | 0.99 | 0.10 | | Мужчина | 0.02 | 0.98 | 0.85 | | Принц | 0.95 | 0.97 | 0.30 | | Король | 0.99 | 0.99 | 0.90 | | Принцесса | 0.96 | 0.05 | 0.30 | | Королева | 0.98 | 0.02 | 0.88 | | Яблоко | 0.00 | 0.50 | 0.00 |

    Посмотрите на эти числа. Теперь слово «Король» — это не просто ID в словаре. Это вектор [0.99, 0.99, 0.90].

    Вектор слова «Мужчина» [0.02, 0.98, 0.85] математически очень похож на вектор «Король» по двум координатам из трех. А вот вектор слова «Яблоко» [0.00, 0.50, 0.00] кардинально отличается от них обоих.

    В реальных Трансформерах (таких как GPT) используется не 3 измерения, а от 512 до 12 288 измерений. Мы, люди, не можем визуализировать пространство из 12 000 измерений. Более того, нейросеть сама придумывает, что означает каждое измерение в процессе обучения. Одно измерение может отвечать за «множественное число», другое за «сарказм», третье за «отношение к еде», а тысячное — за какую-то абстрактную грамматическую связь, для которой в человеческом языке даже нет названия.

    !Визуализация семантического пространства слов

    Как измерить смысловое расстояние: Косинусное сходство

    Если слова теперь — это точки в многомерном пространстве, как нейросети понять, насколько два слова близки по смыслу?

    Для этого используется геометрическая формула, известная как косинусное сходство (Cosine Similarity). Вместо того чтобы измерять расстояние между точками линейкой, математика измеряет угол между векторами, проведенными из начала координат к этим точкам.

    Формула косинусного сходства выглядит так:

    Где:

  • — косинус угла между двумя векторами.
  • и — векторы двух слов (например, «Король» и «Мужчина»).
  • — скалярное произведение векторов (перемножение их координат и сложение результатов).
  • и — длины (магнитуды) этих векторов.
  • Зачем нам знать угол?

  • Если векторы указывают в одном направлении (угол 0 градусов), их косинус равен 1. Это значит, что слова практически идентичны по смыслу (синонимы).
  • Если векторы перпендикулярны (угол 90 градусов), их косинус равен 0. Слова вообще не связаны друг с другом (например, «Король» и «Синхрофазотрон»).
  • Если векторы указывают в противоположные стороны (угол 180 градусов), косинус равен -1. Это антонимы (например, «Горячий» и «Холодный»).
  • !Интерактивный калькулятор косинусного сходства

    Семантическая математика

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

    Классический пример, который потряс мир машинного обучения при появлении алгоритма Word2Vec:

    > Вектор(Король) - Вектор(Мужчина) + Вектор(Женщина) Вектор(Королева)

    Давайте проверим это на нашей упрощенной таблице из трех измерений [Власть, Мужской пол, Возраст]:

  • Король: [0.99, 0.99, 0.90]
  • Минус Мужчина [0.02, 0.98, 0.85] = [0.97, 0.01, 0.05] (Мы получили концепцию «чистой власти», лишенной пола и возраста).
  • Плюс Женщина [0.01, 0.01, 0.80] = [0.98, 0.02, 0.85]
  • Полученный вектор [0.98, 0.02, 0.85] математически ближе всего к вектору слова «Королева» [0.98, 0.02, 0.88] в нашем словаре.

    Нейросеть не знает, что такое монархия или гендер. Но благодаря эмбеддингам она идеально улавливает пропорции и отношения между концепциями. Она понимает, что Париж относится к Франции так же, как Токио относится к Японии.

    Шаг 4. Позиционное кодирование: Чувство времени для Трансформера

    Мы превратили слова в плотные смысловые векторы. Казалось бы, можно отправлять их в механизм внимания (Self-Attention), который мы изучали в прошлой статье. Но здесь Трансформер сталкивается с уникальной проблемой, которой не было у старых рекуррентных сетей (RNN).

    Вспомним: RNN читала текст строго последовательно, слово за словом. Она физически не могла перепутать порядок слов. Трансформер же, ради огромной скорости обучения, загружает в себя все слова предложения одновременно и обрабатывает их параллельно.

    Из-за этого параллелизма для базового механизма внимания два предложения выглядят абсолютно одинаково:

  • «Собака укусила человека»
  • «Человек укусил собаку»
  • Набор векторов один и тот же. Смыслы слов те же. Но смысл предложения меняется на противоположный! Трансформер страдает от «пространственной слепоты» — он знает, какие слова есть в тексте, но не знает, в каком порядке они стоят.

    Чтобы решить эту проблему, создатели Трансформера придумали элегантный трюк — позиционное кодирование (Positional Encoding).

    Идея проста: если модель не видит позицию слова, давайте добавим информацию о позиции прямо внутрь вектора самого слова.

    Для каждой позиции в предложении (1-е слово, 2-е слово, 100-е слово) генерируется свой уникальный вектор такого же размера, как и эмбеддинг слова. Затем эти два вектора просто складываются:

    Где:

  • — итоговый вектор, который пойдет в нейросеть.
  • — смысловой вектор слова (эмбеддинг из словаря).
  • — вектор позиции (штамп с номером места в предложении).
  • Как создаются векторы позиций?

    Инженеры могли бы просто прибавлять число 1 к первому слову, 2 ко второму и так далее. Но при длине текста в тысячи слов эти числа стали бы огромными, что сломало бы хрупкие веса нейросети (эффект затухания или взрыва градиентов).

    Вместо этого в оригинальном Трансформере используются математические функции синуса и косинуса с разными частотами.

    Представьте механические часы. Секундная стрелка вращается быстро, минутная — медленнее, часовая — совсем медленно. Посмотрев на комбинацию углов всех трех стрелок, вы можете точно сказать, какое сейчас время.

    Позиционное кодирование работает так же. Оно создает уникальный «узор» из волн для каждой позиции.

  • Слово «Собака» на первой позиции получит к своему смыслу примесь «узора №1».
  • Слово «Собака» на десятой позиции получит примесь «узора №10».
  • Теперь, когда механизм внимания сравнивает слова, он видит не только их семантическое сходство, но и физическое расстояние между ними в тексте.

    Подводя черту под входными данными

    Давайте соберем весь путь, который проходит текст, прежде чем начнется настоящая магия «мышления» LLM:

  • Токенизация: Текст «Я люблю ИИ» разбивается на токены [Я], [люблю], [И], [И].
  • Словарь ID: Токены превращаются в порядковые номера [14, 892, 45, 45].
  • Эмбеддинги: Каждый номер заменяется на заранее выученный вектор из 512 чисел, содержащий концентрат смысла этого слова.
  • Позиционное кодирование: К каждому вектору прибавляется уникальный волновой узор, обозначающий его место в предложении.
  • Только после этого плотные, наполненные смыслом и координатами векторы отправляются в слои Трансформера. Там, с помощью матриц Запросов (Query), Ключей (Key) и Значений (Value), они начнут обмениваться контекстом, формируя глубокое понимание человеческого языка.

    3. Позиционное кодирование (Positional Encoding): Сохранение порядка слов

    Позиционное кодирование (Positional Encoding): Сохранение порядка слов

    Представьте, что вы читаете захватывающий детектив, но кто-то разрезал книгу на отдельные слова, сложил их в мешок, хорошенько встряхнул и высыпал перед вами на стол. Все слова на месте: имена героев, улики, развязка. Но понять сюжет невозможно. Смысл текста кроется не только в самих словах, но и в их строгой последовательности.

    Именно в такой ситуации оказывается базовая архитектура Трансформера. В отличие от старых рекуррентных нейронных сетей (RNN), которые читали текст как люди — строго слева направо, слово за словом, — Трансформер загружает в себя всю последовательность целиком и обрабатывает её параллельно.

    Параллелизм стал главным техническим прорывом, позволившим обучать Большие Языковые Модели (LLM) на гигантских кластерах видеокарт. Но за эту скорость пришлось заплатить высокую цену: Трансформер от природы страдает абсолютной «пространственной слепотой».

    Для механизма внутреннего внимания (Self-Attention) фразы «Собака укусила человека» и «Человек укусил собаку» абсолютно идентичны. Набор векторов (эмбеддингов) один и тот же. Чтобы модель научилась отличать жертву от агрессора, инженерам потребовалось создать механизм, который возвращает словам их координаты в пространстве текста. Этот механизм называется позиционным кодированием (Positional Encoding).

    Проблема: Как объяснить нейросети, где находится слово?

    В предыдущей статье мы выяснили, что каждое слово (токен) превращается в плотный вектор — массив чисел, хранящий семантический смысл. Например, вектор из 512 чисел.

    Если мы хотим добавить информацию о позиции слова, нам нужно как-то модифицировать эти данные. Давайте пройдем путь исследователей машинного обучения и рассмотрим несколько очевидных, но нерабочих подходов, чтобы понять гениальность итогового решения.

    Наивный подход №1: Абсолютные индексы

    Самая простая идея — добавить к вектору слова его порядковый номер в предложении. Первое слово получает индекс 1, второе — 2, сотое — 100.

    Почему это плохо работает на практике:

  • Масштаб чисел: Векторы слов обычно содержат значения в диапазоне от -1 до 1. Если мы добавим к ним число 1000 (для тысячного слова в тексте), это огромное значение полностью «заглушит» тонкий семантический смысл самого слова.
  • Проблема обобщения: Если модель во время обучения видела тексты длиной максимум 500 слов, она физически не будет знать, что делать с индексом 501. Веса нейросети не адаптированы к таким большим числам, и вычисления сломаются (произойдет взрыв градиентов).
  • Наивный подход №2: Нормализованные дроби

    Хорошо, если большие числа ломают сеть, давайте сожмем их в диапазон от 0 до 1. Первое слово всегда имеет позицию 0.0, последнее — 1.0.

    Если в предложении 3 слова, их позиции будут: 0.0, 0.5, 1.0. Если в предложении 11 слов, позиции будут: 0.0, 0.1, 0.2 ... 1.0.

    Почему это тоже не работает: Шаг (расстояние) между соседними словами постоянно меняется в зависимости от длины текста. В коротком предложении разница между первым и вторым словом равна 0.5. В длинном — 0.1. Для нейросети это катастрофа: она не может выучить универсальное правило того, что такое «соседнее слово», потому что математическое расстояние между соседями всегда разное.

    Идеальная система позиционного кодирования должна отвечать трем строгим требованиям:

  • Выдавать уникальный идентификатор для каждой позиции.
  • Расстояние между любыми двумя позициями должно быть константным и не зависеть от длины текста.
  • Значения должны быть ограничены (не улетать в бесконечность), чтобы модель могла работать с текстами любой длины, даже теми, которые длиннее обучающих.
  • Элегантное решение: Симфония синусов и косинусов

    Создатели оригинальной архитектуры Transformer (в знаменитой статье Attention Is All You Need) предложили использовать тригонометрические функции — синус и косинус с разными частотами.

    Чтобы понять эту концепцию без сложных формул, давайте используем аналогию с механическими часами.

    Представьте циферблат с тремя стрелками: секундной, минутной и часовой.

  • Секундная стрелка вращается очень быстро. Каждую секунду её угол меняется.
  • Минутная стрелка вращается медленнее. За одну секунду её сдвиг почти незаметен.
  • Часовая стрелка движется настолько медленно, что кажется неподвижной.
  • Если вы посмотрите только на секундную стрелку, вы не сможете сказать, какое сейчас время — она показывает одну и ту же позицию каждую минуту. Но если вы запишете точные углы всех трех стрелок одновременно, вы получите уникальную комбинацию, которая не повторится в течение 12 часов.

    Позиционное кодирование в Трансформере работает точно так же, только вместо трех стрелок у него сотни (равно количеству измерений в векторе слова, например, 512). И вместо стрелок используются волны.

    !Интерактивная визуализация позиционного кодирования

    Математика позиционного кодирования

    Для генерации этих «волн» используются две формулы. Одна для четных измерений вектора, другая для нечетных:

    Давайте расшифруем каждую переменную, чтобы магия превратилась в логику:

  • (Positional Encoding) — значение, которое мы вычисляем.
  • — позиция слова в тексте (0, 1, 2, 3...).
  • — индекс измерения внутри вектора (от 0 до 511, если размер вектора 512).
  • — общий размер вектора (например, 512).
  • — константа, выбранная эмпирически. Она растягивает волны так, чтобы они не повторялись слишком быстро.
  • Что происходит внутри этой формулы? Когда индекс измерения маленький (начало вектора), делитель близок к единице. Функция колеблется очень быстро, как секундная стрелка. При переходе от слова к слову значение резко прыгает от -1 до 1.

    Когда индекс большой (конец вектора), делитель становится огромным (близким к 10000). Функция превращается в . Эта волна колеблется невероятно медленно, как часовая стрелка. На протяжении десятков слов её значение почти не меняется.

    В результате для каждого слова генерируется уникальный вектор из 512 чисел, состоящий из комбинации быстрых и медленных волн. Этот вектор — идеальный «штамп времени».

    Как объединить смысл и позицию: Парадокс сложения

    Мы получили два вектора для каждого слова:

  • Эмбеддинг слова: Вектор, хранящий смысл (например, [0.8, -0.2, 0.5...]).
  • Вектор позиции: Вектор, хранящий порядковый номер (например, [0.0, 1.0, 0.1...]).
  • Как их объединить, чтобы передать в нейросеть? Интуиция подсказывает, что их нужно склеить (конкатенировать), получив вектор в два раза длиннее (1024 числа). Одна половина отвечала бы за смысл, другая — за место.

    Но создатели Трансформера сделали нечто контринтуитивное. Они просто сложили их друг с другом поэлементно:

    !Схема сложения смыслового и позиционного векторов

    На первый взгляд, это звучит как безумие. Если мы возьмем смысл слова «Король» и прибавим к нему позицию «5», разве мы не получим бессмысленную кашу? Это как сложить 5 килограммов и 3 километра.

    Почему сложение не разрушает смысл слова? Ответ кроется в геометрии многомерных пространств.

    В нашем привычном трехмерном мире векторы часто мешают друг другу. Но LLM работают в пространствах с тысячами измерений. В таком гигантском пространстве большинство случайно выбранных векторов ортогональны (перпендикулярны) друг другу.

    > Вектор позиции действует как легкий фоновый шум, который имеет очень специфический, математически строгий узор. Нейросеть в процессе обучения легко учится «отделять мухи от котлет» — она распознает семантический смысл по одним паттернам активации, а позицию — по тригонометрической ряби, наложенной поверх.

    Более того, сложение вместо склеивания экономит колоссальное количество оперативной памяти видеокарт, так как размерность данных не увеличивается.

    Относительное позиционное кодирование: Как мыслят современные LLM

    Описанный выше метод с синусами и косинусами называется абсолютным позиционным кодированием. Модель точно знает: «Я — слово номер 5, а ты — слово номер 12».

    Но давайте задумаемся, как читаем текст мы, люди. Когда вы видите фразу «красное яблоко», вам абсолютно неважно, находятся ли эти слова на 10-й и 11-й позиции в тексте, или на 1005-й и 1006-й. Вам важно лишь то, что слово «красное» стоит непосредственно перед словом «яблоко». Важна дистанция между ними, а не их абсолютные координаты.

    Понимание этого факта привело к эволюции архитектуры. Современные флагманские модели (такие как LLaMA от Meta, GPT-4 от OpenAI, Mistral) используют относительное позиционное кодирование (Relative Positional Encoding).

    Самым популярным стандартом сегодня является RoPE (Rotary Positional Embedding — Роторное позиционное кодирование).

    Как работает RoPE (простыми словами)

    Вместо того чтобы прибавлять вектор позиции к вектору слова, RoPE поворачивает вектор слова в многомерном пространстве на определенный угол.

    Чем дальше слово находится в тексте, тем сильнее поворачивается его вектор.

    Представьте компас.

  • Слово «красное» на позиции 1 — стрелка компаса повернута на 10 градусов.
  • Слово «яблоко» на позиции 2 — стрелка повернута на 20 градусов.
  • Когда механизм внимания (Self-Attention) сравнивает эти два слова, он вычисляет угол между их векторами. Разница между 20 и 10 градусами равна 10 градусам.

    Если та же фраза встретится в конце книги:

  • «красное» на позиции 1000 — стрелка повернута на 10000 градусов.
  • «яблоко» на позиции 1001 — стрелка повернута на 10010 градусов.
  • Разница между ними всё ещё равна 10 градусам!

    Благодаря этому математическому трюку, модель идеально улавливает относительное расстояние между словами, где бы они ни находились. Это кардинально улучшило способность LLM понимать длинные контексты, писать связный код и анализировать целые книги без потери логики.

    Подводя итоги этапа входных данных

    Теперь мы полностью видим картину того, как человеческий текст подготавливается для «мозга» нейросети. Это многоступенчатый конвейер:

  • Токенизация: Текст рубится на смысловые кусочки (токены).
  • Словарь: Токены заменяются на их ID (порядковые номера).
  • Эмбеддинги: ID превращаются в плотные многомерные векторы, содержащие концентрат смысла.
  • Позиционное кодирование: К векторам примешивается математический узор (или применяется вращение), чтобы зафиксировать порядок слов.
  • Только пройдя все эти трансформации, данные становятся пригодными для главного вычислительного ядра Трансформера — слоев внимания и полносвязных сетей. Именно там разрозненные векторы начнут обмениваться информацией, формируя то, что мы называем «пониманием контекста». И именно архитектуру этих вычислительных слоев мы разберем в следующей части нашего курса.

    4. Механизм внутреннего внимания (Self-Attention): Запросы, Ключи и Значения

    Механизм внутреннего внимания (Self-Attention): Запросы, Ключи и Значения

    Язык — это не просто набор слов, расставленных в правильном порядке. Это сложная паутина связей, где значение каждого элемента зависит от его окружения.

    Возьмем слово «замок». В предложениях «Я купил новый замок на дверь» и «Мы посетили старинный замок» это слово имеет абсолютно разный смысл. Однако, как мы узнали из предыдущей статьи, на этапе создания эмбеддингов нейросеть присваивает слову «замок» один и тот же базовый вектор, независимо от контекста. Это просто словарное определение.

    Чтобы модель поняла, о каком именно замке идет речь, ей нужно посмотреть на соседние слова: «дверь» или «старинный». Именно эту задачу решает механизм внутреннего внимания (Self-Attention). Он позволяет каждому слову в предложении «посмотреть» на все остальные слова и впитать в себя их контекст, изменив свой первоначальный вектор.

    Аналогия из жизни: Библиотека смыслов

    Чтобы понять, как математически реализован этот процесс, создатели Трансформеров позаимствовали концепцию из систем управления базами данных. В основе Self-Attention лежат три сущности: Запрос (Query), Ключ (Key) и Значение (Value).

    Представьте, что вы пришли в огромную библиотеку, чтобы найти книгу по астрофизике.

  • Вы подходите к библиотекарю и говорите: «Мне нужны книги про черные дыры». Это ваш Запрос (Query) — то, что вы ищете.
  • Библиотекарь открывает каталог, где каждая книга имеет карточку с тегами: «Космос», «Гравитация», «Звезды». Эти теги — Ключи (Keys). Они описывают, что может предложить каждая книга.
  • Когда ваш Запрос совпадает с Ключом (например, «черные дыры» тесно связаны с «гравитацией»), вы берете саму книгу и читаете текст. Содержимое книги — это Значение (Value).
  • !Аналогия Запроса, Ключа и Значения в виде картотеки

    В Трансформере каждое слово одновременно является и посетителем библиотеки, и самой книгой. Каждое слово формирует свой Запрос (что ему нужно от контекста), предоставляет свой Ключ (что оно само значит для других) и содержит Значение (свой фактический смысл).

    | Сущность | Английский термин | Обозначение | Суть простыми словами | | :--- | :--- | :--- | :--- | | Запрос | Query | | «Какая информация от других слов мне нужна, чтобы уточнить мой смысл?» | | Ключ | Key | | «На какие запросы других слов я могу ответить? Какова моя роль?» | | Значение | Value | | «Какую смысловую нагрузку я передам тем словам, которые обратят на меня внимание?» |

    Математика внимания: Шаг за шагом

    Давайте разберем, как эта концепция работает внутри нейросети на примере короткой фразы: «Умный кот».

    На вход механизма внимания поступают векторы этих слов (эмбеддинги + позиционное кодирование). Назовем их (Умный) и (кот).

    Шаг 1: Создание Q, K и V

    Нейросеть не использует исходные векторы напрямую. Она умножает каждый входной вектор на три разные матрицы весов (, , ), которые модель настраивает в процессе обучения.

    В результате для слова «кот» создаются три новых вектора: , и . То же самое происходит для слова «Умный».

    > Матрицы весов — это своеобразные фильтры. Они извлекают из базового вектора слова только ту информацию, которая нужна для конкретной роли (запроса, ключа или значения).

    Шаг 2: Вычисление оценок внимания (Dot Product)

    Теперь слово «кот» хочет понять, насколько сильно ему нужно обратить внимание на слово «Умный». Для этого мы берем Запрос кота () и сравниваем его с Ключом слова умный ().

    Математически это сравнение делается с помощью скалярного произведения (Dot Product).

    Скалярное произведение двух векторов — это операция, которая показывает, насколько эти векторы похожи (направлены в одну сторону в многомерном пространстве). Чем больше число на выходе, тем сильнее связь между словами.

    Оценка внимания =

    Допустим, скалярное произведение дало результат 112. Это просто сырое число (raw score), которое пока мало о чем говорит.

    Шаг 3: Масштабирование (Scaling)

    Если векторы слов очень длинные (например, состоят из 512 чисел), скалярное произведение может выдавать огромные значения (тысячи или десятки тысяч).

    Большие числа — враг нейросетей. Они приводят к тому, что на следующем шаге алгоритм «залипает» и перестает обучаться (проблема затухания градиента). Чтобы этого избежать, сырую оценку делят на квадратный корень из размерности вектора ключа ().

    Если размерность вектора , то . Мы делим нашу сырую оценку 112 на 8 и получаем масштабированную оценку 14.

    Шаг 4: Превращение в проценты (Softmax)

    Слово «кот» вычисляет такие оценки для ВСЕХ слов в предложении, включая само себя. Допустим, мы получили следующие масштабированные оценки для запроса «кот»:

  • Связь с «Умный»: 14
  • Связь с «кот»: 20
  • Чтобы превратить эти абстрактные числа в понятные веса (доли), применяется функция Softmax. Она сжимает любые числа в диапазон от 0 до 1 так, чтобы в сумме они давали ровно 1 (или 100%).

    После применения Softmax мы получаем:

  • Внимание на «Умный»: (12%)
  • Внимание на «кот»: (88%)
  • Это означает, что при формировании своего нового смысла слово «кот» возьмет 88% информации из самого себя и 12% контекста из слова «Умный».

    Шаг 5: Сборка нового смысла

    На финальном этапе мы берем векторы Значений () всех слов и умножаем их на полученные проценты, а затем складываем вместе:

    Новый вектор кота =

    На выходе получается совершенно новый вектор. Это уже не просто словарный «кот». Это вектор, который математически впитал в себя характеристику «умный».

    !Интерактивный калькулятор внутреннего внимания (Self-Attention)

    Главная формула Трансформера

    Все пять шагов, которые мы только что разобрали, создатели архитектуры Transformer записали в одну элегантную формулу. Это сердце любой современной LLM (от ChatGPT до Claude):

    Давайте расшифруем её элементы, чтобы закрепить понимание:

  • , , — матрицы Запросов, Ключей и Значений для всех слов в тексте.
  • — скалярное произведение Запросов и Ключей (поиск совпадений). Буква означает транспонирование матрицы (переворот), что необходимо по правилам линейной алгебры для умножения.
  • — масштабирующий фактор, спасающий нейросеть от огромных чисел.
  • — превращение сырых совпадений в проценты (веса внимания).
  • Умножение на в конце — применение этих процентов к фактическим значениям слов для получения итогового контекстного вектора.
  • Многоголовое внимание (Multi-Head Attention)

    Если вы внимательно следили за логикой, у вас мог возникнуть вопрос: а что, если слову нужно обратить внимание на разные аспекты контекста одновременно?

    Например, в предложении «Вчера я быстро перевел деньги через банк» слово «перевел» должно связаться с «вчера» (чтобы понять время действия), с «быстро» (чтобы понять скорость) и с «деньги» (чтобы понять объект действия).

    Один механизм внимания (одна тройка матриц Q, K, V) физически не может уловить все эти разные типы связей. Он усреднит их и потеряет детали.

    Поэтому инженеры придумали Многоголовое внимание (Multi-Head Attention).

    Вместо того чтобы создавать один большой набор Запросов, Ключей и Значений, Трансформер создает несколько маленьких независимых наборов (обычно от 8 до 96 «голов» в современных LLM).

    Каждая «голова» внимания (Attention Head) обучается искать свои специфические паттерны:

  • Первая голова может стать экспертом по грамматике (связывать подлежащее и сказуемое).
  • Вторая голова может следить за местоимениями (понимать, что «он» относится к «Ивану»).
  • Третья голова может улавливать эмоциональный окрас текста.
  • В конце работы слоя внимания результаты всех «голов» склеиваются вместе и пропускаются через еще одну линейную трансформацию, чтобы объединить все найденные инсайты в единый сверх-информативный вектор.

    Итог этапа

    Механизм внутреннего внимания — это то, что подарило нейросетям способность к «пониманию». Благодаря матрицам Q, K и V слова перестали быть изолированными островами. Они начали общаться друг с другом, обмениваться контекстом и формировать сложные смысловые конструкции.

    Однако векторы, выходящие из слоя внимания, содержат много «сырой» информации о связях. Чтобы окончательно усвоить эти знания и превратить их в логические выводы, Трансформер передает эти данные в следующий блок — полносвязную нейронную сеть (Feed-Forward Network), о которой мы поговорим на следующем этапе нашего погружения под капот LLM.

    5. Математика Self-Attention: Масштабированное скалярное произведение

    В предыдущей статье мы разобрали концептуальную основу механизма внутреннего внимания (Self-Attention). Мы выяснили, что каждое слово в Трансформере выступает в трех ролях: формирует Запрос (), предоставляет Ключ () и содержит фактическое Значение ().

    Теперь пришло время заглянуть в самое сердце архитектуры Трансформера и разобрать математический двигатель, который заставляет эти векторы взаимодействовать. Этот двигатель называется масштабированным скалярным произведением (Scaled Dot-Product Attention).

    Создатели Трансформера из Google описали этот процесс одной элегантной формулой, которая сегодня лежит в основе всех современных больших языковых моделей (LLM), от ChatGPT до Claude:

    Где:

  • , , — матрицы Запросов, Ключей и Значений.
  • — транспонированная матрица Ключей.
  • — размерность вектора ключа.
  • — функция нормализации.
  • На первый взгляд формула может показаться сложной, но она состоит из четырех логичных и последовательных шагов. Давайте разберем каждый из них на конкретных примерах.

    Шаг 1: Скалярное произведение () — Измерение сходства

    Первая задача механизма внимания — понять, насколько сильно каждое слово в предложении должно «обращать внимание» на все остальные слова. Для этого нейросеть берет Запрос одного слова и сравнивает его с Ключами всех остальных слов.

    В линейной алгебре стандартным способом измерения сходства двух векторов является скалярное произведение (Dot Product).

    > Скалярное произведение — это математическая операция, которая перемножает соответствующие координаты двух векторов и складывает результаты. Чем больше итоговое число, тем сильнее векторы направлены в одну сторону (тем больше их смысловое сходство).

    Представим, что наши векторы состоят всего из трех чисел (в реальности их сотни или тысячи). У нас есть слово «банк» (в значении финансового учреждения) и два других слова в предложении: «деньги» и «река».

  • Запрос слова «банк» (): [2, 1, 0]
  • Ключ слова «деньги» (): [3, 2, 0]
  • Ключ слова «река» (): [-1, 0, 3]
  • Вычислим скалярное произведение для пары «банк-деньги»:

    Вычислим скалярное произведение для пары «банк-река»:

    Результат логичен: Запрос «банка» имеет высокое совпадение с Ключом «денег» (8) и отрицательное совпадение с Ключом «реки» (-2).

    Зачем нужна буква T ()?

    В формуле мы видим выражение . Буква означает транспонирование — переворот матрицы, при котором строки становятся столбцами.

    Трансформеры не вычисляют внимание для каждого слова по очереди. Они делают это для всех слов одновременно, используя матричное умножение. Чтобы умножить матрицу Запросов () на матрицу Ключей () по правилам линейной алгебры, количество столбцов первой матрицы должно совпадать с количеством строк второй. Транспонирование матрицы обеспечивает это совпадение, позволяя видеокартам (GPU) мгновенно вычислять оценки сходства для всего текста разом.

    !Схема матричного умножения в механизме внимания

    Шаг 2: Масштабирование (Деление на )

    После умножения мы получаем матрицу «сырых» оценок внимания (raw scores). И здесь возникает серьезная математическая проблема.

    В современных LLM векторы слов имеют огромную размерность. Например, в модели GPT-3 размерность вектора ключа () равна 128. При вычислении скалярного произведения мы перемножаем и складываем 128 пар чисел.

    Если векторы независимы и имеют стандартное распределение (среднее значение 0, дисперсия 1), то их скалярное произведение будет иметь дисперсию, равную . Это означает, что чем длиннее векторы, тем больше разброс получаемых значений. Сырые оценки могут достигать огромных чисел, например, +150 или -120.

    Почему большие числа — это проблема? На следующем шаге эти числа попадут в функцию Softmax. Особенность Softmax в том, что при очень больших входных значениях она выдает вероятности, экстремально близкие к 1 или 0. В таких областях график функции становится почти плоским.

    Когда график плоский, производная (градиент) стремится к нулю. Нейросеть обучается методом обратного распространения ошибки, который опирается на градиенты. Если градиент равен нулю, обучение останавливается. Модель «застревает» и перестает умнеть. Это явление называется затуханием градиента (vanishing gradient).

    Чтобы спасти нейросеть, создатели Трансформера ввели масштабирующий фактор. Они делят сырые оценки на квадратный корень из размерности вектора ключа ().

    Пример с числами: Допустим, размерность . Квадратный корень из 64 равен 8. Если сырая оценка совпадения слов равна 112, мы делим ее на 8: .

    Это простое действие возвращает дисперсию значений обратно к 1, сохраняя числа в безопасном диапазоне, где функция Softmax работает наиболее эффективно.

    Шаг 3: Функция Softmax — Превращение в проценты

    Теперь у нас есть отмасштабированные оценки сходства. Но это все еще абстрактные числа (например, 14, -2, 5). Чтобы использовать их для смешивания смыслов, нам нужно превратить их в доли (проценты), сумма которых равна 1 (или 100%).

    Эту задачу решает функция Softmax:

    Где:

  • — конкретная оценка внимания.
  • — число Эйлера (примерно 2.718).
  • — сумма экспонент всех оценок в ряду.
  • Softmax делает две критически важные вещи:

  • Избавляется от отрицательных чисел. Возведение положительного числа в любую степень (даже отрицательную) всегда дает положительный результат.
  • Усиливает разницу. Экспоненциальная функция растет очень быстро. Она делает большие значения еще больше, а маленькие подавляет, заставляя модель четко фокусироваться на самых важных словах.
  • Пример с числами: Возьмем три отмасштабированные оценки: [3, 1, -1].

  • Возводим в эти степени:
  • - - -
  • Находим сумму:
  • Делим каждое значение на сумму, чтобы получить проценты:
  • - (87%) - (12%) - (1%)

    Итог: слово отдаст 87% своего внимания первому токену, 12% второму и почти проигнорирует третий.

    !Интерактивный калькулятор Softmax и масштабирования

    Шаг 4: Умножение на Значения () — Сборка контекста

    Финальный аккорд формулы — умножение полученных процентов (матрицы весов внимания) на матрицу Значений ().

    Матрица содержит фактическую смысловую нагрузку каждого слова. Умножая ее на веса Softmax, мы создаем взвешенную сумму.

    Вернемся к нашему примеру со словом «банк». Допустим, Softmax распределил внимание так:

  • 80% на слово «деньги»
  • 15% на само слово «банк»
  • 5% на слово «река»
  • Новый вектор для слова «банк» будет вычислен так: Новый вектор =

    На выходе из слоя Self-Attention мы получаем обновленные векторы для каждого слова. Вектор слова «банк» больше не является просто словарным определением. Он математически сдвинулся в многомерном пространстве в сторону концепции «денег», впитав в себя контекст предложения.

    Маскированное внимание (Masked Self-Attention)

    До сих пор мы говорили о том, как слова смотрят на весь текст целиком. Это отлично работает для задач понимания текста (например, классификации или перевода), где модель видит предложение от начала до конца.

    Но большие языковые модели (такие как GPT) работают в режиме генерации текста (Autoregressive generation). Они предсказывают следующее слово на основе предыдущих.

    Если при обучении такой модели позволить слову смотреть на слова, идущие после него, модель просто «подсмотрит» правильный ответ. Это разрушит весь процесс обучения.

    Чтобы этого избежать, в декодерах Трансформеров используется модификация — Маскированное внутреннее внимание (Masked Self-Attention).

    Как работает маска?

    Маскирование происходит между Шагом 2 (масштабирование) и Шагом 3 (Softmax).

    Нейросеть берет матрицу сырых оценок и заменяет все значения, относящиеся к будущим словам, на минус бесконечность ().

    | Запрос \ Ключ | Я | люблю | ИИ | (будущее) | | :--- | :--- | :--- | :--- | :--- | | Я | 12 | | | | | люблю | 4 | 15 | | | | ИИ | 2 | 8 | 10 | |

    Когда эти числа попадают в функцию Softmax, происходит математическая магия. Как мы помним, Softmax возводит число в степень оценки.

    Чему равно ? Оно равно нулю.

    Таким образом, Softmax присваивает будущим словам ровно 0% внимания. Текущее слово может смешивать свой смысл только с самим собой и со словами, стоящими слева от него. Это гарантирует, что модель учится предсказывать текст честно, опираясь только на прошлый контекст.

    Итог

    Формула — это не просто набор символов. Это пошаговый алгоритм извлечения смысла:

  • находит связи между всеми словами через скалярное произведение.
  • стабилизирует вычисления, спасая нейросеть от затухания градиентов.
  • выделяет главное, превращая сырые связи в четкие проценты.
  • предоставляет смысловой материал, который смешивается согласно полученным процентам.
  • Поняв эту математику, вы осознали главный секрет того, как нейросети «понимают» текст. В следующей статье мы перейдем к этапу предварительного обучения (Pre-training) и узнаем, на каких данных и с помощью каких задач Трансформеры настраивают эти самые матрицы Q, K и V, чтобы обрести знания обо всем мире.

    6. Многоголовое внимание (Multi-Head Attention): Параллельный анализ контекста

    В предыдущей статье мы разобрали математический двигатель Трансформера — масштабированное скалярное произведение. Мы увидели, как векторы Запросов (), Ключей () и Значений () взаимодействуют друг с другом, вычисляя проценты внимания через функцию Softmax.

    Однако, если мы используем этот механизм в его базовом виде (один набор матриц для всего текста), мы сталкиваемся с серьезным ограничением. Язык слишком многогранен, чтобы описать все связи между словами с помощью одной оценки сходства.

    Проблема единственного фокуса

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

    Точно так же слова в предложении связаны друг с другом множеством различных способов одновременно.

    Возьмем классическое предложение: > «Ярко-рыжая лиса быстро перепрыгнула через ленивую собаку.»

    Давайте посмотрим на слово «перепрыгнула». С какими словами оно связано?

  • Синтаксическая связь (Кто?): связано со словом «лиса» (подлежащее и сказуемое).
  • Синтаксическая связь (Через кого?): связано со словом «собаку» (объект действия).
  • Обстоятельственная связь (Как?): связано со словом «быстро» (наречие, описывающее действие).
  • Если у нейросети есть только один механизм внимания (одна «голова»), ей придется усреднить все эти связи. Она может отдать 50% внимания «лисе» и 50% «собаке», полностью проигнорировав то, что прыжок был «быстрым». Один вектор внимания физически не способен захватить грамматику, семантику, эмоциональный окрас и логические отсылки одновременно. Возникает информационное узкое горлышко.

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

    Концепция многоголового внимания

    Многоголовое внимание (Multi-Head Attention) — это архитектурный прием, при котором входные векторы слов параллельно обрабатываются несколькими независимыми механизмами внутреннего внимания (головами). Каждая голова имеет свои собственные обучаемые матрицы весов и специализируется на поиске определенного типа связей в тексте.

    Возвращаясь к аналогии с договором: вместо одного читателя мы нанимаем команду специалистов. Юрист ищет правовые риски, бухгалтер проверяет цифры, а менеджер оценивает сроки. Каждый делает свою работу независимо, а затем они собираются вместе и объединяют свои выводы в один итоговый отчет.

    В Трансформере каждая «голова» внимания (Attention Head) учится обращать внимание на свои паттерны:

  • Голова 1 может стать экспертом по поиску подлежащих для глаголов.
  • Голова 2 может связывать местоимения с существительными (понимать, что «он» — это «Александр»).
  • Голова 3 может отслеживать отрицания (связывать частицу «не» со смысловым глаголом).
  • Голова 4 может фокусироваться на эмоциональной окраске прилагательных.
  • !Схема многоголового внимания: разделение данных, параллельная обработка и объединение

    Важно отметить, что мы не программируем эти головы вручную. Нейросеть сама в процессе обучения (через обратное распространение ошибки) распределяет эти роли между головами так, чтобы минимизировать итоговую ошибку предсказания.

    Математика разделения: Как не взорвать видеокарту

    Может показаться, что если мы добавим 8 голов внимания вместо одной, нам потребуется в 8 раз больше вычислительных мощностей и памяти. Но гениальность Multi-Head Attention заключается в том, что вычислительная сложность остается практически такой же, как у одной головы.

    Секрет кроется в разделении размерности (Dimension Splitting).

    В стандартной модели Transformer (например, из оригинальной статьи Attention Is All You Need) каждый токен представляется вектором размерности . Модель использует голов внимания.

    Вместо того чтобы каждая из 8 голов работала с полными векторами из 512 чисел, модель проецирует (сжимает) входные данные в меньшие подпространства. Размерность каждой головы вычисляется по формуле:

    Для нашего примера: .

    Каждая из 8 голов будет работать с векторами размерностью всего 64 числа.

    Шаг 1: Линейные проекции

    Для каждой головы (от 1 до 8) создаются три уникальные матрицы весов:

  • (матрица проекции Запросов)
  • (матрица проекции Ключей)
  • (матрица проекции Значений)
  • Размерность этих матриц — . Когда входной вектор слова (размером 512) умножается на такую матрицу, он превращается в вектор размером 64.

    Этот процесс похож на взгляд на трехмерный объект через разные цветные фильтры. Исходный смысл слова (512 чисел) содержит всю информацию о нем. Умножение на извлекает из него только грамматическую составляющую (64 числа). Умножение на извлекает только эмоциональную составляющую (другие 64 числа).

    Шаг 2: Параллельное вычисление внимания

    Теперь у нас есть 8 независимых наборов размерностью 64. Каждая голова выполняет стандартную операцию масштабированного скалярного произведения, которую мы изучали ранее:

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

    !Интерактивная визуализация работы разных голов внимания на одном предложении

    Шаг 3: Конкатенация (Склейка)

    После того как все 8 голов закончили вычисления, каждая из них выдает обновленный вектор Значений для каждого слова. Размер этого вектора — 64.

    Теперь нам нужно собрать результаты работы нашей «команды экспертов» воедино. Для этого векторы просто склеиваются друг с другом (операция конкатенации):

    Конкатенация 8 векторов по 64 числа дает нам один большой вектор: .

    Мы вернулись к исходной размерности !

    Шаг 4: Финальная линейная проекция

    Просто склеить векторы недостаточно. Первые 64 числа теперь содержат только грамматику, вторые 64 — только семантику и так далее. Нам нужно перемешать эти знания, чтобы модель могла сделать комплексный вывод.

    Для этого склеенный вектор умножается на финальную матрицу весов (размерностью ).

    Итоговая формула многоголового внимания выглядит так:

    Эта матрица работает как главный редактор, который берет отчеты от всех 8 специалистов, анализирует их пересечения и пишет итоговое резюме для каждого слова.

    Анатомия тензоров: Пошаговый пример с числами

    Чтобы окончательно развеять магию, давайте проследим, как меняются формы матриц (тензоров) на каждом этапе. Понимание размерностей — это ключ к пониманию нейросетей.

    Допустим, мы обрабатываем предложение из 4 слов: «Кот спит на столе». Параметры модели: , , .

  • Входные данные (): Матрица размером [4, 512] (4 слова, каждое описано 512 числами).
  • Проекция для Головы 1: Умножаем [4, 512] на матрицу весов [512, 64]. Получаем матрицу Запросов размером [4, 64].
  • Скалярное произведение: Умножаем [4, 64] на транспонированную матрицу Ключей [64, 4]. Результат — матрица сырых оценок размером [4, 4]. Это таблица 4x4, показывающая связь каждого слова с каждым.
  • Softmax: Применяем к матрице [4, 4], превращая числа в проценты.
  • Умножение на Значения: Умножаем матрицу процентов [4, 4] на матрицу Значений [4, 64]. Результат работы первой головы — матрица [4, 64].
  • Конкатенация: Берем 8 таких матриц [4, 64] от всех голов и склеиваем их по горизонтали. Получаем матрицу [4, 512].
  • Финальная проекция: Умножаем [4, 512] на [512, 512]. Итоговый результат слоя внимания — матрица [4, 512].
  • Как видите, слой Multi-Head Attention принимает на вход матрицу [4, 512] и отдает матрицу [4, 512]. Внешне размер данных не изменился, но внутреннее содержание векторов кардинально преобразилось: теперь каждое слово содержит в себе сложный, многослойный контекст всего предложения.

    Эволюция внимания: MQA и GQA

    Классическое многоголовое внимание (MHA), описанное выше, идеально работает при обучении модели. Но когда мы используем уже обученную LLM для генерации текста (этап Inference), возникает проблема с оперативной памятью видеокарт (VRAM).

    При генерации каждого нового слова модель должна помнить Ключи () и Значения () всех предыдущих слов. Это называется KV Cache (Кэш ключей и значений). В классическом MHA для каждой из десятков голов нужно хранить свои уникальные матрицы и . Для длинных текстов (например, контекст в 100 000 токенов) размер KV Cache может превышать десятки гигабайт, что делает генерацию медленной и дорогой.

    Чтобы решить эту проблему, инженеры разработали оптимизированные версии многоголового внимания, которые сегодня используются в передовых моделях (таких как LLaMA 3, Mistral, Claude).

    Multi-Query Attention (MQA)

    В архитектуре MQA у нас по-прежнему много голов для Запросов (), но только одна общая голова для Ключей () и Значений ().

    > Если MHA — это 8 детективов, у каждого из которых свой блокнот с уликами, то MQA — это 8 детективов, которые смотрят на одну общую доску с уликами.

    Это радикально (в раз) сокращает размер KV Cache. Модель генерирует текст намного быстрее и потребляет меньше памяти, при этом качество ответов падает лишь незначительно.

    Grouped-Query Attention (GQA)

    GQA — это золотая середина между классическим MHA и экстремальным MQA. В этом подходе головы Запросов разбиваются на группы. Каждая группа делит между собой одну пару матриц и .

    Например, если у нас 32 головы Запросов, мы можем разбить их на 8 групп (по 4 головы в каждой). Тогда нам нужно хранить в памяти только 8 пар и вместо 32.

    | Тип внимания | Количество | Количество и | Потребление памяти | Качество модели | | :--- | :--- | :--- | :--- | :--- | | MHA (Классика) | (много) | (много) | Очень высокое | Максимальное | | MQA (Один кэш) | (много) | 1 (одна пара) | Минимальное | Слегка снижено | | GQA (Группы) | (много) | (несколько групп) | Среднее | Почти как у MHA |

    Современные LLM, такие как LLaMA 2 и LLaMA 3, используют именно GQA. Это позволяет им обрабатывать огромные контексты на обычных потребительских видеокартах без существенной потери «интеллекта».

    Итог

    Многоголовое внимание — это механизм, который позволяет Трансформерам понимать язык во всей его сложности. Разделяя векторы на меньшие подпространства, модель создает независимых «экспертов», каждый из которых фокусируется на своей грани смысла: от базовой грамматики до тонкого сарказма.

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

    Теперь, когда мы полностью разобрали внутреннее устройство Трансформера — от эмбеддингов до многоголового внимания — мы готовы ответить на следующий важный вопрос: откуда эти матрицы весов берут свои значения? В следующей статье мы перейдем к этапу предварительного обучения (Pre-training) и узнаем, как LLM читают весь интернет, чтобы превратить случайные числа в осмысленное понимание мира.

    7. Полносвязные нейронные сети (Feed-Forward Networks) в Трансформере

    Полносвязные нейронные сети (Feed-Forward Networks) в Трансформере

    На предыдущих этапах мы разобрали, как механизм многоголового внимания (Multi-Head Attention) позволяет словам обмениваться контекстом. Вектор каждого токена, пройдя через слой внимания, впитывает в себя информацию о других словах в предложении.

    Однако, если бы архитектура Трансформера состояла только из слоев внимания, модель была бы неспособна к сложным логическим выводам и запоминанию фактов. Внимание — это механизм связи, но не механизм глубокой обработки.

    Чтобы превратить собранный контекст в конкретные знания и предсказания, Трансформер использует полносвязные нейронные сети (Feed-Forward Networks, или FFN). Этот слой применяется к каждому вектору слова индивидуально и независимо от других слов.

    Проблема линейности и зачем нужен FFN

    Механизм внутреннего внимания, несмотря на свою кажущуюся сложность, математически представляет собой серию умножений и сложений матриц (взвешенную сумму). За исключением функции Softmax, это линейные операции.

    В математике есть строгое правило: любая последовательность линейных преобразований может быть сведена к одному линейному преобразованию.

    Представьте, что вы умножаете число на 2, затем на 3, а затем на 4. Вы можете пропустить эти шаги и просто умножить число на 24. Точно так же, если мы поставим друг за другом 100 слоев внимания без дополнительных элементов, математически они «схлопнутся» в один эквивалентный слой. Модель не станет умнее от добавления глубины, она просто будет выполнять одну и ту же базовую операцию.

    Чтобы нейросеть могла аппроксимировать сложные, нелинейные функции (а человеческий язык — это крайне нелинейная система), нам необходимо внедрить нелинейность. Именно эту роль берет на себя слой FFN.

    Если механизм внимания — это совещание, на котором сотрудники (токены) обмениваются отчетами, то слой FFN — это момент, когда каждый сотрудник возвращается за свой рабочий стол, анализирует полученные данные, применяет к ним свои профессиональные знания и делает индивидуальные выводы.

    Архитектура FFN: Расширение и сжатие

    В классической архитектуре Трансформера слой FFN состоит из двух линейных преобразований (умножений на матрицы весов), между которыми применяется нелинейная функция активации.

    Процесс обработки вектора слова проходит через три этапа:

    1. Этап расширения (Проекция вверх)

    Вектор слова, который выходит из слоя внимания, имеет размерность (в оригинальной статье — 512 чисел). На первом этапе этот вектор умножается на матрицу весов , которая проецирует его в пространство гораздо большей размерности.

    Обычно внутренний скрытый слой FFN в 4 раза больше входного. Таким образом, вектор из 512 чисел превращается в вектор из 2048 чисел.

    Зачем нужно это расширение? Представьте плотно упакованный чемодан (вектор 512). Чтобы найти в нем конкретную вещь, вам нужно вытащить все содержимое и разложить на большой кровати (вектор 2048). В многомерном пространстве нейросети гораздо проще разделить сложные признаки, найти скрытые паттерны и изолировать нужную информацию.

    2. Функция активации (Нелинейность)

    К полученному расширенному вектору применяется функция активации. В классическом Трансформере используется функция ReLU (Rectified Linear Unit).

    Математически она выглядит предельно просто:

    Где:

  • — каждое отдельное число в векторе.
  • — операция, которая оставляет положительные числа без изменений, а все отрицательные числа превращает в нуль.
  • Несмотря на простоту, именно отсечение отрицательных значений создает ту самую нелинейность, которая позволяет Трансформеру обучаться сложным правилам языка.

    В современных моделях (таких как GPT-3 или BERT) часто используется более плавная версия — GELU (Gaussian Error Linear Unit). Она не просто обнуляет отрицательные числа, а взвешивает их на основе статистического распределения, что делает процесс обучения более стабильным.

    3. Этап сжатия (Проекция вниз)

    После того как нелинейная функция отфильтровала информацию (обнулив ненужные связи), огромный вектор размером 2048 умножается на вторую матрицу весов .

    Эта матрица сжимает вектор обратно до исходной размерности (512 чисел). Чемодан снова аккуратно упакован, но теперь в нем лежит только та информация, которая действительно важна для предсказания следующего слова.

    !Схема работы полносвязной сети в Трансформере: расширение и сжатие вектора

    Математическая формула FFN

    Полная формула полносвязного слоя для одного вектора выглядит так:

    Где:

  • — входной вектор токена (размерность 512).
  • — первая матрица весов (размерность ).
  • — вектор смещения (bias) для первого слоя (размерность 2048).
  • — функция активации ReLU.
  • — вторая матрица весов (размерность ).
  • — вектор смещения для второго слоя (размерность 512).
  • Важно подчеркнуть: матрицы и абсолютно одинаковы для всех слов в предложении на данном слое. То есть слово «Кот» и слово «спит» обрабатываются одними и теми же весами. Однако на разных слоях Трансформера (например, на 1-м и на 12-м) эти матрицы будут разными.

    Гипотеза «Банка памяти» (Key-Value Memory)

    Долгое время исследователи понимали математику FFN, но не до конца понимали его семантическую роль. Внимание отвечает за контекст, но где модель хранит фактические знания? Откуда LLM знает, что столица Франции — Париж?

    В 2020 году группа исследователей (Geva et al.) опубликовала прорывную работу, доказав, что слои FFN в Трансформере работают как гигантский банк памяти в формате «Ключ-Значение» (Key-Value).

    Давайте посмотрим на матрицы и под другим углом:

  • Матрица работает как набор Ключей (Паттернов).
  • Когда вектор слова (уже обогащенный контекстом через внимание) умножается на , сеть проверяет, соответствует ли этот вектор определенным шаблонам. Например, один из 2048 нейронов скрытого слоя может активироваться только тогда, когда видит концепцию «страна + запрос столицы». Если на вход поступает вектор фразы «Столица Франции», этот конкретный нейрон выдаст высокое положительное число.

  • Функция активации (ReLU) работает как фильтр.
  • Она обнуляет все нейроны, которые не распознали свои паттерны. Остаются активными только те «ключи», которые совпали с контекстом.

  • Матрица работает как набор Значений (Ответов).
  • Каждому нейрону из скрытого слоя соответствует определенный вектор в матрице . Этот вектор содержит распределение вероятностей словаря. Нейрон, который распознал паттерн «столица Франции», активирует соответствующий ему вектор в , который концептуально означает слово «Париж».

    Таким образом, FFN — это место, где Трансформер хранит свои энциклопедические знания. Чем шире скрытый слой (чем больше в нем нейронов, например, не 2048, а 10000), тем больше фактов может запомнить модель. Именно поэтому увеличение количества параметров в LLM в первую очередь происходит за счет расширения матриц FFN.

    Эволюция FFN: SwiGLU в современных LLM

    Архитектура, описанная в оригинальной статье 2017 года, стала классикой, но наука не стоит на месте. Современные модели с открытым исходным кодом, такие как LLaMA (от Meta) или Mistral, используют модифицированную версию полносвязного слоя, которая называется SwiGLU (Swish Gated Linear Unit).

    Вместо простой функции ReLU и двух матриц, SwiGLU использует три матрицы и более сложную математику ворот (gates).

    В классическом FFN информация просто проходит через фильтр. В SwiGLU вектор разделяется на два потока:

  • Первый поток проходит через функцию активации Swish (которая похожа на ReLU, но более плавная и допускает небольшие отрицательные значения).
  • Второй поток остается линейным.
  • Затем эти два потока перемножаются друг с другом.
  • Первый поток работает как «ворота» (gate) — он решает, какую часть информации из второго потока пропустить дальше. Это позволяет модели более тонко контролировать поток данных.

    Практика показала, что при одинаковом количестве параметров модели с архитектурой SwiGLU обучаются быстрее и показывают лучшие результаты в тестах на логику и понимание текста, чем модели с классическим ReLU FFN.

    Сборка блока: Остаточные связи и Нормализация

    Теперь мы знаем два главных компонента Трансформера: Multi-Head Attention и Feed-Forward Network. Но если мы просто соединим их последовательно, глубокая нейросеть (например, из 96 слоев, как GPT-3) не сможет обучаться из-за проблемы затухания градиента.

    При прохождении через десятки матриц и функций активации, сигнал ошибки, необходимый для обучения, будет искажаться и теряться. Чтобы этого избежать, создатели Трансформера обернули слои Внимания и FFN в защитный механизм, состоящий из двух элементов: Остаточных связей (Residual Connections) и Слойной нормализации (Layer Normalization).

    В архитектуре этот блок называется Add & Norm.

    Остаточные связи (Add)

    Остаточная связь — это обходной путь для данных. Вместо того чтобы заставлять вектор проходить только через сложную математику слоя внимания, мы берем исходный вектор и прибавляем его к результату работы слоя внимания.

    Где:

  • — исходный вектор слова.
  • — результат работы механизма внимания (или FFN).
  • Аналогия: представьте, что вы редактируете документ. — это оригинальный текст. — это ваши правки. Вместо того чтобы полностью переписывать документ, вы просто накладываете правки поверх оригинала. Если правки оказались неудачными (на ранних этапах обучения нейросеть выдает шум), оригинальный текст сохраняется. Это создает «скоростное шоссе» для градиентов, позволяя обучать сети практически неограниченной глубины.

    Слойная нормализация (Norm)

    После сложения векторов () числа в получившемся векторе могут стать слишком большими или слишком маленькими. Это дестабилизирует обучение.

    Слойная нормализация (LayerNorm) берет вектор каждого отдельного слова, вычисляет среднее значение всех его чисел и их дисперсию (разброс). Затем она сдвигает и масштабирует числа так, чтобы их среднее значение стало равно 0, а стандартное отклонение — 1.

    Это похоже на настройку громкости звука: если сигнал слишком тихий, нормализация его усиливает, если слишком громкий — приглушает. Благодаря этому каждый следующий слой Трансформера получает данные в предсказуемом, стандартизированном формате.

    Полный цикл одного слоя Трансформера

    Давайте сведем воедино путь вектора слова через один полный блок Трансформера (Encoder или Decoder):

  • Вход: Вектор слова (с добавленным позиционным кодированием) поступает в блок.
  • Внимание: Вектор проходит через Multi-Head Attention, где обменивается информацией с другими словами. Получаем контекстно-обогащенный вектор.
  • Add & Norm 1: Исходный вектор складывается с результатом внимания, после чего нормализуется.
  • FFN: Нормализованный вектор проходит через полносвязную сеть (расширение активация сжатие), где извлекаются факты и применяются логические правила.
  • Add & Norm 2: Вектор до FFN складывается с результатом FFN, после чего снова нормализуется.
  • Выход: Готовый вектор передается на следующий слой Трансформера.
  • Современные LLM состоят из десятков таких блоков, поставленных друг на друга. С каждым новым слоем векторы становятся все более абстрактными. На первых слоях они отражают базовую грамматику и синтаксис. На средних слоях — семантику и факты. На последних слоях векторы содержат глубокое концептуальное понимание всего текста, готовое для генерации ответа.

    8. Остаточные связи (Residual Connections): Борьба с затуханием градиента

    Остаточные связи (Residual Connections): Борьба с затуханием градиента

    На предыдущих этапах мы собрали два главных вычислительных двигателя Трансформера: механизм многоголового внимания (Multi-Head Attention), который позволяет словам обмениваться контекстом, и полносвязные сети (Feed-Forward Networks), которые работают как банк памяти и логический процессор.

    Кажется, что рецепт создания мощной Большой Языковой Модели (LLM) готов: нужно просто взять эти два слоя, поставить их друг за другом и повторить этот блок 50, 100 или 200 раз. Чем глубже нейросеть, тем более сложные абстракции она способна выучить. Например, модель GPT-3 состоит из 96 таких слоев.

    Однако, если мы просто соединим слои внимания и FFN последовательно, глубокая нейросеть не сможет обучиться. Она застрянет на первых же эпохах, выдавая бессмысленный шум. Причиной этого провала является фундаментальная математическая проблема глубокого обучения — затухание градиента (Vanishing Gradient Problem).

    Чтобы понять, как Трансформеры преодолевают этот барьер и достигают огромной глубины, нам нужно разобраться в механике обучения нейросетей и познакомиться с элегантным решением — остаточными связями (Residual Connections).

    Как обучаются нейросети: Краткий курс по градиентам

    Нейросети не рождаются умными. В момент создания все матрицы весов (в слоях внимания и FFN) заполнены случайными числами. Обучение — это процесс постепенной корректировки этих чисел так, чтобы модель начала выдавать правильные ответы.

    Этот процесс опирается на алгоритм обратного распространения ошибки (Backpropagation). Он работает в два этапа:

  • Прямой проход (Forward Pass): Текст проходит через все слои сети от начала до конца. Модель делает предсказание (например, пытается угадать следующее слово). Поскольку веса случайные, предсказание оказывается ошибочным.
  • Обратный проход (Backward Pass): Вычисляется ошибка (насколько предсказание далеко от истины). Затем эта ошибка передается в обратном направлении — от последнего слоя к первому.
  • В ходе обратного прохода для каждого параметра вычисляется градиент. Простыми словами, градиент — это сигнал, который говорит каждому конкретному числу в матрице: «Тебе нужно немного увеличиться» или «Тебе нужно сильно уменьшиться, чтобы в следующий раз ошибка стала меньше».

    Корпоративная аналогия

    Представьте огромную корпорацию из 100 уровней управления. Генеральный директор (функция потерь) видит, что компания выпустила плохой продукт. Он вызывает вице-президента (99-й слой) и дает ему обратную связь (градиент). Вице-президент корректирует свою работу и передает указания директору (98-й слой). Директор передает их менеджеру, менеджер — супервайзеру, и так далее, вплоть до рядового стажера (1-й слой).

    Проблема затухания градиента

    В математике нейросетей передача ошибки от слоя к слою осуществляется с помощью правила дифференцирования сложной функции (Chain Rule). На практике это означает, что градиент на каждом шаге умножается на производную функции активации и веса текущего слоя.

    Проблема заключается в том, что эти производные часто являются числами, меньшими единицы (например, 0.5, 0.1, 0.01).

    Что происходит, когда мы перемножаем много чисел, которые меньше единицы? Результат стремительно приближается к нулю.

    Давайте посчитаем. Допустим, на каждом слое сигнал ошибки ослабевает всего на 10% (то есть умножается на 0.9). Если у нас сеть из 100 слоев, то сигнал, который дойдет до первого слоя, будет равен:

    Градиент «затух». Возвращаясь к нашей корпоративной аналогии: пока приказ генерального директора спускался через 100 уровней менеджеров, каждый из которых немного смягчал критику, до рядового стажера дошло лишь невнятное бормотание. Стажер (первый слой нейросети) не получает четкого сигнала к изменению и перестает обучаться. А если первые слои не могут извлечь базовые признаки из текста, то и вся остальная сеть будет работать с мусором.

    Остаточные связи: Гениальное решение

    В 2015 году группа исследователей из Microsoft (Kaiming He и коллеги) предложила невероятно простое, но революционное решение этой проблемы в архитектуре ResNet (Residual Networks). Создатели Трансформера позаимствовали эту идею.

    Вместо того чтобы заставлять вектор данных проходить исключительно через сложные преобразования слоя (умножения матриц, функции активации), они добавили обходной путь.

    Математически это выражается простейшей формулой:

    Где:

  • — входной вектор (оригинальные данные до обработки слоем).
  • — результат обработки вектора слоем (например, механизмом внимания или FFN).
  • — итоговый вектор, который пойдет на следующий слой.
  • !Схема остаточной связи в нейронной сети

    Почему это называется «остаточной» связью?

    В классической сети слой пытается выучить полное преобразование данных (превратить в идеальный ).

    С остаточной связью слой учится предсказывать только разницу (остаток, residual) между тем, что у нас уже есть (), и тем, что нам нужно получить.

    Аналогия с редактированием текста: Представьте, что — это черновик статьи. В обычной нейросети каждый редактор (слой) берет черновик, читает его, выбрасывает в корзину и пишет весь текст заново по памяти. На 50-м редакторе от оригинальной мысли может ничего не остаться.

    С остаточными связями редактор берет черновик (), берет красную ручку и пишет только правки на полях (). Итоговый документ — это оригинальный текст плюс правки. Если редактор неопытный (сеть в начале обучения) и его правки — это просто шум, мы можем проигнорировать их (приравнять к нулю), и у нас все равно останется нетронутый оригинальный черновик.

    Математика спасения: Скоростное шоссе для градиентов

    Почему простое сложение () решает проблему затухания градиента? Секрет кроется в том, как операция сложения ведет себя во время обратного распространения ошибки.

    В математическом анализе производная суммы равна сумме производных. Если мы возьмем производную от нашей формулы по , мы получим:

    Эта единица () — спаситель глубокого обучения.

    Во время обратного прохода операция сложения работает как маршрутизатор, который копирует градиент и отправляет его по двум путям:

  • Первый путь идет через сложный слой , где градиент перемножается с матрицами и может затухнуть.
  • Второй путь идет через обходное соединение (ту самую единицу). Умножение на 1 не меняет число.
  • Градиент получает скоростное шоссе (Gradient Highway), по которому он может беспрепятственно промчаться от самого последнего слоя к самому первому, вообще не затухая. Даже если внутри слоя внимания градиент полностью уничтожится (станет равен 0), обходной путь гарантирует, что сигнал ошибки дойдет до предыдущих слоев в первозданном виде.

    Интеграция в Трансформер: Блок Add & Norm

    В архитектуре Трансформера остаточные связи применяются вокруг каждого подслоя. Если вы посмотрите на классическую схему Трансформера, вы увидите блоки с надписью Add & Norm.

    «Add» — это и есть остаточная связь (сложение оригинального вектора с обработанным). «Norm» — это слойная нормализация (Layer Normalization), о которой мы кратко упоминали ранее.

    Полный цикл обработки вектора внутри одного слоя Трансформера выглядит так:

  • Вектор поступает на вход.
  • Вычисляется Multi-Head Attention: .
  • Применяется первая остаточная связь и нормализация: .
  • Вектор проходит через полносвязную сеть: .
  • Применяется вторая остаточная связь и нормализация: .
  • Зачем нужна нормализация после сложения?

    Когда мы складываем два многомерных вектора, значения чисел внутри получившегося вектора могут стать слишком большими. Если на каждом из 96 слоев мы будем прибавлять новые значения, числа вырастут до астрономических масштабов, что приведет к нестабильности обучения (проблема взрывающегося градиента).

    Слойная нормализация (LayerNorm) берет получившийся вектор, вычисляет среднее значение всех его элементов и приводит их к единому масштабу (среднее становится равным 0, а стандартное отклонение — 1). Это стабилизирует сеть, не меняя при этом семантический смысл, закодированный в векторе.

    Эволюция архитектуры: Post-LN против Pre-LN

    Архитектура, описанная выше (где нормализация применяется после сложения), называется Post-LN (Post-Layer Normalization). Именно она была представлена в оригинальной статье «Attention Is All You Need» в 2017 году.

    Однако, когда исследователи попытались масштабировать Трансформеры до размеров современных LLM (миллиарды параметров), они столкнулись с проблемой. Архитектура Post-LN оказалась очень капризной на старте обучения. Из-за того, что нормализация стояла прямо на «скоростном шоссе» остаточной связи, она искажала градиенты на ранних этапах, требуя сложных математических трюков (например, Learning Rate Warmup — искусственного занижения скорости обучения в начале).

    Решение оказалось поразительно простым. Начиная с модели GPT-2, индустрия перешла на архитектуру Pre-LN (Pre-Layer Normalization).

    В подходе Pre-LN нормализация применяется до входа в сложный слой, а не после сложения. Формула изменилась:

    Разница кажется незначительной, но архитектурно она меняет всё. Теперь «скоростное шоссе» () абсолютно чистое. На нем нет ни матричных умножений, ни даже слоев нормализации. Оригинальный вектор может пройти от первого до последнего слоя Трансформера вообще без изменений, если все подслои выдадут нули.

    Почти все современные открытые LLM, включая семейства LLaMA (от Meta), Mistral и Qwen, используют именно архитектуру Pre-LN (или её современные вариации, такие как RMSNorm). Это позволило обучать модели огромной глубины стабильно и без сбоев.

    Итог шага

    Остаточные связи — это невидимый герой архитектуры Трансформеров. Механизм внимания дает модели способность понимать контекст, FFN дает ей знания и логику, но именно остаточные связи (простое математическое сложение ) позволяют собрать эти компоненты в глубокую сеть из десятков слоев, способную к сложному мышлению, не позволяя сигналу обучения затухнуть по пути.

    9. Нормализация слоев (Layer Normalization): Стабилизация скрытых состояний

    Нормализация слоев (Layer Normalization): Стабилизация скрытых состояний

    На предыдущем этапе мы разобрали механизм остаточных связей (Residual Connections), который работает как «скоростное шоссе» для градиентов, позволяя обучать нейросети огромной глубины. Мы выяснили, что в архитектуре Трансформера этот механизм всегда идет в паре с еще одной важнейшей операцией, образуя единый блок Add & Norm.

    «Add» — это сложение оригинального вектора с обработанным. Но что такое «Norm»?

    Если остаточные связи спасают модель от затухания сигнала при обучении, то нормализация слоев (Layer Normalization, или LayerNorm) спасает модель от хаоса и взрыва значений внутри самой сети. Без этого механизма скрытые состояния (векторы, представляющие слова) превратились бы в неконтролируемый набор астрономических чисел уже к пятому слою Трансформера.

    Проблема: Хаос в многомерном пространстве

    Представьте, что вектор токена — это звук. В начале пути (после слоя эмбеддингов) каждое слово звучит четко и с умеренной громкостью.

    Затем этот вектор попадает в механизм внутреннего внимания (Self-Attention). Там он умножается на матрицы Запросов, Ключей и Значений, складывается с векторами других слов. После этого он проходит через остаточную связь (где к нему прибавляют его же прошлую версию) и отправляется в полносвязную сеть (Feed-Forward Network), где снова умножается на огромные матрицы весов.

    При каждом матричном умножении и сложении числа внутри вектора неизбежно меняют свой масштаб.

    Допустим, на входе в первый слой вектор слова «Король» выглядел так:

    После прохождения через механизмы внимания и FFN, из-за постоянных умножений и сложений, значения могут неконтролируемо вырасти:

    К десятому слою эти числа могут достигнуть десятков тысяч. В глубоком обучении это явление тесно связано с проблемой внутреннего ковариационного сдвига (Internal Covariate Shift). Суть в том, что каждый следующий слой нейросети вынужден постоянно адаптироваться к новому, непредсказуемому масштабу данных, которые приходят от предыдущего слоя.

    > Если дирижер хора (функция потерь) пытается научить певцов (слои нейросети) гармонии, но на каждой репетиции одни певцы начинают шептать, а другие — кричать в рупор, хор никогда не споется. Нейросети нужна стабильность.

    Что такое нормализация?

    В математике и статистике нормализация — это процесс приведения данных к единому, стандартному масштабу. Самый популярный вид нормализации (стандартизация) делает так, чтобы среднее значение всех чисел стало равно нулю (), а их разброс (стандартное отклонение) стал равен единице ().

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

    Batch Normalization vs. Layer Normalization

    До появления Трансформеров в 2017 году стандартом индустрии (особенно в компьютерном зрении) была пакетная нормализация (Batch Normalization). Однако создатели Трансформера отказались от нее в пользу нормализации слоев (Layer Normalization). Чтобы понять почему, нужно увидеть разницу между ними.

    Нейросети обучаются не по одному предложению, а «пакетами» (batches). Представьте, что в пакет загрузили 3 предложения, и мы смотрим на первое число (первую координату) в векторах первых слов каждого предложения.

    !Схема сравнения Batch Normalization и Layer Normalization

    Подход 1: Batch Normalization (Нормализация по пакету)

    При Batch Norm мы берем одну конкретную координату (например, координату №1, отвечающую за одушевленность) и вычисляем ее среднее значение среди всех слов во всех предложениях текущего пакета.

    Почему это плохо для текста? Длина предложений всегда разная. Одно предложение состоит из 5 слов, другое из 50. Если мы нормализуем данные поперек пакета, статистика (среднее значение) будет постоянно прыгать в зависимости от того, какие именно предложения случайно попали в этот пакет. Более того, при генерации текста (когда модель пишет по одному слову) размер пакета фактически равен 1, и Batch Norm ломается, так как невозможно посчитать статистику по одному элементу.

    Подход 2: Layer Normalization (Нормализация по слою)

    При Layer Norm мы берем одно конкретное слово (один токен) и вычисляем среднее значение среди всех координат внутри вектора этого слова.

    Мы нормализуем каждый токен индивидуально, опираясь только на его собственные характеристики.

    Почему это идеально для Трансформеров? LayerNorm вообще не зависит от того, сколько предложений в пакете и какой они длины. Вектор слова «Король» будет нормализован абсолютно одинаково, независимо от того, стоит ли оно в предложении из трех слов или в абзаце из тысячи токенов.

    Сравнительная таблица

    | Характеристика | Batch Normalization | Layer Normalization | | :--- | :--- | :--- | | Ось вычисления | По одной фиче (координате) через весь батч | По всем фичам (координатам) внутри одного токена | | Зависимость от размера батча | Критически зависит (плохо работает на малых батчах) | Вообще не зависит (работает даже для одного токена) | | Работа с разной длиной текста | Требует сложных костылей (padding masking) | Работает естественно и без проблем | | Главная сфера применения | Сверточные сети (CNN), компьютерное зрение | Трансформеры (LLM), обработка естественного языка |

    Математика Layer Normalization: Шаг за шагом

    Давайте заглянем под капот и посмотрим, как именно Трансформер нормализует вектор. Процесс состоит из четырех математических шагов.

    Допустим, после слоя внимания мы получили вектор токена , который состоит из 4 координат (в реальности их, например, 4096, но для примера возьмем 4):

    Шаг 1: Вычисление среднего значения ()

    Сначала мы находим среднее арифметическое всех чисел в векторе. Складываем их и делим на количество.

    Где — размерность вектора (в нашем случае 4), а — каждое отдельное число.

    Пример: Среднее значение нашего вектора равно .

    Шаг 2: Вычисление дисперсии ()

    Дисперсия показывает, насколько сильно числа в векторе «разбросаны» относительно среднего значения. Мы берем каждое число, вычитаем из него среднее, возводим результат в квадрат (чтобы избавиться от минусов) и находим среднее от этих квадратов.

    Пример: 1. 2. 3. 4.

    Дисперсия

    Шаг 3: Стандартизация

    Теперь мы берем каждое оригинальное число, вычитаем из него среднее () и делим на стандартное отклонение (корень из дисперсии ).

    Здесь появляется маленькая деталь — (эпсилон). Это крошечное число (например, ), которое добавляется к дисперсии исключительно ради математической безопасности. Если вдруг все числа в векторе одинаковые, дисперсия будет равна нулю. Делить на ноль нельзя, поэтому спасает программу от ошибки (краша).

    Пример (игнорируя для простоты): Стандартное отклонение =

    Новый вектор : 1. 2. 3. 4.

    Наш вектор превратился из в . Его новое среднее значение ровно , а разброс стандартизирован. Мы «укротили» масштаб чисел, не изменив пропорции между ними.

    Шаг 4: Масштабирование и сдвиг (Scale and Shift)

    Если мы остановимся на третьем шаге, мы создадим новую проблему. Мы жестко заставили все векторы в нейросети иметь среднее и отклонение .

    Но что, если для понимания конкретного контекста Трансформеру действительно нужно, чтобы вектор имел смещенное среднее или больший разброс? Жесткая нормализация может уничтожить полезную информацию, которую сеть с трудом извлекла на слое внимания.

    Поэтому в LayerNorm добавляют два обучаемых параметра — (гамма) и (бета).

  • (масштаб) — позволяет сети растянуть или сжать вектор обратно, если это нужно.
  • (сдвиг) — позволяет сети сместить среднее значение вектора.
  • В начале обучения , а (то есть они ничего не меняют). Но в процессе обучения нейросеть сама решает: «Ага, на 15-м слое мне выгоднее, чтобы разброс чисел был чуть больше, поэтому я увеличу для этого слоя».

    Это гениальный компромисс: мы сначала принудительно стабилизируем данные (чтобы избежать взрыва градиентов), а затем даем сети ключи управления ( и ), чтобы она могла аккуратно восстановить нужный ей масштаб.

    Эволюция: От LayerNorm к RMSNorm

    Архитектура Трансформеров не стоит на месте. Когда исследователи начали создавать современные гигантские LLM (такие как LLaMA от Meta или Mistral), они задумались об оптимизации.

    Вычисление среднего значения () и дисперсии на каждом слое для десятков тысяч токенов требует вычислительных ресурсов. Исследователи задались вопросом: «А так ли важно центрировать вектор вокруг нуля (вычитать среднее)? Может быть, достаточно просто ограничить разброс чисел?»

    Так появилась RMSNorm (Root Mean Square Normalization — Нормализация по среднеквадратичному значению).

    Формула RMSNorm выглядит гораздо проще. Она полностью выбрасывает шаг вычисления среднего значения:

    Вместо того чтобы искать среднее и вычитать его, RMSNorm просто берет квадраты всех чисел, находит их среднее и делит вектор на корень из этого значения.

    Почему это важно? Отказ от центрирования (вычитания ) практически не снижает качество работы LLM, но при этом делает операцию нормализации на 10–30% быстрее. В масштабах моделей с 70 миллиардами параметров, которые обучаются месяцами на тысячах видеокарт, это экономит миллионы долларов на электричестве и вычислительных мощностях. Именно поэтому большинство современных открытых LLM используют RMSNorm вместо классического LayerNorm.

    Итог шага

    Нормализация слоев — это внутренний стабилизатор Трансформера.

    Вместе с остаточными связями (о которых мы говорили ранее) они образуют идеальный тандем:

  • Residual Connections гарантируют, что сигнал обучения дойдет до самых первых слоев, не затухнув по пути.
  • Layer Normalization гарантирует, что числа внутри векторов не взорвутся и не превратятся в хаос после прохождения через сложные математические преобразования.
  • Благодаря блоку Add & Norm мы можем собирать Трансформеры как конструктор Lego, ставя друг на друга 10, 50 или 100 слоев, и быть уверенными, что эта гигантская конструкция будет работать стабильно.