关于nn.CrossEntropyLoss的一些小说明
# 遇见的问题
有一天在做一个分类任务实验的时候,发现损失一直降不下去,一直在零点几到一之间徘徊,好嘛,不调试不知道,一调试吓一跳 在验证集上的预测输出完全是正确的,但损失居然不为0,最后一查才发现是nn.CrossEntropyLoss()的问题
# 原因
nn.CrossEntropyLoss()不是单纯的一个交叉熵损失函数,而是多个函数的叠加,它的计算公式自然也发生了改变
它的计算流程如下:
先创建数据:
import torch.nn as nn
import torch
x = torch.rand((3,3))
y = torch.tensor([0,1,1])
#x的值
#tensor([[0.7459, 0.5881, 0.4795],
# [0.2894, 0.0568, 0.3439],
# [0.6124, 0.7558, 0.4308]])
#y的值
#tensor([0, 1, 1])
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- 先经过softmax函数,求出每个类别的概率值,取值在0-1之间
softmax = nn.Softmax()
x_softmax = softmax(x)
#x_softmax
>>>tensor([[0.3817, 0.3259, 0.2924],
[0.3511, 0.2782, 0.3707],
[0.3346, 0.3863, 0.2791]])
1
2
3
4
5
6
7
2
3
4
5
6
7
- 再经过log函数,取对数,原来的变化趋势保持不变,但所有值都会变成负的,原来概率大的,成为负值也大,但是它取绝对值后就是最小的,我们想要的是最小损失,正好贴合
x_log = torch.log(x_softmax)
>>>tensor([[-0.9632, -1.1211, -1.2297],
[-1.0468, -1.2794, -0.9923],
[-1.0947, -0.9512, -1.2762]])
1
2
3
4
5
2
3
4
5
上边两步其实可以用函数nn.LogSoftmax代替,可以看出两个结果相同
ls = nn.LogSoftmax(dim=1)
ls(x)
>>>tensor([[-0.9632, -1.1211, -1.2297],
[-1.0468, -1.2794, -0.9923],
[-1.0947, -0.9512, -1.2762]])
1
2
3
4
5
6
2
3
4
5
6
- 最后使用nn.NLLLoss函数(负对数似然损失函数)求损失
公式:
自己实现:
loss = x_log[range(len(x)),y] #取出每一个样本标签值处的概率
loss = abs(sum(loss)/len(x))
#loss
>>>tensor(1.0646)
1
2
3
4
5
2
3
4
5
使用torch中的函数:
loss_func = nn.NLLLoss()
loss_func(x_log,y)
>>>tensor(1.0646)
1
2
3
4
2
3
4
可以看到结果是一样的
直接使用nn.CrossEntropyLoss进行验证:
loss_func = nn.CrossEntropyLoss()
loss_func(x,y)
>>>tensor(1.0646)
1
2
3
4
2
3
4
# 结论
CrossEntropyLoss的计算公式如下:
所以说,使用CrossEntropyLoss的话,就不要在网络后面加softmax层了,这样会导致计算的损失不正确
# 2023.5.29日更新补充
使用CrossEntropyLoss时,数据集里的标签要从0开始,从1开始的话会出现越界问题
编辑 (opens new window)
上次更新: 2024/05/30, 07:49:34