小言_互联网的博客

吴恩达深度学习 C2_W1

410人阅读  评论(0)

C2_W1

刚刚把大物的PPT做完,突然想起有什么东西好久没做了。于是赶紧对这一周的学习进行一个整理。


训练_开发_测试集

经过了第一部分深度学习神经网络概念的学习,我们对于神经网络是什么,长什么样,有什么作用,该如何构建,已经有了一个非常粗浅的了解(这点存疑)。在这一部分,我们将继续去学习如何有效运作神经网络,内容包括超参数调优,数据处理和算法优化等一系列保证神经网络正确且快速运作的方法。

在建立一个神经网络时,我们首先要考虑如下一些问题:

这些数据显然我们不能一下子就能够预测出最准确的值。因此,我们需要不停地修改不停地训练,直到得到最优秀的方案:


(一直训练一直爽)

但是非常抱歉的就是,在深度学习方面,不同领域在数据方面有关的经验大多数情况下是不可以通用的,即使是非常厉害的专家也不太能直接得到最优的神经网络(你觉得老师不是专家么?)。

我们一般将数据集分为训练集,简单交叉验证集和测试集三个部分:


从名称上我们也能够看出这三个分别的功能:

训练集用来训练模型,即确定模型的权重和偏置这些参数,通常我们称这些参数为学习参数。

而验证集用于模型的选择,更具体地来说,验证集并不参与学习参数的确定,也就是验证集并没有参与梯度下降的过程。验证集只是为了选择超参数,比如网络层数、网络节点数、迭代次数、学习率这些都叫超参数。比如在k-NN算法中,k值就是一个超参数。所以可以使用验证集来求出误差率最小的k。

测试集只使用一次,即在训练完成后评价最终的模型时使用。它既不参与学习参数过程,也不参数超参数选择过程,而仅仅使用于模型的评价。值得注意的是,千万不能在训练过程中使用测试集,而后再用相同的测试集去测试模型。这样做其实是一个cheat,使得模型测试时准确率很高(产生了过拟合)。

在人工智能的小数据时代(就是数据比较少啦),我们往往将整个数据集七三分:60%训练,20%验证,20%测试。但是在大数据时代(看到大数据三个字我就怕),我们的数据量可能是之前的1000倍甚至10000倍,那么验证集和测试集的占比会变得更小,大概各占到1%左右(甚至验证集0.4%,测试集0.1%)。

但是往往会出现训练和测试集不匹配这样的情况:比如我们在做一个对用户上传的照片识别出猫咪的程序,训练集可能是从网络上下载的猫咪照片,而验证集和测试集可能是用户上传的照片。这就会出现一个问题:两种照片的分辨率等一些要素不匹配。解决的方案很简单,就是尽量保证验证集和测试集的数据来自同一分布。

事实上如果没有测试集也是ok的,在验证集上进行评估迭代选用适合的模型就可以了。这个时候我们称验证集为测试集,训练集中同时完成验证集的功能(这一段其实我并没有搞得特别明白,还是先看后面的实操部分吧)。


偏差_方差

首先我们先看一下拟合同一种数据集的三种不同分离器:

左边的那张图,我们可以发现这条直线对应的一个逻辑回归拟合,并不能够很好的拟合该数据集。这是偏差高的情况,我们称其为“欠拟合”。

右边的这张图,我们拟合了一种非常复杂的分离器,这个分离器非常适用于当前这个数据集,但是并不适用于所有的数据集。这是方差高的情况,我们称其为“过拟合”。

中间这张图,分离器复杂度适中,数据拟合适度,我们称其为“适度拟合”。

沿用猫咪识别作为例子:


第一种情况,训练集表现得很好,但是测试集有些问题,说明过度拟合了训练集的数据集。属于方差比较高。

第二种情况:训练集表现得一般,同时测试集也一般,说明分离器本身就有些问题,但是没有过度拟合某个数据集产生较大的误差。属于偏差比较高。

第三种情况:训练集表现得糟糕,测试集更糟糕,分离器有问题,同时还过度拟合了训练集的数据集。属于方差和偏差都比较高的情况。

第四种情况:训练集和测试集表现得都很好,完美!

这上面情况的分析的前提条件都是建立在训练集和测试集都属于同一分布的情况。

紫色线框表示的,就是最为糟糕的那种情况(方差和偏差都高):


机器学习基础

这一章节主要是介绍了关于机器学习流程的框架以及如何处理偏差高和方差高的问题:

我们首先尝试解决偏差高的问题,这里老师提供了两种处理方法:建立更大的神经网络或者训练更长的时间。理论上只要神经网络更大,是一定能够解决偏差高的问题的。

接下来是解决方差高的问题,这里老师依旧提供了两种解决的办法:训练更多的数据(不实际,数据要money的啦),正则化减少过拟合程度(这个内容在后面的章节会进行介绍)。

