深度学习 --- 改善深度神经网络 2


1. 参数初始化方法

一组合理的W和b的初始值虽然不能解决梯度爆炸或者梯度消失的问题,但是却能够很好的缓解这些问题,下面我们介绍两点注意事项和两种初始化方法:

  • W不能为0。否则会有对称性的问题,这会导致每层的隐藏单元都做同样的训练,起到的效果和每层只有一个隐藏单元是一样的,丝毫体现不了深度神经网络的价值。
  • W和b不能太大。否则很容易导致梯度爆炸的问题。

所以,一个好的参数初始化方法,要使得W和b不会比1大很多,也不会比1小很多,不但可以加快训练速度,也能够缓解梯度爆炸和梯度消失的问题。接下来主要介绍两种方法:

  • Xavier Initialization
    首先按照标准正态分布产生随机数,然后再乘以比例因子(scaling factor) 1 n [ l − 1 ] \sqrt{\frac{1}{n^{[l-1]}}} n[l1]1

      W = np.random.randn(n_out, n_in) * np.sqrt(1/n_in)
    

当激活函数为tanh时,效果很好。

  • He Initialization
    它和Xavier很相似,就是比例因子为其2倍,即 2 n [ l − 1 ] \sqrt{\frac{2}{n^{[l-1]}}} n[l1]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 x { t } x^{\{t\}} x{t}

  • 2.compute cost J { t } = 1 1000 ∑ i = 1 1000 L ( y ^ ( i ) , y ( i ) ) + λ 2000 ∑ l = 1 L ∣ ∣ W [ l ] ∣ ∣ F 2 J^{\{t\}} = \frac{1}{1000}\sum_{i=1}^{1000}L(\hat y^{(i)}, y^{(i)}) + \frac{\lambda}{2000}\sum_{l=1}^L||W^{[l]}||^2_F J{t}=10001i=11000L(y^(i),y(i))+2000λl=1LW[l]F2

  • 3.backward propagation on J { t } J^{\{t\}} J{t}

  • 4.update parameters: W : = W − α d W W := W - \alpha dW W:=WαdW b : = b − α d b b := b - \alpha db b:=bαdb
    }

如果需要训练多个epoch,只需在此循环外面再加上epoch的循环即可。
总之,Mini-batch Gradient Descent的过程和Batch Gradient Descent一样,差别就是每次迭代一次的样本数量不同,这样的好处就是小批量多次更新参数,能够及早的得到结果或者发现问题。
另外一个差别就是Cost J的曲线图:

image.png-18kB

image.png-65.6kB

当batch_size=1时,即随机在每个样本上面进行一次前后向传播,更细一次参数,这种方法称为:随机梯度下降(Stochatic Gradient Descent)。下面比较这三种Gradient Descent的方法:

Stochastic Gradient DescentMini-Batch Gradient DescentBatch Gradient Descent
batch_size=1batch_size=t介于[1,m]之间batch_size=m
样本只有1个,振荡严重,总体趋势收敛。但是无法收敛至最小值,只能在其附近徘徊(可以通过小的学习率缓解)。另外一个问题是无法向量化计算,导致计算效率不高样本不大不小,振荡较小,总体趋势收敛。但是无法收敛至最小值,只能在其附近小区域徘徊(可以通过小的学习率缓解)。两个优点:向量化运算效率高;迭代更新快全部样本,收敛趋势平滑。但是每次迭代训练时间很长,参数更新很慢

image.png-54.4kB

下面需要讨论的是如何选择batch size
如果train set的样本比较小,一般 ≤ 2000 \le2000 2000时,可以直接使用batch gradient descent。
如果train set样本比较大时,可考虑使用mini-batch gradient descent,常用的batch size是64,128,256,512。

2.2 Gradient Descent With Momentum

