Pytorch 分类loss总结

在分类问题中,Pytorch提供了多种函数,那么哪种函数是使用softmax;哪些函数不用使用softmax就可以直接套loss;又有哪些函数使用logsoftmax?这里面有一些细节需要我来研究,我找到了pytorch在github上面的这部分代码,以此文记录一下我的学习历程。
分类问题有两种思路:
第一种需要对标签进行处理

NLLLoss(_WeightedLoss)

输入

这个函数的作用适合于样本数量不均衡的情况下,其中_WeightedLoss的维度是(样本个数,类别个数),数值代表了给每个类别分配的权重。这个函数接收到输入后,会给出每个类别的对数概率(因而比较适合样本不均匀的条件)。(也就是说如果你使用NLLoss的话,你可以在forward部分直接在最后一个隐层设定为(类别维度),然后套上一个LogSoftmax层就好了。)

预测

对于predict阶段代码中也给出了方法,可以在网络的最后一层加入一个LogSoftmax,来给出输出
(当然作者也提到了,如果不想手工在最后一层加入LogSoftmax层,也可以使用CrossEntropyLoss来代替。)

标签

标签应该是一个index数组,其中index的范围是[0, C-1], 其中C为类别的数目

例子

m = nn.LogSoftmax(dim=1)
loss = nn.NLLLoss()
# input is of size N x C = 3 x 5
input = torch.randn(3, 5, requires_grad=True)
# each element in target has to have 0 <= value < C
target = torch.tensor([1, 0, 4])
output = loss(m(input), target)
output.backward()

# 2D loss example (used, for example, with image inputs)
N, C = 5, 4
loss = nn.NLLLoss()
# input is of size N x C x height x width
data = torch.randn(N, 16, 10, 10)
conv = nn.Conv2d(16, C, (3, 3))
m = nn.LogSoftmax(dim=1)
# each element in target has to have 0 <= value < C
target = torch.empty(N, 8, 8, dtype=torch.long).random_(0, C)
output = loss(m(conv(data)), target)
output.backward()

torch.nn.CrossEntropyLoss()

CrossEntropyLoss结合和nn.LogSoftmax和nn.NLLLoss两个函数的功能。

输入

CrossEntropyLoss和NLLLoss函数在输入维度部分是一致的,但是与NLLLoss不同的是,CrossEntropyLoss不需要在网络的最后一层加入LogSoftmax层。在源代码的注释里,官方也强调了“The input is expected to contain raw, unnormalized scores for each class.” 不要使用Softmax(这一点也好理解,因为softmax和对数似然loss求梯度之后正好是y-\hat{y})输入维度为(数据个数,数据维度)

预测

在预测的时候需要加入一个Softmax层

标签

CrossEntropyLoss和NLLLoss在标签上是一致的,给出一个index,index里面表明了分类。

loss = nn.CrossEntropyLoss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.empty(3, dtype=torch.long).random_(5)
output = loss(input, target)
output.backward()

torch.nn.BCELoss

BCELoss的作用是计算二分类target和output之间的loss

标签

BCELoss的标签是 0和1之间的数值,维度为1
这里需要强调一下,BCELoss和NLLLoss比较像,需要在网络最后一层套上一个nn.Sigmoid层(和CrossEntropy不一样)

import torch 
import torch.nn as nn

sig = nn.Sigmoid()
loss = nn.BCELoss()
input = torch.randn(3, requires_grad=True)
target = torch.empty(3).random_(2)
output = loss(sig(input), target)
output.backward()

torch.nn.BCEWithLogitsLoss

这个层类似于CrossEntropyLoss,结合和Sigmoid层和BCELoss层,适用于二分类任务(但是相比于Sigmoid+BCELoss数值计算稳定性更好一些)

小结

最后想说一件事情,torch.nn.functional 下面的函数和torch.nn层一致困扰着我,因为他们好像是某种角度看是类似的。在研究代码之后,的确是这样的,torch.nn下的包实现的时候都是在调用torch.nn.functional下面的函数。也算有一个小收获吧!

这篇文章是否对您有帮助?

请您为我打分吧!

平均分数 / 5. 投票数量:

发表评论

电子邮件地址不会被公开。 必填项已用*标注