pytorch中BCEWithLogitsLoss&CrossEntropyLoss函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pytorch中BCEWithLogitsLoss&CrossEntropyLoss函数相关的知识,希望对你有一定的参考价值。

参考技术A 先说结论:

BCEWithLogitsLoss函数包括了 Sigmoid 层和 BCELoss 层. 适用于多标签分类任务

CrossEntropyLoss函数 包含Softmax,层和 NLLLoss层,适用于单标签分类问题

对Sigmoid和Softmax函数不熟悉的可以看上一篇文章:https://www.jianshu.com/p/b13f4f419cce

再来看两个函数的具体计算过程,也是对交叉熵损失函数的一个复习过程.

1. BCEWithLogitsLoss函数:

先对输出向量里的每个元素使用sigmoid函数, 然后使用BCELoss函数
具体例子如下:

在图片多标签分类时,如果3张图片分3类,会输出一个3*3的矩阵。每行代表每一张图片的模型输出向量.

先用Sigmoid给这些值都搞到0~1之间:

假设Target是:(sigmoid用来处理多标签分类问题,这里也可以看出来)

BCELOSS的计算过程如下

BCEWithLogitsLoss就是把Sigmoid-BCELoss合成一步

2. CrossEntropyLoss函数:

在图片单标签分类时,输入m张图片,输出一个m N的Tensor,其中N是分类个数。比如输入3张图片,分三类,最后的输出是一个3 3的Tensor,举个例子:

第1,2,3行分别是第1,2,3张图片的结果,假设第1,2,3列分别是猫、狗和猪的分类得分。 可以看出模型认为第1,2,3张都更可能是猫。然后对每一行使用Softmax,这样可以得到每张图片的概率分布。

这里dim的意思是计算Softmax的维度,这里设置dim=1,可以看到每一行的加和为1。比如第一行0.6600+0.0570+0.2830=1。我们这里一张图片是一行,所以dim应该设置为1。

然后对Softmax的结果取自然对数:

Softmax后的数值都在0~1之间,所以ln之后值域是负无穷到0。NLLLoss的结果就是把上面的输出与Label对应的那个值拿出来,再去掉负号,再求均值。假设我们现在Target是[0,2,1](第一张图片是猫,第二张是猪,第三张是狗)。第一行取第0个元素,第二行取第2个,第三行取第1个,去掉负号,结果是:[0.4155,1.0945,1.5285]。再求个均值,结果是:

CrossEntropyLoss就是把以上Softmax–Log–NLLLoss合并成一步,我们用刚刚随机出来的input直接验证一下结果是不是1.0128:

pytorch二元交叉熵损失函数 nn.BCELoss() 与 torch.nn.BCEWithLogitsLoss()

nn.BCELoss


1、nn.BCELoss

  • nn.BCELoss() 是 二元交叉熵损失函数 (Binary Cross Entropy Loss)
  • 适用于二分类问题,即
    • 模型的输出为一个概率值,表示样本属于某一类的概率
    • 标签为二元值:0 或 1
  • nn.BCELoss() 计算的是二元交叉熵损失,也称为对数损失,它将模型 预测值 和 真实标签值 之间的差异转化为一个标量损失值,用于衡量模型预测的准确性。

2、使用场景

假设有一个 二分类任务:判断一张图片中是否包含猫。

我们可以定义一个二元分类模型,用 Sigmoid 输出一个概率值,表示样本属于猫的概率。 标签值为 0 和 1。

使用以下代码构建模型和损失函数:

import torch
import torch.nn as nn

