多标签分类与BCELoss

在讨论这一个问题之前,先看一个很有意思的事实:

  • 多标签分类的激活函数、损失函数和二分类十分相似,都是sigmoid和binary crossentropy,那么说明这两个问题也有很大的相似之处。

多标签分类

现在我们有这么一张图:
多标签分类与BCELoss_第1张图片
那么二分类问题就可以是,这张图里有没有房子。答案只能是有(1)或者无(0),共两类。

而多标签分类问题就相当于有多个二分类问题,比如这张图里是否有房子、有树、有山、有云朵。对于一张特定的图,这些标签可能都具备,也可能都不具备,那么这就叫多标签分类(注意与多分类区分)。

BCELoss

先看数学表达:
loss ⁡ ( o , t ) = − 1 / n ∑ i ( t [ i ] ∗ log ⁡ ( o [ i ] ) + ( 1 − t [ i ] ) ∗ log ⁡ ( 1 − o [ i ] ) ) \operatorname{loss}(o, t)=-1 / n \sum_{i}(t[i] * \log (o[i])+(1-t[i]) * \log (1-o[i])) loss(o,t)=1/ni(t[i]log(o[i])+(1t[i])log(1o[i]))
t就是target,目标值,需要在[0, 1]之间(不过作为标签其一般也只有0、1这两个值),而o就是模型的预测值,在计算loss之前需要经过sigmoid函数进行处理。

这个公式其实就是交叉熵变形而来的,由于二分类任务的特别性,因此可以直接用 1 − t [ i ] 1-t[i] 1t[i] 1 − o [ i ] 1-o[i] 1o[i]来代替其他的所有可能,二元交叉熵就是这么个意思。计算每一个“预测-目标”对的交叉熵,最后取平均。

这里我们先假设t和o均为:

[
	[0, 1, 1], 
	[1, 1, 1], 
	[0, 0, 0]
]

o由于需要经过sigmoid处理,处理后的结果为:

[
	[0.5000, 0.7311, 0.7311],
	[0.7311, 0.7311, 0.7311],
	[0.5000, 0.5000, 0.5000]
]

相应代码如下:

import torch
from torch.autograd import Variable
import torch.nn as nn

sig = nn.Sigmoid()
pred = torch.Tensor([[0, 1, 1],
                     [1, 1, 1],
                     [0, 0, 0]])
pred = Variable(pred, requires_grad=True)
pred = sig(pred)
print(pred)
label = torch.Tensor([[0, 1, 1], 
                      [1, 1, 1], 
                      [0, 0, 0]])
loss = nn.BCELoss()
print(loss(pred, label))

计算结果为0.4821。可以发现,哪怕预测值和标签值完全相同,相应的BCELoss值也不会为0,这是由公式的数学特性决定的。

我们可以对照公式自己验证一遍:

import math

r11 = 0 * math.log(0.5) + (1-0) * math.log((1 - 0.5))
r12 = 1 * math.log(0.7311) + (1-1) * math.log((1 - 0.7311))
r13 = 1 * math.log(0.7311) + (1-1) * math.log((1 - 0.7311))

r21 = 1 * math.log(0.7311) + (1-1) * math.log((1 - 0.7311))
r22 = 1 * math.log(0.7311) + (1-1) * math.log((1 - 0.7311))
r23 = 1 * math.log(0.7311) + (1-1) * math.log((1 - 0.7311))

r31 = 0 * math.log(0.5) + (1-0) * math.log((1 - 0.5))
r32 = 0 * math.log(0.5) + (1-0) * math.log((1 - 0.5))
r33 = 0 * math.log(0.5) + (1-0) * math.log((1 - 0.5))

r1 = -(r11 + r12 + r13) / 3
r2 = -(r21 + r22 + r23) / 3
r3 = -(r31 + r32 + r33) / 3

bceloss = (r1 + r2 + r3) / 3 
print(bceloss)

输出为0.48206,四舍五入为0.4821,与直接调用loss函数的计算结果相同。

参考

https://www.jianshu.com/p/ac3bec3dde3e

你可能感兴趣的:(基础)