赞
踩
pytorch中多分类问题中最常用的损失函数应该就是CrossEntropyLoss了,传闻该函数结合了LogSoftmax和NLLLoss两个函数,那么这个函数到底是什么来头呢?本文来一探究竟。
交叉熵刻画的是实际输出的分布与期望分布的距离:如果模型输出的结果的分布和期望的分布越相似,那么交叉熵就越小。交叉熵的定义公式为 C r o s s E n t r o p y ( f ( x ) , y ) = − ∑ i = 1 n y i l o g f ( x i ) CrossEntropy(f(\textbf{x}), \textbf{y})=-\sum_{i=1}^{n}{y_ilogf(x_i)} CrossEntropy(f(x),y)=−∑i=1nyilogf(xi),其中 n n n表示 x \textbf{x} x的维度;更一般地,假设 p p p为期望分布, q q q为输出的分布,则 p p p和 q q q的交叉熵就是: C r o s s E n t r o p y ( p , q ) = − ∑ x p ( x ) l o g q ( x ) CrossEntropy(p,q)=-\sum_{x}{p(x)logq(x)} CrossEntropy(p,q)=−∑xp(x)logq(x)。
举个栗子,假设在一个三分类问题中,一条数据的真实标签为 [ 0 , 0 , 1 ] [0,0,1] [0,0,1],而模型A的预测概率为 [ 0.1 , 0.1 , 0.8 ] [0.1,0.1, 0.8] [0.1,0.1,0.8],模型B的预测概率为 [ 0.2 , 0.2 , 0.6 ] [0.2,0.2,0.6] [0.2,0.2,0.6]那么模型A的输出对应的交叉熵为 C 1 = − l o g ( 0.8 ) = 0.09 C_1=-log(0.8)=0.09 C1=−log(0.8)=0.09,而模型B的输出的交叉熵为 C 2 = − l o g ( 0.6 ) = 0.22 C_2=-log(0.6)=0.22 C2=−log(0.6)=0.22,可见即使两个模型都能够预测正确,但是模型A的交叉熵更小,而更小的交叉熵也意味着模型A的预测概率分布与真实的概率分布更相似。
根据定义,Pytorch中的CrossEntropyLoss是将Softmax-log-NLLoss合并到一块的结果,也就是说CrossEntropyLoss就是我们前面所讨论的交叉熵,为什么这么说呢?看下面的推导:
假设一个10分类的神经网络,那么在输出层就应该有10个节点。在Pytorch中如果使用CrossEntropyLoss,这10个节点的后面将不再需要softmax,因为CrossEntropyLoss已经包含了softmax这一部分。softmax的公式为 s o f t m a x ( z j ) = e z j ∑ e z i softmax(z_j)=\frac{e^{z_j}}{\sum{e^{z_i}}} softmax(zj)=∑eziezj,其能够将十个节点的输出进行处理使得 ∑ s o f t m a x ( z i ) = 1 \sum{softmax(z_i)}=1 ∑softmax(zi)=1,也就是对10个节点的输出做了一个变换,且使得其大小关系不变。
在得到softmax的结果之后再将概率值取log,并且执行后面剩下的求和计算。也就是说NLLLOSS的结果就是把取log得到的结果和真实的标签相乘并求和,之后再求均值并取反(求当前mini-batch的均值)。
来看看Pytorch文档中对CrossEntropyLoss的定义:
运行下面的代码:
import torch import torch.nn as nn import numpy as np loss = nn.CrossEntropyLoss() x_input = torch.randn(3, 3) y = torch.tensor([1,2,0]) print('x_input = ', x_input) print('y = ', y) softmax_func = nn.Softmax(dim=1) softmax_output = softmax_func(x_input) print('softmax_output = ', softmax_output) log_output = torch.log(softmax_output) print('log_output = ', log_output) nllloss = nn.NLLLoss() nllloss_output = nllloss(log_output, y) print('nlloss_output = ', nllloss_output) print('crossentropyloss = ', loss(x_input, y))
得到输出为:
x_input = tensor([[ 0.1650, 1.7421, 0.1270],
[-0.1254, -0.7676, -0.1373],
[ 1.3294, -0.0838, -1.2392]])
y = tensor([1, 2, 0])
softmax_output = tensor([[0.1470, 0.7115, 0.1415],
[0.3977, 0.2093, 0.3930],
[0.7576, 0.1844, 0.0581]])
log_output = tensor([[-1.9174, -0.3404, -1.9554],
[-0.9220, -1.5642, -0.9339],
[-0.2777, -1.6908, -2.8462]])
nlloss_output = tensor(0.5173)
crossentropyloss = tensor(0.5173)
可以看到使用softmax-log-nllloss得到的结果和直接使用CrossEntropyLoss得到的结果是完全一样的。
再去看一下NLLLoss损失函数的官方定义:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。