Содержание курса 14 / 37

14 / 37 · Нейросетевые модели последовательностей

Модели sequence-to-sequence

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

На этой странице 11

Классификация отображает последовательность в метку; языковое моделирование продолжает последовательность. Переводу нужны обе половины: прочитать одну последовательность целиком, а затем написать другую, длина которой заранее неизвестна. Рекуррентные ячейки из предыдущей заметки умеют делать каждую половину. Эта заметка соединяет их в энкодер–декодер (encoder–decoder) Суцкевера, Виньялса и Ле (2014) и Чо и соавторов (2014), обучает его на 29 000 немецко-английских пар и измеряет результат.

Обозначения. Токены источника x1,…,xSx_1, \dots, x_S (немецкий), токены перевода y1,…,yTy_1, \dots, y_T (английский). Состояния энкодера h1,…,hSh_1, \dots, h_S; состояния декодера s1,…,sTs_1, \dots, s_T. Перевод обрамлён символом начала ([CLS] в используемом токенизаторе) и символом конца ([SEP]).

Задача и данные#

Multi30k (Elliott et al., 2016) содержит 29 000 подписей к изображениям на немецком с переводами на английский, плюс 1014 валидационных и 1000 тестовых пар. Подписи короткие: после токенизации WordPiece почти все предложения обоих языков укладываются в 32 токена, и последовательности обрезаются до этой длины. Типичная пара:

Zwei junge weiße Männer sind im Freien in der Nähe vieler Büsche. Two young, White males are outside near many bushes.

У каждого языка свой предобученный токенизатор WordPiece (немецкий — 31 102 записи, английский — 30 522); их описывает заметка о токенизации.

Отправная точка: энкодер–декодер с вектором контекста#

Энкодер. Двунаправленная LSTM читает эмбеддинги источника. Её последние скрытые состояния прямого и обратного проходов (каждое H=128H = 128) конкатенируются в 2H2H и проецируются обратно в HH линейным слоем; с состояниями ячейки поступают так же. Результат инициализирует декодер: (s0,c0)=(Wh[h→S;h←1],  Wc[c→S;c←1])(s_0, c_0) = (W_h [\overrightarrow{h}_S; \overleftarrow{h}_1],\; W_c [\overrightarrow{c}_S; \overleftarrow{c}_1]).

Декодер. Однонаправленная LSTM, стартующая из (s0,c0)(s_0, c_0), читает перевод, сдвинутый вправо на один (первым идёт символ начала), и на каждом шаге выдаёт логиты по английскому словарю:

P(yt∣y<t,x)=softmax(Wost),(st,ct)=LSTM(yt−1,(st−1,ct−1)).P(y_t \mid y_{<t}, x) = \mathrm{softmax}(W_o s_t), \qquad (s_t, c_t) = \mathrm{LSTM}\big(y_{t-1}, (s_{t-1}, c_{t-1})\big).

Источник входит только через (s0,c0)(s_0, c_0). Вместе с формулой умножения вероятностей модель задаёт P(y∣x)=∏tP(yt∣y<t,x)P(y \mid x) = \prod_t P(y_t \mid y_{<t}, x).

Рисунок

Кодировщик и декодер: что куда идёт

