2016-06-14 18 views
5

Di seguito è disponibile un'implementazione di una cella RNN di Tensorflow, progettata per emulare l'algoritmo di Alex Graves in questo documento: http://arxiv.org/abs/1603.08983.Utilizzo di TensorArray nel contesto di un while_loop per accumulare i valori

In un singolo timestep nella sequenza denominata via rnn.rnn (con un parametro statico sequence_length, quindi rnn viene srotolato dinamicamente - sto usando una dimensione batch fissa di 20), chiamiamo ricorsivamente ACTStep, producendo output di dimensioni (1.200) dove la dimensione nascosta della cella RNN è 200 e abbiamo una dimensione batch di 1.

Utilizzando il ciclo while in Tensorflow, iteriamo fino a quando la probabilità di interruzione accumulata è sufficientemente elevata. Tutto questo funziona ragionevolmente senza problemi, ma sto avendo problemi ad accumulare stati, probabilità e risultati all'interno del ciclo while, che dobbiamo fare per creare combinazioni ponderate di questi come output/stato finale della cella.

Ho provato ad usare una semplice lista, come sotto, ma questo fallisce quando il grafico è compilato poiché le uscite non sono nello stesso frame (è possibile usare la funzione "switch" in control_flow_ops per inoltrare i tensori a il punto in cui sono richiesti, ovvero la funzione add_n appena prima di restituire i valori?). Ho anche provato a utilizzare la struttura TensorArray, ma trovo che sia difficile da utilizzare in quanto sembra distruggere le informazioni sulla forma e la sua sostituzione manuale non ha funzionato. Inoltre, non sono stato in grado di trovare molta documentazione su TensorArray, presumibilmente come sono, immagino, principalmente per uso TF interno.

Qualsiasi consiglio su come potrebbe essere possibile accumulare correttamente le variabili prodotte da ACTStep sarebbe molto apprezzato.

class ACTCell(RNNCell): 
"""An RNN cell implementing Graves' Adaptive Computation time algorithm""" 
def __init__(self, num_units, cell, epsilon, max_computation): 

    self.one_minus_eps = tf.constant(1.0 - epsilon) 
    self._num_units = num_units 
    self.cell = cell 
    self.N = tf.constant(max_computation) 
@property 
def input_size(self): 
    return self._num_units 
@property 
def output_size(self): 
    return self._num_units 
@property 
def state_size(self): 
    return self._num_units 

def __call__(self, inputs, state, scope=None): 

    with vs.variable_scope(scope or type(self).__name__): 

     # define within cell constants/ counters used to control while loop 
     prob = tf.get_variable("prob", [], tf.float32,tf.constant_initializer(0.0)) 
     counter = tf.get_variable("counter", [],tf.float32,tf.constant_initializer(0.0)) 
     tf.assign(prob,0.0) 
     tf.assign(counter, 0.0) 

     # the predicate for stopping the while loop. Tensorflow demands that we have 
     # all of the variables used in the while loop in the predicate. 
     pred = lambda prob,counter,state,input,\ 
         acc_state,acc_output,acc_probs:\ 
      tf.logical_and(tf.less(prob,self.one_minus_eps), tf.less(counter,self.N)) 

     acc_probs = [] 
     acc_outputs = [] 
     acc_states = [] 


     _,iterations,_,_,acc_states,acc_output,acc_probs = \ 
     control_flow_ops.while_loop(pred, 
     self.ACTStep, 
     [prob,counter,state,input,acc_states,acc_outputs,acc_probs]) 

    # TODO:fix last part of this, need to use the remainder. 
    # TODO: find a way to accumulate the regulariser 

    # here we take a weighted combination of the states and outputs 
    # to use as the actual output and state which is passed to the next timestep. 

    next_state = tf.add_n([tf.mul(x,y) for x,y in zip(acc_probs,acc_states)]) 
    output = tf.add_n([tf.mul(x,y) for x,y in zip(acc_probs,acc_outputs)]) 


    return output, next_state 

def ACTStep(self,prob,counter,state,input, acc_states,acc_outputs,acc_probs): 

    output, new_state = rnn.rnn(self.cell, [input], state, scope=type(self.cell).__name__) 

    prob_w = tf.get_variable("prob_w", [self.cell.input_size,1]) 
    prob_b = tf.get_variable("prob_b", [1]) 
    p = tf.nn.sigmoid(tf.matmul(prob_w,new_state) + prob_b) 

    acc_states.append(new_state) 
    acc_outputs.append(output) 
    acc_probs.append(p) 

    return [tf.add(prob,p),tf.add(counter,1.0),new_state, input,acc_states,acc_outputs,acc_probs] 

risposta

3

Ho intenzione di prefigurare questa risposta che questa NON è una soluzione completa, ma piuttosto alcuni commenti su come migliorare la vostra cella.

