神经网络训练过程中nans的常见原因
Common causes of nans during training of neural networks
我注意到训练期间经常出现 NAN
被引入。
通常它似乎是由 inner-product/fully-connected 中的权重或膨胀的卷积层引入的。
这是因为梯度计算爆炸了吗?还是因为权重初始化(如果是,为什么权重初始化会有这个效果)?或者它可能是由输入数据的性质引起的?
这里的首要问题很简单:在训练过程中出现 NAN 的最常见原因是什么?其次,有哪些方法可以解决这个问题(以及为什么他们这样做工作)?
这种现象我遇到过好几次。以下是我的观察:
梯度放大
原因: 大梯度会使学习过程偏离轨道。
你应该期待什么: 查看运行时日志,你应该查看每次迭代的损失值。你会注意到从迭代到迭代,损失开始显着增长,最终损失会太大而无法用浮点变量表示,它将变成nan
.
你能做什么: 将 base_lr
(在 solver.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
...
有关 caffe 中学习率的更多信息,请参阅 。
错误的损失函数
原因:有时在损失层计算损失会导致出现nan
。例如,Feeding InfogainLoss
layer with non-normalized values、使用带有错误的自定义损失层等
你应该期待什么: 查看运行时日志你可能不会注意到任何异常:损失逐渐减少,突然 nan
出现。
你能做什么:看看你能不能重现错误,将打印输出添加到损失层并调试错误。
例如:有一次我使用了一个损失函数,该损失函数通过标签在批次中出现的频率来归一化惩罚。碰巧的是,如果其中一个训练标签根本没有出现在批次中——计算出的损失会产生 nan
s。在这种情况下,使用足够大的批次(相对于集合中的标签数量)足以避免此错误。
输入错误
原因:您有一个包含nan
的输入!
你应该期待什么: 一旦学习过程“命中”这个错误的输入 - 输出就变成 nan
。查看运行时日志,您可能不会注意到任何异常:损失逐渐减少,突然出现 nan
。
你能做什么: 重新构建你的输入数据集 (lmdb/leveldn/hdf5...) 确保你的 [=133] 中没有错误的图像文件=] 设置。对于调试,您可以构建一个简单的网络来读取输入层,在它上面有一个虚拟损失并运行所有输入:如果其中一个有故障,这个虚拟网络也应该产生 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
}
}
在 y
中获得 nan
的结果。
"BatchNorm"
不稳定
据报道,在某些设置下 "BatchNorm"
层可能会由于数值不稳定而输出 nan
s。
issue was raised in bvlc/caffe and PR #5136 正在尝试修复它。
最近,我开始意识到debug_info
flag: setting debug_info: true
in 'solver.prototxt'
will make caffe print to log more debug information (including gradient magnitudes and activation values) during training: This information can 。
这个答案不是关于 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
}
}
我试图构建一个稀疏自动编码器并在其中包含多个层以诱导稀疏性。虽然 运行 我的网,我遇到了 NaN 的。在删除一些层时(在我的例子中,我实际上不得不删除 1),我发现 NaN 消失了。所以,我猜太稀疏也可能导致 NaN(可能已经调用了一些 0/0 计算!?)
在我的例子中,没有在 convolution/deconvolution 层中设置偏差是原因。
解决方法:在卷积层参数中加入如下内容
bias_filler {
type: "constant"
value: 0
}
learning_rate偏高,应该降低
RNN 代码的准确度为 nan,select 它修复的学习率的低值
我注意到训练期间经常出现 NAN
被引入。
通常它似乎是由 inner-product/fully-connected 中的权重或膨胀的卷积层引入的。
这是因为梯度计算爆炸了吗?还是因为权重初始化(如果是,为什么权重初始化会有这个效果)?或者它可能是由输入数据的性质引起的?
这里的首要问题很简单:在训练过程中出现 NAN 的最常见原因是什么?其次,有哪些方法可以解决这个问题(以及为什么他们这样做工作)?
这种现象我遇到过好几次。以下是我的观察:
梯度放大
原因: 大梯度会使学习过程偏离轨道。
你应该期待什么: 查看运行时日志,你应该查看每次迭代的损失值。你会注意到从迭代到迭代,损失开始显着增长,最终损失会太大而无法用浮点变量表示,它将变成nan
.
你能做什么: 将 base_lr
(在 solver.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
...
有关 caffe 中学习率的更多信息,请参阅
错误的损失函数
原因:有时在损失层计算损失会导致出现nan
。例如,Feeding InfogainLoss
layer with non-normalized values、使用带有错误的自定义损失层等
你应该期待什么: 查看运行时日志你可能不会注意到任何异常:损失逐渐减少,突然 nan
出现。
你能做什么:看看你能不能重现错误,将打印输出添加到损失层并调试错误。
例如:有一次我使用了一个损失函数,该损失函数通过标签在批次中出现的频率来归一化惩罚。碰巧的是,如果其中一个训练标签根本没有出现在批次中——计算出的损失会产生 nan
s。在这种情况下,使用足够大的批次(相对于集合中的标签数量)足以避免此错误。
输入错误
原因:您有一个包含nan
的输入!
你应该期待什么: 一旦学习过程“命中”这个错误的输入 - 输出就变成 nan
。查看运行时日志,您可能不会注意到任何异常:损失逐渐减少,突然出现 nan
。
你能做什么: 重新构建你的输入数据集 (lmdb/leveldn/hdf5...) 确保你的 [=133] 中没有错误的图像文件=] 设置。对于调试,您可以构建一个简单的网络来读取输入层,在它上面有一个虚拟损失并运行所有输入:如果其中一个有故障,这个虚拟网络也应该产生 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
}
}
在 y
中获得 nan
的结果。
"BatchNorm"
不稳定
据报道,在某些设置下 "BatchNorm"
层可能会由于数值不稳定而输出 nan
s。
issue was raised in bvlc/caffe and PR #5136 正在尝试修复它。
最近,我开始意识到debug_info
flag: setting debug_info: true
in 'solver.prototxt'
will make caffe print to log more debug information (including gradient magnitudes and activation values) during training: This information can
这个答案不是关于 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
}
}
我试图构建一个稀疏自动编码器并在其中包含多个层以诱导稀疏性。虽然 运行 我的网,我遇到了 NaN 的。在删除一些层时(在我的例子中,我实际上不得不删除 1),我发现 NaN 消失了。所以,我猜太稀疏也可能导致 NaN(可能已经调用了一些 0/0 计算!?)
在我的例子中,没有在 convolution/deconvolution 层中设置偏差是原因。
解决方法:在卷积层参数中加入如下内容
bias_filler {
type: "constant"
value: 0
}
learning_rate偏高,应该降低 RNN 代码的准确度为 nan,select 它修复的学习率的低值