深度学习的实用层面

训练/验证/测试集

应用型机器学习是一个高速迭代的过程,需要多次循环才能为应用程序找到一个称心的神经网络。项目启动时,我们会有一个初步想法,然后编码并尝试运行这些代码,通过运行和测试得到该神经网络以及配置信息的运行结果,最后可能会根据结果重新完善自己的想法或者更新自己的方案。

图 1

 

循环效率是决定项目进度的一个关键因素,而创建高质量的训练数据集、验证集和测试集也有助于提高循环效率。

我们通常会将数据集划分为几个部分,一部分作为训练集,一部分作为简单交叉验证集,最后一部分作为测试集。接下来我们开始对训练集执行训练算法,通过简单交叉验证集选择最好的模型,经过充分验证我们选定了最终模型,然后就可以在测试集上进行评估了。

图 2数据集

 

大数据时代,我们通常选择数据集中98%的数据作为训练集,1%的数据作为验证集,1%的数据作为测试集。

现代深度学习的另一个趋势是越来越多的人在训练集和测试集分布不匹配的情况下进行训练。训练集可能是从网上抓取下来的图片,而验证集和测试集是用户上传的图片。网上的图片制作精良而,用户上传的照片可能是用手机随意拍摄的,这两类数据有所不同。针对这种情况,要确保验证集和测试集的数据来自同一分布,遵守这个法则,机器学习算法的运行会更快速。

最后,就算没有测试集也不要紧。测试集的目的是对最终所选定的神经网络系统做出无偏估计。如果不需要无偏估计,也可以不设置测试集。所以如果只有验证集而没有测试集,我们要做的就是在训练集上尝试不同的模型,在验证集上进行评估。

偏差/方差

理解偏差和方差的两个关键数据是训练集误差和验证集误差。以识别图片中的小猫为例,假设用肉眼识别几乎是不会出错的。若训练集误差为1%,验证集错误率为11%,可以看出训练集设置的非常好,而验证集设置相对较差,我们可能过度拟合了训练集,这种情况我们称之为“高方差”。通过查看训练集误差和验证集误差,我们便可以诊断算法是否具有高方差。若训练集误差为15%,验证集误差为16%,假设该案列中人的错误率几乎为0%,算法并没有在训练集中得到很好的训练,如果训练数据的拟合度不高就是数据欠拟合,就可以说这种算法偏差比较高。

 

高方差

高偏差

高方差

高偏差

低方差

低偏差

训练集误差

1%

15%

15%

0.5%

验证集误差

11%

16%

30%

1%

机器学习基础

初始模型训练完成后,我们首先要知道算法的偏差高不高,如果偏差较高甚至无法拟合训练集,那么就需要选择一个新网络,比如含有更多隐层或者隐藏单元的网络,或者延迟训练时间。我们需要反复尝试,直到解决偏差问题即可以拟合数据为止,至少能够拟合训练集。只要网络够大,通常能够拟合训练集。

一旦偏差降低到可接受的数值,检查一下方差有没有问题。为了评估方差,我们要查看验证集性能。我们能从一个性能理想的训练集推断出验证集的性能是否也理想。如果方差高,最好的方式就是采用更多训练数据或正则化来减少过拟合。

如果能找到更好的神经网络模型,那么既能解决高偏差问题,又能解决高方差问题。

有两点需要注意:第一点,高偏差和高方差是两种不同的情况,我们尝试降低二者的方法可能完全不同;第二点,在机器学习的初期阶段,关于方差偏差权衡的讨论屡见不鲜,因为我们没有办法只减少偏差或方差却不影响到另外一方。但在当前的深度学习和大数据时代,由于有了足够的数据,只要持续训练一个更大的网络,就可以在不影响方差的同时减少偏差,反之亦然。而训练一个大型神经网络的主要代价也只是计算时间。

正则化

如果你怀疑神经网络过度拟合了数据即存在高方差问题,那么最先想到的方法可能是正则化,另一个解决高方差的办法就是准备更多的数据。

以逻辑回归为例,只需在成本函数后加上相关正则化范数即可。若添加的是L2范数,这种方式称为L2正则化,因为这里用了w矩阵的欧几里德范数,即矩阵中所有元素的平方和。L2正则化是最常见的正则化类型,它又被称作“权重衰减”。

图 3 L2正则化

 

L1正则化加的不是L2范数。如果用的是L1正则化,W最终会是稀疏的,也就是W向量中有很多0。

