TensorFlowの変数を再利用できるように
問題
上の記事にて問題となっていたことが解決したので執筆。LSTMに学習をさせた後、同じコード上で予測をさせたり、同じコード上で続けて予測をさせたりすると以下のエラーが出るのであった。
NotFoundError (see above for traceback): Key Variable_4 not found in checkpoint [[Node: save_1/RestoreV2_4 = RestoreV2[dtypes=[DT_DOUBLE], _device="/job:localhost/replica:0/task:0/device:CPU:0"](_arg_save_1/Const_0_0, save_1/RestoreV2_4/tensor_names, save_1/RestoreV2_4/shape_and_slices)]]
原因
当時はこのVariable_4
がcell内の変数を表しているのかと思っていた。
しかし、これは前利用した時と区別するために新しく名前がつけられているだけで、重み(w)とバイアス(b)であった。
つまり、エラーの原因は以下の通り。
1. 二度目の実行時に変数を再び定義するが、同じコード上でこれを行うと一度目の実行時に定義した変数と区別するために一度目とは違う名前がつけられる。
2. セッションを開始し、tf.Saver().load
で前回の学習で保存されたモデルの変数を復元する。
3. 保存された時とは違う名前の変数を要求され、怒られる。
解決法
これを直すためには二度目の実行時にも同じ名前で変数を定義できるようにしなければならない。
ただ、以下のようなコードで変数を定義してたが、tf.Variable
では変数を同じ名前で再利用する許可ができない(と思われる)。
w_hidden = tf.Variable(tf.random_normal([self.input_layer_size, self.hidden_layer_size], dtype="float64")) b_hidden = tf.Variable(tf.random_normal([self.hidden_layer_size], dtype="float64")) w_output = tf.Variable(tf.random_normal([self.hidden_layer_size, self.output_layer_size], dtype="float64")) b_output = tf.Variable(tf.random_normal([self.output_layer_size], dtype="float64"))
そこで、上の部分をtf.variable_scope
とtf.get_variable
を用いて以下のように書き換えた。
def make_weight_and_bias(scope_name, former_layer_size, latter_layer_size): with tf.variable_scope(scope_name, reuse=tf.AUTO_REUSE): w_init = tf.random_normal([former_layer_size, latter_layer_size], dtype="float64") b_init = tf.random_normal([latter_layer_size], dtype="float64") w = tf.get_variable("w", initializer=w_init, dtype="float64") b = tf.get_variable("b", initializer=b_init, dtype="float64") return w, b w_hidden, b_hidden = make_weight_and_bias("hidden_variable_scope", self.input_layer_size, self.hidden_layer_size) w_output, b_output = make_weight_and_bias("output_variable_scope", self.hidden_layer_size, self.output_layer_size)
tf.variable_scope
にはオプションreuse
があるのでこれをtf.AUTO_REUSE
とすることで同じ名前で変数を再利用することを許可する。
以上の工夫を施した結果、エラーは解決した。