基于动量的梯度下降,这里面涉及到Exponentially Weighted Averages,原理可以参考《指数加权移动平均》,以温度为例总结下来:

  • V t = β V t − 1 + ( 1 − β ) θ t V_t = \beta V_{t-1} + (1-\beta)\theta_t Vt=βVt1+(1β)θt,公式中 θ t \theta_t θt为 t 时刻的实际温度; V t V_t Vt为 t 时刻 EMA 的值; β \beta β为权重系数,范围(0, 1).
  • V 0 = 0 V_0=0 V0=0 时,可得: V t = ( 1 − β ) ( θ t + β θ t − 1 + β 2 θ t − 2 + ⋯ + β t − 1 θ 1 ) V_t = (1 - \beta)(\theta_t + \beta \theta_{t-1} + \beta^2 \theta_{t-2} + \cdots + \beta^{t-1} \theta_1 ) Vt=(1β)(θt+βθt1+β2θt2++βt1θ1),由此可知:每天的实测温度( θ t \theta_t θt)的权重系数以指数等比形式缩小,时间越接近当前时刻,权重系数 β \beta β对当前时刻的 V t V_t Vt的影响越大,而离当前时刻越远,权重影响越小。
  • V t = β V t − 1 + ( 1 − β ) θ t ≈ 1 1 − β V_t = \beta V_{t-1} + (1-\beta)\theta_t \approx \frac{1}{1 - \beta} Vt=βVt1+(1β)θt1β1天之前的温度平均值

总之,通过上述Exponentially Weighted Averages后,我们可以减少振动,提高稳定性。如下图所示:
随着 β \beta β的增大, V t V_t Vt的趋势是越来越平滑稳定。我们接下来就是用这个原理来加快训练速度。

image.png-119.4kB

对于Mini-Batch Gradient Descent,我们知道它在迭代的过程中是上下振荡地向最小点靠近的,如果我们能够减少它在垂直方向的振荡,加速在水平方向的收敛,那么我们就能使用较少的迭代次数使它接近最小点,因此,基于动量的梯度下降的算法由于单纯的梯度下降算法。如下图所示:

2018-10-12_224705.png-70.7kB

具体的代码实现如下:
on iteration t:

  1. compute the d W dW dW d b db db on mini-batch
  2. V d W = β V d W + ( 1 − β ) d W V_{dW} = \beta V_{dW} + (1 - \beta)dW VdW=βVdW+(1β)dW, V d b = β V d b + ( 1 − β ) d b V_{db} = \beta V_{db} + (1 - \beta)db Vdb=βVdb+(1β)db
  3. W : = W − α V d W W := W - \alpha V_{dW} W:=WαVdW b : = b − α V d b b := b - \alpha V_{db} b:=bαVdb

在实践中,一般设置 β = 0.9 \beta = 0.9 β=0.9,后续基本不需要更改这个值,它能工作的很好。

2.3 RMSprop[Root Mean Square prop]

该方法的目标和momentum一样,同样参考上图,纵轴方向为b,横轴方向为W,它也要在垂直方向上抑制振荡,而在水平方向上面加快收敛。

算法如下:
on iteration t:

  1. compute the d W dW dW d b db db on mini-batch
  2. S d W = β S d W + ( 1 − β ) d W 2 S_{dW} = \beta S_{dW} + (1 - \beta)dW^2 SdW=βSdW+(1β)dW2 S d b = β S d b + ( 1 − β ) d b 2 S_{db} = \beta S_{db} + (1 - \beta)db^2 Sdb=βSdb+(1β)db2
  3. W : = W − α d W S d W + ϵ W := W - \alpha \frac{dW}{\sqrt{S_{dW} + \epsilon}} W:=WαSdW+ϵ dW b : = b − α d b S d b + ϵ b := b - \alpha \frac{db}{\sqrt{S_{db} + \epsilon}} b:=bαSdb+ϵ db

现在说明为什么这种方法能够工作:
在上图中,由于垂直方向振荡很大,说明 d b db db的值很大,因此 S d b S_{db} Sdb也就很大, d b S d b \frac{db}{\sqrt{S_{db}}} Sdb db就很小, b b b减去了一个较小的数,最终使得 b b b变化很小,这样就抑制了垂直方向的振动。

