DeepLearning.ai笔记(五)

《改善深层神经网络:超参数调试、正则化以及优化》第二周《优化算法》。
本节主要从模型的训练方法上给出一些可优化的点,包括可以将数据分而治之的Mini-Batch、防止梯度下降方向变化率过大的指数加权平均以及RMSprop和Adam优化算法。

2.1 Mini-Batch梯度下降法

当样本量巨大时,有必要将海量样本拆分成更小的子集。因为海量样本的向量化会收到内存限制,拆分让分布式并行成为可能。
例如,当有5,000,000样本时,可令1000个样本为一组,拆分成5000个子集:

使用符号$x^{\{t\}}\;y^{\{t\}}$来表示第t个样本子集。

目前接触过三种上角标:
$x^{(i)}表示第i个样本\\z^{[l]}表示第l层节点\\x^{\{t\}}表示第t个样本子集$

于是Mini-Batch梯度下降法可以写作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def model(self, X, Y, layers_dims, optimizer, learning_rate = 0.0007, mini_batch_size = 64, beta = 0.9,
beta1 = 0.9, beta2 = 0.999, epsilon = 1e-8, num_epochs = 10000, print_cost = True):
...
# 构造各层W、b的默认值
parameters = self.initialize_parameters(layers_dims)
# 循环代次
for i in range(num_epochs):
...
# 洗牌、分mini-batch子集
minibatches = self.random_mini_batches(X, Y, mini_batch_size, seed)

for minibatch in minibatches: # 遍历每个子集
# 获取子集的样本数据
(minibatch_X, minibatch_Y) = minibatch

# 执行前向算法
a3, caches = self.forward_propagation(minibatch_X, parameters)

# 计算成本
cost = self.compute_cost(a3, minibatch_Y)

# 执行后向算法
grads = self.backward_propagation(minibatch_X, minibatch_Y, caches)

# 更新参数
self.update_parameters_with_gd(parameters, grads, learning_rate)
...

2.2 理解Mini-Batch梯度下降法

之前没有分割小批量的梯度下降叫Batch梯度下降法,和Mini-Batch梯度下降法相比,二者的成本函数曲线不同:

结合上一节代码很容易理解这一点,因为每轮Mini-Batch执行完成后,更新生成的参数W、b被应用到下一轮Mini-Batch,两轮其实是基于不同数据生成的神经子网。如果每个Mini-Batch子集的数据是独立同分布的,生成的参数在各个子集上的趋势应该是一致的,但是终究会有偏差,这就导致了不可能平滑。注意,在代码中,每一代训练完成后,会重新洗牌打乱样本次序,重新生成新的Mini-Batch子集。

观察Mini-Batch每个子集的尺寸,当在极端情况下
Size=m,Mini-Batch退化为batch梯度下降,它会沿着等高线切线方向直奔最小值,但是当样本量极大时,机器会承担不了海量样本向量化的内存开销,这导致计算性能下降。
Size=1,Mini-Batch退化为m个单样本的梯度下降,又称随机梯度下降(Stochastic gradient descent)。它导致梯度下降的方向更加曲折,虽然总体会像最低点演进,但中间会走很多冤枉路,这会增加训练的轮数,降低学习性能。
因此应当在1和m之间取一个合理的值,既能有效利用机器的计算资源,又不让梯度下降的路径过于曲折。如下图所示蓝色是size=m的梯度下降路径,紫色是size=1的梯度下降路径,绿色的size介于二者之间:

一般情况下Mini-Batch的size取值在64, 128, 256, 512中选取。

本节讨论的是size的取值范围及影响,并没有涉及对Mini-Batch的理解。

2.3 指数加权平均

本节引入的方法貌似和前文没有什么关系,其实在后面会用到。它的核心思想是:当数据前后之间有连续性的关联关系时,令每条数据在基于前序若干数据的加权值基础上再加一个变量。本节举的例子是给定一年的气温样本,预测某一天的温度,令样本值为:$θ_1 \,θ_1 \,θ_1 \,…\,θ_{365}$ ,建立预测模型:
$v_0=0$
$v_1=β·v_0+(1-β)·θ_1$
$v_2=β·v_1+(1-β)·θ_2$

$v_t=β·v_{t-1}+(1-β)·θ_t$
该模型可以近似的理解为:它取了$\frac{1}{1-β}$个前序样本的加权平均值。
当β=0.9,即10个前序样本的加权平均;
当β=0.98,即50个前序样本的加权平均;
当β=0.5,即2个前序样本的加权平均;
这只是一个近似的理解,并没有给出数学证明。

2.4 理解指数加权平均

当β=0.9:
$v_{100}=0.1θ_{100} + 0.9v_{99}\\
= 0.1θ_{100} + 0.9(0.1θ_{99} + 0.9v_{98})\\
= 0.1θ_{100} + 0.1×0.9θ_{99} + 0.9^2(0.1θ_{98} + 0.9v_{97})\\
= 0.1θ_{100} + 0.1×0.9θ_{99} + 0.1×0.9^2θ_{98} + 0.9^3(0.1θ_{97} + 0.9 v_{97})\\
=…$
我理解这个加权平均核心是因为系数0.1,它表达的含义是取最近$\frac{1}{1-β}$个样本,每个样本的权重是(1-β),且随着样本越远,按照β的指数级递减,这应该是“指数加权平均”的含义。

