pytorch|【Pytorch基础】torch.nn.BCELoss()和torch.nn.BCEWithLogitsLoss()损失函数


目录

  • 1 交叉熵损失函数
  • 2 二元交叉熵损失函数
    • 2.1 torch.nn.BCELoss()
    • 2.2 torch.nn.BCEWithLogitsLoss()
  • 3 参考文献

1 交叉熵损失函数 ??在之前的损失函数介绍中已经解释过,什么是交叉熵损失函数以及其数学原理(【Pytorch基础】torch.nn.CrossEntropyLoss损失函数介绍)。在多分类问题中输出层的函数是 S o f t m a x Softmax Softmax函数, 在二分类问题中输出层的函数是 S i g m o d Sigmod Sigmod函数。
??而CrossEntropy损失函数适用于总共有N个类别的分类。当N=2时,即二分类任务,只需要判断是还是否的情况,就可以使用二分类交叉熵损失,本小节介绍二分类交叉熵损失函数。
2 二元交叉熵损失函数 2.1 torch.nn.BCELoss() ??BCELoss的全称是Binary Cross Entropy, 即二分类交叉熵损失。如下公式 (y是真实标签,x是预测值):
L o s s = ? 1 N ∑ i = 1 N [ y i log ? ( p i ) + ( 1 ? y i ) log ? ( 1 ? p i ) ] Loss=-\frac{1}{N} \sum_{i=1}^{N}\left[y_{i} \log \left(p_{i}\right)+\left(1-y_{i}\right) \log \left(1-p_{i}\right)\right] Loss=?N1?i=1∑N?[yi?log(pi?)+(1?yi?)log(1?pi?)]
其实这个函数就是CrossEntropyLoss的当类别数N=2时候的特例。因为类别数为2,属于第一类的概率为y,那么属于第二类的概率自然就是(1-y)。因此套用与CrossEntropy损失的计算方法,用对应的标签乘以对应的预测值再求和,就得到了最终的损失。参考文献【3】
(在我自己的问题中二元交叉熵损失函数针对的是单标签二分类问题)关于单标签二分类和多标签二分类对于torch.nn.BCELoss()的使用见参考文献【4】【5】。
其中, N N N是总样本数, y i y_{i} yi?是第 i i i个样本的所属类别, p i p_{i} pi?是第 i i i个样本的预测值,一般来说,它是一个概率值。
举个例子: y i = [ 1 , 0 , 0 ] , p i = [ 0.8 , 0.2 , 0.4 ] y_{i}=[1, 0, 0], p_{i}=[0.8, 0.2, 0.4] yi?=[1,0,0],pi?=[0.8,0.2,0.4]例子来着参考文献【5】
L = ? 1 3 [ ( 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 ) ) ] = 0.319 L=-\frac{1}{3}[(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))]=0.319 L=?31?[(1?log0.8+(1?1)?log(1?0.8))+(0?log0.2+(1?0)?log(1?0.2))+(0?log0.4+(1?0)?log(1?0.4))]=0.319
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 nnbce_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中的预测值应该是个概率 p i p_{i} pi?。
上面的栗子直接给出了预测的 p i p_{i} pi?,这是符合要求的。但在更一般的二分类问题中,网络的输出取值是整个实数域(可正可负可为0)。
??为了由这种输出值得到对应的 p i p_{i} pi?,你可以在网络的输出层之后新加一个Sigmoid层,这样便可以将输出值的取值规范到0和1之间,这就是交叉熵公式中的 p i p_{i} pi?。
当然,可以不更改网络输出,而是在将输出值送入交叉熵公式进行性计算之前,手动用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 nnbce_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)”“”

3 参考文献 【pytorch|【Pytorch基础】torch.nn.BCELoss()和torch.nn.BCEWithLogitsLoss()损失函数】[1]pytorch nn.BCELoss()详解
[2]pytorch二分类损失函数BCEWithLogitsLoss
[3]Pytorch常用损失函数拆解
[4]loss函数之BCELoss
[5](七)详解pytorch中的交叉熵损失函数nn.BCELoss()、nn.BCELossWithLogits(),二分类任务如何定义损失函数,如何计算准确率、如何预测

    推荐阅读