1 前言
楼主最近要修改一下one-hot然后送入交叉熵中,由于pytorch的torch.nn.CrossEntropyLoss()
已经封装好了one-hot,所以需要自定义重写交叉熵,这里主要是多级交叉熵,而不是二分类交叉熵。
2 交叉熵的实现过程
首先看多级交叉熵的计算过程:
L
=
−
1
N
∑
i
N
∑
c
=
1
M
y
i
c
l
o
g
(
p
i
c
)
L = -\frac{1}{N}\displaystyle\sum_i^N\displaystyle\sum_{c=1}^My_{ic}log(p_{ic})
L=−N1i∑Nc=1∑Myiclog(pic)
其中
- M M M表示多分类类别的数量;
- y i c y_{ic} yic只为0和1,表示如果该样本 i i i 的类别为 c c c,则为1否则为0
- p i c p_{ic} pic神经网络输出的样本 i i i 类别为 c c c 的概率
用程序来描述如下:
首先是
p
i
c
p_{ic}
pic,可以看出他就是神经网络输出后加入softmax形成的概率值,
然后是
y
i
c
y_{ic}
yic ,其含义是类别一致为1,不一致为0,很显然符合one-hot的定义,所以pytorch在交叉熵内部封装了one-hot来实现这一步。(注意,这里的y是一个矩阵,不仅仅只是
y
i
c
y_{ic}
yic,而应该是
y
i
y_i
yi,表示一整个样本的真实标签)
连起来,
∑
c
=
1
M
y
i
c
l
o
g
(
p
i
c
)
\displaystyle\sum_{c=1}^My_{ic}log(p_{ic})
c=1∑Myiclog(pic)可以表示为:
然后进行最后一步,对所有样本取平均,即
−
1
N
∑
i
N
-\frac{1}{N}\displaystyle\sum_i^N
−N1i∑N部分,由于这里我们只有一个样本,所以还是一样的结果,只是符号有变化。
3 完整的自定义交叉熵
所以由以上过程,我们自己实现交叉熵的过程为:
class Our_CrossEntropy(torch.nn.Module):
def __init__(self):
super(Our_CrossEntropy,self).__init__()
def forward(self, x ,y):
P_i = torch.nn.functional.softmax(x, dim=1)
y = torch.nn.functional.one_hot(y)
loss = y*torch.log(P_i + 0.0000001)
loss = -torch.mean(torch.sum(loss, dim=1),dim = 0)
return loss
验证一下:
没毛病~
与torch.nn.CrossEntropyLoss()
输出一致
4 使用自己one-hot的交叉熵
回到最初的问题,我需要使用自己修改之后的one-hot,所以自定义交叉熵后,去掉里面的one-hot部分,将one-hot写在函数外面进行修改再导入即可:
class one_hot_CrossEntropy(torch.nn.Module):
def __init__(self):
super(one_hot_CrossEntropy,self).__init__()
def forward(self, x ,y):
P_i = torch.nn.functional.softmax(x, dim=1)
loss = y*torch.log(P_i + 0.0000001)
loss = -torch.mean(torch.sum(loss,dim=1),dim = 0)
return loss
验证一下:
没毛病~
修改一下one-hot,让他不是1:
成功~