2017-07-16 71 views
2

我在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_runafter_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传递到漏失层漏失层。

+0

是否'original_saver.restore'行被移除?看起来你只会在第一次开始重新训练时才会这样做,此后你会使用“MonitoredTrainingSession”保存的检查点。 –

+0

我还没有删除,但它只是恢复原始的参数,它们都被冻结。我不认为我说得很好,但是当我恢复模型时,第一次测试它时,我没有通过“MonitoredTrainingSession”评估它,但是在代码的一部分中,我没有显示,但我会加。我使用不同的保存程序恢复了模型,该程序恢复了所有参数,包括训练会话保留的检查点文件中的新输出层。然后我开始了'QueueRunners'并检查了准确性。但是,当我回到再培训时,我离开了那个声明。 – dylan7

+0

@Allen Lavoie我试着删除'original_saver.restore'这一行,它似乎没有改变结果。不过,正如我上面提到的,我意识到,当我恢复模型并在inceptionV3的arg_scope中设置“is_training = True”时,模型的准确性现在与“MonitoredTrainingSession”所说的内容相匹配。然而,这似乎没有意义,在推断过程中启用丢失如何显着提高模型精度... – dylan7

回答

2

批量规范依赖于变量来保存它规范了汇总统计(从问题的意见dylan7的调试总结)。这些仅在is_training为True时通过UPDATE_OPS集合更新(请参阅batch_norm documentation)。如果这些更新操作没有运行(或者变量被覆盖),那么当is_training为False时,可能会出现基于每个批次丢失的“合理”统计数据(测试数据不是,也不应该用于通知batch_norm摘要统计)。