文中指出$0.9^{10}≈0.35≈\frac{1}{e}$,我没明白他的用意是什么。我的直观理解应该是想说过了这个值$\frac{1}{e}$以后,其权重可忽略不计了,但是为什么呢?

e是自然对数的底数,$e=\mathop{lim}\limits_{n→∞}{1+\frac{1}{n}}^n≈2.71828$,在科学计算中通常不使用以10为底的对数。使用以e为底,能让许多算式得到简化,用它最“自然”,因此称为自然对数。btw:$\frac{1}{e}≈0.367879$

实现指数加权平均的算法:
$v_θ=0 \\
Repeat \{\\
 get next θ_t\\
 v_θ:=β·v_θ+(1-β)·θ_t\\
\}$

2.5 指数加权平均的偏差修正

上一节的实现算法有一个缺陷:在算法初期,由于初值被置为0,且没有更多的前序数据拿进来做加权平均,这会导致初值偏小。等到$\frac{1}{1-β}$个前序样本都加入进来才回归正常。本节引入一个修正系数来解决这个问题:
$v_t=\frac{β·v_{t-1} \;+\; (1-β)·θ_t}{1-β^t}$
在初期t很小,$β^t→1$,分母放大了结果;t越大,$β^t→0$,分母的作用就越小。通过这种方式修正了初期数据。

2.6 动量梯度下降法

本节是对指数加权平均的应用,大致思想是:w:=w-α·dw,dw决定了下一步的方向,减缓每一步dw的变化率,有利于抵消折返的角度,提升学习的效率。如下图:

直观理解是,如果能把原本蓝线走过的梯度下降,修正为红线,即减缓每次迭代的方向变化率,学习率将得到提升。在算法上,将原先w:=w-α·dw; b:=w-α·db修正为:
$v_{dw} = β·v_{dw} + (1-β)·dw\\
v_{db} = β·v_{db} + (1-β)·db\\
w:=w - α·v_{dw}\\
b:=b - α·v_{db}$
算法的核心思想就是采用指数加权平均来作用于原先的dw和db,从而使得变化率的连续性更强,防止梯度下降中的折返消耗。
如果β=0,则动量梯度下降法退化为普通梯度下降;β越大,每轮梯度下降的方向变化越平滑。但是β过大也会导致“船大不好调头”,从而让学习率下降。通常β的取值范围在(0.8, 0,999),默认情况下通常取0.9。

2.7 RMSprop

接下来两节介绍的优化方法,在思想上和动量梯度下降法是一致的,都是希望减小方向的变化率。直接上算法:
$S_{dw} = β_2·S_{dw} + (1 - β_2)·(dw)^2\\
S_{db} = β_2·S_{db} + (1 - β_2)·(db)^2\\
w:=w - α·\frac{dw}{\sqrt{S_{dw} \;+\; ε}}\\
b:=b - α·\frac{db}{\sqrt{S_{db} \;+\; ε}}$

但本节并没有讲该算法的出处和思想起源,为什么取平方呢?这和加权平均差异有点大。不过也没关系,知道意图并知道这么做是有效的就好了~

2.8 Adam优化算法

和前两节是一样的思路,并且把前两节的优化方法结合在一起了。直接上代码:
$v_{dw}=0, \; S_{dw}=0, \; v_{db}=0, \; S_{db}=0\\
on \, iteration \, t:\\
使用mini-batch方法计算dw, db\\
v_{dw}=β_1·v_{dw} + (1-β_1)·dw    v_{db}=β_1·v_{db} + (1-β_1)·db\\
S_{dw}=β_2·S_{dw} + (1-β_2)·(dw)^2 S_{db}=β_2·S_{db} + (1-β_2)·(db)^2\\
v_{dw}=\frac{v_{dw}}{1-β_1^t}   v_{db}=\frac{v_{db}}{1-β_1^t}\\
S_{dw}=\frac{S_{dw}}{1-β_2^t}   S_{db}=\frac{S_{db}}{1-β_2^t}\\
w:=w-α·\frac{v_{dw}}{\sqrt{S_{dw}} \;+\; ε}   b:=b-α·\frac{v_{db}}{\sqrt{S_{db}} \;+\; ε}$
通常超参数选择:$ε:10^{-8} \; \; \; β_1:0.9 \; \; \; β_2:0.999$,
α则根据业务调整。

2.9 学习率衰减

学习率衰减的思想是:随着梯度下降的进行,距离成本最低点越来越近,应该逐步衰减每一轮的学习步长,以避免大幅在最低点附近震荡消耗。此时缩减步长有助于逼近极值点。从图上很容易理解这一点:

蓝线在到达了极值点附近还是以同样的步长来回震动,这导致后期的震荡对于学习不再有效;而绿线的步长越来越小,有助于逼近极值点。理解了思想,算法就很容易看懂了。
方法一:$α:=\frac{1}{1+decay\_rate×epoch\_num}$,其中decay_rate为衰减率,epoch_num为迭代的代次。
方法二:$α:=0.95^{epoch\_num}·α$
方法三:$α:=\frac{k}{\sqrt{epoch\_num}}·α \;或\; α:=\frac{k}{\sqrt{t}}·α$
最土的办法是手动调节,总之就是让后期的α能逐步衰减。

作业

本节作业演示各种优化方案的效果,题目是为双月牙散点图做个分类器。代码没有太多需要注意的,都是局部的技术性优化,就不在这里贴了。

本节作业可参见https://github.com/palanceli/MachineLearningSample/blob/master/DeepLearningAIHomeWorks/mywork.pyclass Coding2_2