这几天看了李宏毅的深度学习课程,趁此机会梳理一下优化器(optimizer
),并附带pytorch
代码
前言
在介绍优化器前,我们要时刻记得:什么是优化器?或者说优化器的作用是什么?
优化器:找到一组
θ
\theta
θ 使得
Σ
x
L
(
θ
;
x
)
{\Sigma}_x L(\theta;x)
ΣxL(θ;x) 最小。 这里的x是训练的样本,L
是定义的损失函数(loss function
)
下面将优化器分成常见的5个基本优化器和之后根据这5个优化器生出的各种变种。
常见的5个基本优化器
SGD (Stochastic Gradient Descent)
- 意义
SGD
的想法很简单,每次按照梯度的反方向更新参数,同时使用 η \eta η来控制更新的步长。初始时使用随机初始的 θ 0 \theta^0 θ0 - 公式
- init: θ 0 {\theta}^0 θ0
- update: ${\theta}^t = {\theta}^{t-1} - \eta \nabla L({\theta}^{t-1}) $
SGDM (Stochastic Gradient Descent with Movement)
-
意义
仔细观察上面的SGD
算法,我们可以发现,当梯度 ∇ L ( θ ) = 0 \nabla L({\theta})=0 ∇L(θ)=0 后(见图1),参数就不会更新了,这时遇到了两种情况:(1).遇到了局部最小值(local minima
) (2). 遇到了鞍点(saddle point
)。而实际上,我们遇到鞍点的情况更多。观察鞍点我们发现实际上仍然有更好的 θ \theta θ,只是因为优化算法的问题导致不能再优化了。
图1. 常见的两种梯度为0的情况 这时引入一个动量,让优化器在 ∇ L ( θ ) = 0 \nabla L({\theta})=0 ∇L(θ)=0的时候不停止,而是继续探索,于是SGDM算法出来了
-
公式
- init θ 0 \theta^0 θ0, v 0 = 0 v^0=0 v0=0
- update:
- v v v: v t = λ v t − 1 − η ∇ L ( θ t − 1 ) v^t = \lambda v^{t-1} - \eta \nabla L({\theta}^{t-1}) vt=λvt−1−η∇L(θt−1)
- θ \theta θ: θ t = θ t − 1 + v t \theta^t = \theta^{t-1} + v^t θt=θt−1+vt
-
解决的痛点: ∇ L ( θ ) = 0 \nabla L({\theta})=0 ∇L(θ)=0时停止优化
-
亮点:引入时间信息
AdaGrad (Adaptive Gradient Algorithm)
- 意义
通过函数可视化的图,我们会发现,当一个位置越 “陡峭”,该位置的梯度值越大(因为梯度是个向量,这里可以把梯度值越大理解为向量中每个值都越大);当一个位置越 “平缓” ,该位置的梯度值越小(见图2)。这样就会导致在 η \eta η固定的时候,在 “陡峭” 的地方,优化器会迈出更大的步长,在 “平缓” 的地方迈出更小的步长。这样就会导致一个问题:优化器来回震荡,优化器很难得到合适的 θ \theta θ。 如图3。
自然,我们想到在 η \eta η下面加个分母解决这个问题,并且这个分母能够动态自适应。于是AdaGrad算法出来了
-
公式
- init: θ 0 , σ 0 = ∣ g 0 ∣ \theta^0,\sigma^0=|g^0| θ0,σ0=∣g0∣,这里为了方便令: g = ∇ L ( θ ) g=\nabla L(\theta) g=∇L(θ)
- update:
- θ t = θ t − 1 − η σ t − 1 g t − 1 {\theta}^{t} = {\theta}^{t-1}-\frac{\eta}{{\sigma}^{t-1}}g^{t-1} θt=θt−1−σt−1ηgt−1
- σ t − 1 = 1 t ∑ i = 0 t − 1 ( g t − 1 ) 2 {\sigma}^{t-1} = \sqrt{\frac{1}{t}\sum\limits_{i=0}^{t-1} (g^{t-1})^2} σt−1=t1i=0∑t−1(gt−1)2
-
解决的痛点:让优化器根据周围环境自适应调整步长
-
亮点:引入空间信息
RMSProP (Root Mean Square Prop)
-
意义
RMSProP
是在AdaGrad
算法上进行改进的。AdaGrad
算法是对以前所有的梯度值都累加到 η \eta η的分母中,这就会导致一个问题:一开始AdaGrad
比较大的时候, η σ \frac{\eta}{\sigma} ση 这个值很小,导致开始优化没几步就卡住。 另外还有一个原因,就是之前的梯度对她的影响都是相同权重的,RMSProP
提出让之前的梯度值对后来的影响逐步衰减。 -
公式
- init: θ 0 , σ 0 = ∣ ∣ g 0 ∣ ∣ \theta^0,\sigma^0=||g^0|| θ0,σ0=∣∣g0∣∣,这里为了方便令: g = ∇ L ( θ ) g=\nabla L(\theta) g=∇L(θ)
- update:
- θ t = θ t − 1 − η σ t − 1 g t − 1 {\theta}^{t} = {\theta}^{t-1}-\frac{\eta}{{\sigma}^{t-1}}g^{t-1} θt=θt−1−σt−1ηgt−1
- σ t = α ( σ t − 1 ) 2 + ( 1 − α ) ( g t ) 2 {\sigma}^t = \sqrt{\alpha {(\sigma^{t-1})}^2 + (1-\alpha){(g^t)}^2} σt=α(σt−1)2+(1−α)(gt)2
-
解决的痛点:初始化梯度太大时,可能训练几步就动不了
-
亮点:多了一个 α \alpha α来控制最近的梯度大小对当前优化的影响
Adam
-
意义
Adam
就是RMSProP+momentum
,将momentum
思想引入RMSProP
中。 -
公式
- init: m 0 = 0 , v 0 = 0 , t = 0 m^0 = 0,v^0 = 0,t=0 m0=0,v0=0,t=0
- update:
- m t = β 1 m t − 1 + ( 1 − β 1 ) g t m^t = \beta_1 m_{t-1} + (1-\beta_1)g^t mt=β1mt−1+(1−β1)gt
- v t = β 2 v t − 1 + ( 1 − β 2 ) ( g t ) 2 v^t = \beta_2 v^{t-1} + (1-\beta_2) (g^t)^2 vt=β2vt−1+(1−β2)(gt)2
- m ^ t = m t 1 − β 1 t \hat{m}^t = \frac{m^t}{1-\beta_1^t} m^t=1−β1tmt //这一步是因为初始 m t m^t mt太小,容易产生偏差,这里除 1 − β 1-\beta 1−β来抵消掉
- v ^ t = v t 1 − β 2 t \hat{v}^t = \frac{v^t}{1-\beta_2^t} v^t=1−β2tvt //这和上面 m ^ t 相 同 \hat{m}^t相同 m^t相同
- θ t = θ t − 1 − η m ^ t v ^ t + ϵ \theta^t = \theta^{t-1} - \eta\frac{\hat{m}^t}{\sqrt{\hat{v}^t}+\epsilon} θt=θt−1−ηv^t+ϵm^t
- 官方建议:
- β 1 = 0.9 \beta_1=0.9 β1=0.9
- β 2 = 0.999 \beta_2=0.999 β2=0.999
- ϵ = 1 0 − 8 \epsilon=10^{-8} ϵ=10−8
-
亮点:结合了
RMSProP
和momentum
的优点
未完待续(后面有时间慢慢补充的)
-
以5个优化器为基础的变种
1.1. 结合Adam和SGD
1.2. 针对Adam的缺点提出的改进
1.3. 针对SGDM提出的
1.4. Nesterov Accelerated Gradient (NAG)在优化时加入对未来的预测
1.5. 加上weihgt decay的优化器 -
各个优化器在pytorch中的代码