Unterschied zwischen diesen Implementierungen von LSTM Autoencoder?

Dec 08 2020

Speziell was diese Frage anspornte, ist das return_sequenceArgument von TensorFlows Version einer LSTM-Schicht.

Die Dokumente sagen:

Boolescher Wert. Gibt an, ob die letzte Ausgabe zurückgegeben werden soll. in der Ausgabesequenz oder der vollständigen Sequenz. Standard: Falsch.

Ich habe einige Implementierungen gesehen, insbesondere Autoencoder, die dieses Argument verwenden, um alles außer dem letzten Element in der Ausgabesequenz als Ausgabe der 'Encoder'-Hälfte des Autoencoders zu entfernen.

Nachfolgend sind drei verschiedene Implementierungen aufgeführt. Ich würde gerne die Gründe für die Unterschiede verstehen, da die Unterschiede sehr groß erscheinen, sich aber alle gleich nennen.

Beispiel 1 (TensorFlow):

Diese Implementierung entfernt alle Ausgaben des LSTM mit Ausnahme des letzten Elements der Sequenz und wiederholt dieses Element einige Male, um die Sequenz zu rekonstruieren:

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)))

Wenn ich mir Implementierungen von Autoencodern in PyTorch anschaue, sehe ich keine Autoren, die dies tun. Stattdessen verwenden sie den gesamten Ausgang des LSTM für den Encoder (manchmal gefolgt von einer dichten Schicht und manchmal nicht).

Beispiel 1 (PyTorch):

Diese Implementierung trainiert eine Einbettung, BEVOR eine LSTM-Schicht angewendet wird ... Sie scheint die Idee eines LSTM-basierten Auto-Encoders fast zu vereiteln ... Die Sequenz ist bereits codiert, wenn sie auf die LSTM-Schicht trifft.

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

Beispiel 2 (PyTorch):

Dieser Beispielcodierer erweitert zuerst die Eingabe mit einer LSTM-Schicht und führt dann die Komprimierung über eine zweite LSTM-Schicht mit einer geringeren Anzahl versteckter Knoten durch. Abgesehen von der Erweiterung scheint dies im Einklang mit diesem Papier zu stehen, das ich gefunden habe:https://arxiv.org/pdf/1607.00148.pdf

Im Decodierer dieser Implementierung gibt es jedoch keine endgültige dichte Schicht. Die Dekodierung erfolgt über eine zweite lstm-Schicht, die die Kodierung wieder auf dieselbe Dimension wie die ursprüngliche Eingabe erweitert. Sehen Sie es hier . Dies steht nicht im Einklang mit dem Papier (obwohl ich nicht weiß, ob das Papier maßgeblich ist oder nicht).

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))

Frage:

Ich wundere mich über diese Diskrepanz bei den Implementierungen. Der Unterschied scheint ziemlich groß zu sein. Sind all diese gültigen Wege, um dasselbe zu erreichen? Oder handelt es sich bei einigen dieser fehlgeleiteten Versuche um einen "echten" LSTM-Autoencoder?

Antworten

2 LucaAngioloni Dec 08 2020 at 22:38

Es gibt keine offizielle oder korrekte Methode zum Entwerfen der Architektur eines LSTM-basierten Autoencoders ... Der Name gibt nur an, dass das Modell ein Autoencoder sein und irgendwo eine LSTM-Ebene verwenden sollte.

Die Implementierungen, die Sie gefunden haben, sind jeweils unterschiedlich und für sich einzigartig, obwohl sie für dieselbe Aufgabe verwendet werden können.

Beschreiben wir sie:

  • TF-Implementierung :

    • Es wird davon ausgegangen , dass der Eingang nur einen Kanal hat , was bedeutet, dass jedes Element in der Sequenz nur eine Zahl ist und dass dies bereits vorverarbeitet ist .
    • Das Standardverhalten von LSTM layerin Keras / TF besteht darin, nur die letzte Ausgabe des LSTM auszugeben. Sie können festlegen, dass alle Ausgabeschritte mit dem return_sequencesParameter ausgegeben werden.
    • In diesem Fall wurden die Eingabedaten auf verkleinert (batch_size, LSTM_units)
    • Bedenken Sie, dass die letzte Ausgabe eines LSTM natürlich eine Funktion der vorherigen Ausgaben ist (insbesondere wenn es sich um eine zustandsbehaftete LSTM handelt).
    • Es wird ein Dense(1)in der letzten Ebene angewendet, um die gleiche Form wie die Eingabe zu erhalten.
  • PyTorch 1 :

    • Sie wenden eine Einbettung auf den Eingang an, bevor er dem LSTM zugeführt wird.
    • Dies ist Standardpraxis und hilft beispielsweise, jedes Eingabeelement in eine Vektorform umzuwandeln (siehe beispielsweise word2vec, wenn in einer Textsequenz jedes Wort, das kein Vektor ist, in einen Vektorraum abgebildet wird). Es ist nur ein Vorverarbeitungsschritt, damit die Daten eine aussagekräftigere Form haben.
    • Dies macht die Idee des LSTM-Autoencoders nicht zunichte, da die Einbettung unabhängig auf jedes Element der Eingabesequenz angewendet wird und daher beim Eintritt in die LSTM-Schicht nicht codiert wird.
  • PyTorch 2 :

    • In diesem Fall ist die Eingabeform nicht (seq_len, 1)wie im ersten TF-Beispiel, sodass der Decoder kein dichtes Nachspiel benötigt. Der Autor hat eine Anzahl von Einheiten in der LSTM-Ebene verwendet, die der Eingabeform entsprechen.

Am Ende wählen Sie die Architektur Ihres Modells in Abhängigkeit von den Daten, auf denen Sie trainieren möchten, insbesondere: der Art (Text, Audio, Bilder), der Eingabeform, der Datenmenge, die Sie haben usw.