pytorch crossentropy为nan
交叉熵损失函数的具体为:
loss = -(x*ln(z)+(1-x)*ln(1-z))
z = softmax(pred_x)
这样当z为0/0时会出现loss为nan的情况
本人的具体原因
网络中用了MultiHeadAttention,attention的mask全为0,这样attention就为nan,造成个别样本的输出特征全为nan。于是就自己用pytorch写了一个cross_entropy loss函数,剔除掉有时候个别为nan的样本。
github地址:Self_cross_entropy
参考解决方案
在pred_x上加一个很小的量,如1e-10
loss = crossentropy(out+1e-8, target)
1
采用更小的学习率
做梯度裁剪
pytorch 梯度裁剪
import torch.nn as nn outputs = model(data) loss = loss_fn(outputs, target) optimizer.zero_grad() loss.backward() nn.utils.clip_grad_norm_(model.parameters(), max_norm = 20 , norm_type = 2 ) optimizer.step() |
nn.utils.clip_grad_norm_ 的参数:
parameters – 一个基于变量的迭代器,会进行梯度归一化
max_norm – 梯度的最大范数
norm_type – 规定范数的类型,默认为L2
还可能是数据有问题
比如这位的.链接
[参考]
https://stats.stackexchange.com/questions/108381/how-to-avoid-nan-in-using-relu-cross-entropy
且新的变量自动全是variable类型,可顺利反向传播
实现好后运行结果出现大量的nan,无法正常运算,使用clamp限制loss计算值的范围
class CrossEntropy(nn.Module):
def __init__(self):
super(CrossEntropy, self).__init__()
def forward(self, inputs, targets):
## torch中要想实现backward就不能使用np,不能用array,只能使用tensor,只有tensor才有requires_grad参数
loss1=-targets*(torch.log(inputs)).cuda()
loss=torch.sum(loss1.clamp(min=0.0001,max=1.0))