Энкодер–декодер на трёх и четырёх шагахЭнкодер из трёх ячеек читает Zwei, Männer, laufen; его последнее состояние становится s₀. Декодер из четырёх ячеек получает на вход [CLS], Two, men, run и выдаёт Two, men, run, [SEP]; каждый выход подаётся на вход следующей ячейки.энкодердекодерZweiLSTMMännerLSTMlaufenLSTM1новоеконтекст s₀2[CLS]LSTMTwo3TwoLSTMmen4menLSTMrun4runLSTM[SEP]5назад на входвходсостояниевеса и гейтывыходЭнкодер–декодер на трёх и четырёх шагахЭнкодер из трёх ячеек читает Zwei, Männer, laufen; его последнее состояние становится s₀. Декодер из четырёх ячеек получает на вход [CLS], Two, men, run и выдаёт Two, men, run, [SEP]; каждый выход подаётся на вход следующей ячейки.энкодердекодерZweiLSTMMännerLSTMlaufenLSTM1новоеконтекст s₀2[CLS]LSTMTwo3TwoLSTMmen4menLSTMrun4runLSTM[SEP]5назад на входвходсостояниевеса и гейтывыход
Иллюстративная пара предложений. Энкодер — та же рекуррентная ячейка, что в заметке о RNN, — читает немецкие токены по одному (1). Его последнее состояние, единственное, что декодер получит из источника, становится начальным состоянием s₀ (2); у LSTM этой заметки это пара (s₀, c₀). Декодер — вторая рекуррентная сеть, языковая модель над английским: из стартового символа и s₀ он предсказывает первое слово (3), подаёт его себе на вход и предсказывает следующее (4), пока не выдаст символ конца (5). При обучении вместо собственных предсказаний на вход подаются правильные слова (teacher forcing).

Что происходит, в порядке номеров на рисунке:

  1. Закодировать. Энкодер применяет рекуррентную ячейку к исходным токенам по одному, ровно как в заметке о RNN; здесь ячейка — LSTM, а энкодер двунаправленный.
  2. Передать. Последние состояния, спроецированные в размерность декодера, становятся его начальной парой состояний (s0,c0)(s_0, c_0), это 2H=2562H = 256 чисел. Эта пара фиксированного размера — всё, что декодер когда-либо увидит из источника.
  3. Начать. Декодер читает стартовый символ, обновляет состояние с s0s_0 до s1s_1 и выдаёт распределение по английскому словарю; самое вероятное слово — первое слово перевода.
  4. Подать обратно. Только что выданное слово становится следующим входом, и шаг повторяется. При обучении вместо него подаётся правильное предыдущее слово (teacher forcing, ниже).
  5. Остановиться. Порождение заканчивается, когда декодер выдаёт символ конца, или после 32 токенов.

Энкодер и декодер — каждый та же рекуррентная сеть из предыдущих заметок; новое — передача в середине, в янтарной рамке, она же узкое место: какой бы длины ни был источник, до декодера он доходит только через (s0,c0)(s_0, c_0).

Обучение — teacher forcing, как и у рекуррентной языковой модели: на вход декодеру подаётся эталонный перевод до позиции t−1t - 1, функция потерь — кросс-энтропия относительно эталонного токена в позиции tt, просуммированная по позициям без учёта паддинга. В коде логиты для позиций 1..T−11..T-1 сравниваются с идентификаторами перевода в позициях 2..T2..T (logits[:, :-1] против ids[:, 1:]).

Порождение — жадное декодирование: начать с символа начала, на каждом шаге брать argmax, подавать его обратно и остановиться на символе конца или через 32 токена. Состояние декодера переносится между шагами, поэтому порождение стоит один шаг LSTM на выходной токен.

Размеры: d=H=128d = H = 128. Во всей модели 8.38 млн параметров, из них 7.9 млн — общая таблица эмбеддингов и выходная матрица; рекуррентные и проекционные слои — 0.46 млн. Модель использует одну таблицу эмбеддингов для обоих языков и индексирует её идентификаторами из любого токенизатора; это упрощение. Таблица рассчитана на больший немецкий словарь, так что любой идентификатор любого токенизатора попадает в её пределы, но токенизаторы обучены независимо: один и тот же идентификатор обозначает в двух языках не связанные токены, и одна строка должна служить обоим. Модель всё равно может учиться, потому что энкодер и декодер читают общие строки в разных контекстах, но каждая такая строка — компромисс между двумя токенами. Раздельные таблицы источника и перевода или один токенизатор, обученный на обоих языках, избавляют от такого совмещения.

