问题描述:在训练神经网络的时候发现神经网络的输出值为nan。并且损失函数输出值也为nan。
当第一次遇到这个问题的时候,我第一反应是神经网络编码出问题了。在检查了N遍过后,派出了这种可能性。通过一点一点的排除,发现问题出现在BCELoss上。
那么为什么会出现nan的情况呢?
在使用ce loss 或者 bceloss的时候,会有log的操作,在半精度情况下,一些非常小的数值会被直接舍入到0,log(0)等于啥?——等于nan啊!
于是逻辑就理通了:回传的梯度因为log而变为nan->网络参数nan-> 每轮输出都变成nan。
解决方案以一:用以下代码代替BCELoss
pred = torch.clamp(pred, min=1e-7, max=1-1e-7)
loss = - target * torch.log(pred) - (1-target) * torch.log(1-pred)
loss = torch.mean(loss)
解决方案二:换用其他的损失函数。
出现此问题的情况还可能是:
- 学习率较大,若此时反向传回来的梯度也很大的时候,参数可能会更新的非常大,倘若不幸,飞成Inf,前向传播求loss的时候,会报NAN。解决方法调小学习率。
- 某些batch的数据产生过大的梯度,解决方法采用梯度裁剪、数据归一化。
- 数据出错,网络中出现log0、除以0等不正常的操作。
【个人认为1、2是互相依赖的,若梯度很大但学习率比较小的话,参数更新值会因为学习率较小而变小,减少NAN出现的概率;若学习率很大但梯度很小的话,参数更新值应该也不会很大,毕竟学习率一般取值不超过1。3是最常出现的错误,也是最容易理解的原因。】
网友评论