优化深度神经网络(一) dropout 初始化

Coursera吴恩达《优化深度神经网络》课程笔记(1)-- 深度学习的实用层面

1. Train/Dev/Test sets  训练集(Training sets)、验证集(Development sets)、测试集(Test sets)

之前人们通常设置Train sets和Test sets的数量比例为70%和30%。如果有Dev sets,则设置比例为60%、20%、20%,分别对应Train/Dev/Test sets。这种比例分配在样本数量不是很大的情况下,例如100,1000,10000,是比较科学的。

但是如果数据量很大的时候,例如100万,这种比例分配就不太合适了。科学的做法是要将Dev sets和Test sets的比例设置得很低。因为Dev sets的目标是用来比较验证不同算法的优劣,从而选择更好的算法模型就行了。因此,通常不需要所有样本的20%这么多的数据来进行验证。对于100万的样本,往往只需要10000个样本来做验证就够了。Test sets也是一样,目标是测试已选算法的实际表现,无偏估计。对于100万的样本,往往也只需要10000个样本就够了。因此,对于大数据样本,Train/Dev/Test sets的比例通常可以设置为98%/1%/1%,或者99%/0.5%/0.5%。

样本数据量越大,相应的Dev/Test sets的比例可以设置的越低一些。

 

现代深度学习还有个重要的问题就是训练样本和测试样本分布上不匹配,意思是训练样本和测试样本来自于不同的分布。

举个例子,假设你开发一个手机app,可以让用户上传图片,然后app识别出猫的图片。在app识别算法中,你的训练样本可能来自网络下载,而你的验证和测试样本可能来自不同用户的上传。从网络下载的图片一般像素较高而且比较正规,而用户上传的图片往往像素不稳定,且图片质量不一。因此,训练样本和验证/测试样本可能来自不同的分布。

解决这一问题的比较科学的办法是尽量保证Dev sets和Test sets来自于同一分布。

值得一提的是,训练样本非常重要,通常我们可以将现有的训练样本做一些处理,例如图片的翻转、假如随机噪声等,来扩大训练样本的数量,从而让该模型更加强大。即使Train sets和Dev/Test sets不来自同一分布,使用这些技巧也能提高模型性能。

2. Bias/Variance

在传统的机器学习算法中,Bias和Variance是对立的,分别对应着欠拟合和过拟合,我们常常需要在Bias和Variance之间进行权衡。

深度学习中,我们可以同时减小Bias和Variance,构建最佳神经网络模型。

深度学习:

减少high bias的方法通常是增加神经网络的隐藏层个数、神经元个数,训练时间延长,选择其它更复杂的NN模型等。在base error不高的情况下,一般都能通过这些方式有效降低和避免high bias,至少在训练集上表现良好。

减少high variance的方法通常是增加训练样本数据,进行正则化Regularization,选择其他更复杂的NN模型等。

4. Regularization

L1 regularization。其表达式为:

J(w,b)=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}||w||_1

||w||_1=\sum_{j=1}^{n_x}|w_j|

L1的在微分求导方面比较复杂。

 

在深度学习模型中,L2 regularization的表达式为:

J(w^{[1]},b^{[1]},\cdots,w^{[L]},b^{[L]})=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}\sum_{l=1}^L||w^{[l]}||^2

||w^{[l]}||^2=\sum_{i=1}^{n^{[l]}}\sum_{j=1}^{n^{[l-1]}}(w_{ij}^{[l]})^2

由于加入了正则化项,梯度下降算法中的 dw^{[l]} 计算表达式需要做如下修改:

dw^{[l]}=dw^{[l]}_{before}+\frac{\lambda}{m}w^{[l]}

w^{[l]}:=w^{[l]}-\alpha\cdot dw^{[l]} w^{[l]}:=w^{[l]}-\alpha\cdot dw^{[l]}

由于加上了正则项, dw^{[l]} 有个增量,在更新 w^{[l]} 的时候,会多减去这个增量,使得 w^{[l]} 比没有正则项的值要小一些。不断迭代更新,不断地减小。