λ是正则化参数,我们通常使用验证集或交叉验证来配置这个参数,它是一个超参数。

正则化可以减少过拟合的原因

我们添加正则项可以避免数据权值矩阵过大。正则化可以减少过拟合的直观理解是如果参数λ设置得足够大,将导致权重矩阵W将接近于0的值,这就相当于很多隐藏单元的权重变为0了,于是基本消除了这些隐藏单元的影响,那么大型神经网络被简化成小型神经网络了,小到如同logistic回归单元,然而深度却很深。

图 4正则化后的神经网络

 

这会使得网络从过拟合状态向高偏差状态接近。但是λ会存在一个中间值,于是会使得网络成为最合适的状态。

Dropout(随机失活)正则化

Dropout正则化的工作原理如下:

假设训练神经网络时存在过拟合,dropout会遍历网络的每一层,并设置消除神经网络中节点的概率,之后我们会删除这些节点并删掉从该节点进出的连线,最后得到一个节点更少、规模更小的神经网络。对于每一个训练样本,我们都采用一个精简后的神经网络来训练它。

图 5 dropout正则化

 

实施dropout的方法如下:

Inverted dropout(反向随机失活)。我们用三层网络举例说明。首先定义向量d3表示一个三层的dropout向量,用来决定第三层中哪些单元归零。然后看它是否小于我们称之为keep-prob的某数,keep-prob表示保留某个隐藏单元的概率,keep-prob=0.8意味着消除任意一个隐藏单元的概率是0.2。d3是一个随机矩阵,每个样本和每个隐藏单元在其中的对应值为1的概率是0.8,为0的概率是0.2。接下来要做的就是从第三层中获取激活函数a3,它的作用就是过滤掉d3中所有等于0的元素。最后我们向往扩展a3,用它除以keep-prob参数。反向随机失活(inverted dropout)方法通过除以keep-prob确保a3的期望值不变。

keep-prob=0.8
np.random.rand(a[3].shape[0],a[3].shape[1])<keep-prob
a[3]=np.multiply(a[3],d[3])
a[3]/=keep-prob 
a[4]=w[4]*a[3]+b[4]

在测试阶段我们并未使用dropout,也就不用去决定消除哪些隐藏单元了。因为在测试阶段进行预测时,我们不希望输出结果是随机的。如果测试阶段应用dropout函数,预测会受到干扰。

理解dropout正则化

通过之前的学习,我们可以产生一个直观认识,好像每次迭代后,神经网络都会变得比以前更小,因此采用一个较小神经网络好像和使用正则化的效果是一样的。第二个直观认识是,通过dropout,某个计算单元的输入特征几乎被消除,它不能依靠任何输入特征,因为输入特征都有可能被随机清除,我们不愿意把所有赌注都放在一个节点上即不愿意给任何一个输入加上太多权重,dropout将产生收缩权重的平方范数的效果,故而它被正式地作为一种正则化的替代形式。

dropout有一个技术细节需要注意,不同层的keep-prob是可以变化的。如果这一层过拟合现象没有那么严重,keep-prob值可能会高一些。如果某一层我们不用担心过拟合问题,那么keep-prob可以为1,即保留所有单元。

我们需要牢记一点,dropout是一种正则化方法,它有助于预防过拟合。因此,除非算法过拟合,否则不会使用dropout。

dropout一大缺点是代价函数J不再被明确定义,每次迭代都会随机移除一些节点。因此调试时我们通常关闭dropout函数,运行代码,确保J函数单调递减,然后再打开dropout函数。

其它正则化方法

扩增数据集

如果想通过扩增训练数据解决过拟合,但扩展训练数据代价很高甚至有时我们无法扩增数据。但我们可以通过添加类似图片来增加训练集,例如水平翻转图片或者随意裁剪图片并把它添加到训练集。以这种方式扩增算法数据进而正则化数据集减少过拟合比较廉价。

图 6 扩增数据集

 

early stopping

术语early stopping的意思是提早停止训练神经网络。我们可以通过early stopping绘制验证集误差。通常验证集误差会呈现先下降然后在某个节点处开始上升的趋势。early stopping的作用是,我们可以神经网络已经在某个迭代过程中表现的很好了,便在此停止训练,即在中间点停止迭代过程。

然而early stopping成本函数的值不够小,因为我们提前停止了优化成本函数。

归一化输入特征

训练神经网络,其中一个加速训练的方法就是归一化输入。如果输入特征处于不同范围内,可能有些输入特征从0到1,另一些输入特征从1到1000,那么归一化输入特征就非常重要了。如果输入特征处于相似范围内,那么归一化就不是很重要了,但执行这类归一化也不会产生什么危害。

