Keras: Umformen, um lstm und conv zu verbinden

Diese Frage existiert alsgithub Problem , auch. Ich möchte ein neuronales Netzwerk in Keras aufbauen, das sowohl 2D-Faltungen als auch eine LSTM-Schicht enthält.

Das Netzwerk sollte MNIST klassifizieren. Die Trainingsdaten in MNIST sind 60000 Graustufenbilder mit handgeschriebenen Ziffern von 0 bis 9. Jedes Bild ist 28 x 28 Pixel groß.

Ich habe die Bilder in vier Teile (links / rechts, oben / unten) aufgeteilt und sie in vier Reihenfolgen neu angeordnet, um Sequenzen für das LSTM zu erhalten.

|     |      |1 | 2|
|image|  ->  -------   -> 4 sequences: |1|2|3|4|,  |4|3|2|1|, |1|3|2|4|, |4|2|3|1|
|     |      |3 | 4|

Eines der kleinen Unterbilder hat die Abmessung 14 x 14. Die vier Sequenzen sind entlang der Breite gestapelt (egal ob Breite oder Höhe).

Dies erzeugt einen Vektor mit der Form [60000, 4, 1, 56, 14], wobei:

60000 ist die Anzahl der Proben 4 ist die Anzahl der Elemente in einer Sequenz (Anzahl der Zeitschritte) 1 ist die Farbtiefe (Graustufen) 56 und 14 sind Breite und Höhe

Jetzt sollte dies einem Keras-Modell zugewiesen werden. Das Problem besteht darin, die Eingabedimensionen zwischen CNN und LSTM zu ändern. Ich habe online gesucht und diese Frage gefunden:Python keras wie man die Größe der Eingabe nach der Faltungsebene in die LSTM-Ebene ändert

Die Lösung scheint eine Reshape-Ebene zu sein, die das Bild glättet, aber die Zeitschritte beibehält (im Gegensatz zu einer Flatten-Ebene, die alles außer der batch_size zusammenfällt).

Hier ist mein Code:

nb_filters=32
kernel_size=(3,3)
pool_size=(2,2)
nb_classes=10
batch_size=64

model=Sequential()

model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1],
    border_mode="valid", input_shape=[1,56,14]))
model.add(Activation("relu"))
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1]))
model.add(Activation("relu"))
model.add(MaxPooling2D(pool_size=pool_size))


model.add(Reshape((56*14,)))
model.add(Dropout(0.25))
model.add(LSTM(5))
model.add(Dense(50))
model.add(Dense(nb_classes))
model.add(Activation("softmax"))

Dieser Code erzeugt eine Fehlermeldung:

ValueError: Gesamtgröße des neuen Arrays muss unverändert bleiben

Anscheinend ist die Eingabe für die Ebene "Umformen" falsch. Alternativ habe ich versucht, die Zeitschritte auch an die Reshape-Ebene zu übergeben:

model.add(Reshape((4,56*14)))

Das fühlt sich nicht richtig an und in jedem Fall bleibt der Fehler derselbe.

Mache ich das richtig? Ist eine Reshape-Ebene das richtige Werkzeug, um CNN und LSTM zu verbinden?

Es gibt ziemlich komplexe Ansätze für dieses Problem. So wie dieses:https: //github.com/fchollet/keras/pull/145 Eine zeitverteilte Ebene, die die Zeitschrittdimension vor den folgenden Ebenen zu verbergen scheint.

Oder dieses:https: //github.com/anayebi/keras-extr Eine Reihe von Spezialebenen zum Kombinieren von CNNs und LSTMs.

Warum gibt es so komplizierte (zumindest erscheinen sie mir kompliziert) Lösungen, wenn eine einfache Umformung den Trick macht?

AKTUALISIERE:

Peinlicherweise habe ich vergessen, dass sich die Dimensionen durch das Pooling und (mangels Polsterung) auch die Windungen ändern. kgrm riet mir, @ zu verwendmodel.summary(), um die Abmessungen zu überprüfen.

Die Ausgabe der Ebene vor der Ebene "Umformen" ist(None, 32, 26, 5), Ich habe die Umformung geändert in:model.add(Reshape((32*26*5,))).

Jetzt ist der ValueError weg, stattdessen beschwert sich der LSTM:

Exception: Eingabe 0 ist nicht kompatibel mit Layer lstm_5: erwartet ndim = 3, gefunden ndim = 2

Es scheint, als müsste ich die Zeitschrittdimension durch das gesamte Netzwerk leiten. Wie kann ich das machen ? Wenn ich es zur input_shape der Convolution hinzufüge, beschwert es sich auch:Convolution2D(nb_filters, kernel_size[0], kernel_size[1], border_mode="valid", input_shape=[4, 1, 56,14])

Exception: Eingabe 0 ist nicht kompatibel mit Layer Convolution2D_44: erwartet ndim = 4, gefunden ndim = 5

Antworten auf die Frage(2)

Ihre Antwort auf die Frage