\begin{eqnarray}w^{[l]} &:=&w^{[l]}-\alpha\cdot dw^{[l]}\\ &=&w^{[l]}-\alpha\cdot(dw^{[l]}_{before}+\frac{\lambda}{m}w^{[l]})\\ &=&(1-\alpha\frac{\lambda}{m})w^{[l]}-\alpha\cdot dw^{[l]}_{before} \end{eqnarray}

其中, (1-\alpha\frac{\lambda}{m})<1

 

选择合适大小的 \lambda 值,就能够同时避免high bias和high variance,得到最佳模型。

还有另外一个直观的例子来解释为什么正则化能够避免发生过拟合。假设激活函数是tanh函数。tanh函数的特点是在z接近零的区域,函数近似是线性的,而当|z|很大的时候,函数非线性且变化缓慢。当使用正则化, \lambda 较大,即对权重 w^{[l]} 的惩罚较大, w^{[l]} 减小。因为 z^{[l]}=w^{[l]}a^{[l]}+b^{[l]} 。当 w^{[l]} 减小的时候, z^{[l]} 也会减小。则此时的 z^{[l]} 分布在tanh函数的近似线性区域。那么这个神经元起的作用就相当于是linear regression。如果每个神经元对应的权重 w^{[l]} 都比较小,那么整个神经网络模型相当于是多个linear regression的组合,即可看成一个linear network。得到的分类超平面就会比较简单,不会出现过拟合现象。

 

6. Dropout Regularization

除了L2 regularization之外,还有另外一种防止过拟合的有效方法:Dropout。

Dropout是指在深度学习网络的训练过程中,对于每层的神经元,按照一定的概率将其暂时从网络中丢弃。也就是说,每次训练时,每一层都有部分神经元不工作,起到简化复杂网络模型的效果,从而避免发生过拟合。

Dropout有不同的实现方法,接下来介绍一种常用的方法:Inverted dropout。假设对于第l层神经元,设定保留神经元比例概率keep_prob=0.8,即该层有20%的神经元停止工作。 dl 为dropout向量,设置 dl 为随机vector,其中80%的元素为1,20%的元素为0。在python中可以使用如下语句生成dropout vector:

dl = np.random.rand(al.shape[0],al.shape[1])<keep_prob  
#随机生成大小为al.shape[0],al.shape[1]的矩阵,将其填充在一个均匀分布的随机样本[0, 1)中,小于keep_prob的为false

然后,第 l 层经过dropout,随机删减20%的神经元,只保留80%的神经元,其输出为:

al = np.multiply(al,dl)

最后,还要对 al 进行scale up处理,即:

al /= keep_prob

之所以要对 al 进行scale up是为了保证在经过dropout后, al 作为下一层神经元的输入值尽量保持不变。假设第 l 层有50个神经元,经过dropout后,有10个神经元停止工作,这样只有40神经元有作用。那么得到的 al 只相当于原来的80%。scale up后,能够尽可能保持 al 的期望值相比之前没有大的变化。

 

Inverted dropout的另外一个好处就是在对该dropout后的神经网络进行测试时能够减少scaling问题。因为在训练时,使用scale up保证 al期望值没有大的变化,测试时就不需要再对样本数据进行类似的尺度伸缩操作了。

对于m个样本,单次迭代训练时,随机删除掉隐藏层一定数量的神经元;然后,在删除后的剩下的神经元上正向和反向更新权重w和常数项b;接着,下一次迭代中,再恢复之前删除的神经元,重新随机删除一定数量的神经元,进行正向和反向更新w和b。不断重复上述过程,直至迭代训练完成。

值得注意的是,使用dropout训练结束后,在测试和实际应用模型时,不需要进行dropout和随机删减神经元,所有的神经元都在工作。

7. Understanding Dropout

为什么dropout可以防止过拟合

理解1.Dropout通过每次迭代训练时,随机选择不同的神经元,相当于每次都在不同的神经网络上进行训练,类似机器学习中Bagging的方法,能够防止过拟合。

