前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >tensorflow出现LossTensor is inf or nan : Tensor had Inf values

tensorflow出现LossTensor is inf or nan : Tensor had Inf values

作者头像
狼啸风云
修改2022-09-02 10:44:06
1.6K0
修改2022-09-02 10:44:06
举报

之前在TensorFlow中实现不同的神经网络,作为新手,发现经常会出现计算的loss中,出现Nan值的情况,总的来说,TensorFlow中出现Nan值的情况有两种,一种是在loss中计算后得到了Nan值,另一种是在更新网络权重等等数据的时候出现了Nan值,本文接下来,首先解决计算loss中得到Nan值的问题,随后介绍更新网络时,出现Nan值的情况。

Loss计算中出现Nan值

在搜索以后,找到StackOverflow上找到大致的一个解决办法(https://stackoverflow.com/questions/33712178/tensorflow-nan-bug)(https://stackoverflow.com/questions/49103830/ctc-losstensor-is-inf-or-nan-tensor-had-inf-values),大致的解决办法就是,在出现Nan值的loss中一般是使用的TensorFlow的log函数,然后计算得到的Nan,一般是输入的值中出现了负数值或者0值,在TensorFlow的官网上的教程中,使用其调试器调试Nan值的出现,也是查到了计算log的传参为0;而解决的办法也很简单,假设传参给log的参数为y,那么在调用log前,进行一次数值剪切,修改调用如下:

loss = tf.log(tf.clip_by_value(y,1e-8,1.0))

这样,y的最小值为0的情况就被替换成了一个极小值,1e-8,这样就不会出现Nan值了,StackOverflow上也给出了相同的解决方案。于是,我就采用了上述的解决方案对于log的参数进行数值限制,但是我更加复杂化了这个限制。

tf.clip_by_value这个函数,是将第一个参数,限制在第二、三个参数指定的范围之内,使用这个函数的原意是要避免0值,并没有限制最大值,因而我将限制的调用修改如下:

loss = tf.log(tf.clip_by_value(y,1e-8,tf.reduce_max(y)))

这样就确保了对于y值的剪切,不会影响到其数值的上限。但是在实际的神经网络中使用的时候,我发现这样修改后,虽然loss的数值一直在变化,可是优化后的结果几乎是保持不变的,这就存在问题了。

经过检查,其实并不能这么简单的为了持续训练,而修改计算损失函数时的输入值。这样修改后,loss的数值很可能(存在0的话确定就是)假的数值,会对优化器优化的过程造成一定的影响,导致优化器并不能正常的工作。

要解决这个假的loss的方法很简单,就是人为的改造神经网络,来控制输出的结果,不会存在0。这就需要设计好最后一层输出层的激活函数,每个激活函数都是存在值域的,详情请见博客http://www.jianshu.com/p/ffd3e63f39ef,比如要给一个在(0,1)之间的输出(不包含0),那么显然sigmoid是最好的选择。不过需要注意的是,在TensorFlow中,tf.nn.sigmoid函数,在输出的参数非常大,或者非常小的情况下,会给出边界值1或者0的输出,这就意味着,改造神经网络的过程,并不只是最后一层输出层的激活函数,你必须确保自己大致知道每一层的输出的一个范围,这样才能彻底的解决Nan值的出现。

举例说明就是TensorFlow的官网给的教程,其输出层使用的是softmax激活函数,其数值在[0,1],这在设计的时候,基本就确定了会出现Nan值的情况,只是发生的时间罢了。

更新网络时出现Nan值

更新网络中出现Nan值很难发现,但是一般调试程序的时候,会用summary去观测权重等网络中的值的更新,因而,此时出现Nan值的话,会报错类似如下:

InvalidArgumentError (see above for traceback): Nan in summary histogram for: weight_1

这样的情况,一般是由于优化器的学习率设置不当导致的,而且一般是学习率设置过高导致的,因而此时可以尝试使用更小的学习率进行训练来解决这样的问题。

最近用Tensorflow训练网络,在增加层数和节点之后,出现loss = NAN的情况,在网上搜寻了很多答案,最终解决了问题,在这里汇总一下。

  • 数据本身,是否存在Nan,可以用numpy.any(numpy.isnan(x))检查一下input和target
  • 在训练的时候,整个网络随机初始化,很容易出现Nan,这时候需要把学习率调小,可以尝试0.1,0.01,0.001,直到不出现Nan为止,如果一直都有,那可能是网络实现问题。学习率和网络的层数一般成反比,层数越多,学习率通常要减小。有时候可以先用较小的学习率训练5000或以上次迭代,得到参数输出,手动kill掉训练,用前面的参数fine tune,这时候可以加大学习率,能更快收敛哦
  • 如果是图片,那么得转化为float 也就是/255.
  • relu和softmax两层不要连着用,最好将relu改成tanh,什么原因呢
  • 参数初始化
  • batch size 选择过小
  • 最后还没有排除问题的话,TensorFlow有专门的内置调试器(tfdbg)来帮助调试此类问题 tensorflow.org/programmers_guide/debugger
代码语言:javascript
复制
from tensorflow.python import debug as tf_debug
<meta charset="utf-8">

# 建立原来的Session

sess = tf.Session()

# 用tfdbg的Wrapper包裹原来的Session对象:

sess = tf_debug.LocalCLIDebugWrapperSession(sess)

sess.add_tensor_filter("has_inf_or_nan", tf_debug.has_inf_or_nan)

# 以上为所有需要的代码变动,其余的代码可以保留不变,因为包裹有的sess和原来的界面一致。

# 但是每次执行`sess.run`的时候,自动进入调试器命令行环境。

sess.run(train_op, feed_dict=...)
在tfdbg命令行环境里面,输入如下命令,可以让程序执行到inf或nan第一次出现。
tfdbg> run -f has_inf_or_nan

一旦inf/nan出现,界面现实所有包含此类病态数值的张量,按照时间排序。所以第一个就最有可能是最先出现inf/nan的节点。可以用node_info, list_inputs等命令进一步查看节点的类型和输入,来发现问题的缘由。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-09-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档