在深度学习的早期时代,往往需要牺牲方差去降低偏差或者牺牲偏差去降低方差。然而随着时代改变,依旧有了不少方法可以同时降低两种误差,或者在至少不做出任何牺牲。比如持续训练一个更大更好的网络。


正则化

这是我们原本的代价函数:


加入正则化之后:


(w几乎涵盖所有参数,而b只是众多参数中的一个参数,往往可以忽略不计)

这种正则化的方式,我们称其为L2正则化。

L1正则化:

L1和L2正则化(往往用L2正则化用的比较多):


λ为正则化参数,是一个需要调整的超级参数,这个参数是可以尝试各种各样的数据进行调试的。

堆叠起来后:

就是求W矩阵中所有元素的平方和。

于是在进行梯度下降法时,dW需要额外计算添加的正则化项,

计算的结果:

此时我们的W相当于乘以了一个(1-αλ/m)的权重,这个系数小于1,因此L2正则化也被称为“权重衰减”。


为什么正则化有利于减少过拟合?

这是一个神经网络建立的过拟合的分离器:


当我们进行了L2正则化,λ设置的越大,总cost不变的情况下,W就设置为越接近于0的值。直观理解就是把多隐藏单元的权重设为0,于是基本上消除了这些隐藏单元的许多影响。如果是这种情况,这个被大大简化了的神经网络会变成一个很小的网络,小到如同一个逻辑回归单元,可是深度却很大,它会使这个网络从过度拟合的状态更接近左图的高偏差状态。

但是λ会存在一个中间值,于是会有一个适度拟合的中间状态。

假设我们用的是tanh这样的双曲线激活函数。


我们发现如果 z 非常小,比如 z 只涉及很小范围的参数(图中原点附近的红色区域),这里我们利用了双曲正切函数的线性状态,只要z可以扩展为这样的更大值或者更小值,激活函数开始变得非线性。


如果正则化参数λ很大,激活函数的参数会相对较小。z比较小时,g(z)基本处于线性,每层几乎都是线性的,和线性回归函数一样。


如果每层都是线性的,那么整个网络就是一个线性网络,即使是一个非常深的深层网络,因具有线性激活函数的特征,最终我们只能计算线性函数,因此,它不适用于非常复杂的决策,以及过度拟合数据集的非线性决策边界,如同我们上面看到的过度拟合高方差的情况。


dropout正则化

dropout正则化即是对每一层进行一个遍历,每一个节点保留的概率为0.5(这个概率可以进行修改并不要求一定是0.5)。如右图中被去除的节点,删掉从该点进出的连线,得到一个节点更少规模更小的神经网络。

如何实施dropout呢?方法有几种,接下来我要讲的是最常用的方法,即inverted dropout(反向随机失活)。

对于某一层(这里举的例子为第三层)定义变量d表示这一层的dropout向量:


d3 = np.random.rand(a3.shape[0],a3.shape[1])

keep.prob的值表示d向量中每一个单位为1的概率(不为1即为0),a3=a3*d3,于是a3中便有1-0.8=0.2的数可能被消除。最后,我们向外扩展a3要用它除以keep.prob。因为a3中元素被消除影响到了W*a的值,于是需要除以keep.prob补上损失的值。

如何在测试阶段训练算法,在测试阶段,我们已经给出了x,或是想预测的变量,用的是标准计数法。我用a([0]),第0层的激活函数标注为测试样本x,我们在测试阶段不使用dropout函数,尤其是像下列情况:

z([1])=w([1]) a([0])+b([1])

a([1])=g([1]) (z([1]))

z([2])= w([2]) a([1])+b([2])

a([2])=⋯

以此类推直到最后一层,预测值为^y。

显然在测试阶段,我们并未使用dropout,自然也就不用抛硬币来决定失活概率,以及要消除哪些隐藏单元了,因为在测试阶段进行预测时,我们不期望输出结果是随机的,如果测试阶段应用dropout函数,预测会受到干扰。

Inverted dropout函数在除以keep-prob时可以记住上一步的操作,目的是确保即使在测试阶段不执行dropout来调整数值范围,激活函数的预期结果也不会发生变化,所以没必要在测试阶段额外添加尺度参数,这与训练阶段不同。


理解dropout

Dropout为什么可以减少过拟合?
它会随机丢弃掉一些结点,所以看起来是在更小的网络上训练。
以下图紫圈的神经元为例,由于在中间做了dropout,所以向它输入的四个神经元可以随机失活,所以紫圈神经元不能把所有权重都压在一个输入神经元上面。因此该单元将这种方式积极地传播开,并且输入增加权重,以此来控制权重,产生收缩权重的平方范数的效果(和L2正则化达到的效果类似)。


keep.prob的值也可以随着每一层不同的情况而发生改变:


如第二层,矩阵的维度是7*7,很大,keep.prob的值也可以相对而言小一点取0.5,其余的层取0.7。而对于输出那一层就直接取1意味着保留所有单元没什么问题。输入层往往不使用dropout。

dropout往往在计算机视觉中使用的比较频繁。dropout的缺陷在于代价函数没有被明确定义,在使用dropout正则化时损失了一些节点,很难根据代价函数进行调试。所以在调试时,一般将keep.prob的值调为1,确保J函数单调递减。


其他正则化方法

除了L2正则化和随机失活(dropout)正则化,还有几种方法可以减少神经网络中的过拟合。

数据扩增:假设你正在拟合猫咪图片分类器,如果你想通过扩增训练数据来解决过拟合,但扩增数据代价高,而且有时候我们无法扩增数据,但我们可以通过添加这类图片来增加训练集。

例如,水平翻转图片,并把它添加到训练集。所以现在训练集中有原图,还有翻转后的这张图片,所以通过水平翻转图片,训练集则可以增大一倍,因为训练集有冗余,这虽然不如我们额外收集一组新图片那么好,但这样做节省了获取更多猫咪图片的花费。

除了水平翻转图片,你也可以随意裁剪图片,这张图是把原图旋转并随意放大后裁剪的,仍能辨别出图片中的猫咪。

通过随意翻转和裁剪图片,我们可以增大数据集,额外生成假训练数据。和全新的,独立的猫咪图片数据相比,这些额外的假的数据无法包含像全新数据那么多的信息,但我们这么做基本没有花费,代价几乎为零,除了一些对抗性代价。

以这种方式扩增算法数据,进而正则化数据集,减少过拟合比较廉价。


如果是数字识别的话,我们还可以通过随意扭曲和旋转数字将这些数据添加到训练集来扩增数据。

还有另外一种常用的方法叫作early stopping,运行梯度下降时,我们可以绘制训练误差,或只绘制代价函数J的优化过程,在训练集上用0-1记录分类误差次数。呈单调下降趋势,如图。


还有验证集误差:


你会发现,验证集误差通常会先呈下降趋势,然后在某个节点处开始上升。early stopping的作用和它的名字一样,就是突然在中间点停止迭代过程,得到一个w值中等大小的弗罗贝尼乌斯范数(在迭代过程和训练过程中w的值会变得越来越大)。

术语early stopping代表提早停止训练神经网络,训练神经网络时,我有时会用到early stopping,但是它也有一个缺点,我们来了解一下。

early stopping的主要缺点就是你不能独立地处理这两个问题(优化J函数和减少方差),因为提早停止梯度下降,也就是停止了优化代价函数J,因为现在你不再尝试降低代价函数J,所以代价函数J的值可能不够小,同时你又希望不出现过拟合,你没有采取不同的方式来解决这两个问题,而是用一种方法同时解决两个问题,这样做的结果就是两个问题都处理的不够完美。

如果不用early stopping,另一种方法就是L2正则化,训练神经网络的时间就可能很长。这导致超级参数搜索空间更容易分解,也更容易搜索,但是缺点在于,你必须尝试很多正则化参数λ的值,这也导致搜索大量λ值的计算代价太高。

Early stopping的优点是,只运行一次梯度下降,你可以找出w的较小值,中间值和较大值,而无需尝试L2正则化超级参数λ的很多值。


归一化输入

假设有两个输入特征x1和x2。


归一化输入的第一步叫做零均值化,就是得到m个样本中x的算数平均值,然后让每一个x减去这个算术平均值。此时我们将数据从第一张图转化为第二张图,x的均值已经为0。

第二步是归一化方差,得到m个样本中x的平方和的1/m,将x除以这个值。得到最右的图片。

最后x1和x2的均值均为0,方差均为1。


原本的代价函数图像和左边的图像一样,非常细长狭窄。x1和x2的值的大小和范围不同,导致W1和W2的值的大小和范围也非常不同。

进行归一化输入时,这个“碗”看起来就圆润的多啦!

如果在左图这样的代价函数上运行梯度下降算法,你就必须使用一个非常小的学习率。因为如果是在这个位置,梯度下降算法可能需要多次迭代过程,直到最后找到最小值。
如果函数是一个更圆的球形轮廓,那么不论从哪个位置开始,梯度下降算法都能更直接地找到最小值,这使得我们可以在梯度下降法中使用较大的步长,而不需要像在左图那样反复执行(即使得代价函数J优化起来更简单更快速)


梯度消失和梯度爆炸

假设你正在训练这样一个极深的神经网络:


为了简单起见设g(z)=z(我感觉这个简单起见,就让我没有明白这个问题的普遍性),于是y hat的值就是一个矩阵的连乘得到的:

无论W矩阵相对于单位矩阵的倍数大于或者小于1。y hat的值都可能变得特别大或者特别小,总的来说就是特别极端。梯度下降算法的步长会非常非常小。梯度下降算法将花费很长时间来学习。