理解2.从权重w的角度。对于某个神经元来说,某次训练时,它的某些输入在dropout的作用被过滤了。而在下一次训练时,又有不同的某些输入被过滤。经过多次训练后,某些输入被过滤,某些输入被保留。这样,该神经元就不会受某个输入非常大的影响,影响被均匀化了。也就是说,对应的权重w不会很大。这从从效果上来说,与L2 regularization是类似的,都是对权重w进行“惩罚”,减小了w的值

 

总结一下,对于同一组训练数据,利用不同的神经网络训练之后,求其输出的平均值可以减少overfitting。Dropout就是利用这个原理,每次丢掉一定数量的隐藏层神经元,相当于在不同的神经网络上进行训练,这样就减少了神经元之间的依赖性,即每个神经元不能依赖于某几个其他的神经元(指层与层之间相连接的神经元),使神经网络更加能学习到与其他神经元之间的更加健壮robust的特征。

dropdout注意点

首先,不同隐藏层的dropout系数keep_prob可以不同。一般来说,神经元越多的隐藏层,keep_prob可以设置得小一些.,例如0.5;神经元越少的隐藏层,keep_out可以设置的大一些,例如0.8,设置是1。

实际应用中,不建议对输入层进行dropout,如果输入层维度很大,例如图片,那么可以设置dropout,但keep_prob应设置的大一些,例如0.8,0.9。总体来说,就是越容易出现overfitting的隐藏层,其keep_prob就设置的相对小一些。没有准确固定的做法,通常可以根据validation进行选择。

8. Other regularization methods

1.增加训练样本数量。但是通常成本较高,难以获得额外的训练样本。但是,我们可以对已有的训练样本进行一些处理来“制造”出更多的样本,称为data augmentation。

2.early stopping。一个神经网络模型随着迭代训练次数增加,train set error一般是单调减小的,而dev set error 先减小,之后又增大。也就是说训练次数过多时,模型会对训练样本拟合的越来越好,但是对验证集拟合效果逐渐变差,即发生了过拟合。因此,迭代训练次数不是越多越好,可以通过train set error和dev set error随着迭代次数的变化趋势,选择合适的迭代次数,即early stopping。

early stopping缺点:

通常来说,机器学习训练模型有两个目标:一是优化cost function,尽量减小J;二是防止过拟合。这两个目标彼此对立的,即减小J的同时可能会造成过拟合,反之亦然。我们把这二者之间的关系称为正交化orthogonalization。

而在深度学习中,我们可以同时减小Bias和Variance,构建最佳神经网络模型。但是,Early stopping的做法通过减少得带训练次数来防止过拟合,这样J就不会足够小。也就是说,early stopping将上述两个目标融合在一起,同时优化,但可能没有“分而治之”的效果好。

与early stopping相比,L2 regularization可以实现“分而治之”的效果:迭代训练足够多,减小J,而且也能有效防止过拟合。而L2 regularization的缺点之一是最优的正则化参数 \lambda 的选择比较复杂。对这一点来说,early stopping比较简单。总的来说,L2 regularization更加常用一些。

9. Normalizing inputs

在训练神经网络时,标准化输入可以提高训练的速度。标准化输入就是对训练数据集进行归一化的操作,即将原始数据减去其均值 \mu 后,再除以其方差 \sigma^2

\mu=\frac1m\sum_{i=1}^mX^{(i)}

\sigma^2=\frac1m\sum_{i=1}^m(X^{(i)})^2

X:=\frac{X-\mu}{\sigma^2}

10. 梯度消失 梯度爆炸

详解机器学习中的梯度消失、爆炸原因及其解决方法

- 预训练加微调

- 梯度剪切、权重正则(针对梯度爆炸)

- 使用不同的激活函数 RELU

- 使用batchnorm

- 使用残差结构*

- 使用LSTM网络

11. 权重w初始化

深度神经网络模型中,以单个神经元为例,该层( l )的输入个数为n,其输出为:

z=w_1x_1+w_2x_2+\cdots+w_nx_n z=w_1x_1+w_2x_2+\cdots+w_nx_n

a=g(z)

这里忽略了常数项b。为了让z不会过大或者过小,思路是让w与n有关,且n越大,w应该越小才好。这样能够保证z不会过大。

激活函数是tanh,在初始化w时,令其方差为 \frac1n