Per cominciare, nella funzione ACTStep, si chiama rnn.rnn per un passo temporale (come definito dalla [input]. Se stai facendo un singolo passo temporale, è probabilmente più efficiente utilizzo semplice la funzione reale self.cell chiamata. È' ll vedere questo stesso meccanismo utilizzato in tensorflow rnncell wrappers

Lei ha detto che avete provato a usare TensorArrays. Hai comprimere e decomprimere i tensorarrays in modo appropriato? Ecco una repo dove troverete sotto model.py i tensorarrays vengono imballati e non imballati correttamente.

Hai anche chiesto se c'è una funzione in control_flow_ops che richiederà l'accumulo di tutti i tensori. Penso che stiate cercando tf.control_dependencies

Potete elencare tutte le operazioni dei tensori di uscita in control_dependicies e che richiederà tensorflow per calcolare tutti i tensori in quel punto.

Inoltre, sembra che la variabile counter sia addestrabile. Sei sicuro di volerlo? Se aggiungi più uno al tuo contatore, probabilmente non otterrai il risultato corretto. D'altro canto, avresti potuto tenerlo appositamente allenato per differenziarlo alla fine per la funzione costo ponderante.

Inoltre credo che la funzione resto dovrebbe essere nello script:

remainder = 1.0 - tf.add_n(acc_probs[:-1]) 
#note that there is a -1 in the list as you do not want to grab the last probability 

Ecco la mia versione del codice modificato:

class ACTCell(RNNCell): 
    """An RNN cell implementing Graves' Adaptive Computation time algorithm 
    Notes: https://www.evernote.com/shard/s189/sh/fd165646-b630-48b7-844c-86ad2f07fcda/c9ab960af967ef847097f21d94b0bff7 

    """ 
    def __init__(self, num_units, cell, max_computation = 5.0, epsilon = 0.01): 

     self.one_minus_eps = tf.constant(1.0 - epsilon) #episolon is 0.01 as found in the paper 
     self._num_units = num_units 
     self.cell = cell 
     self.N = tf.constant(max_computation) 

    @property 
    def input_size(self): 
     return self._num_units 
    @property 
    def output_size(self): 
     return self._num_units 
    @property 
    def state_size(self): 
     return self._num_units 

    def __call__(self, inputs, state, scope=None): 

     with vs.variable_scope(scope or type(self).__name__): 

      # define within cell constants/ counters used to control while loop 
      prob = tf.constant(0.0, shape = [batch_size]) 
      counter = tf.constant(0.0, shape = [batch_size]) 

      # the predicate for stopping the while loop. Tensorflow demands that we have 
      # all of the variables used in the while loop in the predicate. 
      pred = lambda prob,counter,state,input,acc_states,acc_output,acc_probs:\ 
       tf.logical_and(tf.less(prob,self.one_minus_eps), tf.less(counter,self.N)) 

      acc_probs, acc_outputs, acc_states = [], [], [] 

      _,iterations,_,_,acc_states,acc_output,acc_probs = \ 
      control_flow_ops.while_loop(
      pred, 
      self.ACTStep, #looks like he purposely makes the while loop here 
      [prob, counter, state, input, acc_states, acc_outputs, acc_probs]) 

     '''mean-field updates for states and outputs''' 
     next_state = tf.add_n([x*y for x,y in zip(acc_probs,acc_states)]) 
     output = tf.add_n([x*y for x,y in zip(acc_probs,acc_outputs)]) 

     remainder = 1.0 - tf.add_n(acc_probs[:-1]) #you take the last off to avoid a negative ponder cost #the problem here is we need to take the sum of all the remainders 
     tf.add_to_collection("ACT_remainder", remainder) #if this doesnt work then you can do self.list based upon timesteps 
     tf.add_to_collection("ACT_iterations", iterations) 
     return output, next_state 

    def ACTStep(self,prob, counter, state, input, acc_states, acc_outputs, acc_probs): 

     '''run rnn once''' 
     output, new_state = rnn.rnn(self.cell, [input], state, scope=type(self.cell).__name__) 

     prob_w = tf.get_variable("prob_w", [self.cell.input_size,1]) 
     prob_b = tf.get_variable("prob_b", [1]) 
     halting_probability = tf.nn.sigmoid(tf.matmul(prob_w,new_state) + prob_b) 


     acc_states.append(new_state) 
     acc_outputs.append(output) 
     acc_probs.append(halting_probability) 

     return [p + prob, counter + 1.0, new_state, input,acc_states,acc_outputs,acc_probs] 


    def PonderCostFunction(self, time_penalty = 0.01): 
     ''' 
     note: ponder is completely different than probability and ponder = roe 

     the ponder cost function prohibits the rnn from cycling endlessly on each timestep when not much is needed 
     ''' 
     n_iterations = tf.get_collection_ref("ACT_iterations") 
     remainder = tf.get_collection_ref("ACT_remainder") 
     return tf.reduce_sum(n_iterations + remainder) #completely different from probability 

Si tratta di un documento complicato da implementare che sono stato lavorando su me stesso. Non mi dispiacerebbe collaborare con te per averlo fatto a Tensorflow. Se sei interessato, per favore aggiungimi a LeavesBreathe su Skype e possiamo andare da lì.

Problemi correlati