图 7 归一化输入特征前的数据集

 

假设我们有一个训练集,它有两个输入特征。归一化输入需要两个步骤:第一步是零均值化,即将输入特征x1和x2减去它们的均值μ。

图 8 零均值化后的数据集

 

第二步是归一化方差,使得x1和x2的方差都等于1。

图 9 归一化方差后的数据集

 

训练集和测试集的归一化处理应该是相同的,我们希望不论是训练数据还是测试数据都是通过相同μ和σ2定义的相同数据转换,其中μ和σ2是由训练数据计算得来的。

如果使用非归一化输入特征,成本函数便会如图所示,这是一个非常细长狭窄的成本函数。如果在这样的函数上运行梯度下降法,必须使用一个非常小的学习率。

图 10 非归一化输入特征时的成本函数

 

如果使用归一化输入,成本函数看起来将会更对称。梯度下降法能够更直接的找到最小值,所以我们可以在梯度下降法中使用较大步长。

图 11 归一化输入特征后的成本函数

 

梯度消失与梯度爆炸

训练神经网络尤其时深度神经网络时所面临的一个问题是梯度消失或梯度爆炸。也就是说,训练深度网络时,导数(坡度)有时会变得非常大或非常小,甚至以指数方式变小,这加大了训练难度。比如梯度与L(神经网络的层数)相差指数级,梯度下降算法的步长将会非常非常小,梯度下降法将会花费很长时间来学习。

图 12 极深的神经网络

 

假设我们使用的激活函数是g(z)=z,也就是线性激活函数,并且我们忽略b,假设b[l]=0,这样y=w[l]w[l-1]w[l-2]…w[3]w[2]w[1]。

通过计算我们可以得到这样的直观理解,如果权重W只比1大一点或者只比单位矩阵大一点,深度神经网络的每层激活函数的值将爆炸式增长。如果W比1略小一点,在深度神经网络中每层激活函数的值将以指数级递减。上述理解同样适用于与层数L相关的导数或梯度函数。

神经网络的权重初始化

图 13 只有一个单元的神经网络

 

假设b=0,z=w1x1+w2x2+w3x3+w4x4。为了预防z值过大或过小,最合理的方式就是设置wi=1/n,其中n表示神经元的输入特征数量。如果使用ReLU作为激活函数,那么将1/n改为2/n效果会更好。

w[l]=np.random.randn(w[l].shape)*np.sqrt(1/n[l])

如果激活函数的输入特征被零均值化以及标准方差化,使得方差为1,z也会调整到相似范围,从而降低了梯度消失和梯度爆炸问题。因为它给权重矩阵W设置了合理值,它不能比1大很多也不能比1小很多。

梯度检验

在实施backprop时,有一个测试叫作梯度检验,它的作用是确保backprop正确实施。

为了执行梯度检验,首先要做的是把所有参数转换成一个巨大的向量数据,即把所有W矩阵(W[1]…W[L])和b矩阵(b[1]…b[L])转换成向量之后做连接运算,得到一个巨型向量θ。同理,将所有dW(dW[1]…dW[L])和db(db[1]…db[L])转换成一个大向量dθ,它与θ具有相同维度。

为了实施梯度检验,要做的就是循环执行如下操作:

图 14 梯度检验的步骤

 

我们每次只对θi增加ε,其它项保持不变。因为我们使用的是双边误差,对另一边做同样的操作,只不过是减去ε,其它项保持不变。然后我们需要对i的每个值执行前述运算,求得的dθappro向量就是梯度近似值。最后我们通过验证dθappro和dθ是否近似相等来判断使用梯度下降法求得的dθ是否正确。

 

我们采用欧几里德距离判断两向量是否近似相等,通常结果小于10-7我们就认为两个向量近似相等,否则我们则需不断调试,直至其结果小于10-7为止。

图 15 欧几里德距离

 

梯度检验的实用技巧与注意事项

  • 不要在训练中使用梯度检验,它只用于调试,调试后需关闭梯度检验。
  • 如果算法的梯度检验失败,要检查所有项,并试着找出bug。
  • 在实施梯度检验时,如果使用正则化,请记住一定要包括正则项。
  • 梯度检验不能与dropout同时使用。因为每次迭代过程中dropout会随机消除隐层单元的不同子集,难以计算dropout在梯度下降上的成本函数J。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值