第二周:优化算法
本文是改善深层神经网络的笔记。
本章中还存在的问题:指数加权平均的偏差修正的原理?
2.0 重点
本章的主旨在于学习一些可以提高训练速度的算法,大部分都是基于提高学习率。
在Mini-batch之后,我们学习了指数加权平均,之后我们学习了Momentum、RMSprop和两者结合的Adam,最后我们研究了学习率衰减。
2.1 Mini-batch 梯度下降法
为了避免一次将所有的样本全部喂进去太慢。我们引入Mini-batch:
- 记:
X
=
[
x
(
1
)
,
x
(
2
)
,
…
,
x
(
1000
)
∣
x
(
1001
)
,
x
(
1002
)
,
…
,
x
(
2000
)
∣
…
]
X=[x^{(1)},x^{(2)},\dots,x^{(1000)}|x^{(1001)},x^{(1002)},\dots,x^{(2000)}|\dots]
X=[x(1),x(2),…,x(1000)∣x(1001),x(1002),…,x(2000)∣…]
Y = [ y ( 1 ) , y ( 2 ) , … , y ( 1000 ) ∣ x ( 1001 ) , y ( 1002 ) , … , y ( 2000 ) ∣ … ] Y=[y^{(1)},y^{(2)},\dots,y^{(1000)}|x^{(1001)},y^{(1002)},\dots,y^{(2000)}|\dots] Y=[y(1),y(2),…,y(1000)∣x(1001),y(1002),…,y(2000)∣…] - 记 x { t } x^{\{t\}} x{t} y { t } y^{\{t\}} y{t}第t个Mini-batch。这里我们不妨取1000个样本作为一个Batch。因此,我们有
X = [ x { 1 } ∣ x { 2 } ∣ … ∣ x { 5000 } ] X=[x^{\{1\}}|x^{\{2\}}|\dots|x^{\{5000\}}] X=[x{1}∣x{2}∣…∣x{5000}]
Y = [ y { 1 } ∣ y { 2 } ∣ … ∣ y { 5000 } ] Y=[y^{\{1\}}|y^{\{2\}}|\dots|y^{\{5000\}}] Y=[y{1}∣y{2}∣…∣y{5000}]
- 因此,对于Mini-Batch的训练过程为
2.2 理解Mini-batch梯度下降法
Batch和Mini-batch在Cost图像上的区别
- 如果我们每次训练都跑完所有的数据,则CostFunction里面考虑了所有的数据,所以通过调节 w w w它的函数值一定随着每代都下降。
- 但如果我们使用的MiniBatch,则我们此次下降的方向可能与下次下降的方向不同,因此会整Cost的值会振动。
分类
记总样本数为 m m m
- Mini-batch size=m: Batch Gradient Descent(速度慢,因为要考虑到所有的数据)
- Mini-batch size=1: Stochastic Gradient Descent (噪声太大,因此需要调小学习率)
因此,在实践中,我们选择大小适中的MiniBatchSize和学习率。
上图中,紫色的是(SGD),蓝色的是Batch,绿色的是大小适中的MiniBatch。
Mini-Batch大小的选择
- m ≤ 2000 m\leq2000 m≤2000:数据少,使用Batch Gradient Descent
- 一般选用64,128,256,516
- 确保minibatch fit in CPU/GPU memory❓❓
2.3 指数加权平均(Exponentially Weighted Avg)
为了介绍更好的梯度下降算法
- 例子:London的温度
- 记
θ
t
\theta_t
θt为第t天的温度。
V t = β V t − 1 + ( 1 − β ) θ t V_t=\beta V_{t-1}+(1-\beta)\theta_t Vt=βVt−1+(1−β)θt
- 记
θ
t
\theta_t
θt为第t天的温度。
- 当 β \beta β越大,之前的样本衰减越慢,即延迟效果越明显,曲线更加平滑。
- 当 β \beta β越小,越接近原始数据 θ t \theta_t θt
Python模拟:
# 比较不同的beta值的影响
theta = [np.sqrt(i)+np.random.randn() for i in range(250)]
# vt = beta*v(t-1)+(1-beta)theta(t)
beta={0.5,0.9}
plt.figure(figsize=(10,6))
plt.plot(theta,label="Raw Data")
for beta in beta:
v=[theta[0]]
for i in range(1,len(theta)):
v.append(beta*v[-1]+(1-beta)*theta[i])
plt.plot(v,label=f"beta = {beta}")
plt.grid()
plt.legend()
plt.show()
2.4 ⚠️理解指数加权平均
-
Recap:
v t = β v t − 1 + ( 1 − β ) θ t v_t=\beta v_{t-1}+(1-\beta)\theta_t vt=βvt−1+(1−β)θt
其中 θ t \theta_t θt是t时刻的样本。 -
例子:
v 0 = θ 0 v_0 = \theta_0 v0=θ0
v 1 = β θ 0 + ( 1 − β ) θ 1 v_1 = \beta \theta_0+(1-\beta)\theta_1 v1=βθ0+(1−β)θ1
v 2 = β 2 θ 0 + β ( 1 − β ) θ 1 + ( 1 − β ) θ 2 v_2 = \beta^2 \theta_0+ \beta(1-\beta)\theta_1 + (1-\beta)\theta_2 v2=β2θ0+β(1−β)θ1+(1−β)θ2
…
v n = β n θ 0 + β n − 1 ( 1 − β ) θ 1 + ⋯ + ( 1 − β ) θ n v_n = \beta^n \theta_0+ \beta^{n-1}(1-\beta)\theta_1 + \dots + (1-\beta)\theta_n vn=βnθ0+βn−1(1−β)θ1+⋯+(1−β)θn -
如何理解参数 β \beta β?
我们认为 β \beta β反映了均值考虑了多少天的数据:
天 数 = l o g β ( 1 e ) 天数=log_{\beta}(\frac{1}{e}) 天数=logβ(e1)
例如,如果 β = 0.9 \beta=0.9 β=0.9则 天 数 = l o g 0.9 ( 1 e ) = 9.49 ≈ 10 天 天数=log_{0.9}(\frac{1}{e})=9.49\approx10天 天数=log0.9(e1)=9.49≈10天 -
这个结论的来源:
v n = ( 1 − β ) θ n + ( 1 − β ) β θ n − 1 + ( 1 − β ) β 2 θ n − 2 + ⋯ + β n − 1 ( 1 − β ) θ 1 + β n θ 0 v_n = (1-\beta)\theta_n+(1-\beta)\beta\theta_{n-1}+(1-\beta)\beta^2\theta_{n-2}+\dots+\beta^{n-1}(1-\beta)\theta_1+\beta^n \theta_0 vn=(1−β)θn+(1−β)βθn−1+(1−β)β2θn−2+⋯+βn−1(1−β)θ1+βnθ0
我们认为,如果参数比原来的 1 e \frac{1}{e} e1还要小,我们就可以忽略它。
怎么实现?
- 一般我们把第一项设置为0, v : = β v + ( 1 − β ) θ n v:=\beta v+(1-\beta)\theta_n v:=βv+(1−β)θn
- 一般我们不用数组存储,我们只要保存一个数字即可。从而比较节省空间。
与直接取平均的区别?
- 从计算时间和空间上来讲都更优一些。
2.5 指数加权平均的偏差修正
- 如果 v 0 = 0 v_0=0 v0=0则曲线会达到正常值会有一定的偏差:
理论值 | 40 | 49 | 45 |
---|---|---|---|
预测值(无修正) | 0.8 | 1.764 | 2.62 |
预测值(带修正) | 40 | 1014.6 | - |
无修正下的预测:
取
β
=
0.98
\beta=0.98
β=0.98
v
0
=
0
v_0=0
v0=0
v
1
=
β
v
0
+
(
1
−
β
)
θ
1
=
0
+
(
1
−
0.98
)
∗
40
=
0.8
v_1=\beta v_0 +(1-\beta) \theta_1=0+(1-0.98)*40=0.8
v1=βv0+(1−β)θ1=0+(1−0.98)∗40=0.8
v
2
=
0.98
∗
0.8
+
0.02
∗
49
=
1.764
v_2=0.98*0.8+0.02*49=1.764
v2=0.98∗0.8+0.02∗49=1.764
v
3
=
0.98
∗
1.764
+
0.02
∗
45
=
1.764
v_3=0.98*1.764+0.02*45=1.764
v3=0.98∗1.764+0.02∗45=1.764
有修正下的预测:
v
0
=
0
v_0=0
v0=0
v
1
=
(
β
v
0
+
(
1
−
β
)
θ
1
)
/
(
1
−
β
1
)
=
0.8
1
−
0.9
8
1
=
40
v_1=(\beta v_0 +(1-\beta) \theta_1)/(1-\beta^1)=\frac{0.8}{1-0.98^1}=40
v1=(βv0+(1−β)θ1)/(1−β1)=1−0.9810.8=40
v
2
=
0.98
∗
40
+
0.02
∗
49
1
−
0.9
8
2
=
1014.6
v_2=\frac{0.98*40+0.02*49}{1-0.98^2}=1014.6
v2=1−0.9820.98∗40+0.02∗49=1014.6
- 修正方法:
对分母进行修正: v t = β v t − 1 + ( 1 − β ) θ t 1 − β t v_t=\frac{\beta v_{t-1}+(1-\beta)\theta_t}{1-\beta^t} vt=1−βtβvt−1+(1−β)θt
⚠️ 修正之后对于 β \beta β的取值比较敏感, β \beta β的值不应该太大,避免不收敛:
2.6 ⚠️ 动量梯度下降法(Momentum)
- 为了选择较大的学习率(太大有可能发散),并且避免震动的情况。
原理
这里我们又引入了一个超参数 β \beta β,一般取0.9。这意味着,过了前10个数据,我们就可以获得正常的数据。
- 梯度计算
首先通过Mini-batch计算出dw和db。
v d w : = β v d w + ( 1 − β ) d w vdw := \beta vdw + (1-\beta)dw vdw:=βvdw+(1−β)dw
v d b : = β v d b + ( 1 − β ) d b vdb := \beta vdb + (1-\beta)db vdb:=βvdb+(1−β)db
- 参数更新
W : = W − α × v d w W := W-\alpha\times vdw W:=W−α×vdw
b : = b − α × v d b b := b-\alpha\times vdb b:=b−α×vdb
直观解释:
- 解释一:
鉴于我们每次计算的时候都考虑到了前面的多组数据,因此,一些不必要的震动将会被抵消。
- 解释二:
梯度计算中的 v d w vdw vdw可以看成是一个速度,
v d w : = β v d w + ( 1 − β ) d w vdw := \beta vdw + (1-\beta)dw vdw:=βvdw+(1−β)dw
类比物理里面的公式 v ( t ) = v t − 1 + a Δ t v(t)=v_{t-1}+a\Delta t v(t)=vt−1+aΔt,可以把 d w dw dw看成小球的加速度(因为它累计了之前的速度等数据)。因此,正因为小球有惯性,所以不容易改变方向。
2.7 RMSprop (Root Mean Square)
- 为了可以选择较大的学习率(太大有可能发散),并且避免震动的情况。
原理
这里我们又引入了一个超参数 β 2 \beta_2 β2。为了避免与Momentum的 β \beta β重复。
- 梯度计算:
首先通过Mini-batch计算出dw和db。
S d w : = β 2 S d w + ( 1 − β 2 ) d w 2 Sdw:=\beta_2Sdw+(1-\beta_2)dw^2 Sdw:=β2Sdw+(1−β2)dw2
S d b : = β 2 S d b + ( 1 − β 2 ) d b 2 Sdb:=\beta_2Sdb+(1-\beta_2)db^2 Sdb:=β2Sdb+(1−β2)db2
- 参数更新:
w : = w − α d w S d w + ϵ w:=w-\alpha \frac{dw}{\sqrt{Sdw+\epsilon}} w:=w−αSdw+ϵdw
b : = b − α d b S d b + ϵ b:=b-\alpha \frac{db}{\sqrt{Sdb+\epsilon}} b:=b−αSdb+ϵdb
ϵ ≈ 1 0 − 8 \epsilon \approx 10^{-8} ϵ≈10−8为了避免分母为0。
直观解释:
- 如果在b方向上震荡的话,db会很大,从而 S d b Sdb Sdb很大。从而对比SGD中给出的参数更新的公式 b : = b − α d b b:=b-\alpha db b:=b−αdb因为RMSprop对db除了一个很大的数字,所以更新的幅度更小一点。从而解决了震荡的问题。
- 当震动比较平缓的时候,Sdw这种就比较小,更新幅度就比较大。
2.8 Adam优化算法(Adaptive Moment Estimation)
- Adam = Momentum + RMSprop
部分超参数经验值:
学习率 α \alpha α
Momentum β 1 = 0.9 \beta_1=0.9 β1=0.9
RMSpropβ 2 = 0.999 \beta_2=0.999 β2=0.999
ϵ = 1 0 − 8 \epsilon=10^{-8} ϵ=10−8
原理
// 初始化
Vdw = 0, Vdb = 0
Sdw = 0, Sdb = 0
- 对于每个MiniBatch t:
// 反向传播
计算出dw,db。
// “Momentum”
V
d
w
:
=
β
1
V
d
w
+
(
1
−
β
1
)
d
w
,
V
d
b
:
=
β
1
V
d
b
+
(
1
−
β
1
)
d
b
Vdw := \beta_1 Vdw + (1-\beta_1)dw,Vdb := \beta_1 Vdb + (1-\beta_1)db
Vdw:=β1Vdw+(1−β1)dw,Vdb:=β1Vdb+(1−β1)db
// “RMSprop”
S
d
w
:
=
β
2
S
d
w
+
(
1
−
β
2
)
d
w
2
,
S
d
b
:
=
β
2
S
d
b
+
(
1
−
β
2
)
d
b
2
Sdw := \beta_2 Sdw + (1-\beta_2)dw^2,Sdb := \beta_2 Sdb + (1-\beta_2)db^2
Sdw:=β2Sdw+(1−β2)dw2,Sdb:=β2Sdb+(1−β2)db2
// 对于偏差进行修正
V
d
w
c
o
r
r
e
c
t
e
d
:
=
V
d
w
1
−
β
1
t
,
V
d
b
c
o
r
r
e
c
t
e
d
:
=
V
d
b
1
−
β
1
t
Vdw^{corrected} := \frac{Vdw}{1-\beta_1^t},Vdb^{corrected} := \frac{Vdb}{1-\beta_1^t}
Vdwcorrected:=1−β1tVdw,Vdbcorrected:=1−β1tVdb
S d w c o r r e c t e d : = S d w 1 − β 2 t , S d b c o r r e c t e d : = S d b 1 − β 2 t Sdw^{corrected} := \frac{Sdw}{1-\beta_2^t},Sdb^{corrected} := \frac{Sdb}{1-\beta_2^t} Sdwcorrected:=1−β2tSdw,Sdbcorrected:=1−β2tSdb
// 更新参数
w : = w − α V d w c o r r e c t e d S d w c o r r e c t e d + ϵ w:=w-\alpha \frac{Vdw^{corrected}}{\sqrt{Sdw^{corrected}+\epsilon}} w:=w−αSdwcorrected+ϵVdwcorrected
b : = b − α V d b c o r r e c t e d S d b c o r r e c t e d + ϵ b:=b-\alpha \frac{Vdb^{corrected}}{\sqrt{Sdb^{corrected}+\epsilon}} b:=b−αSdbcorrected+ϵVdbcorrected
2.9 学习率衰减
- 为什么要学习率衰减?
在学习初期,我们离极值点比较远,所以我们可以使用较大的学习率。但随着我们靠近极值点,我们需要减少学习率以避免震动。
具体实现
-
α = 1 1 + D e c a y R a t e ∗ E p o c h N u m ∗ α 0 \alpha=\frac{1}{1+DecayRate*EpochNum}*\alpha_0 α=1+DecayRate∗EpochNum1∗α0
-
Exponentially Decay
α = 0.9 5 E p o c h N u m α 0 \alpha=0.95^{EpochNum}\alpha_0 α=0.95EpochNumα0
-
α = k E p o c h N u m α 0 \alpha=\frac{k}{\sqrt{EpochNum}}\alpha_0 α=EpochNumkα0
-
Discrete StairCase
每过一代变化一下
2.10 局部最优的问题
- 实际上导数为0的点,大多为鞍点。所以不太可能陷入局部鞍点。
- 平缓段会延缓学习速率。
第二周测试重点:
- 下面的图中
【1】是普通的SGD
【2】是 β \beta β比较小的Momentum
【3】是 β \beta β比较大的Momentum