我搜了别人的笔记,别人都叫我看这个:详解深度学习中的梯度消失和梯度爆炸


神经网络的初始权重化

这节课将讨论一个能够部分解决梯度梯度消失和梯度爆炸问题的方法。首先是一个单独的神经元:


z=w1*x1+w2*x2++wn*xn。为了预防z值过大或者过小,Wi的值将随着n的值的大小发生改变。

于是:


如果你是用的是Relu激活函数,而不是1/n,方差设置为2/n,效果会更好。

如果激活函数的输入特征被零均值和标准方差化,方差是1,z也会调整到相似范围,这就没解决问题(梯度消失和爆炸问题)。但它确实降低了梯度消失和爆炸问题,因为它给权重矩阵w设置了合理值,所以梯度没有爆炸或消失过快(我解决了但没完全解决)。

tanh函数还会考虑下面两种:


这些公式只是给你一个起点,它们给出初始化权重矩阵的方差的默认值,如果你想添加方差,方差参数则是另一个你需要调整的超级参数(公式只是默认值,真正的方差还是需要通过你不断地去训练和调试才行)。

并且该超级参数调优的效果一般,优先度并不是特别高。


梯度的数值逼近

后面的三小节实际是在讲如何确保back prop正确实施,即进行back prop时,对参数求导过程是否准确。

学过高数的都知道(我不知道,我是fw),对于可导的函数,要求函数在某点的导数时,我们可以利用求导公式直接对函数求导,得到导数公式之后带入该点坐标即可得到函数在该点的导数值。

除此之外,我们还可以利用导数的定义去求解函数在某一点的导数值。其实这里梯度检验的思想就是利用这两种求导思想去检验求导过程是否准确。


这里我们发现相隔两个微小变量计算出来的导数(双边误差)远远要比相隔一个微小变量计算出来的导数(单边误差)要精确。并且两种方法在时间上的复杂度几乎相同,于是我们往往选用前一种方法(双边误差)。


梯度检验

逼近梯度的形式找到了,我们就可以进行梯度检验了。梯度检验帮助节省时间以及发现backprop实施过程中的bug,我们用它来调试和检查backprop实施是否正确。

首先我们将矩阵W向量化和矩阵B连接合成一个大向量(sita),然后得到这个大向量的代价函数J(sita)。矩阵dW向量化和矩阵dB连接合成另一个大向量d(sita),维度与sita相同。


将J函数展开为J(sita1),J(sita2)······一次对sitai进行双边误差,然后比较这个值和d(sitai)的大小。具体怎么得到,就是求两个向量差的模长除以模长和(欧几里得范数)。

假设我们的sigma在这里取10的-7次方,那么如果这个比率约为10的-7次方,我就可以认为这次的梯度检验没有问题,如果这个比率为10的-5次方,这时我就要稍微考虑一下是哪里出了错,就需要把参数向量的每个分量的梯度计算一下,来看一下是哪个分量的梯度计算错误导致了这样的结果,如果这个比率为10的-3次方,那么结果就更严重了,更加需要把参数向量的每个分量的梯度计算一下来看是哪个计算错误。


关于梯度检验实践的注记

首先,不要使用梯度检验去训练,即不要使用梯度检验方法去计算梯度,因为这样做太慢了,在训练过程中,我们还是使用backprop去计算参数梯度,而使用梯度检验去调试,去检验backprop的过程是否准确。

其次,如果我们在使用梯度检验过程中,发现backprop过程出现了问题,如我们在1.13中假设的那样,这时我们就需要对所有的参数进行计算,以判断造成计算偏差的来源在哪里,它可能是在求解b出现问题,也可能是在求解某一层的W出现问题,梯度检验可以帮助我们确定发生问题的范围,以帮助我们调试。

别忘了正则化,如上图所示,如果我们添加了L2范数正则化,在使用backprop计算参数梯度时,不要忘记梯度的形式已经发生了变化,要记得加上正则化部分,同理,在进行梯度检验时,也要记得目标函数J的形式已经发生了变化。

注意,如果我们使用了drop-out正则化,梯度检验就不可用了。为什么呢?因为我们知道drop-out是按照一定的保留概率随机保留一些节点,因为它的随机性,目标函数J的形式变得非常不明确,这时我们便无法再用梯度检验去检验backprop。如果非要使用drop-out且又想检验backprop,我们可以先将保留概率设为1,即保留全部节点,然后用梯度检验来检验backprop过程,如果没有问题,我们再改变保留概率的值来应用drop-out。

这一段就直接抄的老师原话(我老fw了)。


我的信仰不够纯正,说不上热爱,就连努力都只能算勉强。


转载:https://blog.csdn.net/weixin_55835175/article/details/117393917
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场