一、发展背景及基本框架
梯度下降是目前神经网络中使用最为广泛的优化算法之一。为了弥补朴素梯度下降的种种缺陷,研究者们发明了一系列变种算法,从最初的 SGD (随机梯度下降) 逐步演进到 NAdam。然而,许多学术界最为前沿的文章中,都并没有一味使用 Adam/NAdam 等公认“好用”的自适应算法,很多甚至还选择了最为初级的 SGD 或者 SGD with Momentum 等。
深度学习优化算法的发展历程:
SGD -> SGDM -> NAG ->AdaGrad -> AdaDelta -> Adam -> Nadam
最基本的框架——梯度下降法(GD)
梯度下降法(GD:gradient descent )或最速下降法(SD:steepest descent )是求解无约束优化问题最常用的方法,实现简单。
梯度下降是指,在给定待优化的模型参数 θ ∈ R d \theta \in \mathbb{R}^d θ∈Rd和目标函数 J ( θ ) J(\theta) J(θ) 后,算法通过沿梯度 ∇ θ J ( θ ) \nabla_\theta J(\theta) ∇θJ(θ) 的相反方向更新 θ \theta θ 来最小化 J ( θ ) J(\theta) J(θ) 。学习率 η \eta η 决定了每一时刻的更新步长。对于每一个时刻 t t t ,我们可以用下述步骤描述梯度下降的流程:
(1) 计算目标函数关于参数的梯度
g
t
=
∇
θ
J
(
θ
)
g_t = \nabla_\theta J(\theta)
gt=∇θJ(θ)
(2) 根据历史梯度计算一阶和二阶动量
m
t
=
ϕ
(
g
1
,
g
2
,
⋯
 
,
g
t
)
m_t = \phi(g_1, g_2, \cdots, g_t)
mt=ϕ(g1,g2,⋯,gt)
v
t
=
ψ
(
g
1
,
g
2
,
⋯
 
,
g
t
)
v_t = \psi(g_1, g_2, \cdots, g_t)
vt=ψ(g1,g2,⋯,gt)
(3) 更新模型参数
θ
t
+
1
=
θ
t
−
1
v
t
+
ϵ
m
t
\theta_{t+1} = \theta_t - \frac{1}{\sqrt{v_t + \epsilon}} m_t
θt+1=θt−vt+ϵ1mt
其中,
ϵ
\epsilon
ϵ 为平滑项,防止分母为零,通常取 1e-8。
二、GD算法体系
先上图做直观对比:
“长谷 (Long Valley)”点——没有基于梯度信息缩放的算法在这里很难打破对称性——SGD在哪里都找不到, Nesterov Accelerated Gradient(NAG) / Momentum 在优化方向上建立速度之前会出现振荡。(此时自适应算法会更好)
由于大的初始梯度,基于速度的技术(SGD-M ,NAG)被发射出来并在周围反弹。其中 Adagrad、Adadelta、RMSprop 从最开始就找到了正确的方向并快速收敛;SGD 找到了正确方向但收敛速度很慢;SGD-M 和 NAG 最初都偏离了航道,但也能最终纠正到正确方向,SGD-M 偏离的惯性比 NAG 更大。
鞍点(Saddle Point)附近的行为:
NAG /Momentum探索周围,几乎走了不同的路径。
Adadelta/Adagrad/RMSProp像加速SGD一样运行。
2.1-朴素 SGD (Stochastic Gradient Descent)
最为简单,没有动量的概念
这时,更新步骤就是最简单的
θ
i
+
1
=
θ
t
−
η
g
t
\theta_{i+1}= \theta_t - \eta g_t
θi+1=θt−ηgt
SGD 的缺点在于收敛速度慢,可能在长谷处震荡。并且,如何合理的选择学习率是 SGD 的一大难点。
2.2-SGD with Momentum
为了抑制SGD的震荡,SGDM认为梯度下降过程可以加入惯性。下坡的时候,如果发现是陡坡,那就利用惯性跑的快一些。SGDM全称是SGD with momentum,在SGD基础上引入了一阶动量:
m
t
=
γ
m
t
−
1
+
η
g
t
m_t = \gamma m_{t-1} + \eta g_t
mt=γmt−1+ηgt
SGD-M 在原步长之上,增加了与上一时刻步长相关的
γ
m
t
−
1
\gamma m_{t-1}
γmt−1 ,
γ
\gamma
γ 通常取 0.9 左右。这意味着参数更新方向不仅由当前的梯度决定,也与此前累积的下降方向有关。
这使得参数中那些梯度方向变化不大的维度可以加速更新,并减少梯度方向变化较大的维度上的更新幅度。由此产生了加速收敛和减小震荡的效果。
从形式上看,动量算法(红色)引入了变量v 充当速度角色——它代表参数在参数空间移动的方向和速率。速度被设为负梯度的指数衰减平均。
2.3-Nesterov Accelerated Gradient
更进一步的,人们希望下降的过程更加智能:算法能够在目标函数有增高趋势之前,减缓更新速率。
NAG 即是为此而设计的,其在 SGD-M 的基础上进一步改进了步骤 1 中的梯度计算公式:
g
t
=
∇
θ
J
(
θ
−
γ
m
t
−
1
)
g_t = \nabla_\theta J(\theta - \gamma m_{t-1})
gt=∇θJ(θ−γmt−1)
SGD-M 的步长计算了当前梯度(短蓝向量)和动量项 (长蓝向量)。然而,既然已经利用了动量项来更新 ,那不妨先计算出下一时刻
θ
\theta
θ 的近似位置 (棕向量),并根据该未来位置计算梯度(红向量),然后使用和 SGD-M 中相同的方式计算步长(绿向量)。这种计算梯度的方式可以使算法更好的「预测未来」,提前调整更新速率。
2.4-Adagrad(自适应更新学习率)
Ada为Adaptive,自适应算法。
SGD、SGD-M 和 NAG 均是以相同的学习率去更新 θ \theta θ 的各个分量。而深度学习模型中往往涉及大量的参数,不同参数的更新频率往往有所区别。
对于更新不频繁的参数(典型例子:更新 word embedding 中的低频词),我们希望单次步长更大,多学习一些知识;对于更新频繁的参数,我们则希望步长较小,使得学习到的参数更稳定,不至于被单个样本影响太多。
Adagrad算法即可达到此效果。其引入了二阶动量:
Adaptive Subgradient Methods for Online Learning and Stochastic Optimization
v t = diag ( ∑ i = 1 t g i , 1 2 , ∑ i = 1 t g i , 2 2 , ⋯   , ∑ i = 1 t g i , d 2 ) v_t = \text{diag}(\sum_{i=1}^t g_{i,1}^2, \sum_{i=1}^t g_{i,2}^2, \cdots, \sum_{i=1}^t g_{i,d}^2) vt=diag(∑i=1tgi,12,∑i=1tgi,22,⋯,∑i=1tgi,d2)
其中, v t ∈ R d × d v_t \in \mathbb{R}^{d\times d} vt∈Rd×d 是对角矩阵,其元素 v t , i i v_{t, ii} vt,ii 为参数第 i 维从初始时刻到时刻 t 的梯度平方和。
此时,可以这样理解:学习率等效为 η / v t + ϵ \eta / \sqrt{v_t + \epsilon} η/vt+ϵ 。对于此前频繁更新过的参数,其二阶动量的对应分量较大,学习率就较小。这一方法在稀疏数据的场景下表现很好。
2.5-RMSprop
在 Adagrad 中, v t v_t vt是单调递增的,使得学习率逐渐递减至 0,可能导致训练过程提前结束。为了改进这一缺点,可以考虑在计算二阶动量时不累积全部历史梯度,而只关注最近某一时间窗口内的下降梯度。根据此思想有了 RMSprop
记
g
t
⊙
g
t
g_t \odot g_t
gt⊙gt 为
g
t
2
g_t^2
gt2 ,有
v
t
=
γ
v
t
−
1
+
(
1
−
γ
)
⋅
diag
(
g
t
2
)
v_t = \gamma v_{t-1} + (1-\gamma) \cdot \text{diag}(g_t^2)
vt=γvt−1+(1−γ)⋅diag(gt2)
其二阶动量采用指数移动平均公式计算,这样即可避免二阶动量持续累积的问题。和 SGD-M 中的参数类似,\gamma 通常取 0.9 左右。
2.6-Adam
Adam可以认为是 RMSprop 和 Momentum 的结合。和 RMSprop 对二阶动量使用指数移动平均类似,Adam 中对一阶动量也是用指数移动平均计算。
m
t
=
η
[
β
1
m
t
−
1
+
(
1
−
β
1
)
g
t
]
m_t = \eta[ \beta_1 m_{t-1} + (1 - \beta_1)g_t ]
mt=η[β1mt−1+(1−β1)gt]
v
t
=
β
2
v
t
−
1
+
(
1
−
β
2
)
⋅
diag
(
g
t
2
)
v_t = \beta_2 v_{t-1} + (1-\beta_2) \cdot \text{diag}(g_t^2)
vt=β2vt−1+(1−β2)⋅diag(gt2)
其中,初值
m
0
=
0
m_0 = 0
m0=0
v
0
=
0
v_0 = 0
v0=0
注意到,在迭代初始阶段,
m
t
m_t
mt 和
v
t
v_t
vt 有一个向初值的偏移(过多的偏向了 0)。因此,可以对一阶和二阶动量做偏置校正 (bias correction),
m
^
t
=
m
t
1
−
β
1
t
\hat{m}_t = \frac{m_t}{1-\beta_1^t}
m^t=1−β1tmt
v
^
t
=
v
t
1
−
β
2
t
\hat{v}_t = \frac{v_t}{1-\beta_2^t}
v^t=1−β2tvt
再进行更新,
θ
t
+
1
=
θ
t
−
1
v
^
t
+
ϵ
m
^
t
\theta_{t+1} = \theta_t - \frac{1}{\sqrt{\hat{v}_t} + \epsilon } \hat{m}_t
θt+1=θt−v^t+ϵ1m^t
可以保证迭代较为平稳。
三、小结
虽然这些算法在使用的时候或许只是一句代码,但了解其发展历程和基本特点是很有必要的。
参考:
[1]从 SGD 到 Adam —— 深度学习优化算法概览(一) - 骆梁宸的文章 - 知乎
https://zhuanlan.zhihu.com/p/32626442
[2]一个框架看懂优化算法之异同 SGD/AdaGrad/Adam - Juliuszh的文章 - 知乎
https://zhuanlan.zhihu.com/p/32230623
[3]https://blog.csdn.net/u012223913/article/details/78432412
[4]Visualizing Optimization Algos