文章目录

  • 1、负对数似然损失函数
    • 1.1、似然
    • 1.2、似然函数
    • 1.3、极大似然估计
    • 1.4、对数似然
    • 1.5、负对数似然
    • 1.6、pytorch中的应用
  • 2、交叉熵损失函数
    • 2.1、信息量
    • 2.2、信息熵
    • 2.3、相对熵(KL散度)
    • 2.4、交叉熵
    • 2.5、pytorch中的应用
  • 3、使用总结

1、负对数似然损失函数

1.1、似然

在解释负对数似然之前,首先要了解什么是似然。似然(likelihood)和概率(probability)有着一定的区别和联系。似然和概率是针对不同内容的估计和近似。概率表达了给定参数 θ \theta θ下样本随机向量 X = x X=x X=x的可能性,而似然表达了给定样本 X = x X=x X=x下参数 θ = θ 1 \theta=\theta_1 θ=θ1​(相对于另外的参数取值 θ 2 \theta_2 θ2​)为真实值的可能性。用一句话可以总结为:概率是已知参数,推数据。似然是已知数据,推参数。

1.2、似然函数

下面来看一下函数 P ( x ∣ θ ) P(x|\theta) P(x∣θ),输入有两个, x x x表示某一个具体的数据; θ \theta θ表示模型的参数:

  1. 如果 θ \theta θ是已知确定的, x x x是变量,这个函数叫做概率函数(probability function),它描述对于不同的样本点,其出现的概率是多少。

  2. 如果 x x x是已知确定的, θ \theta θ是变量,这个函数叫做似然函数(likelihood function),他描述对于不同的模型参数,出现 x x x这个样本点的概率是多少。

1.3、极大似然估计

假设有训练集 D D D,令 D c D_c Dc​表示训练集 D D D中第 c c c类样本组成的集合,假设这些样本是独立同分布的,则参数 θ c \theta_c θc​对于数据集 D c D_c Dc​的似然是
P ( D c ∣ θ c ) = ∏ x ∈ D c P ( x ∣ θ c ) P(D_c|\theta_c)=\prod_{x \in D_c}P(x|\theta_c) P(Dc​∣θc​)=x∈Dc​∏​P(x∣θc​)
对 θ c \theta_c θc​进行极大似然估计(Maximum likelihood estimation,MLE),就是去寻找能最大化似然 P ( D c ∣ θ c ) P(D_c|\theta_c) P(Dc​∣θc​)的参数值 θ c ^ \hat{\theta_c} θc​^​。直观上看,极大似然估计是试图在 θ c \theta_c θc​所有可能的取值中,找到一个能使数据出现“可能性”最大的值。

1.4、对数似然

从公式可以看出,似然函数是很多个数相乘的形式。然而很多个数相乘并不容易计算容易造成下溢,不方便求导,通常对其求对数。使用对数似然(log-likelihood),连乘就可以写成连加的形式:
L ( θ c ) = l o g P ( D c ∣ θ c ) = ∑ x ∈ D c l o g P ( x ∣ θ c ) L(\theta_c)=log \; P(D_c|\theta_c)=\sum_{x \in D_c}log \; P(x|\theta_c) L(θc​)=logP(Dc​∣θc​)=x∈Dc​∑​logP(x∣θc​)

1.5、负对数似然

对数似然是对概率分布求对数,概率 P ( x ) P(x) P(x)的值为 [ 0 , 1 ] [0,1] [0,1]区间,取对数后为 ( − ∞ , 0 ] (- \infty ,0] (−∞,0]区间。再在这个前面加个符号,变成 [ 0 , ∞ ] [0,\infty] [0,∞]区间,就得到了负对数似然(Negative log-likelihood, NLL)
L ( θ c ) = − ∑ x ∈ D c l o g P ( x ∣ θ c ) L(\theta_c)=-\sum_{x \in D_c}log \; P(x|\theta_c) L(θc​)=−x∈Dc​∑​logP(x∣θc​)
这样就得到了负对数似然函数,我们的目标是要选择合适的参数 θ \theta θ使得这个函数的数值最小。

