(详细全面)softmax和log_softmax的联系和区别,NLLLOSS和CrossEntropyLoss的联系和区别

1.softmax

作用:实现了将n维向量变成n维全为正数,且和为1的向量,在深度学习中可以解释为这个输入属于n个类别的概率。
例子:

import torch.nn.functional as F
inp1=torch.Tensor([1,3,6])
print(inp1)
print(F.softmax(inp1,dim=0))

print("#############")
inp2=torch.Tensor([2,2,2])
print(inp2)
print(F.softmax(inp2,dim=0))

在这里插入图片描述

可以看到,如果n维向量每一个分量是一样的,那么概率1平分给3个类别,表示属于三个类别的概率是相等的。

以inp1为例我们可以验证一下(即用numpy实现softmax()):

import numpy as np

inp1=np.array(inp1)#inp1=[1,3,6]
inp1_pow=np.power(np.e,inp1)

inp1_pow/np.sum(inp1_pow)#对应上述开头的那个公式

在这里插入图片描述
发现这个结果和上述调用softmax()结果是一样的。

2.log_softmax

我们发现只是再求一个Log而已。
import torch.nn.functional as F
inp1=torch.Tensor([1,3,6])
print(inp1)
print(F.log_softmax(inp1,dim=0))

在这里插入图片描述
同样,我们可以验证一下(即用numpy实现log_softmax()):

import numpy as np

inp1=np.array(inp1)
inp1_pow=np.power(np.e,inp1)

inp1_softmax=inp1_pow/np.sum(inp1_pow)#对应上述公式
print("softmax后:")
print(inp1_softmax)
inp1_log_softmax=np.log(inp1_softmax)#再取一次log而已
print("在上述基础上再取log后:")
print(inp1_log_softmax)

在这里插入图片描述
发现和前面log_softmax()还是一样的。

3.softmax和log_softmax

softmax的作用不言而喻,每一项代表概率,我们发现去了Log之后并不是概率了,有什么用呢?

官网解释:https://pytorch.org/docs/stable/generated/torch.nn.functional.log_softmax.html?highlight=log_sof#torch.nn.functional.log_softmax

Applies a softmax followed by a logarithm.

While(尽管) mathematically equivalent to log(softmax(x)), doing these two
operations separately is slower, and numerically unstable. This
function uses an alternative formulation to compute the output and
gradient correctly.

大概意思就是说,虽然可以用log(softmax(x))来代替log_softmax(),但是前者太慢了。需要进行n次指数,n次除法,n次log(忽略加减法)。后者只需要n次指数,1次log。

而做softmax需要n次指数,n次除法。这样看来,似乎Log_softmax()似乎最好。

注意到:
log ⁡ e x e x + e y = x − l o g ( e x + e y ) \log \frac{e^x}{e^x+e^y}=x-log(e^x+e^y) logex+eyex=xlog(ex+ey)
所以两次指数,一次对数,这个算好了可以保存起来,下一次还是继续用。

不过,实际操作中还会有一个使得数值计算更加稳定的算法,因为我们要考虑这种情况,如果(x,y)=(1000,1001)。那么 e 1000 e^{1000} e1000将会发生上溢。与之对应有 e − 1000 e^{-1000} e1000会发生下溢。
从而我们有了如下更加稳定的办法:即取 M = max ⁡ ( x , y ) M=\max(x,y) M=max(x,y)。有:

log ⁡ e x e x + e y = log ⁡ e x / e M e x / e M + e y / e M = x − M − l o g ( e x − M + e y − M ) \log \frac{e^x}{e^x+e^y}=\log \frac{e^x/e^M}{e^x/e^M+e^y/e^M}=x-M-log(e^{x-M}+e^{y-M}) logex+eyex=logex/eM+ey/eMex/eM=xMlog(exM+eyM)

当然了,有人杠,

  1. (x,y)=(0,1000),这个方法没用,对,但是这个方法有的时候有用啊。
  2. 也有人说(x,y)=(-10,10),反而会计算 e − 20 e^{-20} e20,岂不是比原来的 e − 10 e^{-10} e10更加下溢,这个分析也对,但是要记住,上溢是最难受的,下溢还好,我们要更加避免上溢。

所以,这也是一个权衡之术。

4.NLLLOSS和CrossEntropyLoss

NLLLOSS:The negative(负的) log likelihood loss.
CrossEntropyLoss:

其中p为真实分布,q为预测分布。

联系:

It is useful to train a classification problem with C classes.

即共同点是对于分类问题是非常好的两种损失函数。

过渡:

但是严格来说,NLLLOSS并不是一个损失函数,后者才是,前者是基于后者的,但是节省了计算量(区别提前剧透了)。

区别:

Obtaining log-probabilities in a neural network is easily achieved by
adding a LogSoftmax layer in the last layer of your network. You may
use CrossEntropyLoss instead, if you prefer not to add an extra layer.

即:我们以前在做分类任务的时候,例如手写数字识别,最后一层有两种习惯:

  1. 使用softmax层,转化为各个类别概率,这种情况,你应该紧接着使用CrossEntropyLoss损失函数。
  2. 使用log_softmax层,那么使用NLLLOSS最好而且最直接。

解释:

在情况1中,根据CrossEntropyLoss公式,加上这是分类问题,所以标签中只有一个类别(设为z)分量为1,其他类别全为0,我们代入公式,即求和之后只剩下一项。
− log ⁡ q z \quad \quad \quad \quad \qquad \qquad-\log q_z logqz
其中 q z q_z qz表示我们的模型对该输入,属于类别z的概率的预测。

所以情况1计算CrossEntropyLoss的步骤就是取log,再取反。

在情况2中,我们模型的输出直接就是 log ⁡ q z \log q_z logqz(log_softmax层后),所以计算NLLLOSS的步骤只需要取反,十分快速。这就是为什么叫做The negative log likelihood loss.

官网地址:https://pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html#torch.nn.NLLLoss


补充:CrossEntropyLoss大家肯定都已经用过,NLLLOSS使用语法是一样的,伪代码大致是这样。

import torch.nn as nn
import torch.nn.functional as F
class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
		*
		*
		*
    def forward(self,x):
        #x:1*28*28
        x=F.relu(self.conv1(x))
		*
		*
		*
        x=self.fc2(x)
        #shape=(1,10)
        return F.log_softmax(x,dim=1)
       
pred=model(x)
loss=F.nll_loss(pred,target)     
nn.NLLLoss()nn.CrossEntropyLoss()是用于多分类任务的损失函数,在PyTorch中它们实际上是相同的。唯一的区别在于它们接收的输入不同: - nn.NLLLoss()的输入是一个对数概率向量一个目标标签,它不会为我们计算对数概率。适合网络的最后一层是log_softmax损失函数的情况。 - nn.CrossEntropyLoss()的输入是一个预测值一个目标标签,它会为我们自动计算预测值的对数概率,即先做softmax,再做log处理。在实际使用中,两者可以互换使用,效果是一样的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [paddle中nll_loss()CrossEntropyLoss()损失函数区别](https://blog.csdn.net/weixin_43848436/article/details/115448659)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Pytorch中损失函数 NLLLOSS CROSSENTROPYLOSS区别](https://blog.csdn.net/cnhwl/article/details/125518586)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

音程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值