本文包括:
1、单样本三分类为例,讲解 cross__entropy 的详细计算过程,包括手算,以及直接调用函数的计算结果对比;
2、十六样本(batch = 16)五分类为例,讲解 cross__entropy 的详细计算过程
3、给出结论(如果不想看代码,可以直接看结论)
# 单样本三分类
import torch
# 从softmax开始讲起,到最后的 cross_entropy ( softmax ——> log_softmax --> NLLLOSS--> cross_entropy)
# torch.softmax 原理: 1、所有值取指数 2、每个值分别除以总数(三个值相加),得到的三个值相加为一,构造类似概率
x = torch.tensor([-3,1.5,2.7])
so = torch.exp(x)
so_list = so.numpy().tolist() # 将 tensor 转换为 list
j = 0
for i in so_list:
j += i # 得到三个值的和
p = []
for t in so_list:
p.append(t / j) # 得到三个值与总和的比值
b = torch.tensor(p) # 手算得到的值
d = torch.softmax(x,dim=0) # softmax 得到的值,0 - 1 之间
# torch.logsoftmax
c1 = torch.log(b) # 给每个元素取对数
c2 = torch.log_softmax(x,dim=0) # 一定为负值
# torch.NLLLoss
f = torch.tensor([1]) # 标签
jk = - c1[f.item()]
xe = torch.nn.NLLLoss()
gh = torch.unsqueeze(c2,dim = 0)
jhf = torch.unsqueeze(x,dim=0) # NLLLoss 和 CROSS_entropy 都是以batch,也就是以四维输入的
afd = xe(gh,f)
jkx = torch.nn.CrossEntropyLoss()
ad = jkx(jhf,f)
print("手算结果:{}".format(b),"softmax结果{}".format(d)) # 验证 torch.softmax 计算过程
print("手算结果:{}".format(c1), "log_softmax结果{}".format(c2)) # 验证 torch.log_softmax 计算过程
print("手算结果:{}".format(jk), "NLLLoss结果{}".format(afd)) # 验证 torch.log_softmax 计算过程
print("CrossEntropyLoss:{}".format(ad), "NLLLoss结果{}".format(afd)) # 验证 torch.CrossEntropyLoss 计算过程
### 打印结果
手算结果:tensor([0.0026, 0.2309, 0.7666]) softmax结果tensor([0.0026, 0.2309, 0.7666])
手算结果:tensor([-5.9659, -1.4659, -0.2659]) log_softmax结果tensor([-5.9659, -1.4659, -0.2659])
手算结果:1.465850591659546 NLLLoss结果1.465850591659546
CrossEntropyLoss:1.465850591659546 NLLLoss结果1.465850591659546
# 这里以五分类,batch = 16 为例
import torch
import torch.nn as nn
x = torch.tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
y = torch.tensor([[-0.0299, 0.3996, 0.4132, 0.3828, -0.3578],
[ 0.0384, 0.5070, 0.2784, 0.3086, -0.1736],
[-0.1219, 0.5358, 0.6176, 0.2804, -0.0186],
[ 0.1153, 0.5508, 0.2899, 0.3709, -0.1514],
[-0.2253, 0.2107, 0.4944, 0.1685, -0.2234],
[ 0.0670, 0.3559, 0.2721, 0.4018, -0.2393],
[-0.0943, 0.4430, 0.6774, 0.3513, 0.0197],
[-0.1786, 0.4166, 0.4601, 0.5448, -0.1473],
[-0.0938, 0.5514, 0.2839, 0.2177, -0.1892],
[-0.2615, 0.5100, 0.5620, 0.6361, -0.0498],
[-0.0679, 0.4000, 0.2917, 0.4411, -0.3760],
[-0.1139, 0.3442, 0.4538, 0.4446, -0.2071],
[-0.4183, 0.4170, 0.7693, 0.6503, -0.1554],
[ 0.0608, 0.4094, 0.3131, 0.2778, -0.1750],
[-0.0332, 0.4247, 0.4322, 0.4355, -0.2383],
[-0.0277, 0.1793, 0.4213, 0.3589, -0.2416]]
)
d = torch.exp(y)
d1 = torch.softmax(y,dim=1)
log_d1 = torch.log(d1)
nl = torch.nn.NLLLoss(reduction="mean")
NLLL_log_d1 = nl(log_d1,x)
cross = torch.nn.CrossEntropyLoss()
ad = cross(y,x)
nll_i = []
for i in range(y.shape[0]):
y_i = log_d1[i, :]
x_i = torch.unsqueeze(x[i],dim=0)
y_ii = torch.unsqueeze(y_i,dim=0)
nl_i = nl(y_ii,x_i)
nll_i.append(nl_i)
j = 0
for i in nll_i:
j += i
js = j / 16
print("CrossEntropyLoss:{}".format(ad), "softmax + log + 平均{}".format(js), "softmax + log + NLLLoss{}".format(NLLL_log_d1)) # 验证 torch.CrossEntropyLoss 计算过程
### 打印结果
CrossEntropyLoss:1.9328043460845947
softmax + log + 平均1.9328042268753052
softmax + log + NLLLoss1.9328041076660156
结论:
单样本:
在单样本中,NLLLoss = cross__entropy,所以不用再往下计算
多样本:(接单样本的步骤)