21 Seq2Seq
Контекст
Задачи «последовательность → последовательность» (перевод) требовали сложных пайплайнов с ручным выравниванием. Суцкевер, Виньялс, Ле делают это одной нейросетью.
Идея и механизм
Энкодер (LSTM) читает вход и сжимает его в один вектор фиксированной длины — финальное скрытое состояние. Декодер (LSTM) из этого вектора генерирует выход слово за словом: каждое следующее слово — на основе вектора и уже сгенерированного. Обучается на парах (вход, выход) предсказанием следующего токена. Трюк: разворот порядка слов источника заметно поднял качество.
теория вероятностей Авторегрессионная факторизация и узкое место
Модель раскладывает вероятность всей выходной последовательности в произведение пошаговых (цепное правило для вероятностей):
где c — вектор-контекст (финальное состояние энкодера). Декодер на каждом шаге берёт c и уже сгенерированное и выдаёт распределение следующего слова.
Узкое место. Весь вход x сжат в один вектор фиксированного размера c. Чем длиннее предложение, тем больше информации надо втиснуть в ту же размерность → потери растут с длиной. Разворот источника помогает оптимизации: первые слова источника и первые слова перевода оказываются близко в графе зависимостей, и градиент короче — отсюда заметный прирост BLEU. Но фундаментальный bottleneck остаётся, и его снимет attention (#22).
PyTorch Энкодер-декодер на LSTM (схема)
def seq2seq(src, tgt, enc, dec, embed):
_, (h, c) = enc(embed(src)) # сжать вход в контекст (h, c)
out, _ = dec(embed(tgt), (h, c)) # декодер генерирует из контекста
return out # логиты по словарю на каждом шаге
Почему это важно
Закрепил парадигму encoder-decoder, на которой выросли перевод, суммаризация, диалог и позже мультимодальные модели. А его слабое место — фиксированный вектор — напрямую породило следующий шаг, attention, и далее Transformer.
Связи
Оба «кирпича» seq2seq — это LSTM. Способность держать контекст на много шагов (которую дал LSTM) — необходимое условие, чтобы один вектор хоть как-то представлял целое предложение.
Прямое продолжение: вместо одного вектора декодер получает доступ ко всем состояниям энкодера и сам выбирает, на что смотреть. Bottleneck исчезает — и это первый шаг к вниманию как таковому.
Transformer сохраняет идею encoder-decoder, но выкидывает рекуррентность: вместо последовательного сжатия — параллельное self-attention. Парадигма та же, механизм радикально другой.
Вопросы пытливого ума
Почему разворот источника помогает, а разворот цели — нет?
Разворот источника укорачивает путь между началом входа и началом выхода: первое слово перевода зависит от первых слов оригинала, и теперь они рядом в развёрнутой последовательности → градиент короче, оптимизация легче. Цель генерируется слева направо в любом случае, её разворачивать смысла нет. Это чистый трюк оптимизации, а не лингвистики.
Если узкое место известно, зачем вообще изучать seq2seq, а не сразу attention?
Потому что attention — это надстройка над seq2seq, а не замена: encoder-decoder каркас, авторегрессионная генерация и обучение на парах остались. Понять bottleneck — значит понять, зачем нужно внимание. Без seq2seq attention выглядит произвольным трюком, а не решением конкретной проблемы.
Как декодер вообще «знает», когда остановиться?
В словарь добавляют специальный токен конца последовательности (<EOS>); декодер обучается генерировать его, когда перевод закончен, и генерация останавливается. На инференсе обычно используют beam search — держат несколько лучших гипотез, а не жадно берут самое вероятное слово на каждом шаге.
Что читать в оригинале
Читать ключевое — encoder-decoder каркас и трюк с разворотом; это фундамент, на котором дальше строятся attention и Transformer.