Модуль 10. Последовательности и внимание¶
Чему вы научитесь в этом модуле
- Объяснять, почему рекуррентная сеть плохо справляется с длинными зависимостями: дело не в «забывании», а в том, что сигнал вынужден пройти столько шагов, сколько слов отделяют причину от следствия.
- Выводить механизм внимания из одной фразы — взвешенное среднее значений, где веса определяются похожестью запроса на ключи — и читать формулу вслух.
- Объяснять, зачем в формуле деление на \(\sqrt{d}\), и показывать на числах, что без него softmax насыщается.
- Отличать само-внимание от внимания между двумя последовательностями и объяснять, что даёт использование нескольких голов.
- Объяснять, почему внимание само по себе не знает порядка слов, и каким образом позиционное кодирование это исправляет.
- Объяснять, почему карта внимания — это не объяснение решения модели, и к какому типу ошибок из модуля 1 это относится.
Время: около трёх недель. Пререквизиты: модули 8 и 9.
Ноутбук: открыть в Colab · notebooks/10-sequences-and-attention.ipynb
Зачем нужен этот модуль¶
Свёртка из модуля 9 смотрит на мир через окно фиксированного размера. Для изображений это разумный подход: соседние пиксели действительно связаны друг с другом, а далёкие — почти нет. Для текста это не работает. В предложении «кошка, которую я вчера видел у соседа, села на коврик» подлежащее и сказуемое разнесены на десяток слов, но связь между ними ничуть не слабее, чем между соседними словами.
Необходим слой, для которого расстояние между элементами не является препятствием. Механизм внимания (attention) — именно такой слой. Он пришёл на смену рекуррентным сетям, на которых язык моделировали до 2017 года, и лежит в основе всех языковых моделей, которые мы разберём в модуле 11.
Рекуррентность и её ограничения¶
Рекуррентная сеть (RNN) читает последовательность по одному элементу за шаг, передавая от шага к шагу скрытое состояние:
Состояние \(h_t\) — это сжатая память обо всём, что произошло до шага \(t\). Идея кажется естественной, и до 2017 года она была основным подходом к моделированию последовательностей. Однако у неё два фундаментальных ограничения, и оба они не лечатся увеличением числа параметров — они структурные.
Длина пути сигнала. Чтобы информация из первого слова добралась до сотого, она должна пройти через сто последовательных применений функции \(f\). На каждом шаге что-то теряется и что-то подмешивается. Градиент на обратном проходе проделывает тот же путь в обратном направлении и по дороге либо затухает (vanishing gradient), либо взрывается (exploding gradient). Это ровно та же проблема затухания градиента, которую мы обсуждали в модуле 8, с той лишь разницей, что здесь «глубина» сети равна длине входной последовательности, а не числу слоёв.
Невозможность параллельных вычислений. Состояние \(h_t\) невозможно вычислить, пока не вычислено \(h_{t-1}\). Обработка последовательности длины \(n\) — это \(n\) строго последовательных шагов, которые нельзя выполнить одновременно на видеокарте. Время обучения упирается не в объём арифметики, а в её вынужденную последовательность.
LSTM и GRU — варианты рекуррентных сетей с механизмом вентилей (gates) — отодвигают первое ограничение, позволяя информации сохраняться дольше. Но они не устраняют его полностью и совершенно не помогают со вторым. Механизм внимания решает обе проблемы разом: путь между любыми двумя словами становится длиной один шаг, и все такие пути вычисляются параллельно.
Внимание: запрос, ключ, значение¶
Весь механизм можно объяснить одной фразой:
Внимание — это взвешенное среднее значений, где вес каждого значения тем больше, чем больше запрос похож на соответствующий ключ.
Разложим устройство на три роли. У каждого слова в последовательности есть три вектора, полученных из его представления через три обучаемые линейные проекции (матрицы):
Запрос \(q\) — что данное слово ищет в остальных словах. Ключ \(k\) — по чему другие слова смогут его обнаружить. Значение \(v\) — информация, которую это слово отдаёт тому, кто его нашёл.
Похожесть запроса на ключ измеряется скалярным произведением \(q \cdot k\): чем более сонаправлены векторы, тем больше значение. Все \(n\) похожестей одного запроса со всеми ключами собираются в вектор, этот вектор пропускается через softmax — получаются весовые коэффициенты, неотрицательные и в сумме дающие единицу. Итоговый выход для данного слова — это взвешенная сумма значений всех слов с этими весами.
Для всей последовательности целиком, записанной матрицами \(Q\), \(K\), \(V\) (каждая строка соответствует одному слову):
Прочитайте формулу вслух, следуя правилу чтения формул: «\(QK^\top\) — все попарные похожести всех запросов со всеми ключами; делим на корень из размерности; softmax по каждой строке превращает похожести в весовые коэффициенты; умножаем на \(V\) — получаем взвешенное среднее значений». Если формула прочитана и понята — отлично. Если возникло затруднение — вернитесь на абзац выше к трём ролям и перечитайте его заново.
Матрица \(QK^\top\) имеет размер \(n \times n\) — и вот где исчезает проблема длины пути: в ней сразу содержится связь каждого слова с каждым, без необходимости передавать сигнал по цепочке промежуточных состояний.
Кликните слово¶
Ниже — интерактивная визуализация само-внимания на игрушечном предложении. Выберите слово-запрос; второй ряд подсветится в соответствии с весами внимания: чем ярче элемент, тем сильнее выбранное слово на него «смотрит». Похожести здесь выставлены вручную, чтобы иллюстрация была осмысленной, — в настоящей обученной сети их задают матрицы \(Q\) и \(K\).
Ползунок масштаба — не декоративный элемент. Он делит похожести перед softmax, точно так же как \(\sqrt{d_k}\) в формуле. Сдвиньте его влево: внимание становится острым, и слово концентрируется почти на одной единственной позиции. Сдвиньте вправо: внимание размазывается равномерно по всем словам. Следующий раздел объясняет, почему нужное значение масштаба составляет именно \(\sqrt{d_k}\).
Почему делят на \(\sqrt{d}\)¶
Это утверждение, которое стоит проверить на числах, а не принимать на веру.
Скалярное произведение двух случайных векторов размерности \(d\), компоненты которых имеют дисперсию 1 и независимы, само имеет дисперсию \(d\): это сумма \(d\) независимых слагаемых, каждое с дисперсией 1. Следовательно, с ростом размерности значения в матрице \(QK^\top\) раздуваются как \(\sqrt{d}\).
Что с этим делает softmax: чем больше разброс его входов, тем ближе его выход к «победитель забирает всё». На больших числах softmax выдаёт практически one-hot вектор — почти вся масса сосредоточена на одном слове, остальным достаётся практически ноль. А там, где выход softmax почти константен, его производная почти нулевая: обучение останавливается. Это ровно то же насыщение, которое мы наблюдали у сигмоиды в модуле 8, и ровно та же болезнь — затухающий градиент.
Деление на \(\sqrt{d_k}\) возвращает дисперсию похожестей к единице независимо от того, какова размерность. Внимание остаётся «мягким», градиент — живым.
Это не рассуждение, а измерение
В ноутбуке вы сгенерируете случайные матрицы \(Q\) и \(K\) для растущих значений \(d\) и вычислите среднюю максимальную массу softmax — с делением на \(\sqrt{d}\) и без него. Без деления эта масса ползёт к единице — внимание схлопывается в точку. С делением — держится на разумном уровне. Проверка занимает пятнадцать строк кода и отвечает на вопрос «зачем \(\sqrt{d}\)?» числом, а не словами.
Само-внимание и несколько голов¶
Когда матрицы \(Q\), \(K\) и \(V\) получены из одной и той же последовательности, механизм называется само-вниманием (self-attention): слова последовательности смотрят друг на друга. Когда \(Q\) приходит из одной последовательности, а \(K\) и \(V\) — из другой, это перекрёстное внимание (cross-attention), и именно на нём держится машинный перевод: каждое слово перевода ищет, на какие слова оригинала ему стоит опереться.
Одна голова внимания вычисляет одну взвешенную сумму — и в этом её ограничение: одна голова способна отслеживать один тип связи между словами. Несколько голов (multi-head attention) вычисляют внимание параллельно, каждая в своём подпространстве (со своей тройкой матриц проекции), и затем результаты всех голов склеиваются. Одна голова может специализироваться на согласовании подлежащего со сказуемым, другая — на отслеживании антецедентов местоимений. Это происходит не потому, что такое разделение было заложено заранее: так выходит после обучения, и это ровно тот случай, когда объяснение постфактум легко спутать с причиной — об этом подробнее в последнем разделе модуля.
Внимание не знает порядка слов¶
Отложите на секунду интуицию и посмотрите на формулу ещё раз. Переставьте строки в матрицах \(Q\), \(K\), \(V\) одинаковым образом — выход переставится точно так же, но не изменится по составу. Механизм внимания — это операция над множеством, а не над последовательностью: предложения «кошка села на коврик» и «коврик села на кошка» для него различаются лишь тем, какие значения войдут в сумму, но не их порядком.
Это прямая параллель с модулем 9: свёртка эквивариантна к сдвигу — сдвинули вход, сдвинулся и выход. Внимание эквивариантно к произвольной перестановке — а это уже чрезмерная свобода: порядок слов несёт смысл, а слой его не видит.
Проблема решается добавлением к каждому слову специального вектора, зависящего от позиции, — позиционного кодирования. Это могут быть синусоиды различных частот или обучаемая таблица; принципиально важно, что после добавления позиционного кодирования одно и то же слово на разных позициях входит во все вычисления по-разному, и порядок перестаёт быть невидимым для модели.
Блок трансформера¶
Трансформер — это стопка одинаковых блоков. В каждом блоке два подслоя: само-внимание и позиционный MLP (одна и та же небольшая полносвязная сеть, применяемая к каждому слову независимо от остальных). Вокруг каждого подслоя применяются два приёма из модуля 8:
Остаточная связь (residual connection) — выход подслоя прибавляется ко входу, а не заменяет его. Градиент получает короткий путь в обход подслоя, и глубокая стопка блоков становится обучаемой.
Нормировка (layer normalization) удерживает масштаб активаций в разумных пределах от блока к блоку.
Это всё. Внимание смешивает информацию между словами, MLP обрабатывает каждое слово по отдельности, остаточная связь и нормировка делают стопку блоков обучаемой. Языковая модель из модуля 11 — это именно такая стопка, обученная предсказывать следующее слово.
Внимание — это не объяснение¶
Карту внимания очень соблазнительно показать в качестве объяснения работы модели: «модель посмотрела на вот это слово, поэтому и ответила так». Визуализация выглядит убедительно, соблазн велик. Однако это утверждение чаще всего не является проверенным.
Вес внимания сообщает, откуда была взята информация на входе следующего слоя. Он не сообщает, что именно от этого слова зависел итоговый ответ модели: сигнал после слоя внимания проходит ещё через MLP, остаточную связь и десяток блоков сверху, где перемешивается заново. Существуют исследования, в которых веса внимания существенно изменяют, не затрагивая при этом выход модели, — а значит, эти веса не могли быть причиной данного выхода. Существуют и противоположные результаты. Вопрос остаётся открытым, и именно это является содержательным состоянием дискуссии в сообществе.
Для нашего курса важна не конкретная позиция в этом споре, а тип ошибки: красивая карта не является доказательством причинно-следственной связи. Это тот же «зелёный пайплайн» из модуля 1 — только вместо «ноутбук запустился без ошибок» здесь «визуализация выглядит осмысленной». И та же ловушка, что с анализом головок внимания: увидеть структуру в обученной системе легко, но показать, что эта структура является причиной конкретного поведения, — отдельная и значительно более трудная работа.
Одно слово — два разных значения. «Внимание» в этом модуле — это механизм внутри нейронной сети. В модуле 19 «внимание» — это дефицитный ресурс человека, за который борется лента рекомендаций, и рекомендательная система оптимизирует ровно его. Курс держит оба значения рядом не ради каламбура: и в том, и в другом случае «внимание» — это распределение ограниченного ресурса между многими объектами, и ключевой вопрос один — кто и подо что его перераспределяет.
Практическая часть¶
Часть 1. Работа с ноутбуком¶
Откройте notebooks/10-sequences-and-attention.ipynb. Только numpy и matplotlib, всё считается за секунды, обучения нет — внимание строится вручную, чтобы вы видели каждый шаг.
Что содержится внутри:
- Реализация softmax и масштабированного внимания с нуля, в пять строк кода.
- Насыщение softmax: средняя максимальная масса как функция размерности — с делением на \(\sqrt{d}\) и без. Ответ на вопрос «зачем \(\sqrt{d}\)?» — в виде графика.
- Внимание как поиск: ключи-позиции, из которых запрос извлекает нужное значение. Наглядно видно, что внимание — это дифференцируемая операция поиска (lookup).
- Само-внимание на игрушечном предложении и его карта — та же, что в интерактивной фигуре выше, но вычисленная, а не нарисованная вручную.
- Проверка на перестановку: одна и та же последовательность в другом порядке даёт тот же набор ответов, пока не добавлено позиционное кодирование.
Пройдите ноутбук дважды, как описано в правилах работы с курсом: первый раз целиком, второй — с целью сломать.
Часть 2. Ломаем¶
В конце каждого раздела ноутбука описано, что именно нужно сломать. Минимальный набор экспериментов: уберите деление на \(\sqrt{d}\) и посмотрите на карту внимания при \(d = 128\); уберите позиционное кодирование и убедитесь, что предсказание, зависящее от порядка, развалилось; оставьте одну голову вместо нескольких и найдите связь между словами, которую единственная голова перестала удерживать.
Задание¶
Возьмите короткий текст — три-четыре предложения — и свою реализацию само-внимания из ноутбука.
- Постройте карту внимания для одного слоя с одной головой. Выпишите три пары слов с наибольшим весом.
- Для каждой пары ответьте письменно: это осмысленная лингвистическая связь или артефакт? Как это проверить, а не угадать?
- Измените вход таким образом, чтобы веса внимания не изменились, а предложенное «объяснение» стало бессмысленным. Если получилось — вы показали своими руками, почему карта внимания не является объяснением.
- Добавьте позиционное кодирование и покажите на числах, что теперь перестановка слов меняет выход.
Третий пункт — тот, который невозможно списать: он требует проверки утверждения, а не запуска кода.
Проверка усвоения¶
Ответьте вслух, не подглядывая.
- Почему рекуррентной сети трудно удерживать длинную зависимость? Назовите обе причины и объясните, какую из них не устраняют ворота (gates).
- Прочитайте формулу внимания словами, не называя ни одной буквы дважды.
- Что именно раздувается с ростом размерности и почему это ломает softmax? Как деление на \(\sqrt{d}\) исправляет ситуацию?
- Чем само-внимание отличается от перекрёстного внимания? В какой задаче необходимо второе?
- Что дают несколько голов внимания и почему нельзя обойтись одной большой?
- Почему внимание без позиционного кодирования не различает порядок слов? С каким свойством из модуля 9 это составляет пару?
- Дана красивая карта внимания. Что она доказывает относительно решения модели и что — нет?
Что дальше¶
В модуле 11 стопка трансформерных блоков превращается в языковую модель: предобучение на предсказании следующего слова, дообучение, инференс и квантизация. И там же — почему оценка языковой модели оказывается сложнее, чем кажется, и как это возвращает нас к модулю 1: заявленное улучшение LLM переживает смену случайного зерна и честную базовую линию примерно так же редко, как и всё остальное в области.
Принцип
Расстояние между словами перестало быть ценой, но карта того, кто на кого посмотрел, осталась описанием, а не объяснением. Красивая визуализация проверяется точно так же, как зелёный пайплайн: не тем, насколько она убедительна, а тем, переживает ли она попытку её сломать.