Pytorch中torch.nn的损失函数

Cytheria ·
更新时间:2024-09-21
· 584 次阅读

目录

前言

一、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需要和类别数保持一致)

\small loss(y,target)=-\frac{1}{C}\sum_i(target[i] *log(y[i])+(1-target[i]) *log(1-y[i]))

这个地方需要强调的两点:

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)

官方文档中没有看到这个函数,不过还是讲一下。

\small loss(y,target)=-\frac{1}{C}\sum_itarget[i] *log(\sigma (y[i]))+(1-target[i]) *log(\sigma (1-y[i]))

就是相当于先使用\small \sigma (x) = \frac{1}{1+e^{-x}}函数处理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)

\small loss(y, target) = - \frac{1}{C} * \sum_i target[i] * \log((1 + \exp(-y[i]))^{-1}) + (1-target[i]) * \log\left(\frac{\exp(-y[i])}{(1 + \exp(-y[i]))}\right)

这不就是和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的官方中文文档


作者:秋名山翻车的



pytorch 损失 函数 损失函数

需要 登录 后方可回复, 如果你还没有账号请 注册新账号