BLEU: как измерить перевод#

Единственно правильного перевода нет, поэтому доля совпадений с эталоном бессмысленна, а перплексия на токенах не оценивает предложение, которое модель на самом деле породила. BLEU (Papineni et al., 2002) сравнивает n-граммы кандидата с n-граммами одного или нескольких эталонов:

BLEU=BP⋅exp⁡(∑n=1Nwnlog⁡pn),wn=1N,  N=4.\mathrm{BLEU} = \mathrm{BP} \cdot \exp\Big(\sum_{n=1}^{N} w_n \log p_n\Big), \qquad w_n = \tfrac1N,\; N = 4.

pnp_n — модифицированная точность по n-граммам (modified n-gram precision): доля n-грамм кандидата, которые есть в эталоне, причём каждую n-грамму эталона можно сопоставить не больше раз, чем она в нём встречается (так что повтор the the the очков не приносит). Среднее геометрическое по n=1..4n = 1..4 вознаграждает и верные слова, и верные фразы. Штраф за краткость (brevity penalty)

BP=exp⁡(−[rc−1]+)\mathrm{BP} = \exp\Big(-\Big[\frac{r}{c} - 1\Big]_+\Big)

с rr — суммарной длиной эталонов и cc — суммарной длиной кандидатов наказывает выходы короче эталона (одна точность вознаградила бы кандидата из одного слова, оказавшегося верным). Если кандидат на 20% короче эталона, r/c=1.25r/c = 1.25 и BP=e−0.25=0.78\mathrm{BP} = e^{-0.25} = 0.78; кандидат не короче эталона не штрафуется. BLEU считается по всему корпусу, а не усредняется по предложениям, и лежит в пределах от 0 до 1 (часто его приводят в шкале 0–100).

Две оговорки. Реализации BLEU различаются токенизацией и сглаживанием нулевых pnp_n и дают разные числа на одних и тех же выходах, поэтому сравнения корректны только внутри одной реализации (Post, 2018); курс везде использует реализацию из Hugging Face evaluate. И BLEU измеряет пересечение n-грамм с эталоном, а не смысл: верный пересказ получает мало, а гладкое неверное предложение может получить неплохо. Заметка о переводе возвращается к его использованию для сравнения моделей.

Результат#

После 10 эпох с Adam при шаге обучения 10−410^{-4} и размере батча 32 модель на LSTM достигает BLEU на тесте 0.152. Выходы объясняют это число:

Немецкий источникЭталонВыход LSTM
Ein Mann mit einem orangefarbenen Hut, der etwas anstarrt.A man in an orange hat starring at something.a man in a red shirt is standing on a street.
Ein Boston Terrier läuft über saftig-grünes Gras vor einem weißen Zaun.A Boston Terrier is running on lush green grass in front of a white fence.a young man is standing on a street with a large building.
Leute Reparieren das Dach eines Hauses.People are fixing the roof of a house.people are sitting on a street.

Каждый выход — грамматичная английская подпись. Подлежащее часто верно (a man, people), и почти больше ничего: цвета, предметы и действия заменены самыми частыми в обучающей выборке (red shirt, standing, street). Декодер хорошо выучил английскую языковую модель и очень мало узнал о конкретном исходном предложении, которое ему дали.

Почему одного вектора мало#

Единственная информация декодера об источнике — пара (s0,c0)(s_0, c_0), 2×128=2562 \times 128 = 256 чисел, полученных до того, как написан первый токен перевода. Для источника из 20 токенов эта пара должна хранить каждое значимое слово по порядку и так точно, чтобы декодер смог достать четвёртое прилагательное после того, как уже сгенерировал десять токенов и десять раз обновил своё состояние. Ломаются две вещи:

  • Ёмкость. Сводка фиксированного размера, а источник — нет. Длинные источники сжимаются сильнее. Чо и соавторы (2014) измерили, как BLEU падает с длиной предложения именно по этой причине.
  • Затухание. Состояние декодера переписывается на каждом шаге. Всё, что сводка хранила о конце источника, должно пережить порождение начала перевода через ту же рекурсию с гейтами, память которой, как показала предыдущая заметка, конечна.

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

