tensorflow使用高阶api导致训练不收敛问题

摘要

本文将低级api实现的tensorflow网络移植到高级api上遇到的loss值不变和训练结果不收敛问题

引言

tensorflow版本更新很快,猛一回头发现已经推出更高级的api了

主题

tensorflow高级api

api

上图是tensorflow软件栈图,我之前学习和实现的网络模型(0.12a)使用的是 低级api, 现在的新版本(1.10)对低级api进行了封装,形成了高级api(estimator keras),所以对原有模型进行了一次api替换

移植

整个代码的移植过程还是比较顺利的,移植完成以后,代码量比以前减少了很多,但移植完成,在运行时却发现了一些奇怪的现象

问题现象

我这里有两个自己的数据集,其中一个数据集(单个数据量130)在移植后的代码上运行正常,另一个数据集(单个数据集60000)在移植后的代码上运行却出现以下问题:

  • 二分类问题的准确率在50%左右
  • 训练过程中loss值会变化到一个固定值,然后就不再变化了

api

epoch:0

Evaluation results:	{'true_negatives': 48.0, 'global_step': 0, 'loss': 0.7953733, 'true_positives': 0.0, 'accuracy': 0.48, 'false_negatives': 52.0, 'false_positives': 0.0}

epoch:1

Evaluation results:	{'true_negatives': 0.0, 'global_step': 1, 'loss': 0.79326165, 'true_positives': 52.0, 'accuracy': 0.52, 'false_negatives': 0.0, 'false_positives': 48.0}

epoch:2

Evaluation results:	{'true_negatives': 0.0, 'global_step': 2, 'loss': 0.79326165, 'true_positives': 52.0, 'accuracy': 0.52, 'false_negatives': 0.0, 'false_positives': 48.0}

epoch:3

Evaluation results:	{'true_negatives': 0.0, 'global_step': 3, 'loss': 0.79326165, 'true_positives': 52.0, 'accuracy': 0.52, 'false_negatives': 0.0, 'false_positives': 48.0}

epoch:4

Evaluation results:	{'true_negatives': 0.0, 'global_step': 4, 'loss': 0.79326165, 'true_positives': 52.0, 'accuracy': 0.52, 'false_negatives': 0.0, 'false_positives': 48.0}

epoch:5

Evaluation results:	{'true_negatives': 0.0, 'global_step': 5, 'loss': 0.79326165, 'true_positives': 52.0, 'accuracy': 0.52, 'false_negatives': 0.0, 'false_positives': 48.0}

问题分析

因为不同数据集对应的结论不同,所以问题的排查就主要集中在对比两份代码的差异上了。训练正常的代码简称为T代码,训练异常的代码简称为F代码

  • 网络排查

    怀疑模型代码有问题。将F代码尽量用T代码代替,最终替换后,只剩下tfrecord文件读取和解析、网络输入层不一样,然后再训练更新后的F代码,现象依然存在

  • 数据排查

    通过网络排查基本排除网络问题,唯一不同在于数据,于是进行数据验证。将F代码训练过程中的输入数据记录到文件,然后对比F代码读到的数据和制作tfrecord的数据。排查数据编号、数据内容是否一致。最终发现数据一致。

    class _LoggerHook(tf.train.SessionRunHook):
      """Logs loss and runtime."""
    
      def begin(self):
          # print('begin')
          self._step = -1
    
      def before_run(self, run_context):
          # print('before_run')
          self._step += 1
          return tf.train.SessionRunArgs(features)  # Asks for loss value.
    
      def after_run(self, run_context, run_values):
          if self._step == 2:
              logit_value = run_values.results
              print('step ' + str(self._step) + ', features = ' + str(logit_value))
              f1.write(logit_value['data'])  # 训练准确率写入文件
              f1.flush()
              numpy.savetxt(r"/home/zq537/ckpt/ecg_data.txt", logit_value['data'])
              numpy.savetxt(r"/home/zq537/ckpt/index.txt", logit_value['name'])
    
  • 内部训练过程排查

    如果网络和数据都没问题,那么问题排查起来就比较困难了。接下来的方向可能需要深入模型内部的训练过程,看哪些步骤导致loss和准确率不变,将所有操作的输出和反向传播的梯度都记录到tensorboard中进行查看,发现进行少量的训练后,反向传播的梯度值分布都在0附近,这样网络权重基本就不会更新了,网络参数没有变化,自然准确率和loss也不会变化了。api
    是什么原因导致梯度为0?梯度是从loss开始,一层一层往前传的;而loss是由预测值和实际标签共同决定的。于是我开始查看预测值和实际标签的数值。先把数据集进行简化,生成10个数据的数据集,batch-size设为10,然后在训练回调中把稳定(loss不变)时的预测值和实际标签打印出来,发现了问题:稳定状态下预测值大部分两分类的准确率都是1,这很明显是给网络的评判标准(loss函数)有问题

    labels = [[1 0]
             [1 0]
             [0 1]
             [1 0]
             [1 0]
             [0 1]
             [0 1]
             [0 1]
             [0 1]
             [0 1]]
    
    
    logits = [[1.0000000e+00 1.0000000e+00]
             [1.0000000e+00 1.0000000e+00]
             [1.0000000e+00 1.0000000e+00]
             [1.0000000e+00 1.4896728e-36]
             [1.0000000e+00 5.1295980e-18]
             [1.0000000e+00 1.0000000e+00]
             [1.0000000e+00 1.0000000e+00]
             [1.0000000e+00 1.0000000e+00]
             [1.0000000e+00 1.0000000e+00]
             [1.0000000e+00 1.0000000e+00]]
    

    新代码中使用的损失函数是tf.losses.softmax_cross_entropy(onehot_labels=labels, logits=logits),搜索并替换为tensorflow官方module库中的损失函数tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)再进行训练,发现一切正常

问题原因

  • 网络排查
  • 数据排查
  • 内部训练过程排查

解决方案

总结

  • 在pypi官网上找相关模块信息

最开始在网上搜到的方案是ConcurrentLogHandler,但在13年就停止维护了,
合入代码也无法运行。于是又在网上找其他方案(这里浪费了不少时间),其实
ConcurrentLogHandler的homepage页已经说明了替代的库

附录

参考


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值