我在InceptionV3上针对5种花的数据集进行了转移学习。除输出图层外,所有图层都是冻结的。我的实现基于Tensorflow的Cifar10教程,输入数据集的格式与Cifar10相同。MonitoredTrainingSession报告准确性和丢失问题
我已经添加了一个MonitoredTrainingSession(如本教程中所述),以在一定数量的步骤后报告准确性和丢失。下面是代码为MonitoredTrainingSession的部分(几乎相同的教程):
class _LoggerHook(tf.train.SessionRunHook):
def begin(self):
self._step = -1
self._start_time = time.time()
def before_run(self,run_context):
self._step+=1
return tf.train.SessionRunArgs([loss,accuracy])
def after_run(self,run_context,run_values):
if self._step % LOG_FREQUENCY ==0:
current_time = time.time()
duration = current_time - self._start_time
self._start_time = current_time
loss_value = run_values.results[0]
acc = run_values.results[1]
examples_per_sec = LOG_FREQUENCY/duration
sec_per_batch = duration/LOG_FREQUENCY
format_str = ('%s: step %d, loss = %.2f, acc = %.2f (%.1f examples/sec; %.3f sec/batch)')
print(format_str %(datetime.now(),self._step,loss_value,acc,
examples_per_sec,sec_per_batch))
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
if MODE == 'train':
file_writer = tf.summary.FileWriter(LOGDIR,tf.get_default_graph())
with tf.train.MonitoredTrainingSession(
save_checkpoint_secs=70,
checkpoint_dir=LOGDIR,
hooks=[tf.train.StopAtStepHook(last_step=NUM_EPOCHS*NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN),
tf.train.NanTensorHook(loss),
_LoggerHook()],
config=config) as mon_sess:
original_saver.restore(mon_sess,INCEPTION_V3_CHECKPOINT)
print("Proceeding to training stage")
while not mon_sess.should_stop():
mon_sess.run(train_op,feed_dict={training:True})
print('acc: %f' %mon_sess.run(accuracy,feed_dict={training:False}))
print('loss: %f' %mon_sess.run(loss,feed_dict={training:False}))
当两行打印mon_sess.run(train_op...
下的精确度和损耗被去除,损耗和准确性从after_run
印刷,它训练后出乎意料地只有20分钟,报告说该模型在训练集上表现非常好,并且损失正在减少。即使是移动平均损失也报告了很好的结果。它最终对多个随机批次的准确度达到90%以上。
之后,培训课程一段时间内报告的准确性很高,我停止了培训课程,恢复了模型,并从同一批培训中随机分批运行。它表现不佳,只能达到50%至85%的准确度。我确认它被正确地恢复,因为它确实比未经训练的输出层的模型表现更好。
然后我再次从上一个检查点返回训练。精度最初很低,但在大约10个小批量运行之后,精度回到了90%以上。然后我重复了这个过程,但这次增加了两条线以评估训练操作后的损失和准确性。这两个评估报告说,该模型存在问题趋同和表现不佳。虽然现在通过before_run
和after_run,
进行的评估仅偶尔显示出高精度和低损耗(结果跃然而止)。但仍有after_run
有时报100%的准确性(事实上,它不再一致,我认为是因为after_run
也被称为mon_sess.run(accuracy...)
和mon_sess.run(loss...)
)。
为什么MonitoredTrainingSession报告的结果表明模型在真的不行时运行良好? SessionRunArgs
中的两个操作是否与train_op
使用相同的小批量进行喂食,这表明在梯度更新之前批量生产的模型性能?
这里是我用于恢复和测试模型(基于cifar10教程)代码:
elif MODE == 'test':
init = tf.global_variables_initializer()
ckpt = tf.train.get_checkpoint_state(LOGDIR)
if ckpt and ckpt.model_checkpoint_path:
with tf.Session(config=config) as sess:
init.run()
saver = tf.train.Saver()
print(ckpt.model_checkpoint_path)
saver.restore(sess,ckpt.model_checkpoint_path)
global_step = tf.contrib.framework.get_or_create_global_step()
coord = tf.train.Coordinator()
threads =[]
try:
for qr in tf.get_collection(tf.GraphKeys.QUEUE_RUNNERS):
threads.extend(qr.create_threads(sess, coord=coord, daemon=True,start=True))
print('model restored')
i =0
num_iter = 4*NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN/BATCH_SIZE
print(num_iter)
while not coord.should_stop() and i < num_iter:
print("loss: %.2f," %loss.eval(feed_dict={training:False}),end="")
print("acc: %.2f" %accuracy.eval(feed_dict={training:False}))
i+=1
except Exception as e:
print(e)
coord.request_stop(e)
coord.request_stop()
coord.join(threads,stop_grace_period_secs=10)
更新:
所以我能够解决这个问题。但是,我不确定它为什么起作用。在开始模型的arg_scope
中,我传递了一个is_training
布尔占位符,用于批处理标准和初始使用的丢弃。但是,当我删除占位符并将is_training
关键字设置为true时,模型恢复时训练集的准确性非常高。这是以前表现不佳的同一个模型检查点。当我训练它时,我始终将is_training
占位符设置为true。如果将is_training
设置为true,则测试将意味着批量Norm现在使用样本均值和方差。
为什么会告诉Batch Norm现在使用样本平均值和样本标准偏差,就像它在训练期间所做的那样会提高准确度?
这也意味着退出层会丢弃单位,并且在启用丢失层的情况下,训练集和测试集上的测试期间模型的准确性都会更高。
更新2 我通过在上面的代码中arg_scope
被引用tensorflow苗条inceptionv3模型代码去了。我在平均池8x8之后移除了最后的丢失层,准确度保持在99%左右。但是,当我只为批量标准层设置is_training为False时,准确度回落到70%左右。这里是来自slim\nets\inception_v3.py
的arg_scope和我的修改。
with variable_scope.variable_scope(
scope, 'InceptionV3', [inputs, num_classes], reuse=reuse) as scope:
with arg_scope(
[layers_lib.batch_norm],is_training=False): #layers_lib.dropout], is_training=is_training):
net, end_points = inception_v3_base(
inputs,
scope=scope,
min_depth=min_depth,
depth_multiplier=depth_multiplier)
我试图与既除去漏失层,并保持在is_training=True
传递到漏失层漏失层。
是否'original_saver.restore'行被移除?看起来你只会在第一次开始重新训练时才会这样做,此后你会使用“MonitoredTrainingSession”保存的检查点。 –
我还没有删除,但它只是恢复原始的参数,它们都被冻结。我不认为我说得很好,但是当我恢复模型时,第一次测试它时,我没有通过“MonitoredTrainingSession”评估它,但是在代码的一部分中,我没有显示,但我会加。我使用不同的保存程序恢复了模型,该程序恢复了所有参数,包括训练会话保留的检查点文件中的新输出层。然后我开始了'QueueRunners'并检查了准确性。但是,当我回到再培训时,我离开了那个声明。 – dylan7
@Allen Lavoie我试着删除'original_saver.restore'这一行,它似乎没有改变结果。不过,正如我上面提到的,我意识到,当我恢复模型并在inceptionV3的arg_scope中设置“is_training = True”时,模型的准确性现在与“MonitoredTrainingSession”所说的内容相匹配。然而,这似乎没有意义,在推断过程中启用丢失如何显着提高模型精度... – dylan7