Что изменилось#

Рекуррентная языковая модельЭнкодер–декодер
ВходПрефикс той же последовательностиОтдельная исходная последовательность
УсловиеПредыдущие токены через состояниеСводка источника (s0,c0)(s_0, c_0) + предыдущие токены
Длина выходаОткрытаяОткрытая, остановка по символу конца
ОбучениеTeacher forcingTeacher forcing по переводу
ОценкаПерплексияBLEU относительно эталонов

Ограничения#

  • Узкое место. Вся информация об источнике проходит через одну пару состояний фиксированного размера. Это ограничение снимает следующая заметка.
  • Смещение экспозиции (exposure bias). При обучении подаются эталонные префиксы, при порождении — собственные, возможно ошибочные, префиксы модели. Ошибки накапливаются, и ничто в обучении не готовит к ним модель.
  • Жадное декодирование. Взятие argmax на каждом шаге не даёт самой вероятной последовательности; стандартное улучшение — лучевой поиск (beam search) в заметке о переводе.
  • Последовательность. Обе половины рекуррентные, поэтому ни обучение, ни инференс не распараллеливаются вдоль последовательности.
  • BLEU — суррогат. Он вознаграждает поверхностное совпадение и зависит от реализации.

Что нужно запомнить#

  • Энкодер–декодер: закодировать источник в состояние и авторегрессионно декодировать из него перевод; P(y∣x)=∏tP(yt∣y<t,x)P(y \mid x) = \prod_t P(y_t \mid y_{<t}, x).
  • Teacher forcing со сдвинутыми целями и без учёта паддинга, как у языковой модели; жадное декодирование при инференсе.
  • BLEU: среднее геометрическое модифицированных точностей по n-граммам для n=1..4n = 1..4, умноженное на штраф за краткость; считается по корпусу и зависит от реализации.
  • Multi30k с двунаправленным энкодером LSTM на 128 нейронов: BLEU 0.152, гладкие выходы с неверным содержанием.
  • Провал — в передаваемом состоянии фиксированного размера, здесь это (s0,c0)(s_0, c_0) из 256 чисел, а не в гладкости декодера.

Ноутбук#

week04_lstm_attention_transformer.ipynb. Номера ячеек считают все ячейки, включая текстовые, начиная с 1. Приведённые числа взяты из прогона, сохранённого в курсе; у ячеек, изменённых с тех пор под текущие версии библиотек, сохранённого выхода нет.

  • Ячейки 5–10 загружают Multi30k из Hub (29 000 / 1014 / 1000 пар) и строят загрузчики с размером батча 32; ячейки 13–35 настраивают два токенизатора и фиксируют MAX_LENGTH = 32.
  • Ячейки 36–37 приводят формулу BLEU и загружают реализацию из evaluate.
  • Ячейка 39 определяет Seq2SeqLSTM: двунаправленный энкодер, проекции состояний, однонаправленный декодер и жадный generate, который всегда делает 32 шага (выход очищается от токенов после [SEP] функцией clean_text в ячейке 41).
  • Ячейка 42 содержит циклы обучения и оценки: кросс-энтропия без учёта идентификатора паддинга, сдвиг на одну позицию между логитами и целями, доля верных токенов по батчу и BLEU по корпусу на жадных генерациях.
  • Ячейки 44–47 обучают модель 10 эпох (у ячейки обучения нет сохранённого выхода), а текстовая ячейка 48 приводит итоговый BLEU на тесте, 0.152; ячейки 49–54 печатают приведённые выше примеры переводов с источниками и эталонами, а ячейка 55 делает тот же вывод, что и эта заметка.

Дальше#

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

Литература#