.. _sec_encoder-decoder: エンコーダ–デコーダアーキテクチャ ================================= 一般に、機械翻訳 (:numref:`sec_machine_translation`) のようなシーケンス・ツー・シーケンス問題では、 入力と出力は長さがさまざまで、 互いに対応が取れていない。 この種のデータを扱う標準的な方法は、 2つの主要な構成要素からなる *エンコーダ–デコーダ*\ アーキテクチャ (:numref:`fig_encoder_decoder`) を設計することである。 すなわち、可変長の系列を入力として受け取る *エンコーダ*\ と、 エンコードされた入力と ターゲット系列の左側の文脈を受け取り、 ターゲット系列における次のトークンを予測する 条件付き言語モデルとして働く *デコーダ*\ である。 .. _fig_encoder_decoder: .. figure:: ../img/encoder-decoder.svg エンコーダ–デコーダアーキテクチャ。 英仏機械翻訳を例に考えてみよう。 英語の入力系列 “They”, “are”, “watching”, “.” が与えられると、 このエンコーダ–デコーダアーキテクチャは まず可変長の入力を状態にエンコードし、 その後、その状態をデコードして 翻訳された系列を トークンごとに出力として生成する。 “Ils”, “regardent”, “.”。 エンコーダ–デコーダアーキテクチャは 後続の節でさまざまなシーケンス・ツー・シーケンスモデルの基盤となるため、 この節ではこのアーキテクチャを 後で実装するためのインターフェースに落とし込みる。 .. raw:: html
pytorchmxnetjaxtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python from d2l import torch as d2l from torch import nn .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python from d2l import mxnet as d2l from mxnet.gluon import nn .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python from d2l import jax as d2l from flax import linen as nn .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.) .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python from d2l import tensorflow as d2l import tensorflow as tf .. raw:: html
.. raw:: html
エンコーダ ---------- エンコーダのインターフェースでは、 エンコーダが可変長系列を入力 ``X`` として受け取ることだけを指定する。 実装は、この基底 ``Encoder`` クラスを継承する任意のモデルによって提供される。 .. raw:: html
pytorchmxnetjaxtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class Encoder(nn.Block): #@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 .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class Encoder(nn.Module): #@save """The base encoder interface for the encoder--decoder architecture.""" def setup(self): raise NotImplementedError # Later there can be additional arguments (e.g., length excluding padding) def __call__(self, X, *args): raise NotImplementedError .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class Encoder(tf.keras.layers.Layer): #@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 call(self, X, *args): raise NotImplementedError .. raw:: html
.. raw:: html
デコーダ -------- 以下のデコーダのインターフェースでは、 エンコーダの出力 (``enc_all_outputs``) を エンコードされた状態に変換するための 追加の ``init_state`` メソッドを加える。 このステップでは、 入力の有効長など、 追加の入力が必要になる場合があることに注意されたい。 これは :numref:`sec_machine_translation` で説明した。 可変長系列をトークンごとに生成するために、 デコーダは毎回、 入力 (たとえば、1つ前の時刻ステップで生成されたトークン) と エンコードされた状態を 現在の時刻ステップにおける出力トークンへ写像する。 .. raw:: html
pytorchmxnetjaxtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class Decoder(nn.Block): #@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 .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class Decoder(nn.Module): #@save """The base decoder interface for the encoder--decoder architecture.""" def setup(self): raise NotImplementedError # Later there can be additional arguments (e.g., length excluding padding) def init_state(self, enc_all_outputs, *args): raise NotImplementedError def __call__(self, X, state): raise NotImplementedError .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class Decoder(tf.keras.layers.Layer): #@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 call(self, X, state): raise NotImplementedError .. raw:: html
.. raw:: html
エンコーダとデコーダを組み合わせる ---------------------------------- 順伝播では、 エンコーダの出力が エンコードされた状態を生成するために使われ、 この状態は デコーダによってその入力の1つとして さらに利用される。 .. raw:: html
pytorchmxnetjaxtensorflow
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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] .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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] .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python class EncoderDecoder(d2l.Classifier): #@save """The base class for the encoder--decoder architecture.""" encoder: nn.Module decoder: nn.Module training: bool def __call__(self, enc_X, dec_X, *args): enc_all_outputs = self.encoder(enc_X, *args, training=self.training) dec_state = self.decoder.init_state(enc_all_outputs, *args) # Return decoder output only return self.decoder(dec_X, dec_state, training=self.training)[0] .. raw:: html
.. raw:: html
.. raw:: latex \diilbookstyleinputcell .. code:: python 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 call(self, enc_X, dec_X, *args): enc_all_outputs = self.encoder(enc_X, *args, training=True) dec_state = self.decoder.init_state(enc_all_outputs, *args) # Return decoder output only return self.decoder(dec_X, dec_state, training=True)[0] .. raw:: html
.. raw:: html
次の節では、 このエンコーダ–デコーダアーキテクチャに基づいて RNNを用いて シーケンス・ツー・シーケンスモデルを設計する方法を見る。 まとめ ------ エンコーダ–デコーダアーキテクチャは、 入力と出力の両方が 可変長系列からなる場合に対応できるため、 機械翻訳のような シーケンス・ツー・シーケンス問題に適している。 エンコーダは可変長系列を入力として受け取り、 それを固定形状の状態へ変換する。 デコーダは、その固定形状のエンコードされた状態を 可変長系列へ写像する。 演習 ---- 1. ニューラルネットワークを用いてエンコーダ–デコーダアーキテクチャを実装すると仮定する。エンコーダとデコーダは同じ種類のニューラルネットワークでなければならないだろうか。 2. 機械翻訳以外に、エンコーダ–デコーダアーキテクチャを適用できる別の応用例を考えられるか。