引言:
在深度学习的任务目标中,通常我们希望我们的学习结果能够在损失函数上得到一个较好的结果,即朝着损失函数最小的方向前进。但是对于大部分深度学习任务而言,其优化的目标通常是一个非凸函数,其优化难度会比较大,所以也就出现了一系列的优化函数。
接下来我会用比较通俗易懂的语言来介绍一些比较著名的优化算法
回顾:梯度下降法(GD)与随机梯度下降法(SGD)的理解
Note:本文的数学符号可能会与相关书籍的所使用符号略微有点不同,但我的目的是为了尽量使用大家都熟悉的符号,方便大家理解。
- 动量(Momentum):
动量法的核心:引入变量 v v v来充当速度角色。
那速度是什么呢?引入速度能带来什么好处呢?
速度 v v v实际上是负梯度的指数衰减平均,其表达式为 (1) v t = α v t − 1 − η ∇ g v_t=\alpha v_{t-1}-\eta\nabla g\tag{1} vt=αvt−1−η∇g(1)其中, α \alpha α是系数, v v v是速度, η \eta η是学习率, ∇ g \nabla g ∇g是一个batch_size的平均梯度,一般来说,我们会令 v 0 = 0 v_{0}=0 v0=0。其参数 x x x的更新方法为 (2) x t = x t − 1 − v t x_{t}=x_{t-1}-v_{t}\tag{2} xt=xt−1−vt(2)到这里,有细心的小伙伴肯定会问,到底哪里有指数衰减平均?其实,我们可以把式 ( 1 ) (1) (1)稍加改变,如下 (3) v t = α v t − 1 − ( 1 − α ) η 1 − α ∇ g ⎵ T t v_t=\alpha v_{t-1}-(1-\alpha)\underbrace{\frac{\eta}{1-\alpha}\nabla g}_{T_t}\tag{3} vt=αvt−1−(1−α)Tt 1−αη∇g(3)将我圈出部分看成整体 T t T_{t} Tt的话,就会符合指数衰减平均的标准公式 (4) v t = α v t − 1 − ( 1 − α ) T t v_t=\alpha v_{t-1}-(1-\alpha)T_{t}\tag{4} vt=αvt−1−(1−α)Tt(4)将动量应用于SGD算法后,就会有如下结果
其中,左图中黑色的下降轨迹为不带动量的SGD轨迹(事实上黑色线并不是轨迹而是梯度方向,但是加上动量前的轨迹可以粗略的视为黑色线),红色的下降轨迹为带动量的SGD轨迹;右图中给出了在一般曲线上应用指数衰减平均后的结果,其中ema是对原曲线进行指数衰减平均操作后的结果。
可以看出,带动量的SGD算法可以更快地到达局部最小值,其轨迹看起来更加平滑,稳定,同时这也符合指数滑动平均的结果。
当许多连续的梯度指向相同的方向时,步长最大
上面这句话通俗地讲就是当连续的梯度指向相同的方向是,
v
v
v会不断加速,表现在图中就会是一下子到达局部最小值附近。为了帮助理解,我们可以把上面
(
1
)
(1)
(1)式再稍微修改,得
(5)
v
t
=
α
v
t
−
1
+
η
(
−
∇
g
)
v_t=\alpha v_{t-1}+\eta(-\nabla g)\tag{5}
vt=αvt−1+η(−∇g)(5)借助这个式子,我们进行类推
v
0
=
0
v_{0}=0
v0=0
v
1
=
η
(
−
∇
g
)
v_{1}=\eta(-\nabla g)
v1=η(−∇g)
v
2
=
α
v
1
+
η
(
−
∇
g
)
=
(
1
+
α
)
η
(
−
∇
g
)
v_{2}=\alpha v_{1}+\eta(-\nabla g)=(1+\alpha)\eta(-\nabla g)
v2=αv1+η(−∇g)=(1+α)η(−∇g)
v
3
=
α
v
2
+
η
(
−
∇
g
)
=
(
1
+
α
+
α
2
)
η
(
−
∇
g
)
v_{3}=\alpha v_{2}+\eta(-\nabla g)=(1+\alpha+\alpha^2)\eta(-\nabla g)
v3=αv2+η(−∇g)=(1+α+α2)η(−∇g)
.
.
.
.
.
.....
.....
(6)
v
i
n
f
=
(
1
+
α
+
α
2
+
.
.
.
+
α
n
)
⎵
1
1
−
α
η
(
−
∇
g
)
=
η
(
−
∇
g
)
1
−
α
v_{inf}=\underbrace{(1+\alpha+\alpha^2+...+\alpha^n)}_{\frac{1}{1-\alpha}}\eta(-\nabla g)=\frac{\eta(-\nabla g)}{1-\alpha}\tag{6}
vinf=1−α1
(1+α+α2+...+αn)η(−∇g)=1−αη(−∇g)(6)此时,若取
α
=
0.9
\alpha=0.9
α=0.9,则下一步的步长会是10倍于
η
(
−
∇
g
)
\eta(-\nabla g)
η(−∇g)大小,即快速收敛于局部最小值。
- AdaGrad:
在正式介绍AdaGrad之前,先介绍一个数学运算符号 ⨀ \bigodot ⨀,举个栗子 [ 4 , 9 ] ⨀ [ 4 , 9 ] = [ 16 , 81 ] [4,9]\bigodot[4,9]=[16,81] [4,9]⨀[4,9]=[16,81]其作用就是逐元素相乘。
AdaGrad核心:独立地适应适应所有模型参数的学习率,缩放每个参数的反比于其所有梯度历史平方值总和的平方根。
通俗地讲就是,对于每一维的参数空间,我们使用的学习率是不相同的。其梯度更新方法如下: (7) r t = r t − 1 + ∇ g ⨀ ∇ g r_{t}=r_{t-1}+\nabla g\bigodot \nabla g\tag{7} rt=rt−1+∇g⨀∇g(7) (8) x t = x t − 1 − η ϵ + r t ⨀ ∇ g x_{t}=x_{t-1}-\frac{\eta}{\epsilon+\sqrt{r_{t}}}\bigodot \nabla g\tag{8} xt=xt−1−ϵ+rtη⨀∇g(8)其中 r r r是累计梯度平方, ∇ g \nabla g ∇g是梯度, ϵ \epsilon ϵ是一个接近0的数,防止除以0, η \eta η是学习率。为了帮助理解,我还是举个栗子:
假设在二维平面上的梯度 g = [ 4 , 9 ] g=[4,9] g=[4,9],初始时 r = 0 r=0 r=0,则 r 1 = [ 16 , 81 ] r_1=[16,81] r1=[16,81],我们对第一维度进行更新时,采用 x t ( 1 ) = x t − 1 ( 1 ) − η ϵ + 16 × 4 x_t^{(1)}=x_{t-1}^{(1)}-\frac{\eta}{\epsilon+\sqrt{16}}\times4 xt(1)=xt−1(1)−ϵ+16η×4对第二维度进行更新时,采用 x t ( 2 ) = x t − 1 ( 2 ) − η ϵ + 81 × 9 x_t^{(2)}=x_{t-1}^{(2)}-\frac{\eta}{\epsilon+\sqrt{81}}\times9 xt(2)=xt−1(2)−ϵ+81η×9,从上面我们就可以看出,当梯度的某一个方向上比较大时,分母会约束其变小,而当梯度的某一个方向上比较小时,分母会令其相对变大。从中其实可以体现出归一化的效果,有点类似于下图的转换结果:
而在右边这种情况下,收敛速度更快此图来自于李宏毅的深度学习课程PPT
- RMSProp:
一般在凸优化的背景下,AdaGrad算法会有一些令人满意的理论性质,而在非凸问题中,可能表现效果就没有那么好了,因为 r r r采用的是累加方法,这也就使得学习率在到达一个局部最小值附近前,可能分母会变得比较大,导致参数更新基本不变,从而导致训练困难。因此,便出现了RMSProp,其修改AdaGrad以在非凸设定下效果更好。
RMSProp的核心: 使用指数衰减滑动平均以丢弃遥远过去的历史。
其梯度更新方法仅仅修改了AdaGrad中 ( 7 ) (7) (7)式,修改如下: (9) r t = ρ r t − 1 + ( 1 − ρ ) ∇ g ⨀ ∇ g r_{t}=\rho r_{t-1}+(1-\rho)\nabla g\bigodot \nabla g\tag{9} rt=ρrt−1+(1−ρ)∇g⨀∇g(9)其中 ρ \rho ρ为衰减速率,也就是我们之前 ( 5 ) (5) (5)式所用的 α \alpha α,相比于AdaGrad,使用指数衰减平均引入一个新的超参数 ρ \rho ρ,用来控制滑动平均的长度范围
-
Adam:
在理解了前面这些优化算法后,理解Adam就会变得易如反掌~
Adam的核心: RMSProp思想+Momentum思想
其梯度更新方法如下: (10) v t = ρ 1 v t − 1 − ( 1 − ρ 1 ) ∇ g v_t=\rho_1 v_{t-1}-(1-\rho_1) \nabla g\tag{10} vt=ρ1vt−1−(1−ρ1)∇g(10) (11) r t = ρ 2 r t − 1 + ( 1 − ρ 2 ) ∇ g ⨀ ∇ g r_{t}=\rho_2 r_{t-1}+(1-\rho_2)\nabla g\bigodot \nabla g\tag{11} rt=ρ2rt−1+(1−ρ2)∇g⨀∇g(11) (12) v t ^ = v t 1 − ρ 1 t \hat{v_t}=\frac{v_t}{1-\rho_1^t}\tag{12} vt^=1−ρ1tvt(12) (13) r t ^ = r t 1 − ρ 2 t \hat{r_t}=\frac{r_t}{1-\rho_2^t}\tag{13} rt^=1−ρ2trt(13) (14) x t = x t − 1 − η v t ^ ϵ + r t ^ ⨀ ∇ g x_{t}=x_{t-1}-\frac{\eta\hat{v_t}}{\epsilon+\sqrt{\hat{r_{t}}}}\bigodot \nabla g\tag{14} xt=xt−1−ϵ+rt^ηvt^⨀∇g(14)
其中 ( 10 ) (10) (10)是对 ( 3 ) (3) (3)式做了略微修改, ( 11 ) (11) (11)式是对 ( 7 ) (7) (7)式进行了指数衰减, ( 12 ) 、 ( 13 ) (12)、(13) (12)、(13)是对速度 v v v和累计平方梯度 r r r进行了修正(下面会讲原因), ( 14 ) (14) (14)式是在 ( 8 ) (8) (8)式的基础上多乘了 v ^ \hat{v} v^。所以可以看出,在Adam算法中包含了RMSRorp和Momentum的影子。
Adam参数的建议值:
η = 0.001 \eta=0.001 η=0.001、 ρ 1 = 0.9 \rho_1=0.9 ρ1=0.9、 ρ 2 = 0.99 \rho_2=0.99 ρ2=0.99
通过观察 ( 12 ) (12) (12),我们可以发现,当 t t t比较小时, 1 1 − ρ 1 t \frac{1}{1-\rho_1^t} 1−ρ1t1会比较大,从而增大了 v t v_t vt,当 t t t比较大时, 1 1 − ρ 1 t → 1 \frac{1}{1-\rho_1^t}\rightarrow1 1−ρ1t1→1,对 v t v_t vt几乎不参产生影响。同理, ( 13 ) (13) (13)式也是如此。那为什么要这么做呢?我们可以通过前面的一张图来理解 -
总结:
在以上所介绍的优化算法中,并没有完全意义上最优的选择,要针对具体问题具体分析。但是,一般来说,Adam算法真的是首选
[1] Ian Goodfellow,Yoshua Bengio,Aaron courville.深度学习[M].人民邮电出版社.
[2] 动手学习深度学习. 李沐
[3] cs231n. 李飞飞
[4] 深度学习. 李宏毅
如果觉得我有地方讲的不好的或者有错误的欢迎给我留言,谢谢大家阅读(点个赞我可是会很开心的哦)~