目录
- 1 交叉熵损失函数
- 2 二元交叉熵损失函数
- 2.1 torch.nn.BCELoss()
- 2.2 torch.nn.BCEWithLogitsLoss()
- 3 参考文献
1 交叉熵损失函数
在之前的损失函数介绍中已经解释过,什么是交叉熵损失函数以及其数学原理(【Pytorch基础】torch.nn.CrossEntropyLoss损失函数介绍)。在多分类问题中输出层的函数是函数, 在二分类问题中输出层的函数是函数。
而CrossEntropy损失函数适用于总共有N个类别的分类。当N=2时,即二分类任务,只需要判断是还是否的情况,就可以使用二分类交叉熵损失,本小节介绍二分类交叉熵损失函数。
2 二元交叉熵损失函数
2.1 torch.nn.BCELoss()
BCELoss的全称是Binary Cross Entropy, 即二分类交叉熵损失。如下公式 (y是真实标签,x是预测值):
其实这个函数就是CrossEntropyLoss的当类别数N=2时候的特例。因为类别数为2,属于第一类的概率为y,那么属于第二类的概率自然就是(1-y)。因此套用与CrossEntropy损失的计算方法,用对应的标签乘以对应的预测值再求和,就得到了最终的损失。参考文献【3】
(在我自己的问题中二元交叉熵损失函数针对的是单标签二分类问题)关于单标签二分类和多标签二分类对于torch.nn.BCELoss()的使用见参考文献【4】【5】。
其中,是总样本数,是第个样本的所属类别,是第个样本的预测值,一般来说,它是一个概率值。
举个例子:例子来着参考文献【5】
from math import log
loss = ((1*log(0.8) + (1-1)*log(1-0.8)) + (0*log(0.2)+(1-0)*log(1-0.2)) + (0*log(0.4)+(1-0)*log(1-0.4))) / -3
print(loss)
0.3190375754648034
其实,在PyTorch中已经内置了BCELoss,它的主要用途是计算二分类问题的交叉熵,我们可以调用该方法,并将结果与上面手动计算的结果做个比较:
import torch
import torch.nn as nn
bce_loss = nn.BCELoss()
pred_pro = torch.tensor([0.8, 0.2, 0.4], dtype=torch.float)
label = torch.tensor([1, 0, 0], dtype=torch.float)
print(bce_loss(pred_pro, label))
tensor(0.3190)
需要注意的是,输入BCELoss中的预测值应该是个概率。
上面的栗子直接给出了预测的,这是符合要求的。但在更一般的二分类问题中,网络的输出取值是整个实数域(可正可负可为0)。
为了由这种输出值得到对应的,你可以在网络的输出层之后新加一个Sigmoid层,这样便可以将输出值的取值规范到0和1之间,这就是交叉熵公式中的。
当然,可以不更改网络输出,而是在将输出值送入交叉熵公式进行性计算之前,手动用Simgmoid函数做一个映射。
在PyTorch中,提供了BCEWithLogitsLoss方法,它可以直接将输入的值规范到0和1 之间,相当于将Sigmoid和BCELoss集成在了一个方法中。
2.2 torch.nn.BCEWithLogitsLoss()
举个例子来具体进行说明:假设pred是shape为[4,1]的tensor,其中4代表样本个数,2代表该样本分别属于两个类别的概率(前提是规范到了0和1之间,否则就是两个实数域上的值,记住,现在我们讨论的是二分类);target是shape为[4]的tensor,4即样本数。
import torch
import torch.nn as nn
bce_loss = nn.BCELoss()
pred = torch.randn(4, 1) # 预测值
print("pred", pred)
target = torch.rand(4).random_(0, 2) # 真实类别标签
print("target", target)
# 将target进行独热编码
onehot_target = torch.eye(2)[target.long(), :]
print("onehot_target", onehot_target)
sigmoid = nn.Sigmoid()
sigmoid_pred = sigmoid(pred)
print("sigmoid_pred", sigmoid_pred)
loss1 = bce_loss(sigmoid_pred, target.view(4, -1))
print(loss1)
bce_loss2 = nn.BCEWithLogitsLoss()
loss2 = bce_loss2(pred, target.view(4, -1))
print(loss2)
“”“
pred tensor([[ 0.8269],
[-0.7197],
[-0.6237],
[ 0.1657]])
target tensor([0., 0., 0., 1.])
onehot_target tensor([[1., 0.],
[1., 0.],
[1., 0.],
[0., 1.]])
sigmoid_pred tensor([[0.6957],
[0.3275],
[0.3489],
[0.5413]])
tensor(0.6573)
tensor(0.6573)
”“”