以下、このペーパーのAlex GravesのアルゴリズムACTをエミュレートするように設計されたTensorflow RNNセルの実装を示します。http://arxiv.org/abs/1603.08983while_loopのコンテキストでTensorArraysを使用して値を累積します
via rnn.rnn(静的なsequence_lengthパラメータで、rnnが動的に展開されるように、私は20の固定バッチサイズを使用しています)、ACTStepを呼び出して、サイズの出力を再帰的に呼び出しますRNNセルの隠れた次元が200であり、バッチサイズが1である(1,200)。
Tensorflowのwhileループを使用して、累積停止確率が十分に高くなるまで繰り返します。これらのすべては合理的にスムーズに機能しますが、最終的なセル出力/状態として重み付けされた組み合わせを作成するために必要な、whileループ内の状態、確率および出力の蓄積に問題があります。
私は以下のように単純なリストを使ってみましたが、出力が同じフレームにないのでグラフがコンパイルされたときに失敗します(control_flow_opsのswitch関数を使用してテンソルをそれらが必要とされるポイント、すなわち、値を返す直前の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]