看到有个博客举了一个关于硬币的例子来解释什么是最大似然估计,我在这个基础上加工一下看看负对数似然是怎么回事。假设有一个形状不规则的硬币,我们不知道它正面朝上的概率是多少,用 θ \theta θ表示,为模型的参数。想要求得这个模型参数 θ \theta θ是多少合适,就需要数据来进行估计。于是拿这枚硬币抛了10次,得到的数据为:“反正正正正反正正正反”。根据这个实验的结果我们就可以得到负对数似然函数为:
L ( θ ) = − ( l o g ( 1 − θ ) + l o g ( θ ) + l o g ( θ ) + l o g ( θ ) + l o g ( θ ) + l o g ( 1 − θ ) + l o g ( θ ) + l o g ( θ ) + l o g ( θ ) + l o g ( 1 − θ ) ) = − ( 3 l o g ( 1 − θ ) + 7 l o g ( θ ) ) L(\theta)=-(log(1-\theta)+log(\theta)+log(\theta)+log(\theta)+log(\theta)+log(1-\theta)\\+log(\theta)+log(\theta)+log(\theta)+log(1-\theta))=-(3log(1-\theta)+7log(\theta)) L(θ)=−(log(1−θ)+log(θ)+log(θ)+log(θ)+log(θ)+log(1−θ)+log(θ)+log(θ)+log(θ)+log(1−θ))=−(3log(1−θ)+7log(θ))
而我们的目标是使得负对数似然损失函数的值越小越好,我们可以画出损失函数的图像为:

import numpy as np
import matplotlib.pyplot as plt
theta=np.arange(0,1,0.01)
y=-(3*np.log(1-theta)+7*np.log(theta))
plt.plot(theta, y, label="NNLLoss")
plt.xlabel("theta")
plt.ylabel("Loss")
plt.legend()
plt.show()

可以看出,在 θ = 0.7 \theta=0.7 θ=0.7时,负对数似然损失函数取得的值最小,至此就求出了负对数似然损失函数最小的参数取值。(这里正面朝上的概率竟然为0.7,与我们的常识不符呀,有可能是因为抛的次数太少了,或者它确实就是个不规则的硬币哈哈哈,不过都不重要)。

1.6、pytorch中的应用

Pytorch中对应的负对数似然损失函数为:

torch.nn.NLLLoss(weight=None, size_average=None, ignore_index=- 100, reduce=None, reduction='mean')

当网络的输出为每个类别的对数概率的时候才可以使用该损失函数,因此可以在网络的最后一层添加一个LogSoftmax层来获得对数概率。

如果不添加LogSoftmax层,也可以直接使用CrossEntropyLoss损失函数。即CrossEntropyLoss=LogSoftmax+NLLLoss

这个损失所使用的标签应该是 [ 0 , C − 1 ] [0, C-1] [0,C−1]范围内的一个类索引,其中C=类的数量。因此不需要使用one-hot编码(使用one-hot编码会错,这个在下面的代码中进行验证)。

