目录
前言
一、torch.nn.BCELoss(weight=None, size_average=True)
二、nn.BCEWithLogitsLoss(weight=None, size_average=True)
三、torch.nn.MultiLabelSoftMarginLoss(weight=None, size_average=True)
四、总结
前言最近使用Pytorch做多标签分类任务,遇到了一些损失函数的问题,因为经常会忘记(好记性不如烂笔头囧rz),都是现学现用,所以自己写了一些代码探究一下,并在此记录,如果以后还遇到其他损失函数,继续在此补充。
如果有兴趣,我建议大家阅读Pytorch的官方中文文档的loss function部分,讲得比较清晰。
注:官方文档中特别强调了计算出来的结果默认已经对mini-batch取了平均。
一、torch.nn.BCELoss(weight=None, size_average=True)注:以下公式都是针对一个element(即mini-batch=1)的情形,如果mini-batch=m,最后的输出结果默认会对m个loss取平均的。
(关于weight和size_average两个参数我就不介绍了,介绍起来显得太啰嗦,只需要注意如果使用weight参数,那么weight的shape需要和类别数保持一致)
这个地方需要强调的两点:
1、此处的i是指第i个类别,C表示总共有C个类别。
2、 0<=y[i]<=1(官方写的0<=target[i]<=1应该是写错了!)
下面是我实现的代码:
# 自己写的BCELoss函数
def BCE(y, target):
loss = -(target*torch.log(y) + (1-target)*torch.log(1-y))
# 官方文档中特别强调了:计算出来的结果默认对mini-batch取平均
return loss.mean()
if __name__ == '__main__':
# mini-batch = 2 , data shape is [2, 4]
y = torch.FloatTensor([[0.5, 0.9, 0.1, 0.3],
[0.1, 0.2, 0.3, 0.9]])
target = torch.FloatTensor([[0, 1, 0, 0],
[0, 0, 1, 1]])
# 官方的BCELoss()
criterion = nn.BCELoss()
loss = criterion(y, target)
# 自己的BCELoss()
loss2 = BCE(y, target)
print("官方实现的BCELoss:", loss)
print("自己实现的BCELoss:", loss2)
可以看到输出结果和官方是一样的
输出结果:
官方实现的BCELoss: tensor(0.3623)
自己实现的BCELoss: tensor(0.3623)
二、nn.BCEWithLogitsLoss(weight=None, size_average=True)
官方文档中没有看到这个函数,不过还是讲一下。
就是相当于先使用函数处理y,然后再使用BCELoss()函数进行处理。
以下是我实现的代码:
# sigmoid函数
def Sigmoid(x):
return 1 / (1 + torch.exp(-x))
# 自己写的BCELoss函数
def BCE(y, target):
loss = -(target*torch.log(y) + (1-target)*torch.log(1-y))
# 官方文档中特别强调了:计算出来的结果已经对mini-batch取了平均
return loss.mean()
# 自己写的BCEWithLogitsLoss函数
def BCELogit(y, target):
# 首先使用sigmoid函数处理y
y = Sigmoid(y)
# 然后再使用BCELoss()
loss = BCE(y, target)
return loss
f __name__ == '__main__':
# mini-batch = 2 , data shape is [2, 4]
y = torch.FloatTensor([[0.5, 0.9, 0.1, 0.3],
[0.1, 0.2, 0.3, 0.9]])
# 这是一个多标签分类,可以看到每行中可以有多个1
target = torch.FloatTensor([[0, 1, 0, 1],
[0, 0, 1, 1]])
criterion = nn.BCEWithLogitsLoss()
loss = criterion(y, target)
loss2 = BCELogit(y, target)
print("官方实现的BCEWithLogitsLoss:", loss)
print("自己实现的BCEWithLogitsLoss:", loss2)
可以看到输出结果和官方是一样的
输出结果:
官方实现的BCEWithLogitsLoss: tensor(0.6315)
自己实现的BCEWithLogitsLoss: tensor(0.6315)
注:因为对y使用了sigmoid函数,所以0<=y[i]<=1这个条件就不需要了。
个人认为,BCEWithLogitsLoss就是比BCELoss多了一个Sigmoid函数处理。
三、torch.nn.MultiLabelSoftMarginLoss(weight=None, size_average=True)
这不就是和BCEWithLogitsLoss的公式一模一样咩,无非就是把Sigmoid函数展开了(小朋友你是否有很多问号???)
于是我写代码验证了一下
if __name__ == '__main__':
# mini-batch = 2 , data shape is [2, 4]
y = torch.FloatTensor([[0.5, 0.9, 0.1, 0.3],
[0.1, 0.2, 0.3, 0.9]])
# 这是一个多标签分类,可以看到一行中可以有多个1
target = torch.FloatTensor([[0, 1, 0, 1],
[0, 0, 1, 1]])
criterion = nn.BCEWithLogitsLoss()
criterion2 = nn.MultiLabelSoftMarginLoss()
loss = criterion(y, target)
loss2 = criterion2(y, target)
print("官方实现的BCEWithLogitsLoss:", loss)
print("官方实现的MultiLabelSoftMarginLoss:", loss2)
可以看到官方实现的BCEWithLogitsLoss和MultiLabelSoftMarginLoss输出是一样的
输出结果:
官方实现的BCEWithLogitsLoss: tensor(0.6315)
官方实现的MultiLabelSoftMarginLoss: tensor(0.6315)
四、总结
总结一下:
1、BCELoss加上一个Sigmoid函数操作就得到BCEWithLogitsLoss。
2、MultiLabelSoftMarginLoss和BCEWithLogitsLoss从公式上来看是一样的。
我也是最近才看了一下nn.torch的损失函数的内容,如果我写得有错误,还请评论区拍砖、斧正!
参考:https://blog.csdn.net/qq_39507748/article/details/105356845
Pytorch的官方中文文档
作者:秋名山翻车的