机器学习之损失函数
在训练过程中,神经网络模型可以简化为上图中的4部分,今天的主角是损失函数。损失函数的作用是量化模型预测值与真实值之间的差别,也就是负责告诉优化器模型错没错,错的有多离谱。优化器再根据损失函数的结果调整模型参数,模型训练的过程很像是一个负反馈网络。
严格来说,优化器利用的不是损失函数的结果,而是它的导数,也就是梯度。因此损失函数不一定具有零点,但是一定要有最低点(最小值),也就是它的梯度一定要有零点。其次是它必须可导,这样才能求梯度。我们学到的第一个二次函数 y = x 2 y=x^2 y=x2 就是这样的函数。
为了方便描述,先对后面要用到的符号做一个说明:
| 符号 | 含义 |
|---|---|
| Y Y Y | 真实值(向量) |
| Y i Y_i Yi | 真实值(向量)的第 i i i 个值 |
| y y y | 模型预测值(向量) |
| y i y_i yi | 模型预测值(向量)的第 i i i 个值 |
| L L L | 损失函数 |
MAE及其变种
我们能想到的最简单的误差计算公式就是做减法, ∣ Y i − y i ∣ |Y_i-y_i| ∣Yi−yi∣ 这就是误差,它的函数图像如下。
这叫平均绝对误差(Mean Absolute Error),俗称 MAE,也有叫它L1损失函数的。虽然它具有最小值,但是它在最小值处不可导。于是就衍生出了一些 MAE 的变体,它们都是分段函数,主要就是为了解决 MAE 零点不可导问题,比如Smooth L1损失函数。
L
=
{
1
2
(
Y
−
y
)
2
∣
Y
i
−
y
i
∣
<
1
∣
Y
−
y
∣
−
1
2
o
t
h
e
r
L=\begin{dcases} \frac{1}{2}(Y-y)^2 & |Y_i-y_i|<1 \\ |Y-y|-\frac{1}{2} & other \end{dcases}
L=⎩
⎨
⎧21(Y−y)2∣Y−y∣−21∣Yi−yi∣<1other
再比如Huber Loss:
L
=
{
1
2
(
Y
−
y
)
2
∣
Y
i
−
y
i
∣
<
δ
δ
(
∣
Y
−
y
∣
−
1
2
δ
)
o
t
h
e
r
L=\begin{dcases} \frac{1}{2}(Y-y)^2 & |Y_i-y_i|<\delta \\ \delta(|Y-y|-\frac{1}{2}\delta) & other \end{dcases}
L=⎩
⎨
⎧21(Y−y)2δ(∣Y−y∣−21δ)∣Yi−yi∣<δother
它们的核心都是通过分段函数解决MAE零点附近不可导的问题,其他地方还是MAE。
MSE
MSE 叫做均方差,Mean Square Error。它是对误差的平方求和取平均,也被叫做L2损失函数。
L
=
1
n
∑
i
=
0
n
(
Y
i
−
y
i
)
2
L=\frac{1}{n}\sum_{i=0}^{n}{(Y_i-y_i)^2}
L=n1i=0∑n(Yi−yi)2
在线性回归中,常用它来拟合函数。它不仅具有最小值,而且处处可导。
交叉熵
交叉熵是一种熵,一种什么样的熵呢?一种交叉的熵,什么是交叉的熵呢?首先要理解熵。物理学和信息论里都有熵的概念,这里是信息论中的熵。它的定义是:无损编码事件信息的最小平均编码长度。
关键词:最小,长度。
假设事件A出现的概率为
p
p
p,采用二级制编码,需要的长度为:
n
=
−
log
2
p
n=-\log_2{p}
n=−log2p。这也很好理解,所谓编码就是给样本空间中的每一个事件一个编号,事件A出现的概率为
p
p
p,要让事件A出现一次,需要的样本数量就是
1
p
\frac{1}{p}
p1,而
n
n
n 比特二进制所能表示的总可能性是
2
n
2^n
2n,于是就有:
2
n
=
1
p
log
2
2
n
=
log
2
1
p
n
=
−
log
2
p
\begin{aligned} 2^n&=\frac{1}{p} \\ \log_2{2^n}&=\log_2\frac{1}{p} \\ n&=-\log_2{p} \end{aligned}
2nlog22nn=p1=log2p1=−log2p
熵其实就是所有事件编码长度的期望:
E
=
−
∑
i
=
0
n
p
i
log
2
p
i
E=-\sum_{i=0}^n{p_i\log_2{p_i}}
E=−i=0∑npilog2pi
记住这个结果是最小的,如果我们把模型输出结果也看作是一种概率分布,假设
p
i
p_i
pi 表示真实分布概率,而
q
i
q_i
qi 表示模型预测的概率分布,将上面公式中后面的
p
i
p_i
pi 换成
q
i
q_i
qi,于是得到:
E
c
=
−
∑
i
=
0
n
p
i
log
2
q
i
E_c = -\sum_{i=0}^n{p_i\log_2{q_i}}
Ec=−i=0∑npilog2qi
这就是交叉熵!所谓交叉就是把 p i p_i pi 换成 q i q_i qi,前面我们说了熵是最小的长度,那么一定有 E c ≥ E E_c \geq E Ec≥E,当且仅当 q i = p i q_i=p_i qi=pi 时取等号。如果我们将 E c E_c Ec 做为损失函数,它也具有最小值,而且可导,这就是交叉熵损失函数。
这里 p i p_i pi 其实就是 Y i Y_i Yi, q i q_i qi 其实就是 y i y_i yi,所以 L = − ∑ i = 0 n Y i log 2 y i L= -\sum_{i=0}^n{Y_i\log_2{y_i}} L=−∑i=0nYilog2yi 也是对的,只是上面我们选择了贴合概率分布含义的符号而已,下面也是一样。
KL散度
KL是两个人名,库尔贝克和莱布里埃。理解了交叉熵之后,其实KL散度就是交叉熵与熵的差!
E
K
L
=
E
c
−
E
=
−
∑
i
=
0
n
p
i
log
2
q
i
+
∑
i
=
0
n
p
i
log
2
p
i
=
∑
i
=
0
n
p
i
log
2
1
q
i
+
∑
i
=
0
n
p
i
log
2
p
i
=
∑
i
=
0
n
p
i
log
2
p
i
q
i
\begin{aligned} E_{KL}&=E_c-E\\ &= -\sum_{i=0}^n{p_i\log_2{q_i}}+\sum_{i=0}^n{p_i\log_2{p_i}} \\ &= \sum_{i=0}^n{p_i\log_2{\frac{1}{q_i}}}+\sum_{i=0}^n{p_i\log_2{p_i}} \\ &=\sum_{i=0}^n{p_i\log_2{\frac{p_i}{q_i}}} \end{aligned}
EKL=Ec−E=−i=0∑npilog2qi+i=0∑npilog2pi=i=0∑npilog2qi1+i=0∑npilog2pi=i=0∑npilog2qipi
因为 E c ≥ E E_c \geq E Ec≥E,所以 E K L ≥ 0 E_{KL} \geq 0 EKL≥0。它也具有最小值,而且可导。
以两个变量为例,我们可以通过 desmos 在线工具绘制出交叉熵和KL散度的函数图像。

红色是交叉熵,绿色是KL散度,它们的图像非常相似,唯一的区别是最小值是否为零,但是损失函数只要求梯度具有零值,它们都是符合损失函数要求的。
Axon 中的那些损失函数
Axon 是 Elixir 的机器学习库,我们可以来看看它提供的那些损失函数。这些损失函数在官方文档中都有示例,这里我就不搬运示例了,只是结合前面的知识做个中文介绍。
apply_label_smoothing
它并不是一个损失函数,而是一个优化真实值(标签)的函数。在分类任务中,我们常用独热编码来表示分类标签,比如一个4类别的分类标签可能是 Y i = [ 0 , 0 , 1 , 0 ] Y_i=[0,0,1,0] Yi=[0,0,1,0],这叫绝对正确,当模型输出 y i = [ 0.01 , 0.05 , 0.91 , 0.03 ] y_i=[0.01, 0.05,0.91,0.03] yi=[0.01,0.05,0.91,0.03] 时其实已经能够做出判别了,这叫大概正确。但是由于误差任然存在,模型还会去学习那个绝对正确的 1 1 1,这样反而容易让模型过拟合,降低模型的泛化能力。
因此我们可以提前对标签做一点处理,将绝对正确变成大概正确,公式如下:
Y i ′ = ( 1 − ϵ ) Y i + ϵ K (K=类别数) Y^{'}_i=(1-\epsilon)Y_i+\frac{\epsilon}{K} \quad \text{(K=类别数)} Yi′=(1−ϵ)Yi+Kϵ(K=类别数)
ϵ
\epsilon
ϵ 默认为
0.1
0.1
0.1,前面的例子经过 apply_label_smoothing 函数之后结果就变成了
Y
i
′
=
[
0.025
,
0.025
,
0.925
,
0.025
]
Y^{'}_i=[0.025, 0.025, 0.925, 0.025]
Yi′=[0.025,0.025,0.925,0.025]。
独热编码还有一种叫做 稀疏张量(sparse tensor) 的存储方式,它只存储向量中为 1 1 1 的位置,比如 Y = [ [ 0 , 1 , 0 , 0 ] , [ 1 , 0 , 0 , 0 ] , [ 0 , 0 , 1 , 0 ] , [ 0 , 0 , 0 , 1 ] ] Y=\bigl[[0,1,0,0],[1,0,0,0],[0,0,1,0],[0,0,0,1]\bigr] Y=[[0,1,0,0],[1,0,0,0],[0,0,1,0],[0,0,0,1]] 按照稀疏张量的存储方式就是 Y = [ 1 , 0 , 2 , 3 ] Y=[1,0,2,3] Y=[1,0,2,3]。
binary_cross_entropy
它是二分类模型的交叉熵损失函数,它依然是交叉熵,只是缩小了
1
2
\frac{1}{2}
21。公式如下:
L
i
=
−
1
2
(
Y
i
log
(
y
i
)
+
(
1
−
Y
i
)
log
(
1
−
y
i
)
)
L_i = -\frac{1}{2}\Bigl(Y_i \log(y_i) + (1-Y_i) \log(1 - y_i)\Bigr)
Li=−21(Yilog(yi)+(1−Yi)log(1−yi))
categorical_cross_entropy
这就是前面我们介绍过的交叉熵损失函数。就不写公式了。
hinge
这是 支持向量机(SVM) 中使用的损失函数,公式如下:
L
i
=
max
(
1
−
Y
i
×
y
i
,
0
)
L_i = \max(1 - Y_i \times y_i, 0)
Li=max(1−Yi×yi,0)
因其函数图像形似门的合页而得名。真实值 Y i Y_i Yi 的值是 − 1 -1 −1 或 1 1 1,其核心思想是当 Y i × y i ≥ 1 Y_i\times y_i \geq 1 Yi×yi≥1 时不处罚,反之线性处罚。它以 − 1 -1 −1 和 1 1 1 为界,分出了两片安全区,也就是不处罚的区域。 − 1 -1 −1 左边是安全区,右边是处罚区; 1 1 1 右边是安全区,左边是处罚区。
因为 Y i Y_i Yi 的取值是 − 1 -1 −1 或 1 1 1, Y i × y i Y_i\times y_i Yi×yi 表示的其实是样本点距离 − 1 -1 −1 和 1 1 1 这两条边界的距离,这个距离就是所谓的分类间隔,或最大化间隔。
categorical_hinge
hinge 是用于二分类,categorical_hinge 就是多分类版本的 hinge。
L
=
m
a
x
(
0
,
m
a
x
j
∈
k
(
y
j
≠
i
)
−
y
i
+
1
)
L = max\Bigl(0, max_{j\in k}(y_{j\neq i}) − y_i + 1\Bigr)
L=max(0,maxj∈k(yj=i)−yi+1)
这个公式比较晦涩,其中的 m a x j ∈ k ( y j ≠ i ) max_{j\in k}(y_{j\neq i}) maxj∈k(yj=i) 表示的是预测值里面除 y i y_i yi 以外最大的那个。以它为边界,如果 y i y_i yi 和它的距离大于等于 1 1 1 就不处罚,否则线性处罚。
categorical_hinge 的核心思想和 hinge 还是一样的,只不过这里边界不是固定的 − 1 -1 −1 或 1 1 1,而是由预测值里面除 y i y_i yi 之外最大的哪个样本划定的。
connectionist_temporal_classification
连续时序分类,简称 CTC。它是通过添加空元素解决输入输出序列长度不同且无法对齐的情况,常用于语音识别和手写识别。
这个我没办法用一两句话讲清楚,先挖个坑吧。
cosine_similarity
这个比较简单,就是把标签和预测值都当作向量,然后计算他们之间夹角的余弦值。
L
=
1
−
c
o
s
θ
=
1
−
Y
i
⋅
y
i
∣
Y
i
∣
×
∣
y
i
∣
L =1-cos\theta=1 - \frac{Y_i\cdot y_i}{|Y_i|\times|y_i|}
L=1−cosθ=1−∣Yi∣×∣yi∣Yi⋅yi
c o s θ cos\theta cosθ 越大说明预测值与标签越相似。
huber
就是前面介绍过的Huber损失函数。
kl_divergence
就是前面介绍过的KL散度。
label_smoothing
这个也不是损失函数,它以损失函数为参数,应用 apply_label_smoothing 将标签由绝对正确优化为大概正确。
log_cosh
对数双曲余弦函数就是双曲余弦函数取对数,公式如下:
L
=
1
N
∑
i
N
(
Y
i
−
y
i
)
+
log
(
1
+
e
−
2
(
Y
i
−
y
i
)
)
−
log
(
2
)
L = \frac{1}{N} \sum_i^N (Y_i - y_i) + \log(1 + e^{-2(Y_i - y_i)}) - \log(2)
L=N1i∑N(Yi−yi)+log(1+e−2(Yi−yi))−log(2)
图中黑色曲线为对数双曲余弦损失函数,红色为MAE,蓝色为MSE,可以看到,在误差很大时,对数双曲余弦损失函数接近于MAE,而在误差较小时,对数余弦损失函数接近于MSE,可以说是兼具两者优点。
margin_ranking
它是一种用于排序任务的损失函数,常见于推荐系统和信息检索。
l
i
=
max
(
0
,
−
Y
i
∗
(
y
i
(
1
)
−
y
i
(
2
)
)
+
α
)
l_i = \max\Bigl(0, -Y_i * (y^{(1)}_i - y^{(2)}_i) + \alpha\Bigr)
li=max(0,−Yi∗(yi(1)−yi(2))+α)
看起来是不是和 hinge 挺像的?事实也却是如此,这里 y i ( 1 ) y^{(1)}_i yi(1) 和 y i ( 2 ) y^{(2)}_i yi(2) 是待排序的两个样本, Y i Y_i Yi 的取值依然是 1 1 1 或 − 1 -1 −1,当 y i ( 1 ) y^{(1)}_i yi(1) 应该排在 y i ( 2 ) y^{(2)}_i yi(2) 前面时 Y i Y_i Yi 取 1 1 1,否则取 − 1 -1 −1, α \alpha α 时间隔宽度。
mean_absolute_error
就是前面介绍过的 MAE 损失函数。
mean_squared_error
就是前面介绍过的 MSE 损失函数。
poisson
当输出符合泊松分布时,会使用这个损失函数。
L
=
1
C
∑
i
C
y
i
−
Y
i
log
(
y
i
)
L = \frac{1}{C} \sum_i^C y_i - Y_i \log(y_i)
L=C1i∑Cyi−Yilog(yi)
从形式上看,它就是预测值加上交叉熵,所以它的函数图像也和交叉熵的图像非常类似。
soft_margin
软间隔损失函数,相比于硬间隔,它容许存在一定的分类错误,常在SVM中用来处理线性不可分问题。这里给出的是它的一种变体,也叫 Logistic Loss。
L
=
1
N
∑
i
N
log
(
1
+
e
−
Y
i
y
i
)
L = \frac{1}{N}\sum_i^N \log(1 + e^{-Y_i y_i})
L=N1i∑Nlog(1+e−Yiyi)
Y i Y_i Yi 也取 − 1 -1 −1 或 1 1 1,它可以看作是平滑版的 hinge,函数图像也非常相似。
更多推荐



所有评论(0)