同理,在水平方向上, d W dW dW的变化比价小,因此 S d W S_{dW} SdW比较小, d W S d W \frac{dW}{\sqrt{S_{dW}}} SdW dW就比较大, W W W减去了一个比较大的值,最终使得 W W W表换很大,这样就加快了在水平方向的收敛。

注意: ϵ \epsilon ϵ主要是为了避免分母为0,一般 ϵ = 1 0 − 8 \epsilon = 10^{-8} ϵ=108

2.4 Adam[Adaptive Moment Estimation]

这是目前被广泛使用的一种算法,它是将momentum和RMSprop结合在一起。方法如下:

V d W = V d b = S d W = S d b = 0 V_{dW} = V_{db} = S_{dW} = S_{db} = 0 VdW=Vdb=SdW=Sdb=0
on iteration t:

  1. compute the d W dW dW d b db db on mini-batch
  2. momentum:
    V d W = β 1 V d W + ( 1 − β 1 ) d W V_{dW} = \beta_1 V_{dW} + (1 - \beta_1)dW VdW=β1VdW+(1β1)dW, V d b = β 1 V d b + ( 1 − β 1 ) d b V_{db} = \beta_1 V_{db} + (1 - \beta_1)db Vdb=β1Vdb+(1β1)db
  3. RMSprop:
    S d W = β 2 S d W + ( 1 − β 2 ) d W 2 S_{dW} = \beta_2 S_{dW} + (1 - \beta_2)dW^2 SdW=β2SdW+(1β2)dW2 S d b = β 2 S d b + ( 1 − β 2 ) d b 2 S_{db} = \beta_2 S_{db} + (1 - \beta_2)db^2 Sdb=β2Sdb+(1β2)db2
  4. Bias correction:
    V d W c o r r e c t e d = V d W ( 1 − β 1 t ) V_{dW}^{corrected} = \frac{V_{dW}}{(1 - \beta_1^t)} VdWcorrected=(1β1t)VdW V d b c o r r e c t e d = V d b ( 1 − β 1 t ) V_{db}^{corrected} = \frac{V_{db}}{(1 - \beta_1^t)} Vdbcorrected=(1β1t)Vdb
    S d W c o r r e c t e d = S d W ( 1 − β 2 t ) S_{dW}^{corrected} = \frac{S_{dW}}{(1 - \beta_2^t)} SdWcorrected=(1β2t)SdW S d b c o r r e c t e d = S d b ( 1 − β 2 t ) S_{db}^{corrected} = \frac{S_{db}}{(1 - \beta_2^t)} Sdbcorrected=(1β2t)Sdb
  5. update parameters:
    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{V_{dW}^{corrected}}{\sqrt{S_{dW}^{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{V_{db}^{corrected}}{\sqrt{S_{db}^{corrected}} + \epsilon} b:=bαSdbcorrected +ϵVdbcorrected

hyperparameters:

  • α \alpha α needs to be tune
  • β 1 : 0.9 \beta_1: 0.9 β1:0.9 (for d W dW dW)
  • β 2 : 0.999 \beta_2: 0.999 β2:0.999 (for d W 2 dW^2 dW2)
  • ϵ : 1 0 − 8 \epsilon: 10^{-8} ϵ:108
    以上这些参数基本不需要调整,这些默认值已经能够很好地适用很多的深度神经网络了。

3 其他加速训练的方法

3.1 Learning rate decay[学习率衰减]

在Mini-Batch Gradient Descend过程中,如果batch size比较小,它无法接近最小值,而只是在最小值附近振动。这时采用学习率衰减可以改善这个问题,使它更快的收敛至最小值,减少迭代次数。

image.png-49.5kB

常见的方法主要有:

  • Inverse time decay:逆时间衰减
    α = 1 1 + d e c a y _ r a t e ∗ e p o c h _ n u m α 0 \alpha = \frac{1}{1 + {decay\_rate}*epoch\_num} \alpha_0 α=1+decay_rateepoch_num1α0
    decayed_learning_rate = learning_rate / (1 + decay_rate * global_step / decay_step)

  • Exponential Decay:指数衰减
    α = d e c a y _ r a t e e p o c h _ n u m α 0 \alpha = decay\_rate^{epoch\_num}\alpha_0 α=decay_rateepoch_numα0
    decayed_learning_rate = learning_rate * decay_rate ^ (global_step / decay_steps)

  • Natural exponential decay:自然指数衰减
    α = e − d e c a y _ r a t e ∗ e p o c h _ n u m α 0 \alpha = e^{-decay\_rate*epoch\_num}\alpha_0 α=edecay_rateepoch_numα0
    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的增加缓慢减低 α \alpha α,更快的收敛至最小值。
当然现在也有论文开始反驳这种方法了,如下:
DON’T DECAY THE LEARNING RATE, INCREASE THE BATCH SIZE

注意,加快训练的方法有很多种,Learning rate decay并不是那个最先就要去调试的超参

3.2 Batch Normalization[批量归一化]

在上一讲中,我们要求对输入数据X进行归一化,过程如下:

  • zero mean
    μ = 1 m ∑ i = 1 m x ( i ) \mu = \frac{1}{m}\sum_{i=1}^{m}x^{(i)} μ=m1i=1mx(i)
    x ( i ) = x ( i ) − μ x^{(i)} = x^{(i)} - \mu x(i)=x(i)μ

  • scale normalization
    σ 2 = 1 m ∑ i = 1 m ( x ( i ) ) 2 \sigma^2 = \frac{1}{m}\sum_{i=1}^{m}(x^{(i)})^2 σ2=m1i=1m(x(i))2
    x ( i ) = x ( i ) σ x^{(i)} = \frac{x^{(i)}}{\sigma} x(i)=σx(i)

由此,可以使用较大的 α \alpha α,并能提高梯度下降速度。在深度学习中,上一层的输出都是作为了下一层的输入,那么是否可以对上一层的输出都进行一次一样的归一化呢,这样同样也能加快训练速度。这就是Batch Normalization的思想。

在讲述神经网络时,我们知道每一层都有线性输出 Z Z Z和激活输出 A A A,那么Batch Normalization是应用在哪一层呢?目前还没有一个统一的结论,更多人采用的是将其应用在 Z Z Z上面。

BN的实现过程如下:(对于 l l l层的 Z [ l ] Z^{[l]} Z[l]进行BN)
μ = 1 m ∑ i = 1 m Z [ l ] ( i ) \mu = \frac{1}{m}\sum_{i=1}^{m}Z^{[l](i)} μ=m1i=1mZ[l](i)

σ 2 = 1 m ∑ i = 1 m ( Z [ l ] ( i ) − μ ) 2 \sigma^2 = \frac{1}{m}\sum_{i=1}^{m}(Z^{[l](i)} - \mu)^2 σ2=m1i=1m(Z[l](i)μ)2

Z n o r m [ l ] ( i ) = Z [ l ] ( i ) − μ σ 2 + ϵ Z_{norm}^{[l](i)} = \frac{Z^{[l](i)} - \mu}{\sqrt{\sigma^2 + \epsilon}} Znorm[l](i)=σ2+ϵ Z[l](i)μ

以上就可以使得 Z n o r m [ l ] Z_{norm}^{[l]} Znorm[l]均值为0方差为1了。但是输入层的归一化和隐藏层的归一化还是不一样的。在隐藏层,也许你不希望得到的输出是均值0方差1的数据,比如激活函数是sigmoid或tanh时,就不希望方差为1,而是希望方差能够更大,以便充分利用激活函数非线性的作用,而不是方差为1时,激活函数那段近似直线的线性趋于。因此对于隐藏层的归一化需要新增两个超参:

Z ~ [ l ] ( i ) = γ Z n o r m [ l ] ( i ) + β \tilde Z^{[l](i)} = \gamma Z_{norm}^{[l](i)} + \beta Z~[l](i)=γZnorm[l](i)+β

γ = 1 σ 2 + ϵ , β = − μ σ 2 + ϵ \gamma = \frac{1}{\sqrt{\sigma^2 + \epsilon}}, \beta = - \frac{\mu}{\sqrt{\sigma^2 + \epsilon}} γ=σ2+ϵ 1,β=σ2+ϵ μ,它得到的就是上述的均值0方差1的结果。

通过调整 γ , β \gamma, \beta γ,β就可以调节输出数据的均值和方差。

接下来我们介绍如何在深度学习网络中使用BN:

image.png-75.2kB

如图所示,在前向传播中,每层的线性输出 Z [ l ] Z^{[l]} Z[l]后面都要再进行一次BN,得到新的输出 Z ~ [ l ] \tilde Z^{[l]} Z~[l],然后再将其输入到激活函数,同时多记录两个超参 γ [ l ] , β [ l ] \gamma^{[l]}, \beta^{[l]} γ[l],β[l]

同样,在反向传播中,我们同样需要更新这两个参数(和处理 W [ l ] , b [ l ] W^{[l]}, b^{[l]} W[l],b[l]一样):
γ [ l ] : = γ [ l ] − α d γ [ l ] \gamma^{[l]} := \gamma^{[l]} - \alpha d\gamma^{[l]} γ[l]:=γ[l]αdγ[l]
β [ l ] : = β [ l ] − α d β [ l ] \beta^{[l]} := \beta^{[l]} - \alpha d\beta^{[l]} β[l]:=β[l]αdβ[l]

为什么BN能够工作

  • 在前几层的参数变化时,当前层的输出值Z也会变化,但是当使用了BN算法后,它能够保证无论Z值怎么变化,Z的均值和方差将保持不变,这也间接地限制了前几层参数的更新,从而使得Z值变得稳定,后面层适用前面层变化的力量被减弱。实际上,BN算法消弱了前面层和后面层参数之间的耦合,使得当前层更加的独立,这将有助于提高网络学习速度。从后面层的角度来看,前面层的影响不大,因为它们被同一均值和方差所限制。
  • 由于对小批量数据进行归一化,而小批量中也包含噪声,所以均值和方差也有点噪声存在,起到了轻微的正则化的效果,实际和dropout的作用类似,使得后续隐藏单元不要过度依赖前面的隐藏单元。

如何在测试时BN
之前在训练时都是采用了批量的样本,64-512之间的样本,但是在测试时,往往都是针对一个样本的,这时对一个样本求均值 μ \mu μ和方差 σ 2 \sigma_2 σ2显然是不合理的,那么在测试时该如何计算 Z n o r m [ l ] Z_{norm}^{[l]} Znorm[l]呢?
Z n o r m [ l ] = Z [ l ] − μ σ 2 + ϵ Z_{norm}^{[l]} = \frac{Z^{[l]} - \mu}{\sqrt{\sigma^2 + \epsilon}} Znorm[l]=σ2+ϵ Z[l]μ
既然我们无法针对一个样本求均值 μ \mu μ和方差 σ 2 \sigma_2 σ2,那么一般的解决方法是记录下在网络训练时每一层的最新的均值 μ \mu μ和方差 σ 2 \sigma_2 σ2,然后在测试时直接带入计算 Z n o r m [ l ] Z_{norm}^{[l]} Znorm[l]

当然,另外一种更加通用的方法就是使用之前经过的指数加权平均Exponentially Weighted Averages方法,记录下最后的均值 μ \mu μ和方差 σ 2 \sigma_2 σ2,然后在测试时直接带入计算 Z n o r m [ l ] Z_{norm}^{[l]} Znorm[l],然后在使用训练后的参数 γ , β \gamma, \beta γ,β求出 Z ~ [ l ] \tilde Z^{[l]} Z~[l]

至此,我们已经讲述了多种提高训练速度的方法,中间也提出了更多的超参数,它们对训练结果起着重要的作用。因此,接下来我们将讲解,如何选择这些超参数以及如何调试这些超参数。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值