文章目录
- 损失函数
- 深度学习优化思想
- 回归:误差平方和SSE
- 二分类交叉熵损失函数
- 1. 极大似然函数估计求解二分类交叉熵函数
- 2.用tensor实现二分类交叉熵损失
- 多分类交叉熵损失函数
- 1.由二分类推广到多分类
- 2.用PyTorch实现多分类交叉熵损失
损失函数
在之前的文章中,已经建立了最基础的深层神经网络,并能够理解网络的正向传播过程,接下来,我将分享深度学习网络的学习和训练过程,并从最小二乘和梯度下降算法开始拓展,介绍神经网络的损失函数、常用优化算法等信息,实现神经网络的学习和迭代。
深度学习优化思想
在之前的学习中,我们建立神经网络时总是先设定好
w
w
w与
b
b
b的值,接着通过加和求出
z
z
z,再在
z
z
z上嵌套sigmoid或者softmax函数,最终获得神经网络的输出。我们的代码及计算流程,总是从神经网络的左侧向右侧计算的。之前我们提到过,这是神经网络的正向传播过程。但很明显,这并不是神经网络算法的全流程,这个流程虽然可以输出预测结果, 但却无法保证神经网络的输出结果与真实值接近。
在讲解线性回归时,我们提起过,线性回归的任务就是构造一个预测函数来映射输入的特征矩阵 X X X和标签值 y y y的线性关系。构造预测函数核心就是找出模型的权重向量 w w w,并令线性回归的输出结果与真实值相近,也就是求解线性方程组中的 w w w和 b b b。对神经网络而言也是如此,我们的核心任务是求解一组最适合的 w w w和 b b b,令神经网络的输出结果与真实值接近。找寻这个 w w w和 b b b的过程就是“学习”,也叫做“训练”或者“建模”。
那我们如何评价 和 是否合适呢?我们又如何衡量我们的输出结果与真实值之间的差异大小呢?此时, 我们就需要使用机器学习中通用的优化流程了。在讲解autograd的时候,其实我们已经提过这个优化流程,在这里我们稍微复习一下模型训练的基本流程:
1)提出基本模型,明确目标
我们的基本模型就是我们自建的神经网络架构,我们需要求解的就是神经网络架构中的权重向量
w
w
w。
2)确定损失函数/目标函数
我们需要定义某个评估指标,用以衡量模型权重为
w
w
w的情况下,预测结果与真实结果的差异。当真实值与预测值差异越大时,我们就认为神经网络学习过程中丢失了许多信息,丢失的这部分被形象地称为”损失“,因此评估真实值与预测值差异的函数被我们称为“损失函数”。
关键概念:损失函数
衡量真实值与预测结果的差异,评价模型学习过程中产生的损失的函数。
在数学上,表示为以需要求解的权重向量 为自变量的函数 。
如果损失函数的值很小,则说明模型预测值与真实值很接近,模型在数据集上表现优异,权重优秀
如果损失函数的值大,则说明模型预测值与真实值差异很大,模型在数据集上表现差劲,权重糟糕
我们希望损失函数越小越好,以此,我们将问题转变为求解函数 L ( w ) L(w) L(w)的最小值所对应的自变量 w w w。但是,损失函数往往不是一个简单的函数,求解复杂函数就需要复杂的数学工具。在这里,我们使用的数学工具可能有两部分:
- 将损失函数转变成凸函数的数学方法,常见的有拉格朗日变换等
- 在凸函数上求解 的最小值对应的 的方法,也就是以梯度下降为代表的优化算法
3)确定适合的优化算法
4)利用优化算法,最小化损失函数,求解最佳权重
w
w
w(训练)
之前我们在线性回归上走过这个全流程。对线性回归,我们的损失函数是SSE,优化算法是最小二乘法 和梯度下降法,两者都是对机器学习来说非常重要的优化算法。但遗憾的是,最小二乘法作为入门级优 化算法,有较多的假设和先决条件,不足以应对神经网络需要被应用的各种复杂环境。梯度下降法应用 广泛,不过也有很多问题需要改进。接下来,我将主要以分类深层神经网络为例来介绍神经网络中所使 用的入门级损失函数及优化算法。
回归:误差平方和SSE
对于回归类神经网络而言,最常见的损失函数是SSE(Sum of the Squared Errors):
S
S
E
=
∑
i
=
1
m
(
z
i
−
z
i
^
)
2
SSE = \sum^m_{i=1} (z_i - \hat{z_i})^2
SSE=i=1∑m(zi−zi^)2
其中
z
i
z_i
zi是样本
i
i
i的真实值,而
(
^
z
i
)
\hat(z_i)
(^zi)是样本
i
i
i的预测值。对于全部样本的平均损失,则可以写作:
M
S
E
=
1
m
∑
i
=
1
m
(
z
i
−
z
i
^
)
2
MSE = \frac{1}{m} \sum^m_{i=1} (z_i - \hat{z_i})^2
MSE=m1i=1∑m(zi−zi^)2
from torch.nn import MSELoss #类
yhat = torch.randn(size=(50,),dtype=torch.float32)
y = torch.randn(size=(50,),dtype=torch.float32)
criterion =MSELoss() #实例化
loss = criterion(yhat,y)
loss #没有设置随机数种子,所以每次运行的数字都会不一致
#在MSELoss中有重要的参数,reduction
#当reduction = "mean" (默认也是mean),则输出MSE
#当reduction = "sum",则输出SSE
criterion = MSELoss(reduction = "mean") #实例化
criterion(yhat,y)
criterion = MSELoss(reduction = "sum")
criterion(yhat,y)
二分类交叉熵损失函数
二分类神经网络的损失函数是用在二分类任务中最常见的损失函数。二分类交叉熵损失函数(Binary Cross Entropy Loss),也叫做对数损失(log loss)。这个损失函数被广泛地使用在任何输出结果是二分类的神经网络中,即不止限于单层神经网络,还可被拓展到多分类中,因此理解二分类交叉熵损失是非常重要的一环。大多数时候,除非特殊声明为二分类,否则提到交叉熵损失,我们会默认算法的分类目标是多分类。 二分类交叉熵损失函数是由极大似然估计推导出来的,对于有m个样本的数据集而言,在全部样本上的平均损失写作:
L
(
w
)
=
−
∑
i
=
1
m
(
y
i
∗
l
n
(
σ
i
)
+
(
1
−
y
i
)
∗
l
n
(
1
−
σ
i
)
)
L(w) = - \sum^m_{i=1}(y_i*ln(\sigma_i) + (1 - y_i)*ln(1-\sigma_i))
L(w)=−i=1∑m(yi∗ln(σi)+(1−yi)∗ln(1−σi))
在单个样本的损失写作:
L
(
w
)
=
−
(
y
i
∗
l
n
(
σ
i
)
+
(
1
−
y
i
)
∗
l
n
(
1
−
σ
i
)
)
L(w) = - (y_i*ln(\sigma_i) + (1 - y_i)*ln(1-\sigma_i))
L(w)=−(yi∗ln(σi)+(1−yi)∗ln(1−σi))
其中,ln是以自然底数 e e e为底的对数函数, w w w表示求解出来的一组权重(在等号的右侧, w w w在 σ \sigma σ里),m是样本的个数, y i y_i yi是样本 i i i上真实的标签, σ i \sigma_i σi是样本 i i i上,基于参数 w w w计算出来的sigmoid函数的返回值, x i x_i xi是样本 i i i各个特征的取值。我们的目标,就是求解出使 L ( w ) L(w) L(w)最小的 w w w取值。注意,在神经网络中,特征张量 X X X是自变量,权重是 w w w。但在损失函数中,权重 w w w是损失函数的自变量,特征 x x x和真实标签 y y y都是已知的数据,相当于是常数。
1. 极大似然函数估计求解二分类交叉熵函数
二分类交叉熵损失函数是怎么来的呢?为什么这个函数就能够代表二分类的时候,真实值与预测值的差异呢? 在这里,我们基于极大似然法来推导交叉熵损失,这个推导过程能够帮助我们充分了解交叉熵损失的含 义,以及为什么 L ( w ) L(w) L(w)的最小化能够实现模型在数据集上的拟合最好。
极大似然估计(Maximum Likelihood Estimate,MLE)的感性认识
如果一个事件的发生概率很大,那这个事件应该很容易发生。相应的,如果依赖于权重 w w w的任意事件的发生就是我们的目标,那我们只要寻找令其发生概率最大化的权重 w w w就可以了。寻找相应的权重 ,使得目标事件的发生概率最大,就是极大似然估计的基本方法。
其步骤如下:
1、构筑似然函数 P ( w ) P(w) P(w),用于评估目标事件发生的概率,该函数被设计成目标事件发生时,概率最大
2、对整体似然函数取对数,构成对数似然函数 l n P ( w ) lnP(w) lnP(w)
3、在对数似然函数上对权重 w w w求导,并使导数为0,对权重进行求解
在二分类的例子中,我们的“任意事件”就是每个样本的分类都正确,对数似然函数的负数就是我们的损失函数。接下来,我们来看看逻辑回归的对数似然函数是怎样构筑的。
- 构筑对数似然函数
二分类神经网络的标签是[0,1],此标签服从伯努利分布(即0-1分布),因此可得:
样本
i
i
i在由特征向量
x
i
x_i
xi和权重向量
w
w
w组成的预测函数中,样本标签被预测为1的概率为:
P
1
=
P
(
y
^
i
=
1
∣
x
i
,
w
)
=
σ
P_1 = P(\hat{y}_i = 1| x_i,w) = \sigma
P1=P(y^i=1∣xi,w)=σ
对二分类而言,
σ
\sigma
σ 就是sigmoid函数的结果。
样本
i
i
i在由特征向量
x
i
x_i
xi和权重向量
w
w
w组成的预测函数中,样本标签被预测为0的概率为:
P
0
=
P
(
y
^
i
=
0
∣
x
i
,
w
)
=
1
−
σ
P_0 = P(\hat{y}_i = 0| x_i,w) = 1 - \sigma
P0=P(y^i=0∣xi,w)=1−σ
当
P
1
P_1
P1的值为1的时候,代表样本
i
i
i的标签被预测为1,当
P
0
P_0
P0的值为1的时候,代表样本
i
i
i的标签被预测为0。
P
1
P_1
P1与
P
0
P_0
P0相加是一定等于1的。
假设样本 i i i的真实标签 y i y_i yi为1,并且 P 1 P_1 P1也为1的话,那就说明我们将 i i i的标签预测为1的概率很大,与真实值一致,那模型的预测就是准确的,拟合程度很高,信息损失很少。相反,如果真实标签 为1,我们的 P 1 P_1 P1却很接近0,这就说明我们将 i i i的标签预测为1的概率很小,即与真实值一致的概率很小,那模型的预测就是失败的,拟合程度很低,信息损失很多。当 y i y_i yi为0时,也是同样的道理。所以,当 y i y_i yi为1的时候,我们希望 P 1 P_1 P1非常接近1,当 y i y_i yi为0的时候,我们希望 P 0 P_0 P0非常接近1,这样,模型的效果就很好,信息损失就很少。
真实标签 y i y_i yi | 被预测为1的概率 P 1 P_1 P1 | 被预测为0的概率 P 0 P_0 P0 | 样本被预测为? | 与真实值一致吗? | 拟合情况 | 信息损失 |
---|---|---|---|---|---|---|
1 | 0 | 1 | 0 | 否 | 坏 | 大 |
1 | 1 | 0 | 1 | 是 | 好 | 小 |
0 | 0 | 1 | 0 | 是 | 好 | 小 |
0 | 1 | 0 | 1 | 否 | 坏 | 大 |
将两种取值的概率整合,我们可以定义如下等式:
P
(
y
^
i
∣
x
i
,
w
)
=
P
1
y
i
∗
P
0
1
−
y
i
P(\hat{y}_i | x_i,w) = P^{y_i}_1 * P^{1-y_i}_0
P(y^i∣xi,w)=P1yi∗P01−yi
这个等式代表同时代表了
P
0
P_0
P0和
P
1
P_1
P1,在数学上,它被叫做逻辑回归的假设函数。
当样本
i
i
i的真实标签
y
i
y_i
yi为1的时候,
1
−
y
i
1-y_i
1−yi就等于0,
P
0
P_0
P0的0次方就是1,所以
P
(
y
^
i
∣
x
i
,
w
)
P(\hat{y}_i | x_i,w)
P(y^i∣xi,w)就等于
P
0
P_0
P0,这个时候,如果
P
1
P_1
P1为1,模型的效果就很好,损失就很小。
同理,当 y i y_i yi为0的时候, P ( y ^ i ∣ x i , w ) P(\hat{y}_i | x_i,w) P(y^i∣xi,w)就等于 P 0 P_0 P0,此时如果 P 0 P_0 P0非常接近1,模型的效果就很好,损失就很小。
所以,为了达成让模型拟合好,损失小的目的,我们每时每刻都希望 P ( y ^ i ∣ x i , w ) P(\hat{y}_i | x_i,w) P(y^i∣xi,w)的值等于1。而 P ( y ^ i ∣ x i , w ) P(\hat{y}_i | x_i,w) P(y^i∣xi,w)的本质是样本 i i i由特征向量 x i x_i xi和权重 w w w组成的预测函数中,预测出所有可能的 y ^ i \hat{y}_i y^i的概率,因此1是它的最大值。也就是说,每时每刻,我们都在追求 P ( y ^ i ∣ x i , w ) P(\hat{y}_i | x_i,w) P(y^i∣xi,w)的最大值。而寻找相应的参数 w w w,使得每次得到的预测概率最大,正是极大似然估计的基本方法,不过 P ( y ^ i ∣ x i , w ) P(\hat{y}_i | x_i,w) P(y^i∣xi,w)是对单个样本而言的,因此我们还需要将其拓展到多个样本上。
P ( y ^ i ∣ x i , w ) P(\hat{y}_i | x_i,w) P(y^i∣xi,w)是对单个样本 i i i而言的函数,对一个训练集的m个样本来说,我们可以定义如下等式来表达所有样本在特征张量 X X X和权重向量 w w w组成的预测函数中,预测出所有可能的 y ^ \hat{y} y^的概率 P P P为:
P = ∏ i = 1 m P ( y ^ i ∣ x i , w ) = ∏ i = 1 m ( P 1 y i ∗ P 0 1 − y i ) = ∏ i = 1 m ( σ y i ∗ ( 1 − σ ) 1 − y i ) P = \prod_{i=1}^{m} P(\hat{y}_i | x_i,w)=\prod_{i=1}^{m}(P^{y_i}_1 * P_0^{1-y_i}) = \prod_{i=1}^{m}(\sigma^{y_i} * (1 -\sigma)^{1-y_i}) P=i=1∏mP(y^i∣xi,w)=i=1∏m(P1yi∗P01−yi)=i=1∏m(σyi∗(1−σ)1−yi)
这个函数就是逻辑回归的似然函数。对该概率
P
P
P取以
e
e
e为底的对数,再由
l
o
g
(
A
∗
B
)
=
l
o
g
A
+
l
o
g
B
log(A*B) = logA + logB
log(A∗B)=logA+logB和
l
o
g
A
B
=
B
l
o
g
A
logA^B = BlogA
logAB=BlogA可得到逻辑回归的对数似然函数:
l
n
P
=
l
n
∏
i
=
1
m
(
σ
y
i
∗
(
1
−
σ
)
1
−
y
i
)
=
∑
i
=
1
m
l
n
(
σ
y
i
∗
(
1
−
σ
)
1
−
y
i
)
=
∑
i
=
1
m
(
l
n
(
σ
y
i
+
l
n
(
1
−
σ
)
1
−
y
i
)
)
=
∑
i
=
1
m
(
y
i
∗
l
n
(
σ
i
)
+
(
1
−
y
i
)
∗
l
n
(
1
−
σ
)
)
lnP = ln\prod_{i=1}^{m}(\sigma^{y_i} * (1 -\sigma)^{1-y_i}) \\ = \sum^m_{i=1}ln(\sigma^{y_i} * (1 -\sigma)^{1-y_i}) \\ = \sum^m_{i=1}(ln(\sigma^{y_i} + ln(1 -\sigma)^{1-y_i})) \\ = \sum^m_{i=1}(y_i *ln(\sigma_i) + (1 - y_i) *ln(1-\sigma))
lnP=lni=1∏m(σyi∗(1−σ)1−yi)=i=1∑mln(σyi∗(1−σ)1−yi)=i=1∑m(ln(σyi+ln(1−σ)1−yi))=i=1∑m(yi∗ln(σi)+(1−yi)∗ln(1−σ))
这就是二分类交叉熵函数。为了数学上的便利以及更好地定义”损失”的含义,将极大值问题转换为极小值问题,因此我们对
l
n
P
lnP
lnP取负,并且让权重
w
w
w作为函数的自变量,就得到了我们的损失函数
L
(
w
)
L(w)
L(w):
L
(
w
)
=
−
∑
i
=
1
m
(
y
i
∗
l
n
(
σ
i
)
+
(
1
−
y
i
)
∗
l
n
(
1
−
σ
i
)
)
L(w) = -\sum^m_{i=1}(y_i*ln(\sigma_i) + (1 -y_i)*ln(1-\sigma_i))
L(w)=−i=1∑m(yi∗ln(σi)+(1−yi)∗ln(1−σi))
现在,我们已经将模型拟合中的“最小化损失”问题,转换成了对函数求解极值的问题。这就是一个,基于逻辑回归的返回值KaTeX parse error: Undefined control sequence: \simga at position 1: \̲s̲i̲m̲g̲a̲_i的概率性质以及极大似然估计得出的损失函数。在这个函数上,我们只要追求最小值,就能让模型在训练数据上的拟合效果最好,损失最低。
在极大似然估计中,我们只要在对数似然函数上对权重
w
w
w求导,再令导数为0,就可以求解出最合适的
w
w
w,但是对于像交叉熵这样复杂的损失函数,加上神经网络中复杂的权重组合,令所有权重的导数为0并一个个求解方程的难度很大。
2.用tensor实现二分类交叉熵损失
现在,在PyTorch中来实现二分类交叉熵损失函数。首先使用基本的tensor方法来试试看,以加
深我们对二分类交叉熵损失的印象:
import torch
import time
N = 3*pow(10,3)
torch.random.manual_seed(420)
X = torch.rand((N,4),dtype=torch.float32)
w = torch.rand((4,1),dtype=torch.float32,requires_grad=True)
y = torch.randint(low=0,high=2,size=(N,1),dtype=torch.float32)
zhat = torch.mm(X,w)
sigma = torch.sigmoid(zhat)
Loss = -(1/N)*torch.sum((1-y)*torch.log(1-sigma)+y*torch.log(sigma))
多分类交叉熵损失函数
1.由二分类推广到多分类
二分类交叉熵损失可以被推广到多分类上,但在实际处理时,二分类与多分类却有一些关键的区别。依然使用极大似然估计的推导流程,首先我们来确定单一样本概率最大化后的似然函数。 对于多分类的状况而言,标签不再服从伯努利分布(0-1分布),因此我们可以定义,样本i在由特征向量
x
x
x和权重向量
w
w
w组成的预测函数中,样本标签被预测为类别
k
k
k的概率为:
P
k
=
P
(
y
^
i
=
k
∣
x
i
,
w
)
P_k = P(\hat{y}_i = k |x_i,w)
Pk=P(y^i=k∣xi,w)
对于多分类算法而言, 就是softmax函数返回的对应类别的值。
假设一种最简单的情况:我们现在有三分类[1, 2, 3],则样本i被预测为三个类别的概率分别为:
P
1
=
P
(
y
^
i
=
1
∣
x
i
,
w
)
=
σ
1
P
1
=
P
(
y
^
i
=
2
∣
x
i
,
w
)
=
σ
2
P
1
=
P
(
y
^
i
=
3
∣
x
i
,
w
)
=
σ
3
P_1 = P(\hat{y}_i = 1 |x_i,w) = \sigma_1\\ P_1 = P(\hat{y}_i = 2 |x_i,w) = \sigma_2\\ P_1 = P(\hat{y}_i = 3 |x_i,w) = \sigma_3
P1=P(y^i=1∣xi,w)=σ1P1=P(y^i=2∣xi,w)=σ2P1=P(y^i=3∣xi,w)=σ3
假设样本的真实标签为1,我们就希望
P
1
P_1
P1最大,同理,如果样本的真实标签为其他值,我们就希望其他值所对应的概率最大。在二分类中,我们将
y
y
y和
1
−
y
1-y
1−y作为概率
P
P
P的指数,以此来融合真实标签为0和为1的两种状况。但在多分类中,我们的真实标签可能是任意整数,无法使用
y
y
y和
1
−
y
1-y
1−y这样的结构来构建似然函数。所以我们认为,如果多分类的标签也可以使用0和1来表示就好了,这样我们就可以继续使用真实标签作为指数的方式。 因此,对多分类的标签做出了如下变化:
原本的真实标签y是含有[1, 2, 3]三个分类的列向量,现在我们把它变成了标签矩阵,每个样本对应一个向量。(如果你熟悉机器学习或统计学,你能够一眼看出这其实就是独热编码one-hot)。在矩阵中,每一行依旧对应样本,但却由三分类衍生出了三个新的列,分别代表:真实标签是否等于1、等于2以及等于3。在矩阵中,我们使用“1”标注出样本的真实标签的位置,使用0表示样本的真实标签不是这个标签。不难注意到,这个标签矩阵的结构其实是和softmax函数输出的概率矩阵的结构一致,并且一一对应的。
当我们把标签整合为标签矩阵后,我们就可以将单个样本在总共K个分类情况整合为以下的似然函数:
P
(
y
^
i
∣
x
i
,
w
)
=
P
1
y
i
(
k
=
1
)
∗
P
2
y
i
(
k
=
2
)
∗
.
.
.
∗
P
K
y
i
(
k
=
K
)
P(\hat{y}_i|x_i,w) = P_1^{y_i(k=1)} * P_2^{y_i(k=2)} * ...* P_K^{y_i(k=K)}
P(y^i∣xi,w)=P1yi(k=1)∗P2yi(k=2)∗...∗PKyi(k=K)
其中
P
P
P就是样本标签被预测为某个具体值的概率,而右上角的指数就是标签矩阵中对应的值,即这个样本的真实标签是否为当前标签的判断(是就是1,否就是0)。
更具体的,小
k
k
k代表
y
y
y的真实取值,
K
K
K代表总共有
K
K
K个分类。虽然是连乘,但对于一个样本,除了自己所在的真实类别指数
y
i
y_i
yi会是1之外,其他类别的指数都为0,所以被分类为其他类别的概率在这个式子里就都为0。所以我们可以将式子简写为:
P
(
y
^
i
∣
x
i
,
w
)
=
P
j
y
i
(
k
=
j
)
P(\hat{y}_i |x_i,w) = P_j^{y_i(k=j)}
P(y^i∣xi,w)=Pjyi(k=j)
对一个训练集的
m
m
m个样本来说,我们可以定义如下等式来表达所有样本在特征张量
X
X
X和权重向量
w
w
w组成 的预测函数中,预测出所有可能的
y
^
\hat{y}
y^的概率
P
P
P为:
P
=
∏
i
=
1
m
P
(
y
^
i
∣
x
i
,
w
)
=
∏
i
=
1
m
P
j
y
i
(
k
=
j
)
=
∏
i
=
1
m
σ
j
y
i
(
k
=
j
)
P = \prod^m_{i=1}P(\hat{y}_i|x_i,w) \\ = \prod^m_{i=1}P_j^{y_i(k=j)} \\ =\prod^m_{i=1}\sigma_j^{y_i(k=j)}
P=i=1∏mP(y^i∣xi,w)=i=1∏mPjyi(k=j)=i=1∏mσjyi(k=j)
这就是多分类状况下的似然函数。与二分类一致,似然函数解出来后,我们需要对似然函数求对数:
l
n
P
=
l
n
∏
i
=
1
m
σ
j
y
i
(
k
=
j
)
=
∑
i
=
1
m
l
n
(
σ
j
y
i
(
k
=
j
)
)
=
∑
i
=
1
m
y
i
(
k
=
j
)
l
n
σ
i
lnP = ln\prod^m_{i=1}\sigma_j^{y_i(k=j)} \\ = \sum^m_{i=1}ln(\sigma_j^{y_i(k=j)}) \\ = \sum^m_{i=1}y_{i(k=j)}ln\sigma_i
lnP=lni=1∏mσjyi(k=j)=i=1∑mln(σjyi(k=j))=i=1∑myi(k=j)lnσi
其中
σ
\sigma
σ就是softmax函数返回的对应类别的值。再对整个公式取负,就得到了多分类状况下的损失函数:
L
(
w
)
=
−
∑
i
=
1
m
y
i
(
k
=
j
)
l
n
σ
i
L(w) = -\sum^m_{i=1} y_{i(k=j)}ln\sigma_i
L(w)=−i=1∑myi(k=j)lnσi
这个函数就是我们之前提到过的交叉熵函数。不难看出,二分类的交叉熵函数其实是多分类的一种特殊情况。
交叉熵函数十分特殊,虽然我们求解过程中,取对数的操作是在确定了似然函数后才进行的,但从计算结果来看,对数操作其实只对softmax函数的结果
σ
\sigma
σ起效。因此在实际操作中,我们把
l
n
(
s
o
f
t
m
a
x
(
z
)
)
ln(softmax(z))
ln(softmax(z))这样的函数单独定义了一个功能做logsoftmax,PyTorch中可以直接通过nn.logsoftmax类调用这个功 能。同时,我们把对数之外的,乘以标签、加和、取负等等过程打包起来,称之为负对数似然函数 (Negative Log Likelihood function),在PyTorch中可以使用nn.NLLLoss来进行调用。也就是说,在 计算损失函数时,我们不再需要使用单独的softmax函数了。
2.用PyTorch实现多分类交叉熵损失
import torch
import torch.nn as nn
N = 3*pow(10,2)
torch.random.manual_seed(420)
X = torch.rand((N,4),dtype=torch.float32)
w = torch.rand((4,3),dtype=torch.float32,requires_grad=True)
#定义y时应该怎么做?应该设置为矩阵吗?
y = torch.randint(low=0,high=3,size=(N,),dtype=torch.float32)
zhat = torch.mm(X,w)
#从这里开始调用softmax和NLLLoss
logsm = nn.LogSoftmax(dim=1) #实例化
logsigma = logsm(zhat)
criterion = nn.CrossEntropyLoss() #对打包好的CorssEnrtopyLoss而言,只需要输入zhat
criterion(zhat,y.long())
无论时二分类还是多分类,PyTorch都提供了包含输出层激活函数和不包含输出层激活函数的类两种选择。在实际神经网络建模中,类可以被放入定义好的Model类中去构建神经网络的结构,因此是否包含激活函数,就需要由用户来自行选择。
-
重视展示网络结构和灵活性,应该使用不包含输出层激活函数的类
通常在Model类中,__init__中层的数量与forward函数中对应的激活函数的数量是一致的,如果我们使 用内置sigmoid/logsoftmax功能的类来计算损失函数,forward函数在定义时就会少一层(输出层), 网络结构展示就不够简单明了,对于结构复杂的网络而言,结构清晰就更为重要。同时,如果激活函数是单独写的,要修改激活函数就变得很容易,如果混在损失函数中,要修改激活函数时就得改掉整个损失函数的代码,不利于维护。
-
重视稳定性和运算精度,使用包含输出层激活函数的类
如果在一个Model中,很长时间我们都不会修改输出层的激活函数,并且模型的稳定运行更为要紧,我们就使用内置了激活函数的类来计算损失函数。同时,就像之前提到的,内置激活函数可以帮助我们推升运算的精度。
因此,选择哪种损失函数的实现方式,最终还要看我们的需求。