Традиционный дисклеймер
Статья посвящёна проблеме выбора метода позиционного кодирования в нейросетевых моделях на основе архитектуры Transformer. От читателя требуется понимание общих принципов работы Transformer и устройства self-attention. Если хочется сперва разобраться в существующих моделях от самых простых до более современных, можно заглянуть в этот обзор. Если непонятно вообще всё, то лучше начать с основ.
Введение
Это вторая статья о проблеме обработки Transformer длинных последовательностей, прежде всего текстовых. В предыдущем обзоре упор был сделан на методы повышения эффективности подсчёта self-attention, теперь поговорим про методы кодирования позиционной информации. Часть описываемых подходов вместе с несколькими менее популярными работами можно найти в неплохом обзоре.
В общем случае Transformer, в отличие от, например, RNN, обрабатывает входные векторы одновременно и без дополнительной информации о позиции каждого токена будет рассматривать последовательность как «мешок слов». Позиции могут кодироваться различными способами: с использованием синусоидальных векторов и без них, с добавлением векторов или модернизацией подсчёта внимания, с экстраполяцией или интерполяцией обученного контекста. Важными требованиями являются уникальность представления для каждой позиции, независимость расстояний между парами токенов от длины входа, детерминированность представлений и адаптация метода к расширению контекста модели.
Разберём основные популярные подходы, описанные в научных работах и используемые в известных LLM. Изображения либо нарисованы для статьи, либо взяты из первоисточников, туда же рекомендуется идти за подробностями реализаций и экспериментов. Названия подходов взяты либо из самих работ, либо введены в статье и являются сквозными для удобства навигации.
Основные обозначения и формулы
— векторы токенов входной последовательности
— векторы выходов головы self-attention
, — размерности векторов и соответственно
, , — векторы запросов, ключей и значений соответственно для слоя-головы
, , — весовые матрицы для получения векторов запросов, ключей и значений соответственно для слоя-головы
Формулы подсчёта self-attention:
Обзор работ
Sinusoidal и Trainable Absolute, 2017
Первый, наиболее простой, но вполне рабочий способ, был предложен авторами самого Transformer. Позиционная информация кодируется векторами, по одному на каждую абсолютную позицию в обрабатываемом контексте. Вектор позиции прибавляется к смысловому вектору токена (эмбеддингу) на входе модели, после чего результат подаётся в основную часть нейросети.
Сформировать вектор для позиции можно разными способами. Один из вариантов — простой учить такие векторы вместе с остальными частями сети. Это увеличивает число параметров и, как следствие, для небольших моделей может вырастить объём вычислений. Кроме того, при таком подходе модель не может обрабатывать последовательности с длиной, большей её контекста на обучении.
Более популярный и аналогичный по качеству работы метод — использование синусоидальных (тригонометрических) векторов. Элементы вектора определяются формулой:
Теоретически никто не мешает вычислить и использовать такие же векторы для новых позиций при расширении контекста, но на практике это работает не очень хорошо.
Большинство популярных методов работы с позициями — относительные, т.е. кодируется не одиночный индекс, а пара позиций на разных расстояниях друг от друга. Относительное кодирование производится не путём сложения векторов на входе, а через модификацию подсчёта внимания.
Эта работа была одной из первых в области, в ней предлагается для каждого расстояния обучать два вектора и использовать их в обновлённых формулах подсчёта self-attention:
Информация о позиции вкладывается в векторы ключей и значений. Вычисления можно ускорить, раскрыв скобки перед подсчётом, бученные векторы общие для всех голов внимания и слоёв.
Вход модели делится на сегменты, которые обрабатываются последовательно, при обработке -го сегмента используются выходы для -го. Абсолютное позиционное кодирование работать не будет: у обоих сегментов оно одинаковое. Предлагается относительная схема, как и в Relative, позиционная информация переходит в self-attention. Представим в виде суммы смысловой и позиционной частей и распишем формулу подсчёта логитов :
Репараметризуем полученное разложение для относительного кодирования, избавившись от зависимости от компоненты :
Абсолютные позиционные эмбеддинги заменяются на фиксированную синусоидальную матрицу относительных . Векторы запросов для позиционной предлагается брать одинаковыми и моделировать обучаемыми векторами и . Выделяются две весовые матрицы для получения векторов ключей эмбеддингов и позиций соответственно.
Интуитивный смысл каждого из слагаемых можно описать так:
содержательная смысловая связь
связь смысла и позиционной информации
глобальный смысловой сдвиг
глобальный позиционный сдвиг
В Relative есть только (1) и (2), сдвиги отбрасываются, хотя используются дополнительная модификация векторов значений. Кроме того, в Relative произведение заменяется одной обучаемой матрицей, что означает отказ от синусоидальных векторов и, как следствие, ухудшение обобщения на длинный контекст.
В этой популярной модели позиционная информация кодируется скаляром, который прибавляется к перед softmax. Скаляры соответствуют различным расстояниям-отступам . Всего скаляров 32, они в логарифмической шкале покрывают 128 отступов, т.е. близкие к 0 соседние отступы кодируются разными скалярами, а далёкие могут кодироваться одним:
Всем расстояниям, большим 128, соответствует один и тот же скаляр, он способствует обобщению модели на длинный контекст. Позиционные скаляры обучаемые и настраиваются вместе с моделью. Каждый следующий слой расширяет окно улавливаемой позиционной информации (идейно схоже с CNN или окном внимания в Longformer). Обученные скаляры свои для каждой головы self-attention, но общие для всех слоёв модели.
Как и в Transformer-XL, формула подсчёта логитов в self-attention раскладывается, и предлагается использовать первые 3 слагаемых:
По мнению авторов, слагаемое (3) тоже является важным важным для более полного моделирования информации о сдвиге, в то время как (4) — position-to-position term — для относительного кодирования несёт мало дополнительной информации.
Предлагаемая репараметризация довольно похоже на Transformer-XL:
Новые весовые матрицы свои у каждой пары голова-слой, матрица расстояний обучаемая, общая для всех слоёв и своя у каждой головы. Для всех отступов, не попадающих в размер , берутся векторы ближайшего с соответствующего конца отступа.
Интересный факт: несмотря на относительную схему кодирования, перед последним слоем в модели всё равно используются обучаемые абсолютные позиционные эмбеддинги.
Один из самых популярных методов, который не только регулярно используется в современных моделях (LLaMA, Qwen, Mistral), но активно модернизируются, о чем речь будет идти ниже.
Рассмотрим метод шаг за шагом. Если исключить позиционные эмбеддинги, то в обобщенном варианте формула для логитов выглядит так
т.е. зависит от функций от эмбеддингов и абсолютных позиций. Предлагается подобрать функции , такие, что
Можно доказать, что для случая подойдёт преобразование
где — заданная константа. Формула для аналогична. Подходящая функция при этом определяется так:
где — вещественная часть , — сопряжённая матрица к , а — мнимая единица. Применение RoPE заключается в повороте вектора запроса/ключа на угол, зависящий от индекса его позиции. Поворот обоих векторов на один угол, т.е. смещение позиций без изменения расстояния, сохранит значение скалярного произведения.
Полученное преобразование обобщается на любую чётную . Для этого делится на двумерных подпространств, к каждому из которых применяется свой матрица поворота. Итоговое выражение для ( аналогично):
где
В отличие от Absolute применяется не отдельным координатам, а к парам, и использует умножение на вместо суммы (мультипликация вместо аддитивности). В разных экспериментах RoPE показывает себя лучше, чем Absolute и Relative:
Теоретически RoPE должен помогать модели обобщаться на более длинный контекст, чем при обучении, но по факту это не работает, поэтому предпринимаются попытки улучшить его.
Этот метод тоже является достаточно популярным и развивает подход, схожий с T5: вместо добавления позиционных эмбеддингов или репараметризации подсчёта внимания к добавляется скаляр. Но в отличие от T5 скаляры не обучаются и представляют собой произведение , где — заданное на старте число, своё для каждой головы и общее для слоёв. Например, для 8 голов это могут быть .
В сравнении Absolute vs. RoPE vs T5 только T5 показал хорошую способность к обобщению на последовательностях с большей длиной, чем на обучении (до 600 токенов сверх исходных 512), но его преимущество перекрывается возрастающими вычислительными затратами, проще обучить модель с Absolute с большим контекстом. AliBi оказывается достаточно эффективным с т.з. скорости и памяти:
Также он обеспечивает большую степень обобщения, позволяя модели работать с контекстом, в разы более длинным, чем на обучении (по крайней мере с т.з. перплексии):
Один из способ доработки RoPE для лучшей адаптации к длинному контексту. Вводится понятие «ожидаемого значения внимания» для пары токенов на заданном расстоянии. Показывается, что в обычном RoPE при существенном росте расстояния эта величина начинает осциллировать, это портит качество модели:
Проблема объясняется тем, что значения косинуса не являются монотонными при угле поворота, большем . Решение: добавить задаваемые априорно дополнительные множители для каждой пары компонентов векторов и ( и в листинге алгоритма подсчёта внимания из статьи):
Введённые множители масштабируют компоненты векторов и стабилизируют график ожидаемого значения внимания, улучшая поведение модели на длинном контексте.
В введении было сказано, что отсутствие позиционной информации превращает Transformer в модель «мешка слов», но это точно верно только для моделей на основе кодировщика. Декодировщик, обучаемый авторегрессионно, теоретически способен работать без явной позиционной информации по аналогии с рекурентными сетями.
В работе формулируются и доказываются две теоремы. Первая гласит, что такая модель может выделять на своём первом слое абсолютную позиционую информацию. Вторая — что при верности первой на всех последующих слоях будет выявляться относительная информация.
Для проверки гипотезы предлагается маленький эксперимент с моделью размера , контекстом на обучении 20 и на тесте до 40. Модели с разным позиционным кодированием обучаются на 10 задачах, разделенных на 3 группы (задачи вида «сложить 2 числа» или «переставить слова»), можно видеть, что NoPE показывает себя неплохо:
Авторы задаются вопросом о схожести соответствующих выходов слоёв моделей для разных подходов. Близость между моделями и на слое можно определить как
где — дивергенция Йенсена-Шеннона по выходам двух голов. Оказалось, что модель, обучаемая без явной позиционной информации, более всего похожа на модель с кодированием T5:
Второй эксперимент ближе к реальной жизни: модель , контекст 1024 (на тесте до 2560), обучение авторегрессионное на данных из StarCoder. На графиках показана перплексия на 200 последних токенах:
NoPE всё равно ломается при росте длины контекста, хотя показывает себя ощутимо лучше, чем RoPE.
Positional Interpolation RoPE, 2023
Эта работа была опубликована почти одновременно с SuperHOT RoPE, в обеих описываются схожие идеи, существенно изменяющие идею расширения контекста обученной модели. Описанные выше подходы делают экстраполяцию: обучение на одном диапазоне, работа на другом. Вместо этого можно делать интерполяцию: обучить модель с RoPE и вложить увеличенный контекст в тот же диапазон с минимальным дообучением.
Вспомним функцию для получения из RoPE и определим вместо неё новую функцию :
где и — исходная и увеличенная длины контекста. Т.е. если модель выучила позиции 1, 2, 3 и т.д., сжатие в пределах диапазона этих значений приведёт к переходу на кодирование позиций 0.5, 1, 1.5, 2 и т.д.
Показано, что для адаптации к новому контексту достаточно дообучения на последовательностях, а замеры перплексии и качества на части бенчмарков LLaMA и суммаризации показывают преимущество 1К шагов дообучения с PI над 10К шагами обычного дообучения (FT).
В PI RoPE предлагается по сути делать линейную интерполяцию, что не является оптимальным вариантом. Согласно обзорному анализу из работы YaRN на основе теории Neural Tangent Kernel (NTK), для DL-моделей задача выучить многомерный комплексный вектор для кодирования одномерной по своей сути позиционной информации является проблемной. RoPE имеет сходство со специальным одномерным видом Fourier Features из NTK, и равномерное растяжение векторов RoPE (как в PI) приводит к потере высокочастотных деталей, необходимых для различения очень похожих и близких в тексте токенов. Т.е. минимальный поворот, отличающий позиции, оказывается слишком маленьким. Это может быть причиной некоторого падения качества PI RoPE на не-длинных сэмплах после дообучения (чего быть не должно).
В качестве одного из возможных альтернатив предлагается вместо изменения масштаба менять основание (которое 10000), и, как следствие, «скорость вращения» векторов:
Отношение новой и старой длин контекста называют фактором масштаба. Предлагаемый подход может работать адекватно даже без дообучения, но при этом в случае использования дообучения он уступает позиционной интерполяции. Это объясняется тем, что в некоторых измерениях векторов оказываются слишком большие числа, т.е. фактически вместо интерполяции получается экстраполяция.
Схожий подход использовался при обучении моделей LLaMA Long.
Довольно быстро был предложен метод, нивелирующий проблемы двух описанных выше. Введем определение длины волны — числа токенов, необходимого для полного прохода RoPE круга в измерении :
PI RoPE и NTK-Aware RoPE не учитывают длину волны и считают все измерения RoPE одинаково важными для модели. Наблюдения же показывают, что у части измерений , у части наоборот, и дисбаланс может быть сильным. С каждым измерением можно работать по-своему в зависимости от его длины волны. В методе NTK-by-parts RoPE предлагается:
если — не интерполировать
если — интерполировать без экстраполяции (как в PI RoPE)
для прочих делать обычную NTK-Aware интерполяцию
Полученный подход работает лучше PI RoPE и NTK-Aware и с дообучением, и без него.
Ещё одна идея в копилку интерполяционных методов, суть которой в том, чтобы использовать не фиксированный фактор масштаба, а динамический, величина которого зависит от длины текущей обрабатываемой последовательности. Т.е. вместо используется . Показано, что этот подход повышает устойчивость модели к изменению длины контекста.
Работа прежде всего интересна структурированным обзором основных интерполяционных методов (описанных выше), но также авторы предлагают модификацию NTK-by-parts RoPE. Утверждается, что добавление температуры в знаменатель формулы для хорошо влияет на перплексию при расширении контекста. Предлагаемый YaRN = NTK-by-parts RoPE + температура при подсчёте логитов.
В наборе экспериментов подход показывает хорошие результаты (как по перплексии, так и на бенчмарках), кроме того, он (как и другие интерполяционные методы) несложно реализуется и совместим с оптимизациями подсчёта внимания, например, с Flash Attention.
Заключение
Тема кодирования позиционной информации в тренде, работ выходит много, и в ближайшем будущем поток не планирует иссякать. Некоторые идеи реализуются в общепринятых фреймворках ещё до оформления в виде научных публикаций, как это случилось с модификациями интерполяционных кодирований (например, класс LlamaDynamicNTKScalingRotaryEmbedding
в библиотеке transformers).
Можно точно сказать, что однозначного стандарта в этой области ещё нет, хотя чаще всего современные модели учатся на основе ротационных эмбеддингов RoPE и их модификаций, за что можно поблагодарить успех LLaMA. Интерполяционные методы RoPE выглядят очень изящно и перспективно, интересно будет продолжать наблюдать за их развитием. Но пока основной рецепт при обучении своей модели с нуля — попробовать 2-3 популярных варианта на небольшом числе параметров и принимать решение исходя из полученных результатов.
Спасибо за внимание и успехов!
Комментарии (10)
azTotMD
12.12.2023 14:40хороший обзор, спасибо. Надо понимать, что xpos в тексте и xp в формулах - это одно и тоже?
markhor
12.12.2023 14:40Проверяли RoPE и Alibi для своей GPT-like архитектуры на масштабах от 1 B до ~200B. Работало по качеству в пределах погрешности и количества итераций 3к на глобальном батче 4М токенов. Выбрали Алиби за удобство реализации, скорость, и потенциал улучшений для нашей предметной области. Ещё проверили NoPE, и, конечно, оказался полный бред.
diov
12.12.2023 14:40Лично мне было бы интересно узнать больше о методах кодирования, когда мы не прибавляем (не умножаем) смысловую информацию и позиционную. А конкатенируем.
Я прочитал лишь пару не очень убедительных статей на эту тему.
Неужели больше никому не интересно исследовать эту идею?murat_apishev Автор
12.12.2023 14:40Не сталкивался с таким в трансформерах, не очень понятен смысл: придется добавлять проекционные слои для перевода в исходную размерность, и на выходе все равно будет вектор, содержащий совокупную информацию, просто вложенную чуть сложнее. Плюс в относительных методах чаще или делается просто поворот вектора, или добавляется скалярная величина, а не вектор
diov
12.12.2023 14:40Эти проекционные матрицы уже есть: Wq и Wk. Вот только на вход им подают уже смешанные данные. То есть, мы смешали зеленое с мягким, и затем просим модель научиться разделять. Модели приходится адаптироваться. Она учится не использовать пространство эмбеддингов на полную мощь, т.к. смысловые измерения смешиваются с позиционными.
Если бы мы делали concatenate(x_embedding, x_position) * Wq - думаю, мы получили бы результаты лучше.
markhor
12.12.2023 14:40Большое количество решений в современных архитектурах компромиссное по памяти: чем бы нам пожертвовать чтобы втиснуть сеть побольше в условные 80ГБ теслы и при этом не сильно ухудшить баланс качество-потраченные деньги. Раздувание размера на входе усиливает давление на память.
rPman
Помогите пожалуйста разобраться, работа gpt по обработке текста это последовательное пропускание контекстного окна через преобразования трансформера (декодер или вместе с энкодером), целиком, т.е. все окно контекста (если не полностью заполнено, используется нулевой токен) для каждого следующего токена.
Внимание вопрос, почему абсолютное большинство llm-ок, обрабатывает входной набор символов дольше чем генерирует один токен, время линейно зависит от количества токенов но часто 2х быстрее от генерации? Почему тарификация идет по количеству входных токенов, ведь чтение всего окна это время генерации одного токена?
Какая часть алгоритма упущена в описаниях работы gpt нейронок? Все статьи, что гуляют по сети и тут описывают либо внутрянку, что происходит внутри преобразований, как сэкономить при увеличении окна контекста, либо как выбирать следующий токен, либо как работать с обучающими данными, но описанный мной вопрос почему то обходят стороной, точнее это наверное где то описано, но не популярно, знают об этом единицы, считая это само собой разумеющимся?
Inkor
Гугли механизм kv -кэша. Это стандартный способ ускорения работы трансформерных llm-ок, засчет некоторого оверхеда по памяти, позволяющий при инференсе сделать вычислительную сложность атеншена линейной, а не квадратичной от количества токенов при авторегресивной генерации. По сути это сохранения результатов после k, v линейных слоев в память, что бы их каждый раз не пересчитывать. Это также позволяет считать атеншн только по последнему токену, а не по всем. Но вот только это работает, когда уже что-то закешировано. Когда же к нам приходит начальный набор токенов, что бы запустить генерацию для них нужно все посчитать все честно по старинке, что бы закешировать весь этот набор присланных начальных токенов.
murat_apishev Автор
Все так, кэширование позволяет при генерации токена производить подсчет внимания только для этого токена, это стандартный механизм.