reduction参数设置为none的时候,损失可以描述为:
l ( x , y ) = L = { l 1 , ⋯ , l N } T , l n = − w y n x n , y n w c = w e i g h t [ c ] ⋅ 1 { c ≠ i g n o r e _ i n d e x } \mathscr{l}(x,y)=L=\{l_1, \cdots ,l_N\}^T, \; \; \; l_n=-w_{y_n}x_{n,y_n}\;w_c=weight[c] \cdot1 \{c \neq ignore\_index\} l(x,y)=L={l1​,⋯,lN​}T,ln​=−wyn​​xn,yn​​wc​=weight[c]⋅1{c​=ignore_index}
其中, x x x是输入, y y y是目标, w w w是权重, N N N是批次大小。weight参数如果没有设置的话,默认为1。如果reduction不是none(默认是mean),那么:
l ( x , y ) = { ∑ n = 1 N 1 ∑ n = 1 N w w y n l n , if  r e d u c t i o n = ’mean’ ∑ n = 1 N l n , if  r e d u c t i o n = ’sum’ \mathscr{l}(x,y)=\begin{cases} \sum_{n=1}^N \frac{1}{\sum_{n=1}^N w_{w_{yn}}}l_n, & \text{if $reduction$ = 'mean'} \\ \sum_{n=1}^N l_n, & \text{if $reduction$ = 'sum'} \end{cases} l(x,y)={∑n=1N​∑n=1N​wwyn​​1​ln​,∑n=1N​ln​,​if reduction = ’mean’if reduction = ’sum’​
下面用一段代码看看torch.nn.NLLLoss如何使用:

import torch
#就是求完softmax后对每一个数求log
logsoftmax=torch.nn.LogSoftmax()
lossFun=torch.nn.NLLLoss()
input=torch.rand(3,5,requires_grad=True)
print(input)
tensor([[0.1805, 0.5916, 0.0331, 0.4528, 0.0881],[0.5859, 0.1316, 0.1232, 0.5722, 0.6810],[0.8561, 0.3857, 0.6185, 0.5923, 0.4002]])
lsoftmax=logsoftmax(input)
lsoftmax
tensor([[-1.7221, -1.3110, -1.8695, -1.4497, -1.8145],[-1.4703, -1.9246, -1.9330, -1.4840, -1.3752],[-1.3391, -1.8094, -1.5766, -1.6028, -1.7949]])
#不使用one-hot编码
label=torch.tensor([1,0,4])
loss=lossFun(lsoftmax,label)
loss
tensor(1.5254)
#测试使用one-hot编码
onehot_label=torch.tensor([[0.0,1.0,0.0,0.0,0.0],[1.0,0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0,1.0]])
lossFun=torch.nn.NLLLoss()
loss=lossFun(lsoftmax,onehot_label)
loss
RuntimeError: 0D or 1D target tensor expected, multi-target not supported

模型输出在经过LogSoftmax函数后,在经过负对数似然函数的计算过程为:
L o s s = − ( − 1.3110 − 1.4703 − 1.7949 ) / 3 = 1.5254 Loss=-(-1.3110-1.4703-1.7949)/3=1.5254 Loss=−(−1.3110−1.4703−1.7949)/3=1.5254
因此在pytorch中,nn.NLLLoss()函数虽然叫负对数似然函数,但是该函数并没有进行对数运算,而须在最后一层的激活函数上使用nn.LogSoftmax()函数,然后nn.NLLLoss()函数只是做了求和取平均再取反的运算。因此在分类问题中要使用nn.NLLLoss(),必须和nn.LogSoftmax()函数一起使用。当然也可以直接使用nn.CrossEntropyLoss()

在使用nn.NLLLoss()时使用one-hot编码会报错,在使用nn.CrossEntropyLoss()的时候使用one-hot不会报错。

2、交叉熵损失函数

下面看一看交叉熵损失以及如何在Pytorch中使用它。

交叉熵主要是用来判定实际的输出与期望的输出的接近程度。要理解交叉熵,需要先理解以下几个概念。

2.1、信息量

信息是用来消除随机不确定性的东西,也就是说衡量信息量的大小就是看这个信息消除不确定性的程度。

“人会死”,这条信息没有减少不确定性,因为人肯定会死亡的,信息量为0。;“明天会下雨”,我们不知道明天到底会不会下雨,因此明天会下雨的不确定性因素很大,而这句话消除了明天会下雨的不确定性,以按照定义,这句话的信息量很大。

综上所述:信息量的大小与信息发生的概率成反比。概率越大,信息量越小。概率越小,信息量越大。设某一事件发生的概率是 p ( x ) p(x) p(x),其信息量表示为:
I ( x ) = − l o g ( p ( x ) ) I(x)=-log(p(x)) I(x)=−log(p(x))

2.2、信息熵

信息熵也被称为熵,用来表示所有信息量的期望,即:
H ( X ) = − ∑ i = 1 n p ( x i ) l o g ( p ( x i ) ) H(X)=-\sum_{i=1}^np(x_i)log(p(x_i)) H(X)=−i=1∑n​p(xi​)log(p(xi​))
举一个例子,使用明天的天气概率来计算熵:

序号 事件 概率p 信息量
1 晴天 0.5 -log(0.5)
2 雨天 0.2 -log(0.2)
3 多云 0.3 -log(0.3)

则熵为:
H ( X ) = − ( 0.5 ∗ l o g ( 0.5 ) + 0.2 ∗ l o g ( 0.2 ) + 0.3 ∗ l o g ( 0.3 ) ) H(X)=-(0.5*log(0.5)+0.2*log(0.2)+0.3*log(0.3)) H(X)=−(0.5∗log(0.5)+0.2∗log(0.2)+0.3∗log(0.3))

2.3、相对熵(KL散度)

如果对于同一个随机变量X有两个单独的概率分布 P ( X ) P(X) P(X)和 Q ( X ) Q(X) Q(X),其中 Q ( X ) Q(X) Q(X)表示模型所预测的分布, P ( X ) P(X) P(X)表示样本的真实分布。则KL散度用来衡量这两个概率分布之间的差异。计算公式为:
D K L ( p ∣ ∣ q ) = ∑ i = 1 n p ( x i ) l o g ( p ( x i ) q ( x i ) ) D_{KL}(p||q)=\sum_{i=1}^np(x_i)log(\frac{p(x_i)}{q(x_i)}) DKL​(p∣∣q)=i=1∑n​p(xi​)log(q(xi​)p(xi​)​)
KL散度越小,表示 P ( X ) P(X) P(X)与 Q ( X ) Q(X) Q(X)的分布更加接近,可以通过反复训练 Q ( X ) Q(X) Q(X)的分布逼近 P ( X ) P(X) P(X)。

2.4、交叉熵

将KL散度展开为:
D K L ( p ∣ ∣ q ) = ∑ i = 1 n p ( x i ) l o g ( p ( x i ) q ( x i ) ) = ∑ i = 1 n p ( x i ) l o g ( p ( x i ) ) − ∑ i = 1 n p ( x i ) l o g ( q ( x i ) ) = − H ( p ( x ) ) + [ − ∑ i = 1 n p ( x i ) l o g ( q ( x i ) ) ] D_{KL}(p||q)=\sum_{i=1}^np(x_i)log(\frac{p(x_i)}{q(x_i)})\\ =\sum_{i=1}^n p(x_i)log(p(x_i))-\sum_{i=1}^n p(x_i)log(q(x_i))\\=-H(p(x))+[-\sum_{i=1}^n p(x_i)log(q(x_i))] DKL​(p∣∣q)=i=1∑n​p(xi​)log(q(xi​)p(xi​)​)=i=1∑n​p(xi​)log(p(xi​))−i=1∑n​p(xi​)log(q(xi​))=−H(p(x))+[−i=1∑n​p(xi​)log(q(xi​))]
其中 H ( p ( x ) ) H(p(x)) H(p(x))表示信息熵, − ∑ i = 1 n p ( x i ) l o g ( q ( x i ) ) -\sum_{i=1}^n p(x_i)log(q(x_i)) −∑i=1n​p(xi​)log(q(xi​))代表交叉熵,则KL散度=交叉熵-信息熵

进而得到交叉熵的公式为:
H ( p , q ) = − ∑ i = 1 n p ( x i ) l o g ( q ( x i ) ) H(p,q)=-\sum_{i=1}^n p(x_i)log(q(x_i)) H(p,q)=−i=1∑n​p(xi​)log(q(xi​))
而在训练过程中,标签通常采用one-hot编码表示,而样本真实分布的概率 p ( x i ) p(x_i) p(xi​)为1。那么就可以得到交叉熵简化后的公式为:
H ( p , q ) = − ∑ i = 1 n l o g ( q ( x i ) ) H(p,q)=-\sum_{i=1}^n log(q(x_i)) H(p,q)=−i=1∑n​log(q(xi​))
这与上面推导的负对数似然损失函数是一样的哇!!!

2.5、pytorch中的应用

Pytorch中对应的交叉熵损失函数为:

torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=- 100, reduce=None, reduction='mean', label_smoothing=0.0)

计算公式为,当reduction设置为none时,表示为
l ( x , y ) = L = { l 1 , ⋯ , l N } T , l n = − ∑ c = 1 C w c l o g e x p ( x n , c ) ∑ i = 1 C e x p ( x n , i ) y n , c \mathscr{l}(x,y)=L=\{l_1, \cdots ,l_N\}^T, \; \; \; l_n=-\sum_{c=1}^C w_clog\frac{exp(x_{n,c})}{\sum_{i=1}^Cexp(x_{n,i})}y_{n,c} l(x,y)=L={l1​,⋯,lN​}T,ln​=−c=1∑C​wc​log∑i=1C​exp(xn,i​)exp(xn,c​)​yn,c​
如果reduction不是none(默认是mean),那么:
l ( x , y ) = { ∑ n = 1 N l n N , if  r e d u c t i o n = ’mean’ ∑ n = 1 N l n , if  r e d u c t i o n = ’sum’ \mathscr{l}(x,y)=\begin{cases} \frac{\sum_{n=1}^Nl_n}{N}, & \text{if $reduction$ = 'mean'} \\ \sum_{n=1}^N l_n, & \text{if $reduction$ = 'sum'} \end{cases} l(x,y)={N∑n=1N​ln​​,∑n=1N​ln​,​if reduction = ’mean’if reduction = ’sum’​
在使用交叉熵损失函数的时,网络的最后一层不需要加softmax层,因为pytorch中的CrossEntropyLoss()帮助我们实现了该操作,如果添加了softmax,那么就重复了,但效果并不会有什么影响。下面我们看一下交叉熵损失函数的计算过程,以及使用pytorch的实现过程。

根据交叉熵损失函数手动计算

首先假设batch_size为4,分类为3的网络最后一层的输出。

import torch
input=torch.rand(4,3)
input
tensor([[0.0515, 0.6730, 0.2852],[0.0362, 0.3434, 0.7450],[0.7136, 0.6566, 0.2402],[0.6989, 0.0917, 0.7857]])

根据交叉熵损失函数,计算完softmax之后还需要计算每一个值的log数值,因此我们可以使用LogSoftmax函数来计算。

output=torch.nn.LogSoftmax(dim=1)(input)
output
tensor([[-1.4170, -0.7956, -1.1834],[-1.4796, -1.1724, -0.7708],[-0.9429, -0.9999, -1.4163],[-0.9691, -1.5762, -0.8823]])

假设标签为:

[1,0,2,1]

根据交叉熵的计算公式,最终的损失为:
l o s s = − ( − 0.7956 − 1.4796 − 1.4163 − 1.5762 ) / 4 = 1.3169 loss=-(-0.7956-1.4796-1.4163-1.5762)/4=1.3169 loss=−(−0.7956−1.4796−1.4163−1.5762)/4=1.3169
使用pytorch进行计算

#未使用one-hot编码
target = torch.tensor([1,0,2,1])
loss = torch.nn.CrossEntropyLoss()
output = loss(input, target)
output
tensor(1.3169)

上述为未使用one-hot编码,下面试一下标签使用one-hot编码:

#未使用one-hot编码
target = torch.tensor([[0.0,1.0,0.0],[1.0,0.0,0.0],[0.0,0.0,1.0],[0.0,1.0,0.0]])
loss = torch.nn.CrossEntropyLoss()
output = loss(input, target)
output
tensor(1.3169)

可见在使用交叉熵损失函数时,标签可以使用one-hot编码,也可以不使用one-hot编码。

3、使用总结

虽然负对数似然损失函数和交叉熵损失函数的公式类似,但是他们在pytorch中的使用有一定的差别,下面是对pytorch中的nn.NLLLoss()nn.CrossEntropyLoss()的使用总结:

  1. 在使用nn.NLLLoss()是,需要结合nn.LogSoftmax()一起使用,而nn.CrossEntropyLoss()不需要。
  2. 使用nn.CrossEntropyLoss()时,网络的最后一层不需要加softmax层。
  3. 使用nn.NLLLoss()是,标签不能使用one-hot编码标签,在使用nn.CrossEntropyLoss()时,可以使用one-hot标签,也可以不使用one-hot标签。

参考:

1.https://www.jianshu.com/p/269ad3103c41?utm_campaign=hugo&utm_content=note&utm_medium=reader_share&utm_source=qq

2.https://blog.csdn.net/u011508640/article/details/72815981

3.https://www.jianshu.com/p/472c82eb8c21

损失函数-负对数似然和交叉熵(Pytorch中的应用)相关推荐

  1. 损失函数——负对数似然

    阅读本文可以了解如下内容: 似然 似然估计 对数似然 负对数似然 1. 似然 在开始之前需要区分一个知识:似然(likelihood)和概率(probability).概率是一个事件发生的可能性,而似 ...

  2. 负对数似然(negative log-likelihood, NLL)

    目录 1. 似然 2. 最大似然估计 3. 对数似然 4. 负对数似然 5. 补充说明 Reference 1. 似然 似然与概率不同.概率是指一个事件发生的可能性,描述的是对象是事件:似然是指影响事 ...

  3. 交叉熵损失函数、修正Huber损失、极大似然估计、负对数似然、似然与交叉熵、KL散度

    交叉熵损失函数.修正Huber损失.极大似然估计.负对数似然.似然与交叉熵.KL散度 目录

  4. 极大似然估计(Maximum Likelihood Estimattion Theory)是什么?极大似然估计的本质思想是什么?为什么极大似然可以作为损失函数使用?负对数似然损失函数(Negative

    极大似然估计(Maximum Likelihood Estimattion Theory)是什么?极大似然估计的本质思想是什么?为什么极大似然可以作为损失函数使用?负对数似然损失函数(Negative ...

  5. 负对数似然(negative log-likelihood)

    negative log likelihood 文章目录 negative log likelihood 似然函数(likelihood function) Overview Definition 离 ...

  6. sklearn基于make_scorer函数为Logistic模型构建自定义损失函数+代码实战(二元交叉熵损失 binary cross-entropy loss)

    sklearn基于make_scorer函数为Logistic模型构建自定义损失函数+代码实战(二元交叉熵损失 binary cross-entropy loss) # 广义线性模型中的各种连接函数: ...

  7. 负对数似然 交叉熵 mse mae的区别

    交叉熵的介绍见https://blog.csdn.net/jzwei023/article/details/115496906?spm=1001.2014.3001.5501 交叉熵 vs 二阶Los ...

  8. pytorch_lesson10 二分类交叉熵损失函数及调用+多分类交叉熵损失函数及调用

    注:仅仅是学习记录笔记,搬运了学习课程的ppt内容,本意不是抄袭!望大家不要误解!纯属学习记录笔记!!!!!! 文章目录 一.机器学习中的优化思想 二.回归:误差平方和SSE 三.二分类交叉熵损失函数 ...

  9. 机器学习中的各种损失函数(Hinge loss,交叉熵,softmax)

    机器学习中的各种损失函数 SVM multiclass loss(Hinge loss) 这是一个合页函数,也叫Hinge function,loss 函数反映的是我们对于当前分类结果的不满意程度.在 ...

最新文章

  1. C++ int (*s[10])(int) 表示什么?
  2. POJ 1252 Euro Efficiency
  3. vuex 在非组件中调用 mutations 方法
  4. 异常:Invalid or unexpected token
  5. typedef 的使用
  6. 【Python机器学习及实践】笔记
  7. L1-041__048
  8. pycharm查询mysql数据库_pycharm访问mysql数据库的方法步骤
  9. Linux系统学习之兴趣驱动
  10. 计算机显示器本身物理分辨率,电脑显示器常见的分辨率是多少
  11. 移动端微博 php源码,jQuery仿手机新浪微博聊天界面
  12. MySql常见数据类型及五大约束
  13. 澳门大学计算机qs排名,澳门大学世界排名(澳门科技大学qs世界排名2021)
  14. 数字翻译成英语JavaScript
  15. 测试小故事48:想当然
  16. e2e 测试 出现的错误
  17. 优酷电脑客户端占内存很大,清理内存
  18. 用python写个程序送给女朋友_用 Python 哄女朋友开心!你觉得可行嘛?
  19. QGIS制图表达-符号大小随比例尺变化
  20. 2018年大学计算机一级考试成绩,全国计算机一级考试成绩查询入口

热门文章

  1. Office Word 不显示 Citavi 插件,如何修复?
  2. xshell的一些基本操作
  3. windows IDT
  4. python 有限域函数库_python – Sympy:在有限域中求解矩阵
  5. 程序员的种种崩溃瞬间
  6. 安居客 楼盘信息 项目代码-
  7. Cholesky分解(Matlab代码实现)
  8. JAVA 删除File文件中的内容。
  9. C++ 什么时候调用析构函数和构造函数
  10. 安装Mongodb出现2503/2502错误