下面我有一個Tensorflow RNN單元的實現,該單元用於模擬本文中的Alex Graves算法ACT:http://arxiv.org/abs/1603.08983。在while_loop的上下文中使用TensorArrays來累計值
在通過rnn.rnn調用的序列中的單個時間步驟(帶有靜態sequence_length參數,因此rnn動態展開 - 我使用的是固定批量大小爲20),我們遞歸調用ACTStep,生成大小輸出(1,200)其中RNN單元格的隱藏維度爲200,批量大小爲1.
在Tensorflow中使用while循環,我們進行迭代,直到累計停止概率足夠高。所有這些工作都相當順利,但是我在while循環中存在積累狀態,概率和輸出的問題,爲了創建這些作爲最終單元輸出/狀態的加權組合,我們需要做這些工作。
我嘗試過使用一個簡單的列表,如下所示,但是當圖形編譯爲輸出不在同一個框架中時失敗(是否可以使用control_flow_ops中的「開關」功能將張量轉發到在需要它們的地方,即我們返回值之前的add_n函數?)。我也嘗試過使用TensorArray結構,但是我發現這很難使用,因爲它似乎破壞了形狀信息,並且手動替換它沒有奏效。我也無法找到關於TensorArrays的大量文檔,據推測,他們是,我想,主要是用於TF的內部使用。
任何有關如何正確累積由ACTStep生成的變量的建議將非常感謝。
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]