训练期间难治的常见原因
caffe
deep-learning
gradient-descent
machine-learning
5
0

我注意到在培训期间经常发生的是NAN

通常,它似乎是通过权重引入内部产品/完全连接的或卷积层中的。

这是因为梯度计算正在爆炸吗?还是因为权重初始化(如果是这样,为什么权重初始化会产生这种效果)?还是可能是由于输入数据的性质引起的?

这里的首要问题很简单: 在训练过程中发生NAN的最常见原因是什么?其次,有什么方法可以解决这个问题(为什么它们起作用)?

参考资料:
Stack Overflow
收藏
评论
共 3 个回答
高赞 时间 活跃

好问题。
我多次遇到这种现象。这是我的观察结果:


渐变爆炸

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

您应该期望的是:查看运行时日志,您应该查看每个迭代的损失值。您会注意到,损失在迭代之间开始显着增长,最终损失将太大而无法用浮点变量表示,它将变为nan

您可以做什么:base_lr (在solver.prototxt中)减少一个数量级(至少)。如果您有多个损耗层,则应检查日志以查看是哪个层造成了梯度爆炸,并减少了该特定层(而不是一般的base_lr )的loss_weight (在train_val.prototxt中)。


不良的学习率政策和参数

原因: caffe无法计算有效的学习率,而是获取'inf''nan' ,该无效率会乘以所有更新,从而使所有参数无效。

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

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

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


故障损失功能

原因:有时,对损耗层中损耗的计算会导致nan出现。例如, 使用非归一化的值为InfogainLossInfogainLoss ,使用带有错误的自定义损失层等。

您应该期望的是:查看运行时日志,您可能不会注意到任何异常情况:损耗在逐渐减少,并且突然出现了一个nan

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

例如:一旦使用损失,就可以按批次中标签出现的频率归一化惩罚。碰巧的是,如果其中一个培训标签根本没有出现在批处理中-计算得出的损失将产生nan s。在那种情况下,使用足够大的批次(相对于标签中的标签数量)就足以避免此错误。


输入错误

原因:您输入了nan

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

您可以做什么:重建输入数据集(lmdb / leveldn / hdf5 ...),以确保训练/验证集中没有不良的图像文件。对于调试,您可以构建一个简单的网络,该网络读取输入层,在其上具有虚拟损耗并遍历所有输入:如果其中一个输入有故障,则该虚拟网也应产生nan


"Pooling"层中的步幅大于内核大小

由于某些原因,选择stride > kernel_size进行池化可能会导致nan s。例如:

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

结果与nany


"BatchNorm"不稳定性

据报道,由于数值的不稳定性,在某些设置下, "BatchNorm"层可能会输出nan
bvlc / caffe中提出了此问题PR#5136正在尝试修复它。


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

收藏
评论

就我而言,未在卷积/解卷积层中设置偏差是原因。

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

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

收藏
评论

这个答案与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
  }
}
收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号