Grundlegendes zu Keras-LSTMs

311

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:

  1. Die Umformung der Datenreihen in [samples, time steps, features]und,
  2. 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_backArray 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 oneFall 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).Geben Sie hier die Bildbeschreibung ein

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_sizeist 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_sizewurde willkürlich gewählt.): Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

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

Sachinruk
quelle
7
Das erste Foto sollte sein (batch_size, 5, 1); Das zweite Foto sollte (batch_size, 4, 3) sein (wenn es keine folgenden Sequenzen gibt). Und warum ist die Ausgabe immer noch "X"? Sollte es "Y" sein?
Van
1
Hier gehe ich davon aus, dass X_1, X_2 ... X_6 eine einzelne Zahl ist. Und drei Zahlen (X_1, X_2, X_3) ergeben einen Vektor der Form (3,). Eine Zahl (X_1) ergibt einen Vektor der Form (1,).
Van
2
@ Van, deine Annahme ist richtig. Das ist interessant, so dass das Modell im Grunde genommen keine Muster lernt, die über die Anzahl der Zeitschritte hinausgehen. Wenn ich also eine Zeitreihe mit einer Länge von 1000 habe und alle 100 Tage ein Muster visuell sehen kann, sollte ich den Parameter time_steps auf mindestens 100 setzen. Ist dies eine korrekte Beobachtung?
Sachinruk
3
Ja. Wenn Sie 3 relevante Features pro Tag sammeln können, können Sie die Feature-Größe wie auf dem zweiten Foto auf 3 setzen. Unter diesen Umständen lautet die Eingabeform (batch_size, 100, 3).
Van
1
und um Ihre erste Frage zu beantworten, war es, weil ich eine einzelne Zeitreihe nahm. Zum Beispiel Aktienkurse, also stammen X und Y aus derselben Serie.
Sachinruk

Antworten:

173

Zunächst wählen Sie großartige Tutorials ( 1 , 2 ) aus, um zu beginnen.

Was Zeitschritt bedeutet : Time-steps==3In 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_sequencesParameter bei der Initialisierung LSTModer GRUoder SimpleRNN. Wenn return_sequencesist False(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. Wann return_sequencesist True, 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 mich statefulnoch nicht eingeschaltet. Ich bin jedoch nicht damit einverstanden, dass das batch_sizenur 1 sein kann, wenn stateful==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.

Van
quelle
Etwas verwirrt darüber, warum die roten und grünen Kästchen gleich sein müssen. Könntest du dir die Bearbeitung ansehen, die ich vorgenommen habe (hauptsächlich die neuen Bilder) und kommentieren?
Sachinruk
1
Tatsächlich. Überprüfen Sie das Dokument: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.
Van
1
@ Van Wenn ich eine multivariate Zeitreihe habe, sollte ich sie trotzdem verwenden lookback = 1?
Innm
1
Warum unterscheidet sich die LSTM-Dimensionalität des Ausgaberaums (32) von der Anzahl der Neuronen (LSTM-Zellen)?
Sticky
1
Ergänzung zu 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 erstellen fit(), predict()benötigen alle und verwandte Methoden einen Stapel von 5. Beachten Sie jedoch, dass dieser Status nicht mit gespeichert wird model.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.
jlh
191

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=2nur als Beispiel Druck und Temperatur verwendet habe):

Viel zu viel

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:
    • Druck P.
    • Temperatur T.

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:

StandardManyToMany

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=Falsedieses Argument verwenden (oder einfach ignorieren), verwirft Keras automatisch die Schritte vor dem letzten:

ManyToOne

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=Trueum 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:

OneToManyRepeat

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=Falseenthält der zweite Stapel ganz neue Sequenzen, unabhängig vom ersten Stapel
  • In stateful=Truesetzt 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=Truewird 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=Truekönnen wir die Sequenz "stoppen", das, was wir wollen, manipulieren und dort weitermachen, wo wir aufgehört haben.

OneToManyStateful

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

