深度学习 --- 改善深度神经网络 2
文章目录
1. 参数初始化方法
一组合理的W和b的初始值虽然不能解决梯度爆炸或者梯度消失的问题,但是却能够很好的缓解这些问题,下面我们介绍两点注意事项和两种初始化方法:
- W不能为0。否则会有对称性的问题,这会导致每层的隐藏单元都做同样的训练,起到的效果和每层只有一个隐藏单元是一样的,丝毫体现不了深度神经网络的价值。
- W和b不能太大。否则很容易导致梯度爆炸的问题。
所以,一个好的参数初始化方法,要使得W和b不会比1大很多,也不会比1小很多,不但可以加快训练速度,也能够缓解梯度爆炸和梯度消失的问题。接下来主要介绍两种方法:
-
Xavier Initialization
首先按照标准正态分布产生随机数,然后再乘以比例因子(scaling factor)W = np.random.randn(n_out, n_in) * np.sqrt(1/n_in)
当**函数为tanh时,效果很好。
-
He Initialization
它和Xavier很相似,就是比例因子为其2倍,即W = np.random.randn(n_out, n_in) * np.sqrt(2/n_in)
该方法非常适用于当**函数为ReLU时。
2. 深度学习优化算法
一种好的优化算法可以加快训练速度,尤其是当你面对大量的训练数据时,下面介绍几种快速的算法。
2.1 Mini-Batch Gradient Descent
一般情况下分为Train set,Dev set和Test set之后,就可以开始训练。但是当Train Set非常大的时候,比如5 million或者50 million时,每个epoch都需要将所有的想计算一遍,然后才能更新一次参数。按照这样的算法,参数更新起来很慢,训练时间会需要很长。
Mini-Batch Gradient Descent就是为了解决这个问题。它的方法就是将m个样本分割成多个小批量的样本,然后每次梯度下降只在该小批量样本上进行。
下面以5,000,000个样本为例,batch_size为1000(需要循环5000次),循环1个epoch,步骤如下:
for t = 1, 2, … 5000 {
-
1.forward propagation on
-
2.compute cost
-
3.backward propagation on
-
4.update parameters: ,
}
如果需要训练多个epoch,只需在此循环外面再加上epoch的循环即可。
总之,Mini-batch Gradient Descent的过程和Batch Gradient Descent一样,差别就是每次迭代一次的样本数量不同,这样的好处就是小批量多次更新参数,能够及早的得到结果或者发现问题。
另外一个差别就是Cost J的曲线图:
当batch_size=1时,即随机在每个样本上面进行一次前后向传播,更细一次参数,这种方法称为:随机梯度下降(Stochatic Gradient Descent)。下面比较这三种Gradient Descent的方法:
Stochastic Gradient Descent | Mini-Batch Gradient Descent | Batch Gradient Descent |
batch_size=1 | batch_size=t介于[1,m]之间 | batch_size=m |
样本只有1个,振荡严重,总体趋势收敛。但是无法收敛至最小值,只能在其附近徘徊(可以通过小的学习率缓解)。另外一个问题是无法向量化计算,导致计算效率不高 | 样本不大不小,振荡较小,总体趋势收敛。但是无法收敛至最小值,只能在其附近小区域徘徊(可以通过小的学习率缓解)。两个优点:向量化运算效率高;迭代更新快 | 全部样本,收敛趋势平滑。但是每次迭代训练时间很长,参数更新很慢 |
下面需要讨论的是如何选择batch size?
如果train set的样本比较小,一般时,可以直接使用batch gradient descent。
如果train set样本比较大时,可考虑使用mini-batch gradient descent,常用的batch size是64,128,256,512。
2.2 Gradient Descent With Momentum
基于动量的梯度下降,这里面涉及到Exponentially Weighted Averages,原理可以参考《指数加权移动平均》,以温度为例总结下来:
- ,公式中为 t 时刻的实际温度;为 t 时刻 EMA 的值;为权重系数,范围(0, 1).
- 当 时,可得:,由此可知:每天的实测温度()的权重系数以指数等比形式缩小,时间越接近当前时刻,权重系数对当前时刻的的影响越大,而离当前时刻越远,权重影响越小。
- 天之前的温度平均值
总之,通过上述Exponentially Weighted Averages后,我们可以减少振动,提高稳定性。如下图所示:
随着的增大,的趋势是越来越平滑稳定。我们接下来就是用这个原理来加快训练速度。
对于Mini-Batch Gradient Descent,我们知道它在迭代的过程中是上下振荡地向最小点靠近的,如果我们能够减少它在垂直方向的振荡,加速在水平方向的收敛,那么我们就能使用较少的迭代次数使它接近最小点,因此,基于动量的梯度下降的算法由于单纯的梯度下降算法。如下图所示:
具体的代码实现如下:
on iteration t:
- compute the , on mini-batch
- ,
- ,
在实践中,一般设置,后续基本不需要更改这个值,它能工作的很好。
2.3 RMSprop[Root Mean Square prop]
该方法的目标和momentum一样,同样参考上图,纵轴方向为b,横轴方向为W,它也要在垂直方向上抑制振荡,而在水平方向上面加快收敛。
算法如下:
on iteration t:
- compute the , on mini-batch
- ,
- ,
现在说明为什么这种方法能够工作:
在上图中,由于垂直方向振荡很大,说明的值很大,因此也就很大,就很小,减去了一个较小的数,最终使得变化很小,这样就抑制了垂直方向的振动。
同理,在水平方向上,的变化比价小,因此比较小,就比较大,减去了一个比较大的值,最终使得表换很大,这样就加快了在水平方向的收敛。
注意:主要是为了避免分母为0,一般
2.4 Adam[Adaptive Moment Estimation]
这是目前被广泛使用的一种算法,它是将momentum和RMSprop结合在一起。方法如下:
on iteration t:
- compute the , on mini-batch
- momentum:
, - RMSprop:
, - Bias correction:
,
, - update parameters:
hyperparameters:
- needs to be tune
- (for )
- (for )
-
以上这些参数基本不需要调整,这些默认值已经能够很好地适用很多的深度神经网络了。
3 其他加速训练的方法
3.1 Learning rate decay[学习率衰减]
在Mini-Batch Gradient Descend过程中,如果batch size比较小,它无法接近最小值,而只是在最小值附近振动。这时采用学习率衰减可以改善这个问题,使它更快的收敛至最小值,减少迭代次数。
常见的方法主要有:
-
Inverse time decay:逆时间衰减
decayed_learning_rate = learning_rate / (1 + decay_rate * global_step / decay_step) -
Exponential Decay:指数衰减
decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps) -
Natural exponential decay:自然指数衰减
decayed_learning_rate = learning_rate * exp(-decay_rate * global_step) -
Polynomial decay:多项式衰减
global_step = min(global_step, decay_steps)
decayed_learning_rate = (learning_rate - end_learning_rate) *(1 - global_step / decay_steps) ^ (power) + end_learning_rate
参数:
learning_rate:初始值
global_step:全局step数(每个step对应一次batch)
decay_steps:learning rate更新的step周期,即每隔多少step更新一次learning rate的值
decay_rate:指数衰减参数
end_learning_rate:衰减最终值
power:多项式衰减系数
总之,目的都是随着epoch_num的增加缓慢减低,更快的收敛至最小值。
当然现在也有论文开始反驳这种方法了,如下:
《DON’T DECAY THE LEARNING RATE, INCREASE THE BATCH SIZE》
注意,加快训练的方法有很多种,Learning rate decay并不是那个最先就要去调试的超参
3.2 Batch Normalization[批量归一化]
在上一讲中,我们要求对输入数据X进行归一化,过程如下:
-
zero mean
-
scale normalization
由此,可以使用较大的,并能提高梯度下降速度。在深度学习中,上一层的输出都是作为了下一层的输入,那么是否可以对上一层的输出都进行一次一样的归一化呢,这样同样也能加快训练速度。这就是Batch Normalization的思想。
在讲述神经网络时,我们知道每一层都有线性输出和**输出,那么Batch Normalization是应用在哪一层呢?目前还没有一个统一的结论,更多人采用的是将其应用在上面。
BN的实现过程如下:(对于层的进行BN)
以上就可以使得均值为0方差为1了。但是输入层的归一化和隐藏层的归一化还是不一样的。在隐藏层,也许你不希望得到的输出是均值0方差1的数据,比如**函数是sigmoid或tanh时,就不希望方差为1,而是希望方差能够更大,以便充分利用**函数非线性的作用,而不是方差为1时,**函数那段近似直线的线性趋于。因此对于隐藏层的归一化需要新增两个超参:
当,它得到的就是上述的均值0方差1的结果。
通过调整就可以调节输出数据的均值和方差。
接下来我们介绍如何在深度学习网络中使用BN:
如图所示,在前向传播中,每层的线性输出后面都要再进行一次BN,得到新的输出,然后再将其输入到**函数,同时多记录两个超参
同样,在反向传播中,我们同样需要更新这两个参数(和处理一样):
为什么BN能够工作
- 在前几层的参数变化时,当前层的输出值Z也会变化,但是当使用了BN算法后,它能够保证无论Z值怎么变化,Z的均值和方差将保持不变,这也间接地限制了前几层参数的更新,从而使得Z值变得稳定,后面层适用前面层变化的力量被减弱。实际上,BN算法消弱了前面层和后面层参数之间的耦合,使得当前层更加的独立,这将有助于提高网络学习速度。从后面层的角度来看,前面层的影响不大,因为它们被同一均值和方差所限制。
- 由于对小批量数据进行归一化,而小批量中也包含噪声,所以均值和方差也有点噪声存在,起到了轻微的正则化的效果,实际和dropout的作用类似,使得后续隐藏单元不要过度依赖前面的隐藏单元。
如何在测试时BN
之前在训练时都是采用了批量的样本,64-512之间的样本,但是在测试时,往往都是针对一个样本的,这时对一个样本求均值和方差显然是不合理的,那么在测试时该如何计算呢?
既然我们无法针对一个样本求均值和方差,那么一般的解决方法是记录下在网络训练时每一层的最新的均值和方差,然后在测试时直接带入计算。
当然,另外一种更加通用的方法就是使用之前经过的指数加权平均Exponentially Weighted Averages方法,记录下最后的均值和方差,然后在测试时直接带入计算,然后在使用训练后的参数求出。
至此,我们已经讲述了多种提高训练速度的方法,中间也提出了更多的超参数,它们对训练结果起着重要的作用。因此,接下来我们将讲解,如何选择这些超参数以及如何调试这些超参数。