梯度爆炸了吧。
我的解决办法一般以下几条:1、数据归一化(减均值,除方差,或者加入normalization,例如BN、L2 norm等);
2、更换参数初始化方法(对于CNN,一般用xavier或者msra的初始化方法);
3、减小学习率、减小batch size;
4、加入gradient clipping;
我现在的采用方式是:
1. 弱化场景,将你的样本简化,各个学习率等参数采用典型配置,比如10万样本都是同一张复制的,让这个网络去拟合,如果有问题,则是网络的问题。否则则是各个参数的问题。
2. 如果是网络的问题,则通过不断加大样本的复杂度和调整网络(调整拟合能力)来改变。
3. 参数的微调,我个人感觉是在网络的拟合能力和样本的复杂度匹配的情况下,就是可以train到一定水平,然后想进行进一步优化的时候采用。
4. 参数的微调,楼上说得几个也算是一种思路吧,其他的靠自己去积累,另外将weights可视化也是一个细调起来可以用的方法,现在digits tf里面都有相关的工具.
最近做了一组实验,每次在固定的迭代次数段,都会loss突然变nan,导致acc骤降,慢慢变0。
于是找啊找啊找bug……
很难受,在意志力的坚持下,找到海枯石烂终于知道了!
loss突然变nan的原因,很可惜并不是这里其他所有答主所说的“因为梯度爆炸”、“lr过大”、“不收敛”等等原因,而是因为training sample中出现了脏数据!
脏数据的出现导致我的logits计算出了0,0传给 即nan。
所以我通过设置batch_size = 1,shuffle = False,一步一步地将sample定位到了所有可能的脏数据,删掉。期间,删了好几个还依然会loss断崖为nan,不甘心,一直定位一直删。终于tm work out!
之所以会这样,是因为我的实验是实际业务上的真实数据,有实际经验的就知道的,现实的数据非常之脏,基本上数据预处理占据我80%的精力。
好怀念以前可以天真快乐的在open dataset上做task跑模型的时候,真是啥都不用管,专注模型算法……
During experimentation, once the gradient value grows extremely large, it causes an overflow (i.e. NaN) which is easily detectable at runtime; this issue is called the Gradient Explosion Problem.参考斯坦福CS 224D的lecture note,我们也可以找到一些解决方法:
1. 加入Gradient clipping:每当梯度达到一定的阈值,就把他们设置回一个小一些的数字。
2. 调整学习速率。学习速率过大会导致不能正常收敛,因此可以把学习速率适当调小一些。
3. 调整深度神经网络的结构。
To solve the problem of exploding gradients, Thomas Mikolov first introduced a simple heuristic solution that clips gradients to a small number whenever they explode. That is, whenever they reach a certain threshold, they are set back to a small number as shown in Algorithm 1.
Figure 5 visualizes the effect of gradient clipping. It shows the decision surface of a small recurrent neural network with respect to its W matrix and its bias terms, b. The model consists of a single unit of recurrent neural network running through a small number of timesteps; the solid arrows illustrate the training progress on each gradient descent step. When the gradient descent model hits the high error wall in the objective function, the gradient is pushed off to a far-away location on the decision surface. The clipping model produces the dashed line where it instead pulls back the error gradient to somewhere close to the original gradient landscape.
用的是交叉熵cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))的话,最后softmax层输出y_conv的取值范围在[0,1]页就是说允许取0值,有log(0)出现很有可能出现nan啊,cross_entropy = -tf.reduce_mean(y_*tf.log(tf.clip_by_value(y_conv,1e-15,1.0)))在tensorflow里可以限定一下y_conv的取值范围,别的框架不清楚。
相信很多人都遇到过训练一个deep model的过程中,loss突然变成了NaN。在这里对这个问题做一个总结。
一般来说,出现NaN有以下几种情况:
1.如果在迭代的100轮以内,出现NaN,一般情况下的原因是因为你的学习率过高,需要降低学习率。可以不断降低学习率直至不出现NaN为止,一般来说低于现有学习率1-10倍即可。
2.如果当前的网络是类似于RNN的循环神经网络的话,出现NaN可能是因为梯度爆炸的原因,一个有效的方式是增加“gradient clipping”(梯度截断来解决)
3.可能用0作为了除数;
4.可能0或者负数作为自然对数
5.需要计算loss的数组越界(尤其是自己,自定义了一个新的网络,可能出现这种情况)
6.在某些涉及指数计算,可能最后算得值为INF(无穷)(比如不做其他处理的softmax中分子分母需要计算exp(x),值过大,最后可能为INF/INF,得到NaN,此时你要确认你使用的softmax中在计算exp(x)做了相关处理(比如减去最大值等等))
参考:
http://russellsstewart.com/notes/0.html
tensorflow训练中出现nan问题
深度学习中对于网络的训练是参数更新的过程,需要注意一种情况就是输入数据未做归一化时,如果前向传播结果已经是[0,0,0,1,0,0,0,0]这种形式,而真实结果是[1,0,0,0,0,0,0,0,0],此时由于得出的结论不惧有概率性,而是错误的估计值,此时反向传播会使得权重和偏置值变的无穷大,导致数据溢出,也就出现了nan的问题。
解决办法:
1、对输入数据进行归一化处理,如将输入的图片数据除以255将其转化成0-1之间的数据;
2、对于层数较多的情况,各层都做batch_nomorlization;
3、对设置Weights权重使用tf.truncated_normal(0, 0.01, [3,3,1,64])生成,同时值的均值为0,方差要小一些;
4、激活函数可以使用tanh;
5、减小学习率lr。
from:http://blog.csdn.net/fireflychh/article/details/73691373
使用caffe训练时Loss变为nan的原因
梯度爆炸
原因:梯度变得非常大,使得学习过程难以继续
现象:观察log,注意每一轮迭代后的loss。loss随着每轮迭代越来越大,最终超过了浮点型表示的范围,就变成了NaN。
措施:
1. 减小solver.prototxt中的base_lr,至少减小一个数量级。如果有多个loss layer,需要找出哪个损失层导致了梯度爆炸,并在train_val.prototxt中减小该层的loss_weight,而非是减小通用的base_lr。
2. 设置clip gradient,用于限制过大的diff
不当的损失函数
原因:有时候损失层中loss的计算可能导致NaN的出现。比如,给InfogainLoss层(信息熵损失)输入没有归一化的值,使用带有bug的自定义损失层等等。
现象:观测训练产生的log时一开始并不能看到异常,loss也在逐步的降低,但突然之间NaN就出现了。
措施:看看你是否能重现这个错误,在loss layer中加入一些输出以进行调试。
示例:有一次我使用的loss归一化了batch中label错误的次数。如果某个label从未在batch中出现过,loss就会变成NaN。在这种情况下,可以用足够大的batch来尽量避免这个错误。
不当的输入
原因:输入中就含有NaN。
现象:每当学习的过程中碰到这个错误的输入,就会变成NaN。观察log的时候也许不能察觉任何异常,loss逐步的降低,但突然间就变成NaN了。
措施:重整你的数据集,确保训练集和验证集里面没有损坏的图片。调试中你可以使用一个简单的网络来读取输入层,有一个缺省的loss,并过一遍所有输入,如果其中有错误的输入,这个缺省的层也会产生NaN。
案例:有一次公司需要训练一个模型,把标注好的图片放在了七牛上,拉下来的时候发生了dns劫持,有一张图片被换成了淘宝的购物二维码,且这个二维码格式与原图的格式不符合,因此成为了一张“损坏”图片。每次训练遇到这个图片的时候就会产生NaN。良好的习惯是,你有一个检测性的网络,每次训练目标网络之前把所有的样本在这个检测性的网络里面过一遍,去掉非法值。
池化层中步长比核的尺寸大
如下例所示,当池化层中stride > kernel的时候会在y中产生NaN
layer {
name: "faulty_pooling"
type: "Pooling"
bottom: "x"
top: "y"
pooling_param {
pool: AVE
stride: 5
kernel: 3
}
}
致谢
http://stackoverflow.com/questions/33962226/common-causes-of-NaNs-during-training
from:http://blog.csdn.net/huangynn/article/details/52947894