这边简要都说一下深度学习各种优化算法的原理,以及实现。
梯度下降(Gradient Descent)
在说梯度下降前先了解一下学习率(learning rate,我们这里记作 η \eta η)
学习率作为参数决定目标函数能否收敛到局部最小值,以及何时收敛到最小值。学习率太小会导致梯度下降速度过慢,训练耗时很长,学习率太大会导致无法收敛。
尽管梯度下降很少直接用于深度学习, 但了解它是理解下一节随机梯度下降算法的关键。
为了很好都理解选取目标函数(损失函数) f ( x ) = x 2 f(x) = x^2 f(x)=x2
f ′ ( x ) = 2 x f^{\prime}(x) = 2x f′(x)=2x
我们设初始值 x = 10 x = 10 x=10, η = 0.2 \eta = 0.2 η=0.2
x 1 = 10 x_{1} = 10 x1=10 f ( x ) = 100 f(x) = 100 f(x)=100
x 2 = 6 x_{2} = 6 x2=6 x 2 = x 1 − η f ′ ( x 1 ) x_{2} = x_{1} - \eta f^{\prime}(x_{1}) x2=x1−ηf′(x1) f ( x 2 ) = 36 f(x_2) = 36 f(x2)=36
x 3 = 3.6 x_{3} = 3.6 x3=3.6 x 3 = x 2 − η f ′ ( x 2 ) x_{3} = x_{2} - \eta f^{\prime}(x_{2}) x3=x2−ηf′(x2) f ( x 3 ) = 12.96 f(x_3) = 12.96 f(x3)=12.96
…
损失下降如图所示:
批梯度下降(BGD)
所有都样本参数都参加每次迭代更新
缺点:样本很多,更新一次要很久,时间花费和内存开销都非常大
我们通常说都梯度梯度下降指的是批梯度下降,就是用梯度下降公式,迭代所有样本都参数值
随机度下降(SGD)
所谓随机如果使用梯度下降法,则每个自变量迭代的计算代价为 O ( n ) \mathcal{O}(n) O(n),它随 n n n线性增长。因此,当训练数据集较大时,每次迭代的梯度下降计算代价将较高。
随机梯度下降(SGD)可降低每次迭代时的计算代价。在随机梯度下降的每次迭代中,随机都选择一样样本参数进行更新,可以看出计算代价降为为 O ( 1 ) \mathcal{O}(1) O(1).
缺点:但由于每步接受的信息量有限,随机梯度下降法对梯度的估计常常出现偏差,造成目标函数曲线收敛得很不稳定,伴有剧烈波动,有时甚至出现不收敛的情况
小批量梯度下降(MGD)
小批量梯度下降,即min- batch,每次迭代,其实批量的梯度下降就是一种折中的方法,他用了一些小样本来近似全部的,比如使用20个样本或者30个样本进行迭代更新,那比随机的要准确不少了吧,而且批量的话还是非常可以反映样本的一个分布情况的。在深度学习中,这种方法用的是最多的,因为这个方法收敛也不会很慢,收敛的局部最优也是更多的可以接受。注:当每次min-batch参数1时就变成了SGD
缺点:同SGD一样,再收敛时浮动,不稳定,再最优解附近震动,
动量梯度下降
SGD 在遇到沟壑时容易陷入震荡。为此,可以为其引入动量 ,加速 SGD 在正确方向的下降并抑制震荡。
主要原理是用过去梯度的平均值来替换梯度,这大大加快了收敛速度,可以防止在随机梯度下降的优化过程停滞的问题。
在随机梯度下降(SGD)中加入指数加权平均数来更新参数的梯度,其中加权值通常设为0.9。
S
d
W
[
l
]
=
β
S
d
W
[
l
]
+
(
1
−
β
)
d
W
[
l
]
S
d
b
[
l
]
=
β
S
d
b
[
l
]
+
(
1
−
β
)
d
b
[
l
]
W
[
l
]
:
=
W
[
l
]
−
α
S
d
W
[
l
]
b
[
l
]
:
=
b
[
l
]
−
α
S
d
b
[
l
]
\begin{aligned} &S_{d W}[l]=\beta S_{d W}[l]+(1-\beta) d W^{[l]} \\ &S_{d b}[l]=\beta S_{d b}[l]+(1-\beta) d b[l] \\ &W[l]:=W^{[l]}-\alpha S_{d W}[l] \\ &{ }_{b}[l]:=b[l]-\alpha S_{d b}[l] \end{aligned}
SdW[l]=βSdW[l]+(1−β)dW[l]Sdb[l]=βSdb[l]+(1−β)db[l]W[l]:=W[l]−αSdW[l]b[l]:=b[l]−αSdb[l]
那么这样梯度下降过程会有什么变化,如下图所示:
当前后梯度方向一致时,动量梯度下降能够加速学习;而前后梯度方向不一致时,动量梯度下降能够抑制震荡。
AdaGrad 算法
AdaGrad算法会使用一个小批量随机梯度
g
t
gt
gt按元素平方的累加变量
s
t
st
st,在时间为0,AdaGrad将
s
0
s0
s0中每个元素初始化为0。在时间为
t
t
t,首先将小批量随机梯度
g
t
gt
gt按元素平方后累加到变量st:
s
t
←
s
t
−
1
+
g
t
⊙
g
t
s t \leftarrow s t-1+g t \odot g t
st←st−1+gt⊙gt
其中⊙是按元素相乘。接着,我们将目标函数自变量中每个元素的学习率通过按元素运算重新调整一下:
w
t
←
w
t
−
1
−
α
s
t
+
ϵ
⊙
g
t
w_{t} \leftarrow w_{t}-1-\frac{\alpha}{\sqrt{s t+\epsilon}} \odot g_{t}
wt←wt−1−st+ϵα⊙gt
小批量随机梯度按元素平方的累加变量st出现在学习率的分母项中。
1、如果目标函数有关自变量中某个参数的偏导数一直都较大,那么该参数的学习率将下降较快;
2、反之,如果目标函数有关自变量中某个参数的偏导数一直都较小,那么该参数的学习率将下降较慢。
然而,由于
s
t
st
st一直在累加按元素平方的梯度,自变量中每个元素的学习率在迭代过程中一直在降低(或不变)。所以,当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。
RMSprop 算法
当学习率在迭代早期降得较快且当前解依然不佳时,AdaGrad算法在迭代后期由于学习率过小,可能较难找到一个有用的解。为了解决这一问题,RMSProp算法对AdaGrad算法做了一点小小的修改。
不同于AdaGrad算法里状态变量st是截至时间步t所有小批量随机梯度gt按元素平方和,RMSProp(Root Mean Square Prop)算法将这些梯度按元素平方做指数加权移动平均
s
d
w
=
β
s
d
w
+
(
1
−
β
)
(
d
w
)
2
s
d
b
=
β
s
d
b
+
(
1
−
β
)
(
d
b
)
2
w
:
=
w
−
α
s
d
w
+
ϵ
d
w
b
:
=
b
−
α
s
d
b
+
ϵ
d
b
\begin{aligned} &s d w=\beta s_{d w}+(1-\beta)(d w)^{2} \\ &s d b=\beta s_{d b}+(1-\beta)(d b)^{2} \\ &w:=w-\frac{\alpha}{\sqrt{s d w+\epsilon}} d w \\ &b:=b-\frac{\alpha}{\sqrt{s_{d b}+\epsilon}} d b \end{aligned}
sdw=βsdw+(1−β)(dw)2sdb=βsdb+(1−β)(db)2w:=w−sdw+ϵαdwb:=b−sdb+ϵαdb
其中
ϵ
\epsilon
ϵ是一样为了维持数值稳定一个常数。最终自变量每个元素的学习率在迭代过程中就不再一直降低。RMSProp 有助于减少抵达最小值路径上的摆动,并允许使用一个更大的学习率 α,从而加快算法学习速度。
Adam算法
Adam 优化算法(Adaptive Moment Estimation,自适应矩估计)将 Momentum 和 RMSProp 算法结合在一起。Adam算法在RMSProp算法基础上对小批量随机梯度也做了指数加权移动平均。
假设用每一个 mini-batch 计算 dW、db,第
t
t
t次迭代时:
原论文中作者建议的参数设置的值:
v
d
W
=
β
1
v
d
W
+
(
1
−
β
1
)
d
W
v
d
b
=
β
1
v
d
b
+
(
1
−
β
1
)
d
b
v
d
W
c
o
r
r
[
l
]
t
e
d
=
v
1
−
(
β
1
)
t
s
d
W
=
β
2
s
d
W
+
(
1
−
β
2
)
(
d
W
)
2
s
d
b
=
β
2
s
d
b
+
(
1
−
β
2
)
(
d
b
)
2
s
d
W
c
o
r
r
[
l
]
e
d
=
s
1
−
W
2
l
]
\begin{aligned} &v_{d W}=\beta 1 v_{d W}+(1-\beta 1) d W \\ &v_{d b}=\beta 1 v_{d b}+(1-\beta 1) d b \\ &v_{d W}^{c o r r}[l] t e d=\frac{v}{1}-(\beta 1)^{t} \\ &s_{d W}=\beta 2 s d W+(1-\beta 2)(d W)^{2} \\ &s_{d b}=\beta 2 s d b+(1-\beta 2)(d b)^{2} \\ &\left.s_{d W}^{c o r r}[l] e d=\frac{s}{1}-W^{2} l\right] \end{aligned}
vdW=β1vdW+(1−β1)dWvdb=β1vdb+(1−β1)dbvdWcorr[l]ted=1v−(β1)tsdW=β2sdW+(1−β2)(dW)2sdb=β2sdb+(1−β2)(db)2sdWcorr[l]ed=1s−W2l]
其中
l
l
l为某一层,
t
t
t为移动平均第次的值
Adam 算法的参数更新:
W
:
=
W
−
α
v
d
W
corrected
s
d
W
corrected
+
ϵ
b
:
=
b
−
α
v
d
b
corrected
s
d
b
corrected
+
ϵ
\begin{aligned} &W:=W-\alpha \frac{v_{d W}^{\text {corrected }}}{\sqrt{s_{d W}^{\text {corrected }}+\epsilon}} \\ &b:=b-\alpha \frac{v_{d b}^{\text {corrected }}}{\sqrt{s_{d b}^{\text {corrected }}+\epsilon}} \end{aligned}
W:=W−αsdWcorrected +ϵvdWcorrected b:=b−αsdbcorrected +ϵvdbcorrected
Adam 算法的参数更新:
学习率
α
\alpha
α:需要尝试一系列的值,来寻找比较合适的
β1:常用的缺省值为 0.9
β2:Adam 算法的作者建议为 0.999
ϵ:Adam 算法的作者建议为epsilon的默认值
1
e
−
8
1e-8
1e−8
注:β1、β2、ϵ 通常不需要调试
所有优化算法效果对比
图片来源Alec Radford的论文
学习率调度器
学习率退火
如果设置一个固定的学习率 α
在最小值点附近,由于不同的 batch 中存在一定的噪声,因此不会精确收敛,而是始终在最小值周围一个较大的范围内波动。
如果随着时间慢慢减少学习率 α 的大小,在初期 α 较大时,下降的步长较大,能以较快的速度进行梯度下降;而后期逐步减小 α 的值,即减小步长,有助于算法的收敛,更容易接近最优解。
最常用的学习率退火方法:
1、随步数衰减
2、指数衰减
α
=
0.9
5
epoch
∗
α
0
\alpha=0.95^{\text {epoch}} * \alpha 0
α=0.95epoch∗α0
3、
1
/
t
1/t
1/t衰减
α
=
1
1
+
decaye*epoch
∗
α
0
\alpha=\frac{1}{1+\text { decaye*epoch}} * \alpha_0
α=1+ decaye*epoch1∗α0
其中,decay为衰减率(超参数),epoch_num为将所有的训练样本完整过一遍的次数。
对于大型的数据模型,需要使用这些方式去自动进行学习率衰减。而一些小型网络可以直接手动进行调整
参考文献 :