2015-12-10 27 views
6

sto cercando di attuare in KERAS neurale (ish) netto con questo motivo: http://nlp.cs.rpi.edu/paper/AAAI15.pdfMoltiplicando l'uscita di due strati in keras

L'algoritmo è, essenzialmente, tre ingressi. L'ingresso 2 e l'ingresso 3 vengono moltiplicati per la stessa matrice di peso W1 per produrre O2 e O3. L'ingresso 1 viene moltiplicato per W2 per produrre O1. Quindi, dobbiamo prendere il prodotto punto di O1 * O2 e O1 * O3.

Sto provando a implementarlo in keras.

Il mio primo pensiero è stato quello di utilizzare la classe keras Graph e rendere W1 uno strato nodo condiviso con due ingressi e due uscite. Bene finora.

Si pone quindi il problema di come prelevare i prodotti punto di queste due uscite con O1.

ho cercato di definire una funzione personalizzata:

def layer_mult(X, Y): 
     return K.dot(X * K.transpose(Y)) 

Poi:

ntm.add_node(Lambda(layer_mult, output_shape = (1,1)), name = "ls_pos", inputs = ["O1", "O2"]) 
ntm.add_node(Lambda(layer_mult, output_shape = (1,1)), name = "ls_neg", inputs = ["O1", "O3"]) 

Il problema che si pone sulla compilazione, è che KERAS vuole solo per dare lo strato Lambda un ingresso:

1045   func = types.FunctionType(func, globals()) 
    1046   if hasattr(self, 'previous'): 
-> 1047    return func(self.previous.get_output(train)) 
    1048   else: 
    1049    return func(self.input) 

TypeError: layer_mult() takes exactly 2 arguments (1 given) 

Ho pensato che un'alternativa potrebbe essere quella di utilizzare una classe Merge, che ha dot come tipo di unione consentita. Tuttavia, i livelli di input per una classe Merge devono essere passati al costruttore. Quindi, non sembra essere un modo per ottenere gli output dal nodo condiviso nello Merge per aggiungere lo Merge allo Graph.

Se si utilizzavano i contenitori Sequential, è possibile inserire quelli nello Merge. Ma non ci sarebbe un modo per implementare il fatto che i due layer Sequential devono condividere la stessa matrice di peso.

Ho pensato di provare a concatenare O1, O2 e O3 insieme in un singolo vettore come livello di output e quindi fare la moltiplicazione all'interno di una funzione obiettivo. Ma ciò richiederebbe alla funzione obiettivo di dividere il suo input, che non sembra possibile in keras (le relative funzioni Theano non passano attraverso l'API di keras).

Qualcuno sa una soluzione?

EDIT:

ho pensato che avevo fatto qualche progresso, perché ho scoperto che shared_node sta attuando dot (anche se la sua non nella documentazione).

Così ho avuto modo:

ntm = Graph() 
ntm.add_input(name='g', input_shape=(300,)) # Vector of 300 units, normally distributed around zero 
ntm.add_node([pretrained bit], name = "lt", input = "g") # 300 * 128, output = (,128) 
n_docs = 1000 
ntm.add_input("d_pos", input_shape = (n_docs,)) # (,n_docs) 
ntm.add_input("d_neg", input_shape = (n_docs,)) # (,n_docs) 

ntm.add_shared_node(Dense(128, activation = "softmax", 
#      weights = pretrained_W1, 
         W_constraint = unitnorm(), 
         W_regularizer = l2(0.001) 
        ), name = "ld", 
        inputs = ["d_pos", "d_neg"], 
        outputs = ["ld_pos", "ld_neg"], 
        merge_mode=None) # n_docs * 128, output = (,128) * 2 
ntm.add_shared_node(ActivityRegularization(0,0), #ActivityRegularization is being used as a passthrough - the function of the node is to dot* its inputs 
        name = "ls_pos", 
        inputs = ["lt", "d_pos"], 
        merge_mode = 'dot') # output = (,1) 
ntm.add_shared_node(ActivityRegularization(0,0), 
        name = "ls_neg", 
        inputs = ["lt", "d_neg"], 
        merge_mode = 'dot') # output = (,1) 
ntm.add_shared_node(ActivityRegularization(0,0), 
        name = "summed", 
        inputs = ["ls_pos", "ls_neg"], 
        merge_mode = 'sum') # output = (,1) 
ntm.add_node(ThresholdedReLU(0.5), 
      input = "summed", name = "loss") # output = (,1) 
ntm.add_output(name = "loss_out", 
       input= "loss") 
def obj(X, Y): 
    return K.sum(Y) 
ntm.compile(loss = {'loss_out' : obj}, optimizer = "sgd") 

E ora l'errore è:

>>> ntm.compile(loss = {'loss_out' : obj}, optimizer = "sgd") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/models.py", line 602, in compile 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/advanced_activations.py", line 149, in get_output 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/core.py", line 117, in get_input 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/core.py", line 1334, in get_output 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/core.py", line 1282, in get_output_sum 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/core.py", line 1266, in get_output_at 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/core.py", line 730, in get_output 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/core.py", line 117, in get_input 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/core.py", line 1340, in get_output 
    File "build/bdist.macosx-10.5-x86_64/egg/keras/layers/core.py", line 1312, in get_output_dot 
    File "/Volumes/home500/anaconda/envs/[-]/lib/python2.7/site-packages/theano/tensor/var.py", line 360, in dimshuffle 
    pattern) 
    File "/Volumes/home500/anaconda/envs/[-]/lib/python2.7/site-packages/theano/tensor/elemwise.py", line 164, in __init__ 
    (input_broadcastable, new_order)) 
ValueError: ('You cannot drop a non-broadcastable dimension.', ((False, False, False, False), (0, 'x'))) 
+0

Se non l'hai già, mi piacerebbe suggerire la creazione di un problema github per questo (anche se non sono uno sviluppatore di Keras). Inoltre, per quanto riguarda (ab) usando lo strato Siamese per questo, producendo O1 due volte con una matrice di peso condivisa? –

+0

Ciao, hai trovato la soluzione al tuo problema? – Bharat

risposta

2

È possibile utilizzare questo

main_branch.add (Merge ([branch_1, branch_2], mode = 'punto'))

+0

Accetto la risposta in modo che la gente non debba continuare a commentarla. È risultato essere molto facile e la tua risposta è un esempio di un modo per farlo. – Bob

+0

Sto provando qualcosa di simile [per favore date un'occhiata] (http://stackoverflow.com/questions/42297359/typeerror-output-tensors-to-a-model-must-be-keras-tensors) ma semplicemente non lavoro. Tutto quello che sto cercando di fare è moltiplicare un tensore per uno scalare. – displayname

0

sto affrontando il problema simile. Penso a una soluzione, ma non l'ho ancora provata.

  1. Utilizzo di Livelli di convoluzione per il modello sequenziale A che accetta sia Input2 che Input3 come input.In questo modo, lo stesso kernel di convoluzione verrà applicato a Input2 e Input3, ovvero lo stesso peso W1.

  2. Prendendo Input1 come input di un altro modello sequenziale B.

  3. Utilizzando uno strato di unione per unire l'uscita di A e B. E punto può essere realizzata anche tramite funzione personalizzata di uno strato di unione.

+0

Attualmente sto provando questo (vedi [qui] (http://stackoverflow.com/questions/42297359/typeerror-output-tensors-to-a-model-must-be-keras-tensors)) ma non funziona come Ottengo un 'TypeError' che dice che il tensore di uscita deve essere un tensore Keras. – displayname