Ich versuche mein Verständnis von LSTMs in Einklang zu bringen und habe hier in diesem Beitrag von Christopher Olah , der in Keras implementiert wurde, darauf hingewiesen . Ich folge dem Blog von Jason Brownlee für das Keras-Tutorial. Was mich hauptsächlich verwirrt ist, ist:
- Die Umformung der Datenreihen in
[samples, time steps, features]
und, - Die Stateful LSTMs
Konzentrieren wir uns auf die beiden oben genannten Fragen unter Bezugnahme auf den unten eingefügten Code:
# reshape into X=t and Y=t+1
look_back = 3
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], look_back, 1))
testX = numpy.reshape(testX, (testX.shape[0], look_back, 1))
########################
# The IMPORTANT BIT
##########################
# create and fit the LSTM network
batch_size = 1
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
for i in range(100):
model.fit(trainX, trainY, nb_epoch=1, batch_size=batch_size, verbose=2, shuffle=False)
model.reset_states()
Hinweis: create_dataset verwendet eine Folge der Länge N und gibt ein N-look_back
Array zurück, von dem jedes Element eine Längenfolge ist look_back
.
Was sind Zeitschritte und Funktionen?
Wie zu sehen ist, ist TrainX ein 3-D-Array, wobei Time_steps und Feature die letzten beiden Dimensionen sind (3 und 1 in diesem speziellen Code). Bedeutet dies in Bezug auf das Bild unten, dass wir den many to one
Fall betrachten, in dem die Anzahl der rosa Kästchen 3 beträgt? Oder bedeutet dies wörtlich, dass die Kettenlänge 3 beträgt (dh nur 3 grüne Kästchen werden berücksichtigt).
Wird das Merkmalargument relevant, wenn wir multivariate Reihen betrachten? zB zwei Finanztitel gleichzeitig modellieren?
Stateful LSTMs
Bedeutet Stateful LSTMs, dass wir die Zellenspeicherwerte zwischen Chargenläufen speichern? Wenn dies der Fall ist, batch_size
ist es einer, und der Speicher wird zwischen den Trainingsläufen zurückgesetzt. Was war der Grund zu sagen, dass er zustandsbehaftet war? Ich vermute, dass dies mit der Tatsache zusammenhängt, dass Trainingsdaten nicht gemischt werden, aber ich bin mir nicht sicher, wie.
Irgendwelche Gedanken? Bildreferenz: http://karpathy.github.io/2015/05/21/rnn-effectiveness/
Bearbeiten 1:
Ein bisschen verwirrt über @ vans Kommentar, dass die roten und grünen Kästchen gleich sind. Entsprechen die folgenden API-Aufrufe nur zur Bestätigung den abgewickelten Diagrammen? Besonders unter Hinweis auf das zweite Diagramm ( batch_size
wurde willkürlich gewählt.):
Bearbeiten 2:
Informationen zu Personen, die den Deep-Learning-Kurs von Udacity absolviert haben und immer noch verwirrt über das Argument time_step sind, finden Sie in der folgenden Diskussion: https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169
Aktualisieren:
Es stellte sich heraus, dass model.add(TimeDistributed(Dense(vocab_len)))
ich gesucht habe. Hier ist ein Beispiel: https://github.com/sachinruk/ShakespeareBot
Update2:
Ich habe den größten Teil meines Verständnisses von LSTMs hier zusammengefasst: https://www.youtube.com/watch?v=ywinX5wgdEU
quelle
Antworten:
Zunächst wählen Sie großartige Tutorials ( 1 , 2 ) aus, um zu beginnen.
Was Zeitschritt bedeutet :
Time-steps==3
In X.shape (Beschreiben der Datenform) gibt es drei rosa Kästchen. Da in Keras jeder Schritt eine Eingabe erfordert, sollte die Anzahl der grünen Kästchen normalerweise der Anzahl der roten Kästchen entsprechen. Es sei denn, Sie hacken die Struktur.viele zu viele vs. viele zu eins : In Keras gibt es einen
return_sequences
Parameter bei der InitialisierungLSTM
oderGRU
oderSimpleRNN
. Wennreturn_sequences
istFalse
(Standard), so ist es viele zu einem , wie in der Abbildung dargestellt. Seine Rückkehrform ist(batch_size, hidden_unit_length)
, die den letzten Zustand darstellt. Wannreturn_sequences
istTrue
, dann sind es viele zu viele . Seine Rückgabeform ist(batch_size, time_step, hidden_unit_length)
Wird das Feature-Argument relevant : Feature-Argument bedeutet "Wie groß ist Ihr rotes Kästchen" oder wie hoch ist die Eingabedimension für jeden Schritt? Wenn Sie beispielsweise aus 8 Arten von Marktinformationen Vorhersagen treffen möchten, können Sie Ihre Daten mit generieren
feature==8
.Stateful : Sie können den Quellcode nachschlagen . Wenn Sie den Status initialisieren
stateful==True
, wird der Status aus dem letzten Training als Anfangsstatus verwendet, andernfalls wird ein neuer Status generiert. Ich habe michstateful
noch nicht eingeschaltet. Ich bin jedoch nicht damit einverstanden, dass dasbatch_size
nur 1 sein kann, wennstateful==True
.Derzeit generieren Sie Ihre Daten mit gesammelten Daten. Stellen Sie sich vor, Ihre Bestandsinformationen werden als Stream geliefert, anstatt auf einen Tag zu warten, um alle sequentiellen Daten zu erfassen. Sie möchten Eingabedaten online generieren, während Sie mit dem Netzwerk trainieren / Vorhersagen treffen. Wenn Sie 400 Aktien haben, die sich dasselbe Netzwerk teilen, können Sie festlegen
batch_size==400
.quelle
stateful: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
lookback = 1
?stateful=True
: Die Losgröße kann beliebig sein, aber Sie müssen sich daran halten. Wenn Sie Ihr Modell mit einer Stapelgröße von 5 erstellenfit()
,predict()
benötigen alle und verwandte Methoden einen Stapel von 5. Beachten Sie jedoch, dass dieser Status nicht mit gespeichert wirdmodel.save()
, was möglicherweise unerwünscht erscheint. Sie können den Status jedoch manuell zur hdf5-Datei hinzufügen, wenn Sie ihn benötigen. Auf diese Weise können Sie jedoch die Stapelgröße ändern, indem Sie lediglich ein Modell speichern und neu laden.Als Ergänzung zur akzeptierten Antwort zeigt diese Antwort das Verhalten von Keras und wie jedes Bild erreicht werden kann.
Allgemeines Keras-Verhalten
Die interne Standardverarbeitung von Keras ist immer eine Menge zu viele, wie im folgenden Bild (wo ich
features=2
nur als Beispiel Druck und Temperatur verwendet habe):In diesem Bild habe ich die Anzahl der Schritte auf 5 erhöht, um Verwechslungen mit den anderen Dimensionen zu vermeiden.
Für dieses Beispiel:
Unser Eingabearray sollte dann folgende Form haben
(N,5,2)
:Eingänge für Schiebefenster
Oft sollen LSTM-Schichten die gesamten Sequenzen verarbeiten. Das Teilen von Fenstern ist möglicherweise nicht die beste Idee. Die Ebene hat interne Zustände darüber, wie sich eine Sequenz entwickelt, wenn sie vorwärts geht. Windows eliminiert die Möglichkeit, lange Sequenzen zu lernen, und beschränkt alle Sequenzen auf die Fenstergröße.
In Fenstern ist jedes Fenster Teil einer langen Originalsequenz, aber von Keras werden sie jeweils als unabhängige Sequenz angesehen:
Beachten Sie, dass Sie in diesem Fall zunächst nur eine Sequenz haben, diese jedoch in viele Sequenzen unterteilen, um Fenster zu erstellen.
Das Konzept "Was ist eine Sequenz" ist abstrakt. Die wichtigen Teile sind:
Erreichen jedes Falles mit "einzelnen Schichten"
Viele bis viele Standard erreichen:
Mit einer einfachen LSTM-Schicht können Sie viele zu viele erreichen, indem Sie Folgendes verwenden
return_sequences=True
:Viele zu einem erreichen:
Wenn Sie genau dieselbe Ebene verwenden, führt Keras genau dieselbe interne Vorverarbeitung durch. Wenn Sie
return_sequences=False
dieses Argument verwenden (oder einfach ignorieren), verwirft Keras automatisch die Schritte vor dem letzten:Eins zu viele erreichen
Dies wird jetzt nicht nur von Keras LSTM-Layern unterstützt. Sie müssen Ihre eigene Strategie erstellen, um die Schritte zu multiplizieren. Es gibt zwei gute Ansätze:
stateful=True
um wiederholt die Ausgabe eines Schritts zu übernehmen und als Eingabe für den nächsten Schritt zu dienen (Anforderungenoutput_features == input_features
)Eins zu viele mit Wiederholungsvektor
Um sich an das Standardverhalten von Keras anzupassen, benötigen wir schrittweise Eingaben. Daher wiederholen wir die Eingaben einfach für die gewünschte Länge:
Stateful verstehen = True
Jetzt kommt eine der möglichen Verwendungen von
stateful=True
(neben dem Vermeiden des Ladens von Daten, die nicht sofort in den Speicher Ihres Computers passen)Mit Stateful können wir "Teile" der Sequenzen schrittweise eingeben. Der Unterschied ist:
stateful=False
enthält der zweite Stapel ganz neue Sequenzen, unabhängig vom ersten Stapelstateful=True
setzt der zweite Stapel den ersten Stapel fort und erweitert die gleichen Sequenzen.Es ist, als würde man die Sequenzen auch in Fenster teilen, mit diesen beiden Hauptunterschieden:
stateful=True
Diese Fenster werden als einzelne lange Sequenz verbundenIn
stateful=True
wird jede neue Charge so interpretiert, dass sie die vorherige Charge fortsetzt (bis Sie anrufenmodel.reset_states()
).Beispiel für Eingaben, Charge 1 enthält die Schritte 1 und 2, Charge 2 enthält die Schritte 3 bis 5:
Beachten Sie die Ausrichtung der Tanks in Charge 1 und Charge 2! Deshalb brauchen wir
shuffle=False
(es sei denn, wir verwenden natürlich nur eine Sequenz).Sie können beliebig viele Chargen auf unbestimmte Zeit haben. (Verwenden Sie für variable Längen in jeder Charge
input_shape=(None,features)
.Eins zu viele mit stateful = True
Für unseren Fall hier werden wir nur 1 Schritt pro Stapel verwenden, da wir einen Ausgabeschritt erhalten und ihn zu einer Eingabe machen möchten.
Bitte beachten Sie, dass das Verhalten auf dem Bild nicht "verursacht durch" ist
stateful=True
. Wir werden dieses Verhalten in einer manuellen Schleife unten erzwingen. In diesem Beispielstateful=True
können wir die Sequenz "stoppen", das, was wir wollen, manipulieren und dort weitermachen, wo wir aufgehört haben.Ehrlich gesagt ist der Wiederholungsansatz wahrscheinlich die bessere Wahl für diesen Fall. Aber da wir uns das ansehen
stateful=True
, ist dies ein gutes Beispiel. Der beste Weg, dies zu nutzen, ist der nächste "viele zu viele" Fall.Schicht:
Jetzt brauchen wir eine manuelle Schleife für Vorhersagen:
Viele zu viele mit stateful = True
Jetzt erhalten wir hier eine sehr schöne Anwendung: Versuchen Sie anhand einer Eingabesequenz, die zukünftigen unbekannten Schritte vorherzusagen.
Wir verwenden die gleiche Methode wie im obigen "Eins zu Viele", mit dem Unterschied, dass:
Schicht (wie oben):
Ausbildung:
Wir werden unser Modell trainieren, um den nächsten Schritt der Sequenzen vorherzusagen:
Vorhersagen:
Die erste Stufe unserer Vorhersage beinhaltet die "Anpassung der Zustände". Deshalb werden wir die gesamte Sequenz erneut vorhersagen, auch wenn wir diesen Teil bereits kennen:
Jetzt gehen wir zur Schleife wie im Fall von Eins zu Viele. Aber setzen Sie die Zustände hier nicht zurück! . Wir möchten, dass das Modell weiß, in welchem Schritt der Sequenz es sich befindet (und es weiß, dass es sich aufgrund der oben gemachten Vorhersage im ersten neuen Schritt befindet).
Dieser Ansatz wurde in diesen Antworten und Dateien verwendet:
Komplexe Konfigurationen erreichen
In allen obigen Beispielen habe ich das Verhalten von "einer Schicht" gezeigt.
Sie können natürlich viele Ebenen übereinander stapeln, nicht unbedingt alle nach demselben Muster, und Ihre eigenen Modelle erstellen.
Ein interessantes Beispiel, das aufgetaucht ist, ist der "Autoencoder" mit einem "Many-to-One-Encoder", gefolgt von einem "One-to-Many" -Decoder:
Encoder:
Decoder:
Verwenden der "Wiederholungs" -Methode;
Autoencoder:
Trainiere mit
fit(X,X)
Zusätzliche Erklärungen
Wenn Sie Details zur Berechnung von Schritten in LSTMs oder Details zu den
stateful=True
oben genannten Fällen wünschen, lesen Sie in dieser Antwort mehr: Zweifel bezüglich des Verständnisses von Keras-LSTMsquelle
my_cell = LSTM(num_output_features_per_timestep, return_state=True)
, gefolgt von einer Schleife vona, _, c = my_cell(output_of_previous_time_step, initial_states=[a, c])
Wenn Sie in Ihrer letzten RNN-Schicht return_sequences haben, können Sie keine einfache dichte Schicht verwenden, sondern TimeDistributed.
Hier ist ein Beispiel für einen Code, der anderen helfen könnte.
words = keras.layers.Input (batch_shape = (Keine, self.maxSequenceLength), name = "input")
quelle