当我在训练我的图时,我发现我忘记在图中添加dropout层。但我已经训练了很长时间并获得了一些检查点。所以我是否可以加载这些检查点,添加dropout层,然后继续训练?我的代码现在是这样的:
# create a graph vgg_fcn = fcn8_vgg_ours.FCN8VGG()with tf.name_scope("content_vgg"): vgg_fcn.build(batch_images, train = True, debug=True)labels = tf.placeholder("int32", [None, HEIGHT, WIDTH])# do something...#####init_glb = tf.global_variables_initializer()init_loc = tf.local_variables_initializer()sess.run(init_glb)sess.run(init_loc)coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)ckpt_dir = "./checkpoints"if not os.path.exists(ckpt_dir): os.makedirs(ckpt_dir)ckpt = tf.train.get_checkpoint_state(ckpt_dir)start = 0if ckpt and ckpt.model_checkpoint_path: start = int(ckpt.model_checkpoint_path.split("-")[1]) print("start by epoch: %d"%(start)) saver = tf.train.Saver() saver.restore(sess, ckpt.model_checkpoint_path)last_save_epoch = start# continue training
所以如果我改变了FCN8VGG的结构(添加了一些dropout层),那么它会使用meta文件来替换我刚刚创建的图吗?如果会,如何改变结构以继续训练而不必从头开始训练?
回答:
这里有一个使用另一个模型检查点中的变量初始化新模型的简单示例。请注意,如果你可以直接将variable_scope
传递给init_from_checkpoint
,事情会简单得多,但在这里我假设原始模型在设计时并未考虑到恢复的问题。
首先定义一个带有一些变量的简单模型,并进行一些训练:
运行first_model()
,训练看起来不错,我们得到了一个first_model_checkpoint文件:
0 109.432100 0.0812649200 8.97705e-07300 9.64064e-11400 9.09495e-13500 0.0600 0.0700 0.0800 0.0900 0.0
接下来,我们可以在不同的图中定义一个全新的模型,并从该检查点初始化它与first_model共享的变量:
def second_model(): previous_variables = [ var_name for var_name, _ in tf.contrib.framework.list_variables('./first_model_checkpoint')] with tf.Graph().as_default(): fake_input = tf.constant([[1., 2., 3., 4.], [5., 6., 7., 8.]]) layer_one_output = tf.contrib.layers.fully_connected( inputs=fake_input, num_outputs=5, activation_fn=None) # 添加一个batch_norm层,这会创建一些新的变量。用tf.identity替换它应该可以验证模型一的变量是否被忠实地恢复(即损失应该与模型一训练结束时相同)。 batch_norm_output = tf.contrib.layers.batch_norm(layer_one_output) layer_two_output = tf.contrib.layers.fully_connected( inputs=batch_norm_output, num_outputs=1, activation_fn=None) target = tf.constant([[10.], [-3.]]) loss = tf.reduce_sum((layer_two_output - target) ** 2) train_op = tf.train.AdamOptimizer(0.01).minimize(loss) # 我们已经定义完变量,现在处理初始化器。首先找出第一个模型检查点中的哪些变量映射到这个模型中的变量。 restore_map = {variable.op.name:variable for variable in tf.global_variables() if variable.op.name in previous_variables} # 将第一个模型变量的初始化器设置为从第一个模型检查点中恢复它们 tf.contrib.framework.init_from_checkpoint( './first_model_checkpoint', restore_map) # 对于新变量,global_variables_initializer将正常初始化它们。对于restore_map中的变量,它们将从检查点中初始化。 init_op = tf.global_variables_initializer() saver = tf.train.Saver() with tf.Session() as session: session.run(init_op) for i in range(10): _, evaled_loss = session.run([train_op, loss]) print(i, evaled_loss) saver.save(session, './second_model_checkpoint')
在这种情况下,previous_variables
看起来像这样:
['beta1_power', 'beta2_power', 'fully_connected/biases', 'fully_connected/biases/Adam', 'fully_connected/biases/Adam_1', 'fully_connected/weights', 'fully_connected/weights/Adam', 'fully_connected/weights/Adam_1', 'fully_connected_1/biases', 'fully_connected_1/biases/Adam', 'fully_connected_1/biases/Adam_1', 'fully_connected_1/weights', 'fully_connected_1/weights/Adam', 'fully_connected_1/weights/Adam_1']
请注意,由于我们没有使用任何变量范围,命名取决于定义层的顺序。如果名称发生变化,你需要手动构建restore_map
。
如果我们运行second_model
,由于batch_norm
层尚未训练,损失最初会上升:
0 38.59761 36.40332 33.35883 29.85554 26.1695 22.51856 19.08387 16.00968 13.40359 11.3298
然而,用tf.identity
替换batch_norm
可以验证之前训练的变量已经被恢复。