10.6. Архитектура кодировщик–декодировщик

В общем случае для задач преобразования последовательностей в последовательности, таких как машинный перевод (Section 10.5), входные и выходные данные имеют переменную длину и не выровнены. Стандартный подход к обработке таких данных заключается в использовании архитектуры кодировщик–декодировщик (Fig. 10.6.1), состоящей из двух основных компонентов: кодировщика, который принимает на вход последовательность переменной длины, и декодировщика, действующего как условная языковая модель. Декодировщик получает закодированный вход и левый контекст целевой последовательности, предсказывая следующий токен в целевой последовательности.

../_images/encoder-decoder.svg

Fig. 10.6.1 Архитектура кодировщик–декодировщик.

Рассмотрим машинный перевод с английского на французский в качестве примера. Для входной последовательности на английском языке: «They», «are», «watching», «.» архитектура кодировщик–декодировщик сначала кодирует входную последовательность переменной длины в состояние, а затем декодирует это состояние, генерируя выходную переведенную последовательность токен за токеном: «Ils», «regardent», «.». Поскольку архитектура кодировщик–декодировщик лежит в основе различных моделей преобразования последовательности в последовательность, рассматриваемых в последующих разделах, в данном разделе мы преобразуем эту архитектуру в интерфейс, который будет реализован позже.

from torch import nn
from d2l import torch as d2l

10.6.1. Кодировщик

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

class Encoder(nn.Module):  #@save
    """The base encoder interface for the encoder--decoder architecture."""
    def __init__(self):
        super().__init__()

    # Later there can be additional arguments (e.g., length excluding padding)
    def forward(self, X, *args):
        raise NotImplementedError

10.6.2. Декодировщик

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

class Decoder(nn.Module):  #@save
    """The base decoder interface for the encoder--decoder architecture."""
    def __init__(self):
        super().__init__()

    # Later there can be additional arguments (e.g., length excluding padding)
    def init_state(self, enc_all_outputs, *args):
        raise NotImplementedError

    def forward(self, X, state):
        raise NotImplementedError

10.6.3. Объединение кодировщика и декодировщика

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

class EncoderDecoder(d2l.Classifier):  #@save
    """The base class for the encoder--decoder architecture."""
    def __init__(self, encoder, decoder):
        super().__init__()
        self.encoder = encoder
        self.decoder = decoder

    def forward(self, enc_X, dec_X, *args):
        enc_all_outputs = self.encoder(enc_X, *args)
        dec_state = self.decoder.init_state(enc_all_outputs, *args)
        # Return decoder output only
        return self.decoder(dec_X, dec_state)[0]

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

10.6.4. Итоги

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

10.6.5. Упражнения

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

  2. Помимо машинного перевода, можете ли вы привести другой пример применения архитектуры кодировщик–декодировщик?

Обсуждения