Diese Frage als Problem besteht akzeptiert, auch: https://github.com/fchollet/keras/issues/4266Keras eine Recurrent Schicht zu schreiben, die Bilder
Ich versuche, eine Faltungs zu implementieren - LSTM. Es ist eine wiederkehrende Ebene, die ein Bild als Eingabe akzeptiert und eine Faltung verwendet, um die verschiedenen Gatter im LSTM zu berechnen. Also ich versuche, Recurrent
Unterklasse und ändern Sie die Eingabe Dimension.
Um dies zu tun, lese ich die Dokumentation auf writing a custom layer und folgte dem Vorschlag, Quellcode zu lesen, um zu verstehen, was unter der Haube passiert.
Ich las den Code für recurrent.py und denken, dass die Struktur klar ist: Sie erben von Recurrent
aber nicht überschreiben rufen, sondern bieten Sie eine benutzerdefinierte Funktion step
und Recurrent
wird jeder kümmern den Schritt des Auftragens Eintrag in einer Sequenz.
Als Ausgangspunkt habe ich den Code für die GRU genommen und versucht, ihn an meine Bedürfnisse anzupassen. Ich möchte eine 2D-Faltung und eine GRU kombinieren (normalerweise ist es ein LSTM, aber das ist nicht wirklich wichtig - ich entschied mich, eine C-GRU zu implementieren)
Die Idee ist, eine gewöhnliche 2D-Faltung im Modell zu haben welches 3 Merkmale ausgibt. Diese 3 Merkmale werden als die r-, z- und h-Aktivierungen in der GRU verwendet. In der benutzerdefinierten Ebene muss ich nur den Status verfolgen. Meine Schicht hat nicht einmal trainierbare Gewichte, sie sind in der Faltung enthalten.
Bemerkenswerte Änderungen an der ursprünglichen GRU
Code sind:
def step(self, x, states):
# the previous state is a 2D vector
h_tm1 = states[0] # previous memory
z=self.inner_activation(x[:,0,:,:])
r=self.inner_activation(x[:,1,:,:])
hh=self.activation(x[:,2,:,:])
h = z * h_tm1 + (1 - z) * hh
return h, [h]
Wie Sie sehen können, bin ich die Eigenschaften aus der Faltung einfach wiederzuverwenden. Die Multiplikationen sollten elementweise durchgeführt werden. Ich werde dies debuggen, um sicherzustellen, dass es das beabsichtigte Verhalten hat.
Da der Zustand 2D wird, ich bin die Änderung der initial_state
auch:
def get_initial_states(self, x):
initial_state=K.zeros_like(x) # (samples, timesteps, input_dim)
# input_dim = (3, x_dim, y_dim)
initial_state=K.sum(initial_state, axis=(1,2)) # (samples, x_dim, y_dim)
return initial_state
Die output_shape
scheint für Recurrent Netzwerke fest einprogrammiert werden. Ich überschreibt es:
def get_output_shape_for(self, input_shape):
#TODO: this is hardcoding for th layout
return (input_shape[0],1,input_shape[2],input_shape[3])
andere Sache, die hartcodiert ist, ist die input_spec
. im Konstruktor nach dem Aufruf von super, zwingende ich es mit meiner Eingang Dimension:
class CGRU(Recurrent):
def __init__(self,
init='glorot_uniform', inner_init='orthogonal',
activation='tanh', inner_activation='hard_sigmoid', **kwargs):
self.init = initializations.get(init)
self.inner_init = initializations.get(inner_init)
self.activation = activations.get(activation)
self.inner_activation = activations.get(inner_activation)
#removing the regularizers and the dropout
super(CGRU, self).__init__(**kwargs)
# this seems necessary in order to accept 5 input dimensions
# (samples, timesteps, features, x, y)
self.input_spec=[InputSpec(ndim=5)]
Es gibt noch andere kleine Änderungen. Sie können den gesamten Code finden Sie hier: http://pastebin.com/60ztPis3
Wenn lief, dies erzeugt die folgende Fehlermeldung:
theano.tensor.var.AsTensorError: ('Cannot convert [None] to TensorType',)
Die ganze Fehlermeldung auf Pastebin: http://pastebin.com/Cdmr20Yn
Ich versuche, das zu debuggen Code. Aber das ist ziemlich schwer, es geht tief in den Keras Quellcode ein. Eine Sache: Die Ausführung erreicht nie meine benutzerdefinierte step
Funktion. Offenbar geht also etwas in der Konfiguration schief.In der Funktion call
von Recurrent
ist input_shape ein Tupel mit den Einträgen (None, 40,1,40,40)
Dies ist korrekt. Meine Sequenz hat 40 Elemente. Jeder ist ein Bild mit 1 Merkmal und 40x40 Auflösung. Ich benutze das "th" Layout.
Hier ist die call
Funktion von Recurrent
. Mein Code erreicht den Anruf K.rnn
, das Setup sieht gut aus für mich. Input_spec scheint korrekt zu sein. Aber während K.rnn
stürzt es ab. Ohne meine Schrittfunktion zu erreichen.
An diesem Punkt bin ich verloren. Es scheint mir, dass ich einen Teil der Konfiguration vermisse.
UPDATE:
Hm, jetzt bin ich ein seltsames Problem mit: Mein Code ist jetzt:
# this is the actual input, fed to the network
inputs = Input((1, 40, 40, 40))
# now reshape to a sequence
reshaped = Reshape((40, 1, 40, 40))(inputs)
conv_inputs = Input((1, 40, 40))
conv1 = Convolution2D(3, 3, 3, activation='relu', border_mode='same')(conv_inputs)
convmodel = Model(input=conv_inputs, output=conv1)
convmodel.summary()
#apply the segmentation to each layer
time_dist=TimeDistributed(convmodel)(reshaped)
from cgru import CGRU
up=CGRU(go_backwards=False, return_sequences=True, name="up")
up=up(time_dist)
output=Reshape([1,40,40,40])(up)
model=Model(input=inputs, output=output)
print(model.summary())
Auf einem Computer mit Theano als Backend, das funktioniert. Das Modell Zusammenfassung ist:
________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
====================================================================================================
input_1 (InputLayer) (None, 1, 40, 40, 40) 0
____________________________________________________________________________________________________
reshape_1 (Reshape) (None, 40, 1, 40, 40) 0 input_1[0][0]
____________________________________________________________________________________________________
timedistributed_1 (TimeDistribute(None, 40, 3, 40, 40) 30 reshape_1[0][0]
____________________________________________________________________________________________________
up (CGRU) (None, 40, 1, 40, 40) 0 timedistributed_1[0][0]
____________________________________________________________________________________________________
reshape_2 (Reshape) (None, 1, 40, 40, 40) 0 up[0][0]
====================================================================================================
Total params: 30
____________________________________________________________________________________________________
Aber auf einem Computer mit tensorflow als Backend, schlägt der Code. Ich habe eine model.summary()
für die convmodel
hinzugefügt. Bis zu, dass es funktioniert:
Layer (type) Output Shape Param # Connected to
====================================================================================================
input_4 (InputLayer) (None, 1, 40, 40) 0
____________________________________________________________________________________________________
convolution2d_2 (Convolution2D) (None, 3, 40, 40) 30 input_4[0][0]
====================================================================================================
Total params: 30
Aber dann stürzt das Programm ab:
ValueError: Shapes (?, ?, 40, 40) and (40, ?, 40) are not compatible
Es ist wie Theano und Tensorflow scheint haben unterschiedliche (und nicht kompatibel) Platzhalter für die batch_size? Bitte beachten Sie, dass ich Keras so konfiguriert habe, dass in beiden Fällen das "th" -Bildlayout verwendet wird.