2016-11-02 4 views
1

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.

Antwort

0

Ich denke, das Problem ist gelöst. Die initial_states erwartet eine Liste und die output_dimension musste behoben werden. Jetzt scheint es zu funktionieren. Es gibt einige andere Probleme mit dem zugrundeliegenden Backend (zB Theano vs Tensorflow), aber das scheint für diese Frage offtopic zu sein.

Sobald ich sicher bin, dass das Problem wirklich behoben wurde und dass der Layer lernen kann, werde ich diese Antwort mit allen notwendigen Schritten aktualisieren.

Verwandte Themen