极大似然法
考虑我们在训练一个参数为 ϕ \boldsymbol\phi ϕ、输入为 x \mathbf{x} x的模型 f [ x , ϕ ] \mathbf{f}[\mathbf{x},\boldsymbol{\phi}] f[x,ϕ]。如果转换一下视角,计算模型在给定输入 x \mathbf{x} x时对可能的输出 y \mathbf{y} y计算条件概率分布 P r ( y ∣ x ) Pr(\mathbf{y}|\mathbf{x}) Pr(y∣x)。对每一个样本 ( x i , y i ) (\mathbf{x_i},\mathbf{y_i}) (xi,yi),损失函数鼓励在分布 P r ( y i ∣ x i ) Pr(\mathbf{y_i}|\mathbf{x_i}) Pr(yi∣xi) 下输出 y i \mathbf{y_i} yi时有高的概率。
但是如何适配模型
f
[
x
,
ϕ
]
\mathbf{f}[\mathbf{x},\boldsymbol{\phi}]
f[x,ϕ]去计算概率分布呢?我们首先选择一个定义在输出
y
\mathbf{y}
y的值域内的参数化概率分布
P
r
(
y
∣
θ
)
Pr(\mathbf{y}|\boldsymbol{\theta})
Pr(y∣θ), 再基于训练样本让模型对概率分布的参数进行估计。于是模型对每一个训练输入
x
i
\mathbf{x_i}
xi计算得到不同的分布参数
θ
i
=
f
[
x
i
,
ϕ
]
\boldsymbol{\theta_i} = \mathbf{f}[\mathbf{x_i}, \boldsymbol{\phi}]
θi=f[xi,ϕ],其训练输出
y
i
\mathbf{y_i}
yi在其相应的概率分布
P
r
(
y
i
∣
θ
i
)
Pr(\mathbf{y_i}|\boldsymbol{\theta_i})
Pr(yi∣θi)下应该有较高的概率。所以,我们会选择使所有的
I
I
I个样本的组合概率最大的模型参数:
ϕ
^
=
argmax
ϕ
[
∏
i
=
1
I
Pr
(
y
i
∣
x
i
)
]
=
argmax
ϕ
[
∏
i
=
1
I
Pr
(
y
i
∣
θ
i
)
]
=
argmax
ϕ
[
∏
i
=
1
I
Pr
(
y
i
∣
f
[
x
i
,
ϕ
]
)
]
(
1
)
\begin{aligned} \hat{\boldsymbol{\phi}} & =\underset{\phi}{\operatorname{argmax}}\left[\prod_{i=1}^I \operatorname{Pr}\left(\mathbf{y}_i \mid \mathbf{x}_i\right)\right] \\ & =\underset{\phi}{\operatorname{argmax}}\left[\prod_{i=1}^I \operatorname{Pr}\left(\mathbf{y}_i \mid \boldsymbol{\theta}_i\right)\right] \\ & =\underset{\phi}{\operatorname{argmax}}\left[\prod_{i=1}^I \operatorname{Pr}\left(\mathbf{y}_i \mid \mathbf{f}\left[\mathbf{x}_i, \boldsymbol{\phi}\right]\right)\right] \qquad (1) \end{aligned}
ϕ^=ϕargmax[i=1∏IPr(yi∣xi)]=ϕargmax[i=1∏IPr(yi∣θi)]=ϕargmax[i=1∏IPr(yi∣f[xi,ϕ])](1)
上式中的组合概率项被称为参数的似然(likelihood),上式即极大似然法(Maximum likelihood criterion),也被称为极大似然估计(Maximum likelihood estimation, MLE)。
极大似然法有两个假设,即通常所说的假设数据是独立同分布的(independent and identically distributed (i.i.d.))。即首先假设数据来自相同的数据分布,其次假设在给定输入时条件概率
P
r
(
y
i
∣
x
i
)
Pr(\mathbf{y_i}|\mathbf{x_i})
Pr(yi∣xi) 是独立的,所以训练数据的总似然满足下式的分解:
P
r
(
y
1
,
y
2
,
…
,
y
I
∣
x
1
,
x
2
,
…
,
x
I
)
=
∏
i
=
1
I
Pr
(
y
i
∣
x
i
)
(
2
)
Pr(\mathbf{y_1}, \mathbf{y_2}, \ldots, \mathbf{y_I}|\mathbf{x_1}, \mathbf{x_2},\ldots,\mathbf{x_I}) = \prod_{i=1}^I \operatorname{Pr}\left(\mathbf{y}_i \mid \mathbf{x}_i\right) \qquad (2)
Pr(y1,y2,…,yI∣x1,x2,…,xI)=i=1∏IPr(yi∣xi)(2)
但公式(1)的最大似然法不是很实用,因为每一项
P
r
(
y
i
∣
f
[
x
i
,
ϕ
]
)
Pr(\mathbf{y_i}|\mathbf{f}\left[\mathbf{x}_i, \boldsymbol{\phi}\right])
Pr(yi∣f[xi,ϕ])可能会很小,这样许多项的乘积会非常非常小,在实际计算的精度很难去量化它,所以一般会使用最大对数似然:
ϕ
^
=
argmax
ϕ
[
∏
i
=
1
I
Pr
(
y
i
∣
f
[
x
i
,
ϕ
]
)
]
=
argmax
ϕ
[
log
[
∏
i
=
1
I
Pr
(
y
i
∣
f
[
x
i
,
ϕ
]
)
]
]
=
argmax
ϕ
[
∑
i
=
1
I
log
[
Pr
(
y
i
∣
f
[
x
i
,
ϕ
]
)
]
]
(
3
)
\begin{aligned} \hat{\boldsymbol{\phi}} & =\underset{\phi}{\operatorname{argmax}}\left[\prod_{i=1}^I \operatorname{Pr}\left(\mathbf{y}_i \mid \mathbf{f}\left[\mathbf{x}_i, \boldsymbol{\phi}\right]\right)\right] \\ & =\underset{\phi}{\operatorname{argmax}}\left[\log \left[ \prod_{i=1}^I \operatorname{Pr}\left(\mathbf{y}_i \mid \mathbf{f}\left[\mathbf{x}_i, \boldsymbol{\phi}\right]\right) \right]\right] \\ & =\underset{\phi}{\operatorname{argmax}}\left[\sum_{i=1}^I \log \left[ \operatorname{Pr}\left(\mathbf{y}_i \mid \mathbf{f}\left[\mathbf{x}_i, \boldsymbol{\phi}\right]\right) \right]\right] \qquad (3) \end{aligned}
ϕ^=ϕargmax[i=1∏IPr(yi∣f[xi,ϕ])]=ϕargmax[log[i=1∏IPr(yi∣f[xi,ϕ])]]=ϕargmax[i=1∑Ilog[Pr(yi∣f[xi,ϕ])]](3)
而通常在进行模型训练时,我们一般会最小化损失,所以会将上述的最大对数似然添加一个负号变成负对数似然法(negetive log-likelihood criterion):
ϕ
^
=
argmin
ϕ
[
−
∑
i
=
1
I
log
[
Pr
(
y
i
∣
f
[
x
i
,
ϕ
]
)
]
]
=
argmin
ϕ
[
L
[
ϕ
]
]
(
4
)
\begin{aligned} \hat{\boldsymbol{\phi}} & =\underset{\phi}{\operatorname{argmin}}\left[-\sum_{i=1}^I \log \left[ \operatorname{Pr}\left(\mathbf{y}_i \mid \mathbf{f}\left[\mathbf{x}_i, \boldsymbol{\phi}\right]\right) \right]\right] \\ & = \underset{\phi}{\operatorname{argmin}}\left[ L[\boldsymbol{\phi}] \right] \qquad (4) \end{aligned}
ϕ^=ϕargmin[−i=1∑Ilog[Pr(yi∣f[xi,ϕ])]]=ϕargmin[L[ϕ]](4)
二分类
二分类(binary classification)的目标是给数据 x \mathbf{x} x一个0或1的标签 y ∈ { 0 , 1 } y \in \{0, 1\} y∈{0,1}。比如我们会判断一封邮件是否是垃圾邮件,一个西瓜是好瓜还是坏瓜。
我们用负对数似然来推导出二分类的损失函数,首先在标签y的值域选择一个概率分布,伯努利分布(Bernouli distribution)刚好是一个合适的选择,它只有一个参数
λ
∈
[
0
,
1
]
\lambda \in [0, 1]
λ∈[0,1]表示y=1的概率:
Pr
(
y
∣
λ
)
=
{
1
−
λ
y
=
0
λ
y
=
1
,
(
5
)
\operatorname{Pr}(y \mid \lambda)=\left\{\begin{array}{ll} 1-\lambda & y=0 \\ \lambda & y=1 \end{array},\right. \qquad (5)
Pr(y∣λ)={1−λλy=0y=1,(5)
上式也可以等价地写成更紧凑的指数形式:
P
r
(
y
∣
λ
)
=
(
1
−
λ
)
1
−
y
⋅
λ
y
(
6
)
Pr(y|\lambda) = (1-\lambda)^{1-y} \cdot \lambda^y \qquad (6)
Pr(y∣λ)=(1−λ)1−y⋅λy(6)
接着, 我们用机器学习模型
f
[
x
,
ϕ
]
f[\mathbf{x}, \boldsymbol{\phi}]
f[x,ϕ]来预测概率分布的参数
λ
\lambda
λ,因为
λ
\lambda
λ的值域为[0, 1],但是我们并不能保证模型输出在这个范围内,于是我们使用sigmoid函数将模型的输出映射到[0, 1]:
s
i
g
[
z
]
=
1
1
+
exp
[
−
z
]
(
7
)
sig[z] = \frac{1}{1 + \exp[-z]} \qquad (7)
sig[z]=1+exp[−z]1(7)
所以模型预测的概率分布参数
λ
=
s
i
g
[
f
[
x
,
ϕ
]
]
\lambda = sig[f[\mathbf{x}, \boldsymbol{\phi}]]
λ=sig[f[x,ϕ]],式(6)的似然变成了:
P
r
(
y
∣
x
)
=
(
1
−
s
i
g
[
f
[
x
,
ϕ
]
]
)
1
−
y
⋅
s
i
g
[
f
[
x
,
ϕ
]
]
y
(
8
)
Pr(y|\mathbf{x}) = (1 - sig[f[\mathbf{x}, \boldsymbol{\phi} ]])^{1-y} \ \cdot sig[f[\mathbf{x}, \boldsymbol{\phi}]]^y \qquad (8)
Pr(y∣x)=(1−sig[f[x,ϕ]])1−y ⋅sig[f[x,ϕ]]y(8)
所以二分类的损失函数为在训练集上的负对数似然:
L
[
ϕ
]
=
∑
i
=
1
I
−
(
1
−
y
i
)
log
[
(
1
−
s
i
g
[
f
[
x
,
ϕ
]
]
−
y
i
log
[
s
i
g
[
f
[
x
,
ϕ
]
]
]
(
9
)
L[\boldsymbol{\phi}] =\sum_{i=1}^I -(1-y_i) \log [(1 - sig[f[\mathbf{x}, \boldsymbol{\phi} ]]\ - y_i \log \left[sig[f[\mathbf{x}, \boldsymbol{\phi}]] \right] \qquad(9)
L[ϕ]=i=1∑I−(1−yi)log[(1−sig[f[x,ϕ]] −yilog[sig[f[x,ϕ]]](9)
上式也被称为二元交叉熵损失(binary cross-entropy loss)。
多分类
多分类(multiclass classification)是将数据 x \mathbf{x} x分类到K>2个类别中的一个,即 y ∈ { 1 , 2 , … , K } y \in \{ 1, 2, \ldots, K \} y∈{1,2,…,K}, 比如预测手写数字是0-9里的哪一个,预测一个不完整句子的下一个可能词是什么。
我们再次尝试用负对数似然来推导出多分类的损失函数,首先在标签y的值域选择一个概率分布,因为
y
∈
{
1
,
2
,
…
,
K
}
y \in \{ 1, 2, \ldots, K \}
y∈{1,2,…,K},所以选择类别分布(categorical distribution),它有K个参数
λ
1
,
λ
2
,
…
,
λ
K
\lambda_1, \lambda_2, \ldots, \lambda_K
λ1,λ2,…,λK来决定每个类别的概率,这些参数的值域都为[0, 1],并且它们的和为1以确保概率分布的有效性:
P
r
(
y
=
k
)
=
λ
k
(
10
)
Pr(y=k) = \lambda_k \qquad (10)
Pr(y=k)=λk(10)
接着, 我们用有K个输出的模型
f
[
x
,
ϕ
]
f[\mathbf{x}, \boldsymbol{\phi}]
f[x,ϕ]来预测K个参数,我们同样无法确保模型的输出满足类别分布的要求,与二分类一样,我们也使用一个映射函数,这次我们选取的函数为softmax函数,它的输入为长度为K的任意向量,其输出为同样长度的向量,每个向量的值都在[0,1]范围内并且向量元素之和为1。第k个softmax函数的输出为:
softmax
k
[
z
]
=
exp
[
z
k
]
∑
k
′
=
1
K
exp
[
z
k
′
]
(
11
)
\text{softmax}_k[\mathbf{z}] = \frac {\exp[z_k]}{\sum_{k^{\prime}=1}^K \exp[z_{k^{\prime}}] } \qquad (11)
softmaxk[z]=∑k′=1Kexp[zk′]exp[zk](11)
于是输入
x
\mathbf{x}
x得到标签y的似然为:
P
r
(
y
=
k
∣
x
)
=
softmax
k
[
f
[
x
,
ϕ
]
]
(
12
)
Pr(y=k|\mathbf{x}) = \text{softmax}_k [\mathbf{f}[\mathbf{x}, \boldsymbol{\phi}] ] \qquad (12)
Pr(y=k∣x)=softmaxk[f[x,ϕ]](12)
因此得到多分类的损失函数为下式定义的在训练集上的负对数似然:
L
[
ϕ
]
=
−
∑
i
=
1
I
log
[
softmax
y
i
[
f
[
x
i
,
ϕ
]
]
]
=
−
∑
i
=
1
I
(
f
y
i
[
x
i
,
ϕ
]
−
log
[
∑
k
′
=
1
K
exp
[
f
k
′
[
x
i
,
ϕ
]
]
]
)
(
13
)
\begin{aligned} L[\boldsymbol{\phi}] &= - \sum^I_{i=1} \log [\text{softmax}_{y_i} [\mathbf{f}[x_i, \boldsymbol{\phi}] ] ] \\ &=- \sum^I_{i=1} \left(f_{y_i}[x_i, \boldsymbol{\phi}] - \log \left[\sum_{k^{\prime}=1}^K \exp[f_{k^{\prime}} [x_i, \boldsymbol{\phi}]] \right] \right) \qquad (13) \end{aligned}
L[ϕ]=−i=1∑Ilog[softmaxyi[f[xi,ϕ]]]=−i=1∑I(fyi[xi,ϕ]−log[k′=1∑Kexp[fk′[xi,ϕ]]])(13)
上式中的
f
k
[
x
i
,
ϕ
]
f_{k}[x_i, \boldsymbol{\phi}]
fk[xi,ϕ]是指神经网络的第k个输出,而上式也被称为多分类交叉熵损失(multiclass cross-entropy loss)。
交叉熵与负对数似然
在前面推导二分类和多分类的损失函数时,提到它们也被称为交叉熵损失,事实上交叉熵损失与使用负对数似然是等价的。
交叉熵损失的思想是找到使得观测数据y的经验分布q(y)和模型分布
P
r
(
y
∣
θ
)
Pr(y|\boldsymbol{\theta})
Pr(y∣θ)距离最小的参数
θ
\boldsymbol{\theta}
θ。两个概率分布q(z)和p(z)的距离可以使用KL散度(Kullback-Leibler(KL) divergence)来评估:
D
K
L
[
q
∣
∣
p
]
=
∫
q
(
z
)
log
[
q
(
z
)
p
(
z
)
]
d
z
=
∫
−
∞
∞
q
(
z
)
log
[
q
(
z
)
]
d
z
−
∫
−
∞
∞
q
(
z
)
log
[
p
(
z
)
]
d
z
(
14
)
\begin{aligned} D_{KL}[q||p] & = \int q(z) \log \left[ \frac{q(z)}{p(z)} \right] dz \\ &=\int_{-\infty}^{\infty} q(z) \log[q(z)] dz - \int_{-\infty}^{\infty} q(z) \log[p(z)] dz \end{aligned} \qquad (14)
DKL[q∣∣p]=∫q(z)log[p(z)q(z)]dz=∫−∞∞q(z)log[q(z)]dz−∫−∞∞q(z)log[p(z)]dz(14)
数据集
{
y
i
}
i
=
1
I
\{y_i\}^I_{i=1}
{yi}i=1I的经验数据分布可用下式来表示:
q
(
y
)
=
1
I
∑
i
=
1
I
δ
[
y
−
y
i
]
(
15
)
q(y) = \frac{1}{I} \sum^I_{i=1} \delta [y - y_i] \qquad (15)
q(y)=I1i=1∑Iδ[y−yi](15)
上式中的
δ
[
⋅
]
\delta[\cdot]
δ[⋅]是Dirac delta函数(Dirac delta函数
δ
[
z
]
\delta [\mathbf{z}]
δ[z](即信号与系统里说的脉冲函数)的面积为1且全部集中在
z
=
0
\mathbf{z}=\mathbf{0}
z=0处,有N个元素的数据集可以被看作对包括N个中心为
x
i
\mathbf{x}_i
xi的delta函数求和并用1/N做归一化的概率分布(如上式所示意),delta函数的一个关键性质是
∫
f
[
x
]
δ
[
x
−
x
0
]
d
x
=
f
[
x
0
]
\int f[\mathbf{x}] \delta [\mathbf{x} - \mathbf{x}_0] d\mathbf{x} = f[\mathbf{x}_0]
∫f[x]δ[x−x0]dx=f[x0])。
我们想要减少模型分布
P
r
(
y
∣
θ
)
Pr(y|\boldsymbol{\theta})
Pr(y∣θ)和上述经验分布的KL散度:
θ
^
=
argmin
θ
[
∫
−
∞
∞
q
(
y
)
log
[
q
(
y
)
]
d
y
−
∫
−
∞
∞
q
(
y
)
log
[
Pr
(
y
∣
θ
)
]
d
y
]
=
argmin
θ
[
−
∫
−
∞
∞
q
(
y
)
log
[
Pr
(
y
∣
θ
)
]
d
y
]
,
(
16
)
\begin{aligned} \hat{\boldsymbol{\theta}} & =\underset{\boldsymbol{\theta}}{\operatorname{argmin}}\left[\int_{-\infty}^{\infty} q(y) \log [q(y)] d y-\int_{-\infty}^{\infty} q(y) \log [\operatorname{Pr}(y \mid \boldsymbol{\theta})] d y\right] \\ & =\underset{\boldsymbol{\theta}}{\operatorname{argmin}}\left[-\int_{-\infty}^{\infty} q(y) \log [\operatorname{Pr}(y \mid \boldsymbol{\theta})] d y\right], \qquad (16) \end{aligned}
θ^=θargmin[∫−∞∞q(y)log[q(y)]dy−∫−∞∞q(y)log[Pr(y∣θ)]dy]=θargmin[−∫−∞∞q(y)log[Pr(y∣θ)]dy],(16)
上式的第一行里的第一项因为它不依赖于
θ
\boldsymbol{\theta}
θ所以消失了,剩下的第二项被称为交叉熵(cross-entropy)。
将式(15)代入到上式:
θ
^
=
argmin
θ
[
−
∫
−
∞
∞
(
1
I
∑
i
=
1
I
δ
[
y
−
y
i
]
)
log
[
Pr
(
y
∣
θ
)
]
d
y
]
=
argmin
θ
[
−
1
I
∑
i
=
1
I
log
[
Pr
(
y
i
∣
θ
)
]
]
=
argmin
θ
[
−
∑
i
=
1
I
log
[
Pr
(
y
i
∣
θ
)
]
]
.
(
17
)
\begin{aligned} \hat{\boldsymbol{\theta}} & =\underset{\boldsymbol{\theta}}{\operatorname{argmin}}\left[-\int_{-\infty}^{\infty}\left(\frac{1}{I} \sum_{i=1}^I \delta\left[y-y_i\right]\right) \log [\operatorname{Pr}(y \mid \boldsymbol{\theta})] d y\right] \\ & =\underset{\boldsymbol{\theta}}{\operatorname{argmin}}\left[-\frac{1}{I} \sum_{i=1}^I \log \left[\operatorname{Pr}\left(y_i \mid \boldsymbol{\theta}\right)\right]\right] \\ & =\underset{\boldsymbol{\theta}}{\operatorname{argmin}}\left[-\sum_{i=1}^I \log \left[\operatorname{Pr}\left(y_i \mid \boldsymbol{\theta}\right)\right]\right] . \qquad (17) \end{aligned}
θ^=θargmin[−∫−∞∞(I1i=1∑Iδ[y−yi])log[Pr(y∣θ)]dy]=θargmin[−I1i=1∑Ilog[Pr(yi∣θ)]]=θargmin[−i=1∑Ilog[Pr(yi∣θ)]].(17)
上面的第一行到第二行利用了delta函数的性质,第二行到第三行是因为系数1/I不影响最小值的位置。
在机器学习中,分布参数
θ
\boldsymbol{\theta}
θ由模型
f
[
x
i
,
ϕ
]
\mathbf{f}[\mathbf{x_i}, \boldsymbol{\phi}]
f[xi,ϕ]计算得到,于是我们将式(17)可变成下式:
ϕ
^
=
argmin
ϕ
[
−
∑
i
=
1
I
log
[
Pr
(
y
i
∣
f
[
x
i
,
ϕ
]
)
]
]
\hat{\boldsymbol{\phi}}= \underset{\boldsymbol{\phi}}{\operatorname{argmin}}\left[-\sum_{i=1}^I \log \left[\operatorname{Pr}\left(y_i \mid \mathbf{f}[\mathbf{x_i}, \boldsymbol{\phi}]\right)\right]\right]
ϕ^=ϕargmin[−i=1∑Ilog[Pr(yi∣f[xi,ϕ])]]
如果对比一下,就会发现上式与负对数似然的定义式(4)是一样的,我们经过推导证明了交叉熵与负对数似然是等价的。
pytorch里的交叉熵实现
pytorch里不同的实现交叉熵的方法:
torch.nn.functional.binary_cross_entropy
计算二元交叉熵,输入为概率,也就是logits值要先经过sigmoid函数转换为概率。torch.nn.functional.binary_cross_entropy_with_logits
计算二元交叉熵,输入为logits。它相当于将Sigmoid层和BCELoss层合成为一个层,可以使用log-sum-exp技巧使得数值计算更稳定。torch.nn.functional.cross_entropy
计算交叉熵,使用logits作为输入,在其内部实现了LogSoftmax。有ignore_index参数用来忽略掉一些目标值使其对梯度没有影响。torch.nn.functional.nll_loss
与cross_entropy类似,只是要自己将logits经过LogSoftmax后再作为其输入。
# BINARY LABELS
import torch
labels = torch.tensor([1, 0, 1, 1, 1, 0], dtype=torch.float)
logits = torch.tensor([2.2, -1.1, 1.2, 2.2, 0.1, -0.5], dtype=torch.float)
torch.nn.functional.binary_cross_entropy_with_logits(logits, labels)
# tensor(0.3132)
## logits 需要先经过sigmoid转换
torch.nn.functional.binary_cross_entropy(torch.sigmoid(logits), labels)
# tensor(0.3132)
## MULTICLASS
labels = torch.tensor([1, 0, 2], dtype=torch.long)
logits = torch.tensor([[2, -0.5, 0.1],
[-1.1, 2, 0.0],
[1.2, 2.2, 3.1]], dtype=torch.float)
torch.nn.functional.cross_entropy(logits, labels)
# tensor(2.1388)
torch.nn.functional.nll_loss(torch.nn.functional.log_softmax(logits, dim=1), labels)
# tensor(2.1388)
## BINARY CROSS ENTROPY VS MULTICLASS IMPLEMENTATION(用交叉熵实现二分类)
labels = torch.tensor([1, 0, 1], dtype=torch.float)
probas = torch.tensor([0.9, 0.1, 0.8], dtype=torch.float)
torch.nn.functional.binary_cross_entropy(probas, labels)
# tensor(0.1446)
labels = torch.tensor([1, 0, 1], dtype=torch.long)
probas = torch.tensor([[0.1, 0.9],
[0.9, 0.1],
[0.2, 0.8]], dtype=torch.float)
torch.nn.functional.nll_loss(torch.log(probas), labels)
# tensor(0.1446)
参考资料
-
《Understanding Deep Learning》第5章(本文的图片来自此书)
-
https://sebastianraschka.com/faq/docs/pytorch-crossentropy.html
-
pytorch文档