训练期间nans的常见原因

时间:2015-11-27 17:23:30

标签: machine-learning neural-network deep-learning caffe gradient-descent

我注意到在培训期间经常出现NAN

通常,内部产品/完全连接或卷积层中的重量似乎会被引入。

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

这里的首要问题很简单:培训期间NAN发生的最常见原因是什么?其次,有什么方法可以解决这个问题(以及为什么会这样做?)

5 个答案:

答案 0 :(得分:100)

好问题。
我多次遇到过这种现象。以下是我的观察:

渐变爆炸

原因:大型渐变会使学习过程偏离正轨。

您应该期待什么:查看运行时日志,您应该查看每次迭代的损失值。您会注意到,从迭代到迭代,损失开始显着显着,最终损失将太大而无法由浮点变量表示,它将变为nan

你能做什么:base_lr(在solver.prototxt中)降低一个数量级(至少)。如果您有多个损失图层,则应检查日志以查看哪个图层对渐变爆炸负责,并减少该特定图层的loss_weight(在train_val.prototxt中),而不是通用{{1} }。

学习率不高的政策和参数

原因: caffe无法计算有效的学习率,而是获得base_lr'inf',此无效率会使所有更新倍增,从而使所有参数无效。

您应该期待什么:查看运行时日志,您应该会看到学习率本身变为'nan',例如:

'nan'

您可以做什么:修复影响... sgd_solver.cpp:106] Iteration 0, lr = -nan 文件中学习率的所有参数。
例如,如果您使用'solver.prototxt'而忘记定义lr_policy: "poly"参数,则最终会得到max_iter ...
有关caffe学习率的更多信息,请参阅this thread

故障丢失功能

原因:有时,损失层中损失的计算会导致显示lr = nan个。例如,使用带有错误的自定义丢失层等提供InfogainLoss layer with non-normalized values

您应该期待什么:查看运行时日志,您可能不会注意到任何异常:丢失逐渐减少,并且突然出现nan

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

例如:一旦我使用了一个损失,通过批量中标签出现的频率来规范惩罚。碰巧的是,如果其中一个训练标签没有出现在批次中 - 计算的损失产生了nan s。在这种情况下,使用足够大的批次(相对于集合中的标签数量)足以避免此错误。

输入错误

原因:您的输入中包含nan

你应该期待什么:一旦学习过程“命中”这个错误的输入 - 输出变为nan。查看运行时日志,您可能不会注意到任何异常:丢失逐渐减少,并且突然出现nan

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

大于nan

中的内核大小

出于某种原因,选择"Pooling">用于汇总的stride可能会导致kernel_size s。例如:

nan

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

y

中的不稳定因素

据报道,由于数值不稳定,在某些设置下"BatchNorm"图层可能会输出"BatchNorm"
这个issue是在bvlc / caffe中引发的,PR #5136正在尝试修复它。

最近,我开始意识到debug_info标记:在nan中设置debug_info: true会在训练期间记录更多的调试信息(包括渐变幅度和激活值):此信息可以help in spotting gradient blowups and other problems in the training process

答案 1 :(得分:3)

这个答案不是nan的原因,而是提出一种帮助调试它的方法。 你可以拥有这个python层:

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
  }
}

答案 2 :(得分:3)

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

解决方案:将以下内容添加到卷积层参数中。

bias_filler {       类型:“常数”       值:0     }

答案 3 :(得分:0)

learning_rate很高,应该降低 RNN代码的精度是nan,请选择较低的学习率值

答案 4 :(得分:-1)

我正在尝试构建一个稀疏的自动编码器,并在其中有几个层来诱导稀疏性。在运行我的网时,我遇到了NaN的。在删除一些层(在我的情况下,我实际上必须删除1),我发现NaN消失了。所以,我猜太多的稀疏性也可能导致NaN的问题(可能会调用一些0/0计算!?)