神经网络训练过程中南非人的常见病因

我注意到在训练过程中经常出现 NAN被引入的情况。

通常情况下,它似乎是由内部产品/完全连接或卷积层中的重量引入的。

发生这种情况是因为梯度计算爆炸了吗?或者是因为权重初始化(如果是这样,为什么权重初始化有这种效果) ?或者它可能是由输入数据的性质引起的?

这里的首要问题很简单: 在训练过程中出现 NAN 最常见的原因是什么?其次,有哪些方法可以解决这个问题(为什么这些方法有效) ?

66014 次浏览

I came across this phenomenon several times. Here are my observations:


渐变爆炸

原因: 大的梯度使学习过程偏离了轨道。

您应该期望: 查看运行时日志,您应该查看每次迭代的损失值。您将注意到,从一次迭代到另一次迭代,损失开始增长 意义重大,最终损失将太大,以至于无法用浮点变量来表示,它将变成 nan

你能做什么: 至少减少一个数量级的 base_lr(在 solver.Prototxt 中)。如果你有几个损失层,你应该检查日志,看看哪一层是负责梯度爆炸和减少 loss_weight(在 train _ val。而不是一般的 base_lr


错误的学习率策略和参数

原因: affe 无法计算一个有效的学习速率,取而代之的是 'inf''nan',这个无效的速率乘以所有的更新,从而使所有的参数无效。

您应该期望: 查看运行时日志,您应该看到学习速率本身变成了 'nan',例如:

... sgd_solver.cpp:106] Iteration 0, lr = -nan

您可以做什么: 修复影响 'solver.prototxt'文件中学习速度的所有参数。
例如,如果使用 lr_policy: "poly"而忘记定义 max_iter参数,那么最终将得到 lr = nan..。
有关咖啡学习速度的更多信息,请参见 这根线


故障丢失功能

Reason: Sometimes the computations of the loss in the loss layers causes nans to appear. For example, Feeding 具有非标准化值的 InfogainLoss, using custom loss layer with bugs, etc.

你应该期待什么: 查看运行时日志你可能不会注意到任何异常: 损失正在逐渐减少,突然出现一个 nan

你能做什么: 查看是否可以重现错误,将打印输出添加到丢失层并调试错误。

For example: Once I used a loss that normalized the penalty by the frequency of label occurrence in a batch. It just so happened that if one of the training labels did not appear in the batch at all - the loss computed produced nans. In that case, working with large enough batches (with respect to the number of labels in the set) was enough to avoid this error.


输入错误

原因: 您有一个包含 nan的输入!

你应该期望的是: 一旦学习过程“命中”了这个错误的输入输出,它就变成了 nan。查看运行时日志,您可能不会注意到任何异常: 损失正在逐渐减少,突然出现一个 nan

您可以做什么: 重新构建您的输入数据集(lmdb/leveldn/hdf5...) ,确保您的训练/验证集中没有错误的图像文件。对于调试,你可以构建一个简单的网络来读取输入层,在它上面有一个虚拟损失,并运行所有的输入: 如果其中之一是错误的,这个虚拟网络也应该产生 nan


"Pooling"层大于内核大小的跨度

For some reason, choosing stride > kernel_size for pooling may results with nans. For example:

layer {
name: "faulty_pooling"
type: "Pooling"
bottom: "x"
top: "y"
pooling_param {
pool: AVE
stride: 5
kernel: 3
}
}

结果与 y中的 nan


"BatchNorm"中的不稳定性

据报道,在一些设置下,由于数值不稳定,"BatchNorm"层可能输出 nan
这个 问题是在 bvlc/affe 中提出的,PR # 5136正试图修复它。


最近,我开始意识到 debug_info标志: 在 'solver.prototxt'中设置 debug_info: true将使咖啡因打印记录更多的调试信息(包括梯度大小和激活值)在训练期间: 这些信息可以 帮助发现训练过程中的梯度爆破和其他问题

这个答案不是关于 nans 的原因,而是提出了一种帮助调试它的方法。 你可以有这个蟒蛇图层:

class checkFiniteLayer(caffe.Layer):
def setup(self, bottom, top):
self.prefix = self.param_str
def reshape(self, bottom, top):
pass
def forward(self, bottom, top):
for i in xrange(len(bottom)):
isbad = np.sum(1-np.isfinite(bottom[i].data[...]))
if isbad>0:
raise Exception("checkFiniteLayer: %s forward pass bottom %d has %.2f%% non-finite elements" %
(self.prefix,i,100*float(isbad)/bottom[i].count))
def backward(self, top, propagate_down, bottom):
for i in xrange(len(top)):
if not propagate_down[i]:
continue
isf = np.sum(1-np.isfinite(top[i].diff[...]))
if isf>0:
raise Exception("checkFiniteLayer: %s backward pass top %d has %.2f%% non-finite elements" %
(self.prefix,i,100*float(isf)/top[i].count))

train_val.prototxt的某些特定位置添加这个图层可能会引起麻烦:

layer {
type: "Python"
name: "check_loss"
bottom: "fc2"
top: "fc2"  # "in-place" layer
python_param {
module: "/path/to/python/file/check_finite_layer.py" # must be in $PYTHONPATH
layer: "checkFiniteLayer"
param_str: "prefix-check_loss" # string for printouts
}
}

我试图建立一个稀疏的自动编码器,并在其中有几个层,以诱导稀疏。当我运行我的网络时,我遇到了 NaN。在删除一些图层时(在我的例子中,我实际上必须删除1) ,我发现 NaN 消失了。因此,我猜想太多的稀疏性也可能导致 NaN 的出现(一些0/0计算可能已经被调用了! ?)

在我的情况下,没有设置在卷积/反卷积层的偏差是原因。

Solution: add the following to the convolution layer parameters.

bias_filler {
type: "constant"
value: 0
}

learning_rate is high and should be decreased 在 RNN 代码的准确性是南,与选择低值的学习率它确定

还有一个办法可以帮助像我一样被困住的人

我在一个网络上接收 nan 或 inf 损失,我设置了 float16dtype 跨层和输入数据。在所有其他方法都失败后,我想到切换回 float32,Nan 的损失得到了解决!

所以底线是,如果将 dtype 切换为 float16,将其切换回 float32。