好问题。 我也经常遇到这种情况。这是我的观察结果:
梯度爆炸 原因:较大的梯度会使学习过程偏离轨道。 查看运行窗口,应查看每次迭代的损失值。你会注意到,损失在每次迭代之间都开始显着增长,最终损失太大而无法用浮点变量表示,它将变为nan。
将base_lr(在resolver.prototxt中)至少减少一个数量级。如果你有多个损失层,则应检查窗口以了解造成梯度爆炸的是哪一层,并减少loss_weight特定层(在train_val.prototxt中),而不是一般层base_lr。
不良的学习率和参数设置 原因: caffe无法计算出有效的学习率,而得到'inf'或'nan',该无效学习率会乘以所有更新数据,从而使所有参数无效。
查看运行时窗口,你可以看到学习率本身变为'nan',例如:
... sgd_solver.cpp:106] Iteration 0, lr = -nan
修复所有影响'solver.prototxt'文件学习率的参数。例如,如果使用lr_policy: "poly",却忘记定义max_iter参数,最终将得到 lr = nan...
错误的损失函数 原因:有时,损失层中损失的计算会导致nans出现。例如,InfogainLoss使用非标准化的数据,使用带有bug的自定义损失层等。 看运行窗口,你可能不会注意到任何异常情况:损耗在逐渐减少,突然nan就出现了。
查看是否可以重现错误,将打印输出添加到损失层并调试错误。 例如:一旦我使用了损失函数,就可以按批次中标签出现的频率归一化惩罚。碰巧的是,如果其中一个训练标签根本没有出现在批次中,那么所计算的损失将产生nans。在那种情况下,处理足够大的批次(相对于标签中的标签数量)足以避免此错误。
输入错误 原因:输入nan! 一旦学习过程“完成”,该错误的输入输出就会变成nan。 重新构建输入数据集(lmdb / leveldn / hdf5 ...),以确保训练/验证集中没有不良的图像文件。你可以构建一个简单的网络,该网络读取输入层,在其上具有虚拟损耗和所有输入:如果其中一个输入有故障,则该虚拟网也应产生nan。
"Pooling"层步长比内核大 例如:
layer {
name: "faulty_pooling"
type: "Pooling"
bottom: "x"
top: "y"
pooling_param {
pool: AVE
stride: 5
kernel: 3
}
}
结果是Y中有NANs。
不稳定的 "BatchNorm" 由于数值的不稳定性,在某些设置"BatchNorm"层下可能会输出nan