如果激活函数是ReLU,权重w的初始化一般令其方差为 \frac2n

Yoshua Bengio提出了另外一种初始化w的方法,令其方差为 \frac{2}{n^{[l-1]}n^{[l]}}

可以根据不同的激活函数选择不同方法。另外,我们可以对这些初始化方法中设置某些参数,作为超参数,通过验证集进行验证,得到最优参数,来优化神经网络。

13. 梯度检查

我们将介绍如何进行梯度检查,来验证训练过程中是否出现bugs。

1.梯度检查首先要做的是分别将 W^{[1]},b^{[1]},\cdots,W^{[L]},b^{[L]} 这些矩阵构造成一维向量,然后将这些一维向量组合起来构成一个更大的一维向量 \theta 。这样cost function J(W^{[1]},b^{[1]},\cdots,W^{[L]},b^{[L]}) 就可以表示成 J(\theta)

 

2.将反向传播过程通过梯度下降算法得到的 dW^{[1]},db^{[1]},\cdots,dW^{[L]},db^{[L]} 按照一样的顺序构造成一个一维向量 d\thetad\theta 的维度与 \theta 一致。

 

3.利用 J(\theta) 对每个 \theta_i 计算近似梯度,其值与反向传播算法得到的 d\theta_i 相比较,检查是否一致。例如,对于第i个元素,近似梯度为:

 

d\theta_{approx}[i]=\frac{J(\theta_1,\theta_2,\cdots,\theta_i+\varepsilon,\cdots)-J(\theta_1,\theta_2,\cdots,\theta_i-\varepsilon,\cdots)}{2\varepsilon}

 

4.计算完所有 \theta_i 的近似梯度后,可以计算 d\theta_{approx}d\theta 的欧氏(Euclidean)距离来比较二者的相似度。公式如下:

 

\frac{||d\theta_{approx}-d\theta||_2}{||d\theta_{approx}||_2+||d\theta||_2}

 

5.如果欧氏距离越小,例如 10^{-7} ,甚至更小,则表明 d\theta_{approx}d\theta 越接近,即反向梯度计算是正确的,没有bugs。

如果欧氏距离较大,例如 10^{-5} ,则表明梯度计算可能出现问题,需要再次检查是否有bugs存在。

如果欧氏距离很大,例如 10^{-3} ,甚至更大,则表明 d\theta_{approx}d\theta 差别很大,梯度下降计算过程有bugs,需要仔细检查。

 

在进行梯度检查的过程中有几点需要注意的地方:

  • 不要在整个训练过程中都进行梯度检查,仅仅作为debug使用。
  • 如果梯度检查出现错误,找到对应出错的梯度,检查其推导是否出现错误。
  • 注意不要忽略正则化项,计算近似梯度的时候要包括进去。
  • 梯度检查时关闭dropout,检查完毕后再打开dropout。
  • 随机初始化时运行梯度检查,经过一些训练后再进行梯度检查(不常用)。

 

下图是一个利用sigmoid函数作为激活函数的含四个隐藏层的神经网络训练的梯度下降图。这个神经网络遇到了梯度消失的问题。下面哪个叙述是正确的?(A)深度学习 DL基础 中
 第一隐藏层对应D,第二隐藏层对应C,第三隐藏层对应B,第四隐藏层对应A
 第一隐藏层对应A,第二隐藏层对应C,第三隐藏层对应B,第四隐藏层对应D
 第一隐藏层对应A,第二隐藏层对应B,第三隐藏层对应C,第四隐藏层对应D
 第一隐藏层对应B,第二隐藏层对应D,第三隐藏层对应C,第四隐藏层对应A 

由于反向传播算法进入起始层,学习能力降低,这就是梯度消失。换言之,梯度消失是梯度在前向传播中逐渐减为0, 按照图标题所说, 四条曲线是4个隐藏层的学习曲线, 那么第一层梯度最高(损失函数曲线下降明显), 最后一层梯度几乎为零(损失函数曲线变成平直线). 所以D是第一层, A是最后一层。

posted @ 2018-04-11 17:08  喵喵帕斯  阅读(2158)  评论(0编辑  收藏  举报