class CatClassifier(nn.Module):
    def __init__(self):
        super(CatClassifier, self).__init__()
        self.fc = nn.Linear(3*256*256, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        x = self.sigmoid(x)
        return x

model = CatClassifier()
criterion = nn.BCELoss()

在每次迭代时,我们可以通过以下代码计算损失:

outputs = model(inputs)
loss = criterion(outputs, labels.float())

3、nn.BCELoss 计算公式

L = − 1 N ∑ i = 1 N [ y i log ⁡ ( y i ^ ) + ( 1 − y i ) log ⁡ ( 1 − y i ^ ) ] L = -\\frac1N \\sum_i=1^N [y_i \\log(\\haty_i) + (1-y_i) \\log(1-\\haty_i)] L=N1i=1N[yilog(yi^)+(1yi)log(1yi^)]

其中:

  • N N N 表示样本数量
  • y i y_i yi 表示第 i i i 个样本的实际标签
  • y i ^ \\haty_i yi^ 表示第 i i i 个样本的预测值

如果 y i = 1 y_i=1 yi=1,则第一项 y i log ⁡ ( y i ^ ) y_i \\log(\\haty_i) yilog(yi^) 生效,第二项 ( 1 − y i ) log ⁡ ( 1 − y i ^ ) (1-y_i) \\log(1-\\haty_i) (1yi)log(1yi^) 失效;
如果 y i = 0 y_i=0 yi=0,则第一项失效,第二项生效。

因为 y i ^ \\haty_i yi^ 值的范围是 0 ~ 1, 所以, log ⁡ ( y i ^ ) \\log(\\haty_i) log(yi^) log ⁡ ( 1 − y i ^ ) \\log(1-\\haty_i) log(1yi^) 的值都是负数,如下图红色曲线。 所以,损失函数的最前面有个负号,将损失值变为正数。

因此,当模型的预测值与标签值越接近时,损失值越小。


4、torch.nn.BCEWithLogitsLoss() 与 nn.BCELoss() 的区别

nn.BCELoss() 的输入是 二元分类模型的预测值 y ^ \\haty y^ 和 实际标签 y y y。并且 y ^ \\haty y^ 的范围是 [0,1],因为二元分类模型内部已经对预测结果做了 sigmoid 处理。
n n . B C E L o s s ( ) = − 1 N ∑ i = 1 N [ y i log ⁡ ( y i ^ ) + ( 1 − y i ) log ⁡ ( 1 − y i ^ ) ] nn.BCELoss() = -\\frac1N \\sum_i=1^N [y_i \\log(\\haty_i) + (1-y_i) \\log(1-\\haty_i)] nn.BCELoss()=N1i=1N[yilog(yi^)+(1yi)log(1yi^)]

torch.nn.BCEWithLogitsLoss() 的输入是也是 二元分类模型的输出值 z z z 和实际标签 y y y不同的是 z z z 在模型内部没有经过 sigmoid 处理,是任意实数。这种情况下,sigmoid 处理就被放到了损失函数中,所以,torch.nn.BCEWithLogitsLoss() 函数内部的计算过程是先对 z z z 应用 sigmoid 函数,将其映射到 [0,1] 范围内,然后使用二元交叉熵计算预测值和实际标签之间的损失值。
n n . B C E W i t h L o g i t s L o s s ( ) = − 1 N ∑ i = 1 N [ y i log ⁡ σ ( z i ) + ( 1 − y i ) log ⁡ ( 1 − σ ( z i ) ) ] nn.BCEWithLogitsLoss() = -\\frac1N \\sum_i=1^N [y_i \\log \\sigma(z_i) + (1-y_i) \\log(1-\\sigma(z_i))] nn.BCEWithLogitsLoss()=N1i=1N[yilogσ(zi)+(1yi)log(1σ(zi))]

另外,torch.nn.BCEWithLogitsLoss() 还支持设置 pos_weight 参数,用于处理样本不平衡的问题。而 nn.BCELoss() 不支持设置 pos_weight 参数。


5、torch.nn.BCELoss() 函数

torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')

参数说明:

  • weight :用于样本加权的权重张量。如果给定,则必须是一维张量,大小等于输入张量的大小。默认值为 None。
  • reduction :指定如何计算损失值。可选值为 ‘none’、‘mean’ 或 ‘sum’。默认值为 ‘mean’。

6、torch.nn.BCEWithLogitsLoss() 函数

torch.nn.BCEWithLogitsLoss(weight=None, 
                           size_average=None, 
                           reduce=None, 
                           reduction='mean', 
                           pos_weight=None)

参数说明:

  • weight:用于对每个样本的损失值进行加权。默认值为 None。
  • reduction:指定如何对每个 batch 的损失值进行降维。可选值为 ‘none’、‘mean’ 和 ‘sum’。默认值为 ‘mean’。
  • pos_weight:用于对正样本的损失值进行加权。可以用于处理样本不平衡的问题。例如,如果正样本比负样本少很多,可以设置 pos_weight 为一个较大的值,以提高正样本的权重。默认值为 None。

以上是关于pytorch中BCEWithLogitsLoss&CrossEntropyLoss函数的主要内容,如果未能解决你的问题,请参考以下文章

修改后的 PyTorch 损失函数 BCEWithLogitsLoss 返回 NaNs

pytorch二元交叉熵损失函数 nn.BCELoss() 与 torch.nn.BCEWithLogitsLoss()

Pytorch常用损失函数nn.BCEloss();nn.BCEWithLogitsLoss();nn.CrossEntropyLoss();nn.L1Loss(); nn.MSELoss();(代码

为啥pytorch loss越来越高?

BCEWithLogitsLoss:试图将预测标签的二进制输出作为张量,与输出层混淆

小曾带你深入浅出机器学习(小白入门必备,近3万字带你了解机器学习)