bidirectional_rnn
とGRUCell
を使用していますが、これはTensorflowのRNNに関する一般的な質問です。
重み行列(非表示への入力、非表示から非表示への入力)を初期化する方法が見つかりませんでした。それらはランダムに初期化されますか?ゼロに?作成するLSTMごとに異なる方法で初期化されますか?
編集:この質問のもう1つの動機は、いくつかのLSTMを事前にトレーニングし、後続のモデルでそれらの重みを使用することです。現在、すべての状態を保存してモデル全体を復元せずにそれを行う方法がわかりません。
ありがとう。
RNNの重み行列を初期化する方法
人々はRNNの重み行列にランダム正規初期化を使用していると思います。 TensorFlow GitHubリポジトリの例 を確認してください。ノートブックは少し長いので、単純なLSTMモデルがあり、tf.truncated_normal
を使用して重みを初期化し、tf.zeros
を使用してバイアスを初期化します(以前はtf.ones
を使用してバイアスを初期化しようとしましたが、また動作するようです)。標準偏差は、自分で調整できるハイパーパラメータだと思います。重みの初期化がグラジエントフローにとって重要な場合があります。私の知る限り、LSTM自体は勾配消失問題を処理するように設計されています(そして勾配クリッピングは勾配爆発問題を支援するためのものです)ので、おそらくsuperである必要はありません。 LSTMでのstd_dev
の設定に注意しますか?畳み込みニューラルネットワークのコンテキストでXavier初期化( Xavier初期化子のTF APIドキュメント )を推奨する論文を読みました。人々がRNNでそれを使用しているかどうかはわかりませんが、それが役立つかどうかを確認したい場合は、RNNでそれらを試すこともできると思います。
@Allenの回答と、コメントに残されたフォローアップの質問をフォローアップします。
変数スコープで初期化を制御する方法は?
例としてリンクした TensorFlow GitHub python Notebook )で単純なLSTMモデルを使用します。 具体的には、可変スコープ制御を使用して上の図のコードのLSTM部分を再因数分解したい場合は、次のようにコーディングできます...
import tensorflow as tf
def initialize_LSTMcell(vocabulary_size, num_nodes, initializer):
'''initialize LSTMcell weights and biases, set variables to reuse mode'''
gates = ['input_gate', 'forget_gate', 'memory_cell', 'output_gate']
with tf.variable_scope('LSTMcell') as scope:
for gate in gates:
with tf.variable_scope(gate) as gate_scope:
wx = tf.get_variable("wx", [vocabulary_size, num_nodes], initializer)
wt = tf.get_variable("wt", [num_nodes, num_nodes], initializer)
bi = tf.get_variable("bi", [1, num_nodes, tf.constant_initializer(0.0)])
gate_scope.reuse_variables() #this line can probably be omitted, b.z. by setting 'LSTMcell' scope variables to 'reuse' as the next line, it'll turn on the reuse mode for all its child scope variables
scope.reuse_variables()
def get_scope_variables(scope_name, variable_names):
'''a helper function to fetch variable based on scope_name and variable_name'''
vars = {}
with tf.variable_scope(scope_name, reuse=True):
for var_name in variable_names
var = tf.get_variable(var_name)
vars[var_name] = var
return vars
def LSTMcell(i, o, state):
'''a function for performing LSTMcell computation'''
gates = ['input_gate', 'forget_gate', 'memory_cell', 'output_gate']
var_names = ['wx', 'wt', 'bi']
gate_comp = {}
with tf.variable_scope('LSTMcell', reuse=True):
for gate in gates:
vars = get_scope_variables(gate, var_names)
gate_comp[gate] = tf.matmul(i, vars['wx']) + tf.matmul(o, vars['wt']) + vars['bi']
state = tf.sigmoid(gate_comp['forget_gate']) * state + tf.sigmoid(gate_comp['input_gate']) * tf.tanh(gate_comp['memory_cell'])
output = tf.sigmoid(gate_comp['output_gate']) * tf.tanh(state)
return output, state
再ファクタリングされたコードの使用法は、次のようになります...
initialize_LSTMcell(volcabulary_size, num_nodes, tf.truncated_normal_initializer(mean=-0.1, stddev=.01))
#...Doing some computation...
LSTMcell(input_tensor, output_tensor, state)
リファクタリングされたコードはそれほど単純に見えないかもしれませんが、スコープ変数制御を使用すると、スコープのカプセル化が保証され、柔軟な変数制御が可能になります(少なくとも私の意見では)。
いくつかのLSTMを事前トレーニングし、後続のモデルでそれらの重みを使用する場合。すべての状態を保存せずにモデル全体を復元せずにそれを行う方法
事前にトレーニングされたモデルがフリーズしてロードされていると仮定すると、フリーズした「wx」、「wt」、「bi」を使用する場合は、親スコープ名と変数名を簡単に見つけて、同様の構造を使用して変数をフェッチできます。 get_scope_variables
funcで。
with tf.variable_scope(scope_name, reuse=True):
var = tf.get_variable(var_name)
変数スコープの理解と変数の共有 へのリンクは次のとおりです。これがお役に立てば幸いです。
RNNモデルはget_variable
で変数を作成し、それらの変数を作成するコードをvariable_scope
と デフォルトの初期化子を渡す でラップすることで初期化を制御できます。 RNNが明示的に指定しない限り( コードを見る 、そうではありません)、 uniform_unit_scaling_initializer
が使用されます 。
また、2番目のモデルを宣言し、そのvariable_scopeにreuse=True
を渡すことで、モデルの重みを共有できるはずです。名前空間が一致している限り、新しいモデルは最初のモデルと同じ変数を取得します。
特定の初期化子を使用してすべてのカーネルの重みを初期化する簡単な方法は、初期化子をtf.variable_scope()
に残すことです。例えば:
with tf.variable_scope('rnn', initializer=tf.variance_scaling_initializer()):
basic_cell= tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
outputs, state= tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)