nn.CrossEntropyLoss是在PyTorch中常用的交叉熵损失函数。它主要用于解决多分类问题,但也可以用于解决二分类问题。该函数有两个输入参数。第一个参数是网络的最后一层的输出,是一个二维数组,其中每个向量包含不同类别的概率值。第二个参数是传入的标签,即某个类别的索引值,表示样本对应的真实类别。
在有时需要修改模型时,可能需要修改损失函数的运算过程。直接改变PyTorch中的代码可能会有些麻烦,因此我们可以先按照nn.CrossEntropyLoss的原理自己实现一个版本,然后在此基础上进行修改。
关于nn.CrossEntropyLoss的原理,这篇博客已经有详细介绍,因此在此不再赘述。简单来说,该函数先进行softmax操作,然后再进行log操作。最后,对每个样本的标签处的预测值求和,取平均值,再取绝对值变为一个正数。以下是博客链接:
https://blog.csdn.net/Lucinda6/article/details/116162198
但是按照这篇文章实现时会遇到了一些问题,有时候先sofmax再log时,有时会softmax出来0导致log到inf.直接用LogSoftmax是可以的,按这个实现时的代码如下:
def selfCrossEntropyLoss(selfx,target):
ls = nn.LogSoftmax(dim=1)
selfloss=ls(selfx).double()
selfloss = abs(torch.sum(selfloss) / len(selfx))
return selfloss
但是还是有问题,sum和len算多维数据时会算不全,只算了一个维度,比如shape是(100,61)时,len只会算到100,最后改了这个后,又和torch的原交叉熵比会有一点小差别,比如71和65的差别,大差不差只能是。
为了在不同维度的张量上使用,后来将nn.LogSoftmax(dim=1)修改为nn.LogSoftmax(dim=-1),在计算平均log_softmax值时,将abs()函数改为torch.mean()函数,能提高精度。最后,用了gather()函数和unsqueeze()函数对预测值进行索引,并使用squeeze()函数去除不必要的维度,以计算损失值。这样算下来结果是和torch的原交叉熵一样的,代码如下:
def selfCrossEntropyLoss2(selfx, target):
ls = nn.LogSoftmax(dim=-1)
selfloss = ls(selfx).double()
selfloss = torch.mean(selfloss.gather(1, target.unsqueeze(1)).squeeze()) * -1
return selfloss
ok这样就可以在nn.CrossEntropyLoss的基础上添加自己的其他魔改了。