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]