ManyToManyStateful

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=Trueoben genannten Fällen wünschen, lesen Sie in dieser Antwort mehr: Zweifel bezüglich des Verständnisses von Keras-LSTMs

Daniel Möller
quelle
1
Sehr interessante Verwendung von Stateful mit der Verwendung von Ausgängen als Eingänge. Als zusätzliche Anmerkung wäre eine andere Möglichkeit, dies zu tun, die funktionale Keras-API zu verwenden (wie Sie es hier getan haben, obwohl ich glaube, dass Sie die sequentielle hätten verwenden können) und einfach dieselbe LSTM-Zelle für jeden Zeitschritt wiederzuverwenden , während sowohl der resultierende Zustand als auch die Ausgabe von der Zelle an sich selbst übergeben werden. Dh 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])
Jacob R
1
Zellen und Länge sind völlig unabhängige Werte. Keines der Bilder repräsentiert die Anzahl der "Zellen". Sie sind alle für "Länge".
Daniel Möller
1
@ DanielMöller Ich weiß, es ist ein bisschen spät, aber deine Antwort erregt wirklich meine Aufmerksamkeit. Einer Ihrer Punkte hat alles an meinem Verständnis darüber, was Batch für LSTM ist, erschüttert. Sie bieten Beispiel mit N Tanks, fünf Schritten und zwei Funktionen. Ich glaubte, dass, wenn die Charge zum Beispiel zwei ist, dies bedeutet, dass zwei Proben (Tanks mit 5 Schritten 2 Merkmalen) in das Netzwerk eingespeist und danach die Gewichte angepasst werden. Aber wenn ich richtig verstehe, geben Sie an, dass Charge 2 bedeutet, dass Zeitschritte der Proben auf 2 geteilt werden und die erste Hälfte aller Proben an LSTM-> Gewichtsaktualisierung und dann an die zweite Stelle weitergeleitet wird.
Viceriel
1
Ja. Bei einem Stateful = True, Batch 1 = Gruppe von Proben, aktualisieren. Dann Charge 2 = mehr Schritte für dieselbe Gruppe von Proben, aktualisieren.
Daniel Möller
2
Ich wünschte, ich könnte dies 100 Mal positiv bewerten. Super nützliche Antwort.
Adamconkey
4

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

    # Build a matrix of size vocabularySize x EmbeddingDimension 
    # where each row corresponds to a "word embedding" vector.
    # This layer will convert replace each word-id with a word-vector of size Embedding Dimension.
    embeddings = keras.layers.embeddings.Embedding(self.vocabularySize, self.EmbeddingDimension,
        name = "embeddings")(words)
    # Pass the word-vectors to the LSTM layer.
    # We are setting the hidden-state size to 512.
    # The output will be batchSize x maxSequenceLength x hiddenStateSize
    hiddenStates = keras.layers.GRU(512, return_sequences = True, 
                                        input_shape=(self.maxSequenceLength,
                                        self.EmbeddingDimension),
                                        name = "rnn")(embeddings)
    hiddenStates2 = keras.layers.GRU(128, return_sequences = True, 
                                        input_shape=(self.maxSequenceLength, self.EmbeddingDimension),
                                        name = "rnn2")(hiddenStates)

    denseOutput = TimeDistributed(keras.layers.Dense(self.vocabularySize), 
        name = "linear")(hiddenStates2)
    predictions = TimeDistributed(keras.layers.Activation("softmax"), 
        name = "softmax")(denseOutput)  

    # Build the computational graph by specifying the input, and output of the network.
    model = keras.models.Model(input = words, output = predictions)
    # model.compile(loss='kullback_leibler_divergence', \
    model.compile(loss='sparse_categorical_crossentropy', \
        optimizer = keras.optimizers.Adam(lr=0.009, \
            beta_1=0.9,\
            beta_2=0.999, \
            epsilon=None, \
            decay=0.01, \
            amsgrad=False))
Sanjay Krishna
quelle