首先我们来看一下nn和nn.functional有什么区别
nn.functional.xxx是函数接口,而nn.Xxx是nn.functional.xxx的类封装,并且nn.Xxx都继承于一个共同祖先nn.Module。这一点导致nn.Xxx除了具有nn.functional.xxx功能之外,内部附带了nn.Module相关的属性和方法,例如train(), eval(),load_state_dict, state_dict 等。
nn.functional.xxx 就是直接调用
nn.functional.NLLLoss(nn.functional.log_softmax(data),target)
nn.Xxx 就是先定义,之后用的时候再赋值,如
loss = nn.NLLLoss()
conv = nn.Conv2d(16, C, (3, 3))
m = nn.LogSoftmax(dim=1)
#下面再赋值
output = loss(m(conv(data)), target)
参考:https://zhuanlan.zhihu.com/p/61379965
多分类损失函数
多分类任务用到最多的就是nn.NLLLOSS和nn.CrossEntropyLoss。这两者的关系实际上是
nn.CrossEntropyLoss = nn.NLLLOSS + LogSoftmax
nn.NLLLoss
网络的最后一层后有LogSoftmax,就用nn.NLLLoss。也就是我们要先对input用一下log_softmax函数,再作为nn.NLLLoss的输入。
如果不想让网络的最后一层是log_softmax层的话,就可以采用CrossEntropyLoss完全代替此函数。
NLLLoss就是的计算公式可以这样表示
loss(input, class) = -input[class] 也就是把这个类对应的像素的值找出来,再取一个负号
对图像来说,我们现在有C个通道的hxw图像,然后有一个target,那么对某一个像素来说,我们的target的值为几,则我们就选择第几个通道的这个像素位置值的负值。
nn.functional.null_loss
torch.nn.functional.nll_loss(input, target, weight=None, size_average=None, ignore_index=-100, reduce=None, reduction=‘mean’)
- input 预测值
一维:(N,C),二维:(N,C,H,W) ,k维:(
N
,
C
,
d
1
,
d
2
,
.
.
.
,
d
k
)
(N,C,d_1,d_2,…,d_k)
C是要分类的类别的数量,N是batchsize
注意input在输入NLLLoss()之前,需要对input进行log_softmax函数激活,即将input转换成概率分布的形式,并且取对数。 - target 真实值
一维:(N),二维:(N,H,W),k维:(
N
,
d
1
,
d
2
,
.
.
.
,
d
k
)
(N,d_1,d_2,…,d_k)
其中每个值都是大于等于0小于等于C-1的,也就代表了属于哪一类。
对于二维也就是图像的多分类问题来说,就表示这个像素点属于哪一类,这也就是语义分割问题 - weight (Tensor, optional)
给每一个类设置一个权重,必须为大小为C的tensor。常用于类别不均衡问题。 - size_average(bool)
当reduce=True时有效。为True时,返回的loss为除以权重之和的平均值;为False时,返回的各样本的loss之和。 - reduce(bool)
返回值是否为标量,默认为True。 - ignore_index(int)
忽略某一类别,不计算其loss,其loss会为0,并且,在采用size_average时,不会计算那一类的loss,除的时候的分母也不会统计那一类的样本。
特别注意,当带上权值,reduce = True, size_average = True, 其计算公式为:
当input为[[0.6, 0.2, 0.2], [0.4, 1.2, 0.4]],target= [0, 1],
①不加权重
l1 = -0.6 , l2=-1.2 loss=l1+l2=-0.6-1.2=-1.8
②加权重
weight = [0.6, 0.2, 0.2]
l1 = – 0.60.6 = – 0.36
l2 = – 1.20.2 = – 0.24
loss = -0.36/(0.6+0.2) + -0.24/(0.6+0.2) = -0.75
例子:
>>> # 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 = F.nll_loss(F.log_softmax(input), target)
>>> output.backward()
nn.NLLLoss
torch.nn.NLLLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction=‘mean’)
参数和上面的一样
例子:
>>> # 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()