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:
- Wir haben N Öltanks
- Wir haben 5 Stunden damit verbracht, stündlich Maßnahmen zu ergreifen (Zeitschritte)
- Wir haben zwei Merkmale gemessen:
Unser Eingabearray sollte dann folgende Form haben (N,5,2)
:
[ Step1 Step2 Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
....
Tank N: [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
]
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:
[ Step1 Step2 Step3 Step4 Step5
Window A: [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window B: [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window C: [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
....
]
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:
- Sie können Stapel mit vielen einzelnen Sequenzen haben
- Was die Sequenzen zu Sequenzen macht, ist, dass sie sich in Schritten entwickeln (normalerweise Zeitschritte).
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
:
outputs = LSTM(units, return_sequences=True)(inputs)
#output_shape -> (batch_size, steps, units)
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:
outputs = LSTM(units)(inputs)
#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned
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:
- Erstellen Sie eine konstante mehrstufige Eingabe, indem Sie einen Tensor wiederholen
- Verwenden Sie a,
stateful=True
um wiederholt die Ausgabe eines Schritts zu übernehmen und als Eingabe für den nächsten Schritt zu dienen (Anforderungen output_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:
outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)
#output_shape -> (batch_size, steps, units)
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:
- In
stateful=False
enthält der zweite Stapel ganz neue Sequenzen, unabhängig vom ersten Stapel
- In
stateful=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:
- Diese Fenster überlagern sich nicht !!
stateful=True
Diese Fenster werden als einzelne lange Sequenz verbunden
In stateful=True
wird jede neue Charge so interpretiert, dass sie die vorherige Charge fortsetzt (bis Sie anrufen model.reset_states()
).
- Sequenz 1 in Charge 2 setzt Sequenz 1 in Charge 1 fort.
- Sequenz 2 in Charge 2 setzt Sequenz 2 in Charge 1 fort.
- Die Sequenz n in Charge 2 setzt die Sequenz n in Charge 1 fort.
Beispiel für Eingaben, Charge 1 enthält die Schritte 1 und 2, Charge 2 enthält die Schritte 3 bis 5:
BATCH 1 BATCH 2
[ Step1 Step2 | [ Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], | [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], | [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
.... |
Tank N: [[Pn1,Tn1], [Pn2,Tn2], | [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
] ]
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 Beispiel stateful=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:
outputs = LSTM(units=features,
stateful=True,
return_sequences=True, #just to keep a nice output shape even with length 1
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
Jetzt brauchen wir eine manuelle Schleife für Vorhersagen:
input_data = someDataWithShape((batch, 1, features))
#important, we're starting new sequences, not continuing old ones:
model.reset_states()
output_sequence = []
last_step = input_data
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
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:
- Wir werden die Sequenz selbst als Zieldaten verwenden, einen Schritt voraus
- Wir kennen einen Teil der Sequenz (also verwerfen wir diesen Teil der Ergebnisse).
Schicht (wie oben):
outputs = LSTM(units=features,
stateful=True,
return_sequences=True,
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
Ausbildung:
Wir werden unser Modell trainieren, um den nächsten Schritt der Sequenzen vorherzusagen:
totalSequences = someSequencesShaped((batch, steps, features))
#batch size is usually 1 in these cases (often you have only one Tank in the example)
X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X
#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
model.reset_states()
model.train_on_batch(X,Y)
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:
model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step
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).
output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
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:
inputs = Input((steps,features))
#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)
#many to one layer:
outputs = LSTM(hidden3)(outputs)
encoder = Model(inputs,outputs)
Decoder:
Verwenden der "Wiederholungs" -Methode;
inputs = Input((hidden3,))
#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)
#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)
#last layer
outputs = LSTM(features,return_sequences=True)(outputs)
decoder = Model(inputs,outputs)
Autoencoder:
inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)
autoencoder = Model(inputs,outputs)
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-LSTMs