总结: NLLLoss, CrossEntropyLoss, BCELoss, BCEWithLogitsLoss比较,以及交叉熵损失函数推导
一、pytorch中各损失函数的比较
Pytorch中Softmax、Log_Softmax、NLLLoss以及CrossEntropyLoss的关系与区别详解
Pytorch详解BCELoss和BCEWithLogitsLoss
Focal Loss理解-菜鸟笔记 (coonote.com)
| 概念 | “单标签” 多分类 | “多标签” 多分类 | “多标签” 二分类 |
|---|---|---|---|
| 任务示例 | 手写数字识别(0-9) | 图片多物体标注(猫、狗、鸟) | 垃圾邮件判断 + 是否含附件 + 是否紧急(三个独立的是/否问题) |
| “分类” (候选项) | 10个数字 {0...9} 或 3种动物 {猫,狗,鸟} |
3种物体 {猫,狗,鸟} |
通常只有 1个 类别(是/否),但可以扩展为多个独立二分类任务 |
| “标签” (某样本的答案) | 一个整数(例如:5 或 猫) |
一个向量(例如:[1, 0, 1],表示有猫、没有狗、有鸟) |
一个标量 0/1(例如:1 表示是垃圾邮件),或多个独立的 0/1 组合 |
| 逻辑关系 | 答案必须是其中一个且唯一 | 答案可以同时包含多个(非互斥) | 每个问题独立回答 是(1) / 否(0)(互不干扰) |
| 输出维度 | [batch_size, num_classes] |
[batch_size, num_classes](每个类别独立判断) |
[batch_size, 1](单一任务)或 [batch_size, num_classes](多个独立任务) |
| 输出激活函数 | Softmax(概率和为1) | Sigmoid(每个维度独立映射) | Sigmoid(单个概率值) |
| 推荐损失函数 | CrossEntropyLoss |
BCEWithLogitsLoss(每个类别独立二分类) |
BCEWithLogitsLoss |
-
“分类” = 问题一共有多少个选项。是所有可能的候选答案选项(即类别集合)。
-
“标签” = 这道题目的正确答案是哪个或哪几个选项。是指当前样本的gt。
CrossEntropyLoss 做的是:例如手写数字识别,从这10个“分类”选项里,找出那个正确答案“标签”的概率,并把它的负对数作为损失。它不关心你错得有多离谱,只关心你把正确答案预测得够不够好。
总结这两篇博客的内容就是:
- CrossEntropyLoss函数包含Softmax层、log和NLLLoss层,适用于单标签任务,主要用在单标签多分类任务上,当然也可以用在单标签二分类上。
- BCEWithLogitsLoss函数包括了Sigmoid层和BCELoss层,适用于二分类任务,可以是单标签二分类,也可以是多标签二分类任务。
- 以上这几个损失函数本质上都是交叉熵损失函数,只不过是适用范围不同而已。
第一条的原因是:

也就是说,各个class的得分是互斥的,这个class得分多了,另个class的得分会减少。
第二条的原因是:

也就是说,各个class的得分是独立的,互不影响,所以可以进行多标签预测。


二、程序示例
在使用中,最常遇到的情况是,CrossEntropyLoss的predict是一个二维张量,target是一维张量,例如:
loss = nn.CrossEntropyLoss() predict = torch.randn(3, 5, requires_grad=True) # 3个样本,5个类别 target = torch.empty(3, dtype=torch.long).random_(5) # torch.long表示长整型,torch.empty(3)表示产生一维向量,长度为3,元素内容为空。 # random_(5)表示用0到4的整数去填充3个空元素。之所以是整数,是因为前面规定了torch.long。 output = loss(predict, target) output.backward()
CrossEntropyLoss的计算公式为(本质上是交叉熵公式+softmax公式):

BCEWithLogitsLoss和BCELoss的predict和target必须保持维度相同,即同时是一维张量,或者同时是二维张量,例如:
m = nn.Sigmoid() loss = nn.BCELoss() # predict和target同为一维张量 predict = torch.randn(3, requires_grad=True) target = torch.empty(3).random_(2) # 填充的是0或1 output = loss(m(predict), target) output.backward() # predict和target同为二维张量 predict = torch.randn([5, 3], requires_grad=True) target = torch.empty([5, 3]).random_(2) output = loss(m(predict), target) output.backward()
-------------------------------------------
loss = nn.BCEWithLogitsLoss() # predict和target同为一维张量 predict = torch.randn(3, requires_grad=True) target = torch.empty(3).random_(2) output = loss(predict, target) output.backward() # predict和target同为二维张量 predict = torch.randn([5,3], requires_grad=True) target = torch.empty([5,3]).random_(2) output = loss(predict, target) output.backward()
三、交叉熵损失函数的推导
以下的内容摘自知乎:交叉熵、相对熵(KL散度)、JS散度和Wasserstein距离(推土机距离)


对于二分类问题,假设是猫和狗的分类问题,则p(x=猫)=1-p(x=狗),同样地q(x=猫)=1-q(x=狗),所以,对于某一张图片(样本),它的损失可通过如下公式计算:

这个二分类公式其实是cross entropy between two Bernoulli distributions。这个公式不仅可以用于单标签的二分类问题,也可以用于多标签的二分类问题。在pytorch的BCEWithLogitsLoss函数或者BCELoss函数中,实际计算公式是这样的:

式中,n是指总的类别数目,这个公式指的是单个样本的损失。对单标签二分类时,即当n=2时,(2)式和(1)式等价,证明:

简单的算例证明可以参考知乎:pytorch中的损失函数总结 第6小节

浙公网安备 33010602011771号