深度学习优化算法
梯度下降想必没有人不知道,深度学习的优化算法都是基于梯度下降,这里对一些算法做一个总结。
Momentum
又称动量法,将目标函数梯度的指数加权平均作为更新的方向。
v
t
=
γ
v
t
−
1
+
η
t
g
t
x
t
=
x
t
−
1
−
v
t
\boldsymbol{v}_t = \gamma \boldsymbol{v}_{t-1}+\eta_t\boldsymbol{g}_t\\ \boldsymbol{x}_t = \boldsymbol{x}_{t-1}-\boldsymbol{v}_t
vt=γvt−1+ηtgtxt=xt−1−vt
γ
\gamma
γ为超参数,满足
0
≤
γ
<
1
0\le \gamma \lt 1
0≤γ<1;
v
t
\boldsymbol{v}_t
vt为动量变量,在时间步0初始化为
0
\boldsymbol{0}
0;
g
t
\boldsymbol{g}_t
gt目标函数为在时间步
t
t
t的小批量梯度;
η
t
\eta_t
ηt为时间步
t
t
t的学习率。
动量法近似于将最近 1 1 − γ \frac{1}{1-\gamma} 1−γ1个时间步的普通更新量做了指数加权平均。因此,自变量在各个方向上的移动幅度不仅取决于当前梯度,还取决于过去的各个梯度在各个方向上是否一致,避免自变量更新幅度过大导致越过最优解。
AdaGrad
AdaGrad算法使用一个小批量梯度
g
t
\boldsymbol{g}_t
gt按元素平方的累加变量
s
t
\boldsymbol{s}_t
st。在时间步0,将
s
0
\boldsymbol{s}_0
s0初始化为
0
\boldsymbol{0}
0,在时间步
t
t
t,令
s
t
=
s
t
−
1
+
g
t
⊙
g
t
x
t
=
x
t
−
1
−
η
s
t
+
ϵ
⊙
g
t
\boldsymbol{s}_t=\boldsymbol{s}_{t-1}+\boldsymbol{g}_t\odot\boldsymbol{g}_t\\ \boldsymbol{x}_t = \boldsymbol{x}_{t-1}-\frac{\eta}{\sqrt{\boldsymbol{s}_t+\epsilon}}\odot\boldsymbol{g}_t
st=st−1+gt⊙gtxt=xt−1−st+ϵη⊙gt
ϵ
\epsilon
ϵ是一个极小的常数,用于维持数值稳定性,如
1
0
−
6
10^{-6}
10−6。
很显然,AdaGrad算法能够避免梯度过大。若某元素的偏导数一直较大,那么该元素的学习率下降较快;反之该元素的学习率下降较慢。
由于 s t \boldsymbol{s}_t st一直在增大,那么学习率就一直降低。所以,当学习率在迭代早期降得过快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。
RMSProp
AdaGrad算法的缺点十分明显,因此,RMSProp对AdaGrad算法做了一点修改。不同于AdaGrad算法中的
s
t
\boldsymbol{s}_t
st是所有小批量梯度
g
t
\boldsymbol{g}_t
gt的平方和,RMSProp算法将梯度的平方做指数加权移动平均。也就是说
s
t
=
γ
s
t
−
1
+
(
1
−
γ
)
g
t
⊙
g
t
x
t
=
x
t
−
1
−
η
s
t
+
ϵ
⊙
g
t
\boldsymbol{s}_t=\gamma\boldsymbol{s}_{t-1}+(1-\gamma)\boldsymbol{g}_t\odot\boldsymbol{g}_t\\ \boldsymbol{x}_t = \boldsymbol{x}_{t-1}-\frac{\eta}{\sqrt{\boldsymbol{s}_t+\epsilon}}\odot\boldsymbol{g}_t
st=γst−1+(1−γ)gt⊙gtxt=xt−1−st+ϵη⊙gt
RMSProp的状态变量
s
t
\boldsymbol{s}_t
st可以看作是最近
1
1
−
γ
\frac{1}{1-\gamma}
1−γ1个时间步的小批量梯度的平方的加权平均,这样学习率就不会一直降低。
AdaDelta
AdaDelta算法也是针对AdaGrad算法的缺点做了改进,与RMSProp算法一样,AdaDelta算法的状态变量
s
t
\boldsymbol{s}_t
st的计算方式为
s
t
=
ρ
s
t
−
1
+
(
1
−
ρ
)
g
t
⊙
g
t
\boldsymbol{s}_t=\rho\boldsymbol{s}_{t-1}+(1-\rho)\boldsymbol{g}_t\odot\boldsymbol{g}_t
st=ρst−1+(1−ρ)gt⊙gt
0
≤
ρ
<
1
0 \le \rho \lt 1
0≤ρ<1。
AdaDelta算法还维护了额外的状态变量
Δ
x
t
\Delta\boldsymbol{x}_t
Δxt,在时间步0初始化为
0
\boldsymbol{0}
0,使用
Δ
x
t
−
1
\Delta\boldsymbol{x}_{t-1}
Δxt−1来计算自变量的变化量
g
t
′
=
Δ
x
t
−
1
+
ϵ
s
t
+
ϵ
⊙
g
t
\boldsymbol{g}'_t=\sqrt{\frac{\Delta\boldsymbol{x}_{t-1}+\epsilon}{\boldsymbol{s}_t+\epsilon}}\odot\boldsymbol{g}_t
gt′=st+ϵΔxt−1+ϵ⊙gt
之后更新自变量
x
t
=
x
t
−
1
−
g
t
′
\boldsymbol{x}_t = \boldsymbol{x}_{t-1}-\boldsymbol{g}'_t
xt=xt−1−gt′
最后,使用
Δ
x
t
\Delta\boldsymbol{x}_t
Δxt来记录自变量变化量
g
t
′
\boldsymbol{g}'_t
gt′按元素平方的指数加权移动平均
Δ
x
t
=
ρ
Δ
x
t
−
1
+
(
1
−
ρ
)
g
t
′
⊙
g
t
′
\Delta\boldsymbol{x}_t=\rho\Delta\boldsymbol{x}_{t-1}+(1-\rho)\boldsymbol{g}'_t\odot\boldsymbol{g}'_t
Δxt=ρΔxt−1+(1−ρ)gt′⊙gt′
可以看到,AdaDelta没有学习率参数,而是使用
Δ
x
t
−
1
\sqrt{\Delta\boldsymbol{x}_{t-1}}
Δxt−1来代替学习率。
Adam
Adam算法在RMSProp算法的基础上对小批量梯度也做了指数加权移动平均,可以看成RMSProp和Momentum的结合
Adam算法使用了动量变量
v
t
\boldsymbol{v}_t
vt和RMSProp算法中的状态变量
s
t
\boldsymbol{s}_t
st,在时间步0均初始化为
0
\boldsymbol{0}
0。给定超参数
β
1
\beta_1
β1(作者推荐设为0.9)和
β
2
\beta_2
β2(作者推荐设为0.999),两者的计算方式为
v
t
=
β
1
v
t
−
1
+
(
1
−
β
1
)
g
t
s
t
=
β
2
s
t
−
1
+
(
1
−
β
2
)
g
t
⊙
g
t
\boldsymbol{v}_t = \beta_1\boldsymbol{v}_{t-1}+(1-\beta_1)\boldsymbol{g}_t\\ \boldsymbol{s}_t=\beta_2\boldsymbol{s}_{t-1}+(1-\beta_2)\boldsymbol{g}_t\odot\boldsymbol{g}_t
vt=β1vt−1+(1−β1)gtst=β2st−1+(1−β2)gt⊙gt
由于
s
0
\boldsymbol{s}_0
s0和
v
0
\boldsymbol{v}_0
v0均为
0
\boldsymbol{0}
0,在时间步
t
t
t有
v
t
=
(
1
−
β
1
)
∑
i
=
1
t
β
1
t
−
i
g
i
\boldsymbol{v}_t=(1-\beta_1)\sum_{i=1}^t\beta_1^{t-i}\boldsymbol{g}_i
vt=(1−β1)∑i=1tβ1t−igi,各个小批量梯度的权值累加起来为
(
1
−
β
1
)
∑
i
=
1
t
β
1
t
−
i
=
1
−
β
1
t
(1-\beta_1)\sum_{i=1}^t\beta_1^{t-i}=1-\beta_1^t
(1−β1)∑i=1tβ1t−i=1−β1t。当
t
t
t较小时,过去各个小批量t梯度的权值之和会比较小,如当
β
1
=
0.9
\beta_1=0.9
β1=0.9
v
1
=
0.1
g
1
\boldsymbol{v}_1=0.1\boldsymbol{g}_1
v1=0.1g1,为了消除这个影响,对于任意时间步
t
t
t,将
v
t
\boldsymbol{v}_t
vt除以
1
−
β
1
t
1-\beta_1^t
1−β1t,从而使过去各个时间步小批量梯度的权值之和为1,这也叫偏差修正
v
^
t
=
v
t
1
−
β
1
t
s
^
t
=
s
t
1
−
β
2
t
\hat{\boldsymbol{v}}_t=\frac{\boldsymbol{v}_t}{1-\beta_1^t}\\ \hat{\boldsymbol{s}}_t=\frac{\boldsymbol{s}_t}{1-\beta_2^t}\\
v^t=1−β1tvts^t=1−β2tst
之后,使用修正后的变量
v
^
t
\hat{\boldsymbol{v}}_t
v^t和
s
^
t
\hat{\boldsymbol{s}}_t
s^t,计算自变量变化量
g
t
′
=
η
v
^
t
s
^
t
+
ϵ
\boldsymbol{g}'_t=\frac{\eta\hat{\boldsymbol{v}}_t}{\sqrt{\hat{\boldsymbol{s}}_t}+\epsilon}
gt′=s^t+ϵηv^t
η
\eta
η是学习率,最后使用
g
t
′
\boldsymbol{g}'_t
gt′更新自变量
x
t
=
x
t
−
1
−
g
t
′
\boldsymbol{x}_t = \boldsymbol{x}_{t-1}-\boldsymbol{g}'_t
xt=xt−1−gt′
显然,还可以将Adam算法和AdaDelta算法结合,使用
Δ
x
t
−
1
\sqrt{\Delta\boldsymbol{x}_{t-1}}
Δxt−1来代替学习率。
总结
Momentum对梯度做了指数加权平均,防止更新幅度过大越过最优解。
AdaGrad对梯度的平方求和,防止更新幅度过大,但学习率会一直降低。
RMSProp对AdaGrad做了改进,对梯度的平方做指数加权移动平均,学习率不会一直降低。
AdaDelta也是对AdaGrad的改进,对自变量的变化量平方的指数加权平均开根号,代替学习率。
Adam可以看作是Momentum和RMSProp的结合,即对梯度做了加权平均,也用梯度平方的加权平均来防止更新幅度过大。
总的来说,Momentum对更新方向做修正,AdaGrad、RMSProp和AdaDelta对学习率做修正,Adam对更新方向和学习率都做了修正。