LSTMオートエンコーダのこれらの実装の違いは?

Dec 08 2020

具体的には、この質問に拍車をかけたのは、return_sequenceTensorFlowのバージョンのLSTMレイヤーの議論です。

ドキュメントによると:

ブール値。最後の出力を返すかどうか。出力シーケンス、または完全なシーケンスで。デフォルト:False。

いくつかの実装、特にこの引数を使用して出力シーケンスの最後の要素以外のすべてをオートエンコーダの「エンコーダ」半分の出力として削除するオートエンコーダを見てきました。

以下は3つの異なる実装です。非常に大きな違いのように見えますが、すべて同じものと呼ばれているため、違いの背後にある理由を理解したいと思います。

例1(TensorFlow):

この実装では、シーケンスの最後の要素を除くLSTMのすべての出力を取り除き、その要素を数回繰り返してシーケンスを再構築します。

model = Sequential()
model.add(LSTM(100, activation='relu', input_shape=(n_in,1)))
# Decoder below
model.add(RepeatVector(n_out))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(TimeDistributed(Dense(1)))

PyTorchでのオートエンコーダーの実装を見ると、作成者がこれを行っているのはわかりません。代わりに、LSTMの出力全体をエンコーダーに使用します(高密度レイヤーが続く場合とそうでない場合があります)。

例1(PyTorch):

この実装は、LSTMレイヤーが適用される前に埋め込みをトレーニングします... LSTMベースのオートエンコーダーのアイデアをほぼ打ち負かすようです...シーケンスは、LSTMレイヤーに到達するまでにすでにエンコードされています。

class EncoderLSTM(nn.Module):
  def __init__(self, input_size, hidden_size, n_layers=1, drop_prob=0):
    super(EncoderLSTM, self).__init__()
    self.hidden_size = hidden_size
    self.n_layers = n_layers

    self.embedding = nn.Embedding(input_size, hidden_size)
    self.lstm = nn.LSTM(hidden_size, hidden_size, n_layers, dropout=drop_prob, batch_first=True)

  def forward(self, inputs, hidden):
    # Embed input words
    embedded = self.embedding(inputs)
    # Pass the embedded word vectors into LSTM and return all outputs
    output, hidden = self.lstm(embedded, hidden)
    return output, hidden

例2(PyTorch):

この例のエンコーダー、最初に1つのLSTMレイヤーで入力を拡張し、次に少数の非表示ノードを持つ2番目のLSTMレイヤーを介して圧縮を行います。拡張に加えて、これは私が見つけたこの論文と一致しているようです:https://arxiv.org/pdf/1607.00148.pdf

ただし、この実装のデコーダーには、最終的な高密度レイヤーはありません。デコードは、エンコードを元の入力と同じ次元に拡張する2番目のlstmレイヤーを介して行われます。こちらをご覧ください。これは論文と一致していません(論文が信頼できるかどうかはわかりませんが)。

class Encoder(nn.Module):
  def __init__(self, seq_len, n_features, embedding_dim=64):
    super(Encoder, self).__init__()
    self.seq_len, self.n_features = seq_len, n_features
    self.embedding_dim, self.hidden_dim = embedding_dim, 2 * embedding_dim
    self.rnn1 = nn.LSTM(
      input_size=n_features,
      hidden_size=self.hidden_dim,
      num_layers=1,
      batch_first=True
    )
    self.rnn2 = nn.LSTM(
      input_size=self.hidden_dim,
      hidden_size=embedding_dim,
      num_layers=1,
      batch_first=True
    )
  def forward(self, x):
    x = x.reshape((1, self.seq_len, self.n_features))
    x, (_, _) = self.rnn1(x)
    x, (hidden_n, _) = self.rnn2(x)
    return hidden_n.reshape((self.n_features, self.embedding_dim))

質問:

実装におけるこの不一致について疑問に思っています。違いはかなり大きいようです。同じことを達成するためのこれらの有効な方法はすべてありますか?それとも、「実際の」LSTMオートエンコーダーでのこれらの誤った試みのいくつかはありますか?

回答

2 LucaAngioloni Dec 08 2020 at 22:38

LSTMベースのオートエンコーダーのアーキテクチャーを設計する公式または正しい方法はありません...名前が提供する唯一の詳細は、モデルがオートエンコーダーであり、どこかでLSTMレイヤーを使用する必要があるということです。

あなたが見つけた実装は、同じタスクに使用できたとしても、それぞれが異なり、独自のものです。

それらを説明しましょう:

  • TFの実装

    • 入力にはチャネルが1つしかないことを前提としています。つまり、シーケンス内の各要素は単なる数値であり、これはすでに前処理されていることを意味します。
    • デフォルトの動作LSTM layerKeras / TFは、出力にLSTMの唯一の最後の出力である、あなたは出力にして、すべての出力段階に設定できreturn_sequences、パラメータを。
    • この場合、入力データはに縮小されています (batch_size, LSTM_units)
    • LSTMの最後の出力は、もちろん前の出力の関数であると考えてください(特に、ステートフルLSTMの場合)。
    • Dense(1)入力と同じ形状を取得するために、最後のレイヤーにを適用します。
  • PyTorch 1

    • LSTMに供給される前に、入力に埋め込みを適用します。
    • これは標準的な方法であり、たとえば、各入力要素をベクトル形式に変換するのに役立ちます(たとえば、テキストシーケンスで、ベクトルではない各単語がベクトル空間にマップされるword2vecを参照してください)。データがより意味のある形式になるように、これは前処理ステップにすぎません。
    • 埋め込みは入力シーケンスの各要素に個別適用されるため、これはLSTMオートエンコーダーの概念を損なうものではなく、LSTMレイヤーに入るときにエンコードされません。
  • PyTorch 2

    • この場合、入力形状は(seq_len, 1)最初のTFの例のようではないため、デコーダーは後密度を必要としません。著者は、入力形状に等しい数のユニットをLSTMレイヤーで使用しました。

最終的には、トレーニングするデータに応じてモデルのアーキテクチャを選択します。具体的には、性質(テキスト、オーディオ、画像)、入力形状、データ量などです。