吴恩达深度学习课程笔记Lesson05(下)

第二门课 改善深层神经网络:超参数调试、正则化以及优化(Improving Deep Neural Networks:Hyperparameter tuning, Regularization and Optimization)

第一周:深度学习的实践层面(Practical aspects of Deep Learning)(下)

1.7 理解 dropout(Understanding Dropout)

Dropout可以随机删除网络中的神经单元,他为什么可以通过正则化发挥如此大的作用呢?

直观上理解:不要依赖于任何一个特征,因为该单元的输入可能随时被清除,因此该单元通过这种方式传播下去,并为单元的四个输入增加一点权重,通过传播所有权重,dropout将产生收缩权重的平方范数的效果,和之前讲的 L 2 L2 L2正则化类似;实施dropout的结果实它会压缩权重,并完成一些预防过拟合的外层正则化; L 2 L2 L2对不同权重的衰减是不同的,它取决于激活函数倍增的大小。

总结一下,dropout的功能类似于 L 2 L2 L2正则化,与 L 2 L2 L2正则化不同的是应用方式不同会带来一点点小变化,甚至更适用于不同的输入范围。

在这里插入图片描述

第二个直观认识是,我们从单个神经元入手,如图,这个单元的工作就是输入并生成一些有意义的输出。通过dropout,该单元的输入几乎被消除,有时这两个单元会被删除,有时会删除其它单元,就是说,我用紫色圈起来的这个单元,它不能依靠任何特征,因为特征都有可能被随机清除,或者说该单元的输入也都可能被随机清除。我不愿意把所有赌注都放在一个节点上,不愿意给任何一个输入加上太多权重,因为它可能会被删除,因此该单元将通过这种方式积极地传播开,并为单元的四个输入增加一点权重,通过传播所有权重,dropout将产生收缩权重的平方范数的效果,和我们之前讲过的 L 2 L2 L2正则化类似,实施dropout的结果是它会压缩权重,并完成一些预防过拟合的外层正则化。

事实证明,dropout被正式地作为一种正则化的替代形式, L 2 L2 L2对不同权重的衰减是不同的,它取决于倍增的激活函数的大小。

总结一下,dropout的功能类似于 L 2 L2 L2正则化,与 L 2 L2 L2正则化不同的是,被应用的方式不同,dropout也会有所不同,甚至更适用于不同的输入范围。

在这里插入图片描述

实施dropout的另一个细节是,这是一个拥有三个输入特征的网络,其中一个要选择的参数是keep-prob,它代表每一层上保留单元的概率。所以不同层的keep-prob也可以变化。第一层,矩阵 W [ 1 ] W^{[1]} W[1]是7×3,第二个权重矩阵 W [ 2 ] W^{[2]} W[2]是7×7,第三个权重矩阵 W [ 3 ] W^{[3]} W[3]是3×7,以此类推, W [ 2 ] W^{[2]} W[2]是最大的权重矩阵,因为 W [ 2 ] W^{[2]} W[2]拥有最大参数集,即7×7,为了预防矩阵的过拟合,对于这一层,我认为这是第二层,它的keep-prob值应该相对较低,假设是0.5。对于其它层,过拟合的程度可能没那么严重,它们的keep-prob值可能高一些,可能是0.7,这里是0.7。如果在某一层,我们不必担心其过拟合的问题,那么keep-prob可以为1,为了表达清除,我用紫色线笔把它们圈出来,每层keep-prob的值可能不同。

在这里插入图片描述

注意keep-prob的值是1,意味着保留所有单元,并且不在这一层使用dropout,对于有可能出现过拟合,且含有诸多参数的层,我们可以把keep-prob设置成比较小的值,以便应用更强大的dropout,有点像在处理 L 2 L2 L2正则化的正则化参数 λ \lambda λ,我们尝试对某些层施行更多正则化,从技术上讲,我们也可以对输入层应用dropout,我们有机会删除一个或多个输入特征,虽然现实中我们通常不这么做,keep-prob的值为1,是非常常用的输入值,也可以用更大的值,或许是0.9。但是消除一半的输入特征是不太可能的,如果我们遵守这个准则,keep-prob会接近于1,即使你对输入层应用dropout

总结一下,如果你担心某些层比其它层更容易发生过拟合,可以把某些层的keep-prob值设置得比其它层更低,缺点是为了使用交叉验证,你要搜索更多的超级参数,另一种方案是在一些层上应用dropout,而有些层不用dropout,应用dropout的层只含有一个超级参数,就是keep-prob

结束前分享两个实施过程中的技巧,实施dropout,在计算机视觉领域有很多成功的第一次。计算视觉中的输入量非常大,输入太多像素,以至于没有足够的数据,所以dropout在计算机视觉中应用得比较频繁,有些计算机视觉研究人员非常喜欢用它,几乎成了默认的选择,但要牢记一点,dropout是一种正则化方法,它有助于预防过拟合,因此除非算法过拟合,不然我是不会使用dropout的,所以它在其它领域应用得比较少,主要存在于计算机视觉领域,因为我们通常没有足够的数据,所以一直存在过拟合,这就是有些计算机视觉研究人员如此钟情于dropout函数的原因。直观上我认为不能概括其它学科。

在这里插入图片描述

dropout一大缺点就是代价函数 J J J不再被明确定义,每次迭代,都会随机移除一些节点,如果再三检查梯度下降的性能,实际上是很难进行复查的。定义明确的代价函数 J J J每次迭代后都会下降,因为我们所优化的代价函数 J J J实际上并没有明确定义,或者说在某种程度上很难计算,所以我们失去了调试工具来绘制这样的图片。我通常会关闭dropout函数,将keep-prob的值设为1,运行代码,确保J函数单调递减。然后打开dropout函数,希望在dropout过程中,代码并未引入bug。我觉得你也可以尝试其它方法,虽然我们并没有关于这些方法性能的数据统计,但你可以把它们与dropout方法一起使用。

1.8 其他正则化方法(Other regularization methods)

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

在这里插入图片描述

一.数据扩增

假设你正在拟合猫咪图片分类器,如果你想通过扩增训练数据来解决过拟合,但扩增数据代价高,而且有时候我们无法扩增数据,但我们可以通过添加这类图片来增加训练集。例如,水平翻转图片,并把它添加到训练集。所以现在训练集中有原图,还有翻转后的这张图片,所以通过水平翻转图片,训练集则可以增大一倍,因为训练集有冗余,这虽然不如我们额外收集一组新图片那么好,但这样做节省了获取更多猫咪图片的花费。

在这里插入图片描述

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

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

在这里插入图片描述

像这样人工合成数据的话,我们要通过算法验证,图片中的猫经过水平翻转之后依然是猫。大家注意,我并没有垂直翻转,因为我们不想上下颠倒图片,也可以随机选取放大后的部分图片,猫可能还在上面。

对于光学字符识别,我们还可以通过添加数字,随意旋转或扭曲数字来扩增数据,把这些数字添加到训练集,它们仍然是数字。为了方便说明,我对字符做了强变形处理,所以数字4看起来是波形的,其实不用对数字4做这么夸张的扭曲,只要轻微的变形就好,我做成这样是为了让大家看的更清楚。实际操作的时候,我们通常对字符做更轻微的变形处理。因为这几个4看起来有点扭曲。所以,数据扩增可作为正则化方法使用,实际功能上也与正则化相似。

二.early stopping

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

在这里插入图片描述

因为在训练过程中,我们希望训练误差,代价函数 J J J都在下降,通过early stopping,我们不但可以绘制上面这些内容,还可以绘制验证集误差,它可以是验证集上的分类误差,或验证集上的代价函数,逻辑损失和对数损失等,你会发现,验证集误差通常会先呈下降趋势,然后在某个节点处开始上升,early stopping的作用是,你会说,神经网络已经在这个迭代过程中表现得很好了,我们在此停止训练吧,得到验证集误差,它是怎么发挥作用的?

在这里插入图片描述

当你还未在神经网络上运行太多迭代过程的时候,参数 w w w接近0,因为随机初始化 w w w值时,它的值可能都是较小的随机值,所以在你长期训练神经网络之前 w w w依然很小,在迭代过程和训练过程中 w w w的值会变得越来越大,比如在这儿,神经网络中参数 w w w的值已经非常大了,所以early stopping要做就是在中间点停止迭代过程,我们得到一个 w w w值中等大小的弗罗贝尼乌斯范数,与 L 2 L2 L2正则化相似,选择参数w范数较小的神经网络,但愿你的神经网络过度拟合不严重。

在这里插入图片描述

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

我认为机器学习过程包括几个步骤,其中一步是选择一个算法来优化代价函数 J J J,我们有很多种工具来解决这个问题,如梯度下降,后面我会介绍其它算法,例如MomentumRMSpropAdam等等,但是优化代价函数 J J J之后,我也不想发生过拟合,也有一些工具可以解决该问题,比如正则化,扩增数据等等。

在这里插入图片描述

在机器学习中,超级参数激增,选出可行的算法也变得越来越复杂。我发现,如果我们用一组工具优化代价函数 J J J,机器学习就会变得更简单,在重点优化代价函数 J J J时,你只需要留意 w w w b b b J ( w , b ) J(w,b) J(w,b)的值越小越好,你只需要想办法减小这个值,其它的不用关注。然后,预防过拟合还有其他任务,换句话说就是减少方差,这一步我们用另外一套工具来实现,这个原理有时被称为“正交化”。思路就是在一个时间做一个任务,后面课上我会具体介绍正交化,如果你还不了解这个概念,不用担心。

但对我来说early stopping的主要缺点就是你不能独立地处理这两个问题,因为提早停止梯度下降,也就是停止了优化代价函数 J J J,因为现在你不再尝试降低代价函数 J J J,所以代价函数 J J J的值可能不够小,同时你又希望不出现过拟合,你没有采取不同的方式来解决这两个问题,而是用一种方法同时解决两个问题,这样做的结果是我要考虑的东西变得更复杂。

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

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

如果你还不能完全理解这个概念,没关系,下节课我们会详细讲解正交化,这样会更好理解。

虽然 L 2 L2 L2正则化有缺点,可还是有很多人愿意用它。吴恩达老师个人更倾向于使用 L 2 L2 L2正则化,尝试许多不同的 λ \lambda λ值,假设你可以负担大量计算的代价。而使用early stopping也能得到相似结果,还不用尝试这么多 λ \lambda λ值。

这节课我们讲了如何使用数据扩增,以及如何使用early stopping降低神经网络中的方差或预防过拟合。

1.9 归一化输入(Normalizing inputs)

训练神经网络,其中一个加速训练的方法就是归一化输入。假设一个训练集有两个特征,输入特征为2维,归一化需要两个步骤:

  1. 零均值

  2. 归一化方差;

    我们希望无论是训练集和测试集都是通过相同的 μ μ μ σ 2 σ^2 σ2定义的数据转换,这两个是由训练集得出来的。

在这里插入图片描述

第一步是零均值化, μ = 1 m ∑ i = 1 m x ( i ) \mu = \frac{1}{m}\sum_{i =1}^{m}x^{(i)} μ=m1i=1mx(i),它是一个向量, x x x等于每个训练数据 x x x减去 μ \mu μ,意思是移动训练集,直到它完成零均值化。

在这里插入图片描述

第二步是归一化方差,注意特征 x 1 x_{1} x1的方差比特征 x 2 x_{2} x2的方差要大得多,我们要做的是给 σ \sigma σ赋值, σ 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,这是节点 y y y 的平方, σ 2 \sigma^{2} σ2是一个向量,它的每个特征都有方差,注意,我们已经完成零值均化, ( x ( i ) ) 2 ({x^{(i)})}^{2} (x(i))2元素 y 2 y^{2} y2就是方差,我们把所有数据除以向量 σ 2 \sigma^{2} σ2,最后变成上图形式。

x 1 x_{1} x1 x 2 x_{2} x2的方差都等于1。提示一下,如果你用它来调整训练数据,那么用相同的 μ μ μ σ 2 \sigma^{2} σ2来归一化测试集。尤其是,你不希望训练集和测试集的归一化有所不同,不论 μ μ μ的值是什么,也不论 σ 2 \sigma^{2} σ2的值是什么,这两个公式中都会用到它们。所以你要用同样的方法调整测试集,而不是在训练集和测试集上分别预估 μ μ μ σ 2 \sigma^{2} σ2。因为我们希望不论是训练数据还是测试数据,都是通过相同μ和 σ 2 \sigma^{2} σ2定义的相同数据转换,其中 μ μ μ σ 2 \sigma^{2} σ2是由训练集数据计算得来的。

我们为什么要这么做呢?为什么我们想要归一化输入特征,回想一下右上角所定义的代价函数。

J ( w , b ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) J(w,b)=\frac{1}{m}\sum\limits_{i=1}^{m}{L({{{\hat{y}}}^{(i)}},{{y}^{(i)}})} J(w,b)=m1i=1mL(y^(i),y(i))

如果你使用非归一化的输入特征,代价函数会像这样:

在这里插入图片描述

这是一个非常细长狭窄的代价函数,你要找的最小值应该在这里。但如果特征值在不同范围,假如 x 1 x_{1} x1取值范围从1到1000,特征 x 2 x_{2} x2的取值范围从0到1,结果是参数 w 1 w_{1} w1 w 2 w_{2} w2值的范围或比率将会非常不同,这些数据轴应该是 w 1 w_{1} w1 w 2 w_{2} w2,但直观理解,我标记为 w w w b b b,代价函数就有点像狭长的碗一样,如果你能画出该函数的部分轮廓,它会是这样一个狭长的函数。

然而如果你归一化特征,代价函数平均起来看更对称,如果你在上图这样的代价函数上运行梯度下降法,你必须使用一个非常小的学习率。因为如果是在这个位置,梯度下降法可能需要多次迭代过程,直到最后找到最小值。但如果函数是一个更圆的球形轮廓,那么不论从哪个位置开始,梯度下降法都能够更直接地找到最小值,你可以在梯度下降法中使用较大步长,而不需要像在左图中那样反复执行。

当然,实际上 w w w是一个高维向量,因此用二维绘制 w w w并不能正确地传达并直观理解,但总地直观理解是代价函数会更圆一些,而且更容易优化,前提是特征都在相似范围内,而不是从1到1000,0到1的范围,而是在-1到1范围内或相似偏差,这使得代价函数 J J J优化起来更简单快速。

在这里插入图片描述

实际上如果假设特征 x 1 x_{1} x1范围在0-1之间, x 2 x_{2} x2的范围在-1到1之间, x 3 x_{3} x3范围在1-2之间,它们是相似范围,所以会表现得很好。

当它们在非常不同的取值范围内,如其中一个从1到1000,另一个从0到1,这对优化算法非常不利。但是仅将它们设置为均化零值,假设方差为1,就像上一张幻灯片里设定的那样,确保所有特征都在相似范围内,通常可以帮助学习算法运行得更快。

所以如果输入特征处于不同范围内,可能有些特征值从0到1,有些从1到1000,那么归一化特征值就非常重要了。如果特征值处于相似范围内,那么归一化就不是很重要了。执行这类归一化并不会产生什么危害,我通常会做归一化处理,虽然我不确定它能否提高训练或算法速度。

这就是归一化特征输入,下节课我们将继续讨论提升神经网络训练速度的方法。

1.10 梯度消失/梯度爆炸(Vanishing / Exploding gradients)

训练神经网络,尤其是深度神经所面临的一个问题就是梯度消失或梯度爆炸,也就是你训练神经网络的时候,导数或坡度有时会变得非常大,或者非常小,甚至于以指数方式变小,这加大了训练的难度。

这节课,你将会了解梯度消失或梯度爆炸的真正含义,以及如何更明智地选择随机初始化权重,从而避免这个问题。
假设你正在训练这样一个极深的神经网络,为了节约幻灯片上的空间,我画的神经网络每层只有两个隐藏单元,但它可能含有更多,但这个神经网络会有参数 W [ 1 ] W^{[1]} W[1] W [ 2 ] W^{[2]} W[2] W [ 3 ] W^{[3]} W[3]等等,直到 W [ l ] W^{[l]} W[l],为了简单起见,假设我们使用激活函数 g ( z ) = z g(z)=z g(z)=z,也就是线性激活函数,我们忽略 b b b,假设 b [ l ] b^{[l]} b[l]=0,如果那样的话,输出$ y=W{[l]}W{[L -1]}W^{[L - 2]}\ldots W{[3]}W{[2]}W{[1]}x$,如果你想考验我的数学水平,$W{[1]} x = z{[1]}$,因为$b=0$,所以我想$z{[1]} =W^{[1]} x , , a^{[1]} = g(z{[1]})$,因为我们使用了一个线性激活函数,它等于$z{[1]} ,所以第一项 ,所以第一项 ,所以第一项W^{[1]} x = a{[1]}$,通过推理,你会得出$W{[2]}W^{[1]}x =a{[2]}$,因为$a{[2]} = g(z{[2]})$,还等于$g(W{[2]}a{[1]})$,可以用$W{[1]}x 替换 替换 替换a{[1]}$,所以这一项就等于$a{[2]} ,这个就是 ,这个就是 ,这个就是a{[3]}$($W{[3]}W{[2]}W{[1]}x$)。

在这里插入图片描述

所有这些矩阵数据传递的协议将给出 y ^ \hat y y^而不是 y y y的值。

假设每个权重矩阵 W [ l ] = [ 1.5 0 0 1.5 ] W^{[l]} = \begin{bmatrix} 1.5 & 0 \\0 & 1.5 \\\end{bmatrix} W[l]=[1.5001.5],从技术上来讲,最后一项有不同维度,可能它就是余下的权重矩阵, y = W [ 1 ] [ 1.5 0 0 1.5 ] ( L − 1 ) x y= W^{[1]}\begin{bmatrix} 1.5 & 0 \\ 0 & 1.5 \\\end{bmatrix}^{(L -1)}x y=W[1][1.5001.5](L1)x,因为我们假设所有矩阵都等于它,它是1.5倍的单位矩阵,最后的计算结果就是 y ^ \hat{y} y^ y ^ \hat{y} y^也就是等于 1.5 ( L − 1 ) x {1.5}^{(L-1)}x 1.5(L1)x。如果对于一个深度神经网络来说 L L L值较大,那么 y ^ \hat{y} y^的值也会非常大,实际上它呈指数级增长的,它增长的比率是 1.5 L {1.5}^{L} 1.5L,因此对于一个深度神经网络, y y y的值将爆炸式增长。

相反的,如果权重是0.5, W [ l ] = [ 0.5 0 0 0.5 ] W^{[l]} = \begin{bmatrix} 0.5& 0 \\ 0 & 0.5 \\ \end{bmatrix} W[l]=[0.5000.5],它比1小,这项也就变成了 0.5 L {0.5}^{L} 0.5L,矩阵 y = W [ 1 ] [ 0.5 0 0 0.5 ] ( L − 1 ) x y= W^{[1]}\begin{bmatrix} 0.5 & 0 \\ 0 & 0.5 \\\end{bmatrix}^{(L - 1)}x y=W[1][0.5000.5](L1)x,再次忽略 W [ L ] W^{[L]} W[L],因此每个矩阵都小于1,假设 x 1 x_{1} x1 x 2 x_{2} x2都是1,激活函数将变成 1 2 \frac{1}{2} 21 1 2 \frac{1}{2} 21 1 4 \frac{1}{4} 41 1 4 \frac{1}{4} 41 1 8 \frac{1}{8} 81 1 8 \frac{1}{8} 81等,直到最后一项变成 1 2 L \frac{1}{2^{L}} 2L1,所以作为自定义函数,激活函数的值将以指数级下降,它是与网络层数数量 L L L相关的函数,在深度网络中,激活函数以指数级递减。

我希望你得到的直观理解是,权重 W ​ W​ W只比1略大一点,或者说只是比单位矩阵大一点,深度神经网络的激活函数将爆炸式增长,如果 W ​ W​ W比1略小一点,可能是 [ 0.9 0 0 0.9 ] ​ \begin{bmatrix}0.9 & 0 \\ 0 & 0.9 \\ \end{bmatrix}​ [0.9000.9]

在这里插入图片描述

在深度神经网络中,激活函数将以指数级递减,虽然我只是讨论了激活函数以与 L L L相关的指数级数增长或下降,它也适用于与层数 L L L相关的导数或梯度函数,也是呈指数级增长或呈指数递减。

对于当前的神经网络,假设 L = 150 L=150 L=150,最近Microsoft对152层神经网络的研究取得了很大进展,在这样一个深度神经网络中,如果激活函数或梯度函数以与 L L L相关的指数增长或递减,它们的值将会变得极大或极小,从而导致训练难度上升,尤其是梯度指数小于 L L L时,梯度下降算法的步长会非常非常小,梯度下降算法将花费很长时间来学习。

总结一下,我们讲了深度神经网络是如何产生梯度消失或爆炸问题的,实际上,在很长一段时间内,它曾是训练深度神经网络的阻力,虽然有一个不能彻底解决此问题的解决方案,但是已在如何选择初始化权重问题上提供了很多帮助。

1.11 神经网络的权重初始化(Weight Initialization for Deep NetworksVanishing / Exploding gradients)

上节课,我们学习了深度神经网络如何产生梯度消失和梯度爆炸问题,最终针对该问题,我们想出了一个不完整的解决方案,虽然不能彻底解决问题,却很有用,有助于我们为神经网络更谨慎地选择随机初始化参数,为了更好地理解它,我们先举一个神经单元初始化地例子,然后再演变到整个深度网络。

在这里插入图片描述

我们来看看只有一个神经元的情况,然后才是深度网络。

单个神经元可能有4个输入特征,从 x 1 x_{1} x1 x 4 x_{4} x4,经过 a = g ( z ) a=g(z) a=g(z)处理,最终得到 y ^ \hat{y} y^,稍后讲深度网络时,这些输入表示为 a [ l ] a^{[l]} a[l],暂时我们用 x x x表示。

z = w 1 x 1 + w 2 x 2 + … + w n x n z = w_{1}x_{1} + w_{2}x_{2} + \ldots +w_{n}x_{n} z=w1x1+w2x2++wnxn b = 0 b=0 b=0,暂时忽略 b b b,为了预防 z z z值过大或过小,你可以看到 n n n越大,你希望 w i w_{i} wi越小,因为 z z z w i x i w_{i}x_{i} wixi的和,如果你把很多此类项相加,希望每项值更小,最合理的方法就是设置 w i = 1 n w_{i}=\frac{1}{n} wi=n1 n n n表示神经元的输入特征数量,实际上,你要做的就是设置某层权重矩阵 w [ l ] = n p . r a n d o m . r a n d n ( shape ) ∗ np.sqrt ( 1 n [ l − 1 ] ) w^{[l]} = np.random.randn( \text{shape})*\text{np.}\text{sqrt}(\frac{1}{n^{[l-1]}}) w[l]=np.random.randn(shape)np.sqrt(n[l1]1) n [ l − 1 ] n^{[l - 1]} n[l1]就是我喂给第 l l l层神经单元的数量(即第 l − 1 l-1 l1层神经元数量)。

在这里插入图片描述

结果,如果你是用的是Relu激活函数,而不是 1 n \frac{1}{n} n1,方差设置为 2 n \frac{2}{n} n2,效果会更好。你常常发现,初始化时,尤其是使用Relu激活函数时, g [ l ] ( z ) = R e l u ( z ) g^{[l]}(z) =Relu(z) g[l](z)=Relu(z),它取决于你对随机变量的熟悉程度,这是高斯随机变量,然后乘以它的平方根,也就是引用这个方差 2 n \frac{2}{n} n2。这里,我用的是 n [ l − 1 ] n^{[l - 1]} n[l1],因为本例中,逻辑回归的特征是不变的。但一般情况下 l l l层上的每个神经元都有 n [ l − 1 ] n^{[l - 1]} n[l1]个输入。如果激活函数的输入特征被零均值和标准方差化,方差是1, z z z也会调整到相似范围,这就没解决问题(梯度消失和爆炸问题)。但它确实降低了梯度消失和爆炸问题,因为它给权重矩阵 w w w设置了合理值,你也知道,它不能比1大很多,也不能比1小很多,所以梯度没有爆炸或消失过快。

在这里插入图片描述

我提到了其它变体函数,刚刚提到的函数是Relu激活函数,一篇由Herd等人撰写的论文曾介绍过。对于几个其它变体函数,如tanh激活函数,有篇论文提到,常量1比常量2的效率更高,对于tanh函数来说,它是 1 n [ l − 1 ] \sqrt{\frac{1}{n^{[l-1]}}} n[l1]1 ,这里平方根的作用与这个公式作用相同( np.sqrt ( 1 n [ l − 1 ] ) \text{np.}\text{sqrt}(\frac{1}{n^{[l-1]}}) np.sqrt(n[l1]1)),它适用于tanh激活函数,被称为Xavier初始化。Yoshua Bengio和他的同事还提出另一种方法,你可能在一些论文中看到过,它们使用的是公式 2 n [ l − 1 ] + n [ l ] \sqrt{\frac{2}{n^{[l-1]} + n^{\left[l\right]}}} n[l1]+n[l]2 。其它理论已对此证明,但如果你想用Relu激活函数,也就是最常用的激活函数,我会用这个公式 np.sqrt ( 2 n [ l − 1 ] ) \text{np.}\text{sqrt}(\frac{2}{n^{[l-1]}}) np.sqrt(n[l1]2),如果使用tanh函数,可以用公式 1 n [ l − 1 ] \sqrt{\frac{1}{n^{[l-1]}}} n[l1]1 ,有些作者也会使用这个函数。

实际上,我认为所有这些公式只是给你一个起点,它们给出初始化权重矩阵的方差的默认值,如果你想添加方差,方差参数则是另一个你需要调整的超级参数,可以给公式 np.sqrt ( 2 n [ l − 1 ] ) \text{np.}\text{sqrt}(\frac{2}{n^{[l-1]}}) np.sqrt(n[l1]2)添加一个乘数参数,调优作为超级参数激增一份子的乘子参数。有时调优该超级参数效果一般,这并不是我想调优的首要超级参数,但我发现调优过程中产生的问题,虽然调优该参数能起到一定作用,但考虑到相比调优,其它超级参数的重要性,我通常把它的优先级放得比较低。

希望你现在对梯度消失或爆炸问题以及如何为权重初始化合理值已经有了一个直观认识,希望你设置的权重矩阵既不会增长过快,也不会太快下降到0,从而训练出一个权重或梯度不会增长或消失过快的深度网络。我们在训练深度网络时,这也是一个加快训练速度的技巧。

1.12 梯度的数值逼近(Numerical approximation of gradients)

在实施backprop时,有一个测试叫做梯度检验,它的作用是确保backprop正确实施。因为有时候,你虽然写下了这些方程式,却不能100%确定,执行backprop的所有细节都是正确的。为了逐渐实现梯度检验,我们首先说说如何计算梯度的数值逼近,下节课,我们将讨论如何在backprop中执行梯度检验,以确保backprop正确实施。

在这里插入图片描述

我们先画出函数 f f f,标记为 f ( θ ) f\left( \theta \right) f(θ) f ( θ ) = θ 3 f\left( \theta \right)=\theta^{3} f(θ)=θ3,先看一下 θ \theta θ的值,假设 θ = 1 \theta=1 θ=1,不增大 θ \theta θ的值,而是在 θ \theta θ 右侧,设置一个 θ + ε \theta +\varepsilon θ+ε,在 θ \theta θ左侧,设置 θ − ε \theta -\varepsilon θε。因此 θ = 1 \theta=1 θ=1 θ + ε = 1.01 , θ − ε = 0.99 \theta +\varepsilon =1.01,\theta -\varepsilon =0.99 θ+ε=1.01,θε=0.99,,跟以前一样, ε \varepsilon ε的值为0.01,看下这个小三角形,计算高和宽的比值,就是更准确的梯度预估,选择 f f f函数在 θ − ε \theta -\varepsilon θε上的这个点,用这个较大三角形的高比上宽,技术上的原因我就不详细解释了,较大三角形的高宽比值更接近于 θ \theta θ的导数,把右上角的三角形下移,好像有了两个三角形,右上角有一个,左下角有一个,我们通过这个绿色大三角形同时考虑了这两个小三角形。所以我们得到的不是一个单边公差而是一个双边公差。

在这里插入图片描述

我们写一下数据算式,图中绿色三角形上边的点的值是 f ( θ + ε ) f( \theta +\varepsilon ) f(θ+ε),下边的点是 f ( θ − ε ) f( \theta-\varepsilon) f(θε),这个三角形的高度是 f ( θ + ε ) − f ( θ − ε ) f( \theta +\varepsilon)-f(\theta -\varepsilon) f(θ+ε)f(θε),这两个宽度都是ε,所以三角形的宽度是 2 ε 2\varepsilon 2ε,高宽比值为 f ( θ + ε ) − ( θ − ε ) 2 ε \frac{f(\theta + \varepsilon ) - (\theta -\varepsilon)}{2\varepsilon} 2εf(θ+ε)(θε),它的期望值接近 g ( θ ) g( \theta) g(θ) f ( θ ) = θ 3 f( \theta)=\theta^{3} f(θ)=θ3传入参数值, f ( θ + ε ) − f ( θ − ε ) 2 ε = ( 1.01 ) 3 − ( 0.99 ) 3 2 × 0.01 \frac {f\left( \theta + \varepsilon \right) - f(\theta -\varepsilon)}{2\varepsilon} = \frac{{(1.01)}^{3} - {(0.99)}^{3}}{2 \times0.01} 2εf(θ+ε)f(θε)=2×0.01(1.01)3(0.99)3,大家可以暂停视频,用计算器算算结果,结果应该是3.0001,而前面一张幻灯片上面是,当 θ = 1 \theta =1 θ=1时, g ( θ ) = 3 θ 2 = 3 g( \theta)=3\theta^{2} =3 g(θ)=3θ2=3,所以这两个 g ( θ ) g(\theta) g(θ)值非常接近,逼近误差为0.0001,前一张幻灯片,我们只考虑了单边公差,即从$\theta 到 到 \theta +\varepsilon 之间的误差, 之间的误差, 之间的误差,g( \theta) 的值为 3.0301 ,逼近误差是 0.03 ,不是 0.0001 ,所以使用双边误差的方法更逼近导数,其结果接近于 3 ,现在我们更加确信, 的值为3.0301,逼近误差是0.03,不是0.0001,所以使用双边误差的方法更逼近导数,其结果接近于3,现在我们更加确信, 的值为3.0301,逼近误差是0.03,不是0.0001,所以使用双边误差的方法更逼近导数,其结果接近于3,现在我们更加确信,g( \theta) 可能是 可能是 可能是f$导数的正确实现,在梯度检验和反向传播中使用该方法时,最终,它与运行两次单边公差的速度一样,实际上,我认为这种方法还是非常值得使用的,因为它的结果更准确。

在这里插入图片描述

这是一些你可能比较熟悉的微积分的理论,如果你不太明白我讲的这些理论也没关系,导数的官方定义是针对值很小的 ε \varepsilon ε,导数的官方定义是 f ′ θ ) = ⁡ f ( θ + ε ) − f ( θ − ε ) 2 ε f^{'}\theta) = \operatorname{}\frac{f( \theta + \varepsilon) -f(\theta -\varepsilon)}{2\varepsilon} fθ)=2εf(θ+ε)f(θε),如果你上过微积分课,应该学过无穷尽的定义,我就不在这里讲了。

对于一个非零的 ε \varepsilon ε,它的逼近误差可以写成 O ( ε 2 ) O(\varepsilon^{2}) O(ε2),ε值非常小,如果 ε = 0.01 \varepsilon=0.01 ε=0.01 ε 2 = 0.0001 \varepsilon^{2}=0.0001 ε2=0.0001,大写符号 O O O的含义是指逼近误差其实是一些常量乘以 ε 2 \varepsilon^{2} ε2,但它的确是很准确的逼近误差,所以大写 O O O的常量有时是1。然而,如果我们用另外一个公式逼近误差就是 O ( ε ) O(\varepsilon) O(ε),当 ε \varepsilon ε小于1时,实际上 ε \varepsilon ε ε 2 \varepsilon^{2} ε2大很多,所以这个公式近似值远没有左边公式的准确,所以在执行梯度检验时,我们使用双边误差,即 f ( θ + ε ) − f ( θ − ε ) 2 ε \frac{f\left(\theta + \varepsilon \right) - f(\theta -\varepsilon)}{2\varepsilon} 2εf(θ+ε)f(θε),而不使用单边公差,因为它不够准确。

在这里插入图片描述

如果你不理解上面两条结论,所有公式都在这儿,不用担心,如果你对微积分和数值逼近有所了解,这些信息已经足够多了,重点是要记住,双边误差公式的结果更准确,下节课我们做梯度检验时就会用到这个方法。

今天我们讲了如何使用双边误差来判断别人给你的函数 g ( θ ) g( \theta) g(θ),是否正确实现了函数 f f f的偏导,现在我们可以使用这个方法来检验反向传播是否得以正确实施,如果不正确,它可能有bug需要你来解决。

1.13 梯度检验(Gradient checking)

梯度检验帮我们节省了很多时间,也多次帮我发现backprop实施过程中的bug,接下来,我们看看如何利用它来调试或检验backprop的实施是否正确。

假设你的网络中含有下列参数, W [ 1 ] W^{[1]} W[1] b [ 1 ] b^{[1]} b[1]…… W [ l ] W^{[l]} W[l] b [ l ] b^{[l]} b[l],为了执行梯度检验,首先要做的就是,把所有参数转换成一个巨大的向量数据,你要做的就是把矩阵 W W W转换成一个向量,把所有 W W W矩阵转换成向量之后,做连接运算,得到一个巨型向量 θ \theta θ,该向量表示为参数 θ \theta θ,代价函数 J J J是所有 W W W b b b的函数,现在你得到了一个 θ \theta θ的代价函数 J J J(即 J ( θ ) J(\theta) J(θ))。接着,你得到与 W W W b b b顺序相同的数据,你同样可以把 d W [ 1 ] dW^{[1]} dW[1] d b [ 1 ] {db}^{[1]} db[1]…… d W [ l ] {dW}^{[l]} dW[l] d b [ l ] {db}^{[l]} db[l]转换成一个新的向量,用它们来初始化大向量 d θ d\theta dθ,它与 θ \theta θ具有相同维度。

同样的,把 d W [ 1 ] dW^{[1]} dW[1]转换成矩阵, d b [ 1 ] db^{[1]} db[1]已经是一个向量了,直到把 d W [ l ] {dW}^{[l]} dW[l]转换成矩阵,这样所有的 d W dW dW都已经是矩阵,注意 d W [ 1 ] dW^{[1]} dW[1] W [ 1 ] W^{[1]} W[1]具有相同维度, d b [ 1 ] db^{[1]} db[1] b [ 1 ] b^{[1]} b[1]具有相同维度。经过相同的转换和连接运算操作之后,你可以把所有导数转换成一个大向量 d θ d\theta dθ,它与 θ \theta θ具有相同维度,现在的问题是 d θ d\theta dθ和代价函数 J J J的梯度或坡度有什么关系?

在这里插入图片描述

这就是实施梯度检验的过程,英语里通常简称为“grad check”,首先,我们要清楚 J J J是超参数 θ \theta θ的一个函数,你也可以将J函数展开为 J ( θ 1 , θ 2 , θ 3 , … … ) J(\theta_{1},\theta_{2},\theta_{3},\ldots\ldots) J(θ1,θ2,θ3,……),不论超级参数向量 θ \theta θ的维度是多少,为了实施梯度检验,你要做的就是循环执行,从而对每个 i i i也就是对每个 θ \theta θ组成元素计算 d θ approx [ i ] d\theta_{\text{approx}}[i] dθapprox[i]的值,我使用双边误差,也就是

d θ approx [ i ] = J ( θ 1 , θ 2 , … θ i + ε , … ) − J ( θ 1 , θ 2 , … θ i − ε , … ) 2 ε d\theta_{\text{approx}}\left[i \right] = \frac{J\left( \theta_{1},\theta_{2},\ldots\theta_{i} + \varepsilon,\ldots \right) - J\left( \theta_{1},\theta_{2},\ldots\theta_{i} - \varepsilon,\ldots \right)}{2\varepsilon} dθapprox[i]=2εJ(θ1,θ2,θi+ε,)J(θ1,θ2,θiε,)

只对 θ i ​ \theta_{i}​ θi增加 ε ​ \varepsilon​ ε,其它项保持不变,因为我们使用的是双边误差,对另一边做同样的操作,只不过是减去 ε ​ \varepsilon​ ε θ ​ \theta​ θ其它项全都保持不变。

在这里插入图片描述

从上节课中我们了解到这个值( d θ approx [ i ] d\theta_{\text{approx}}\left[i \right] dθapprox[i])应该逼近 d θ [ i ] d\theta\left[i \right] dθ[i]= ∂ J ∂ θ i \frac{\partial J}{\partial\theta_{i}} θiJ d θ [ i ] d\theta\left[i \right] dθ[i]是代价函数的偏导数,然后你需要对i的每个值都执行这个运算,最后得到两个向量,得到 d θ d\theta dθ的逼近值 d θ approx d\theta_{\text{approx}} dθapprox,它与 d θ d\theta dθ具有相同维度,它们两个与 θ \theta θ具有相同维度,你要做的就是验证这些向量是否彼此接近。

在这里插入图片描述

具体来说,如何定义两个向量是否真的接近彼此?我一般做下列运算,计算这两个向量的距离, d θ approx [ i ] − d θ [ i ] d\theta_{\text{approx}}\left[i \right] - d\theta[i] dθapprox[i]dθ[i]的欧几里得范数,注意这里( ∣ ∣ d θ approx − d θ ∣ ∣ 2 {||d\theta_{\text{approx}} -d\theta||}_{2} ∣∣dθapproxdθ∣∣2)没有平方,它是误差平方之和,然后求平方根,得到欧式距离,然后用向量长度归一化,使用向量长度的欧几里得范数。分母只是用于预防这些向量太小或太大,分母使得这个方程式变成比率,我们实际执行这个方程式, ε \varepsilon ε可能为 1 0 − 7 10^{-7} 107,使用这个取值范围内的 ε \varepsilon ε,如果你发现计算方程式得到的值为 1 0 − 7 10^{-7} 107或更小,这就很好,这就意味着导数逼近很有可能是正确的,它的值非常小。

在这里插入图片描述

如果它的值在 1 0 − 5 10^{-5} 105范围内,我就要小心了,也许这个值没问题,但我会再次检查这个向量的所有项,确保没有一项误差过大,可能这里有bug

如果左边这个方程式结果是 1 0 − 3 10^{-3} 103,我就会担心是否存在bug,计算结果应该比 1 0 − 3 10^{- 3} 103小很多,如果比 1 0 − 3 10^{-3} 103大很多,我就会很担心,担心是否存在bug。这时应该仔细检查所有 θ \theta θ项,看是否有一个具体的 i i i值,使得 d θ approx [ i ] d\theta_{\text{approx}}\left[i \right] dθapprox[i]与$ d\theta[i]$大不相同,并用它来追踪一些求导计算是否正确,经过一些调试,最终结果会是这种非常小的值( 1 0 − 7 10^{-7} 107),那么,你的实施可能是正确的。

在这里插入图片描述

在实施神经网络时,我经常需要执行forepropbackprop,然后我可能发现这个梯度检验有一个相对较大的值,我会怀疑存在bug,然后开始调试,调试,调试,调试一段时间后,我得到一个很小的梯度检验值,现在我可以很自信的说,神经网络实施是正确的。

现在你已经了解了梯度检验的工作原理,它帮助我在神经网络实施中发现了很多bug,希望它对你也有所帮助。

1.14 梯度检验应用的注意事项(Gradient Checking Implementation Notes)

这节课,分享一些关于如何在神经网络实施梯度检验的实用技巧和注意事项。

在这里插入图片描述

首先,不要在训练中使用梯度检验,它只用于调试。我的意思是,计算所有 i i i值的 d θ approx [ i ] d\theta_{\text{approx}}\left[i\right] dθapprox[i]是一个非常漫长的计算过程,为了实施梯度下降,你必须使用 W W W b b b backprop来计算 d θ d\theta dθ,并使用backprop来计算导数,只要调试的时候,你才会计算它,来确认数值是否接近 d θ d\theta dθ。完成后,你会关闭梯度检验,梯度检验的每一个迭代过程都不执行它,因为它太慢了。

第二点,如果算法的梯度检验失败,要检查所有项,检查每一项,并试着找出bug,也就是说,如果 d θ approx [ i ] d\theta_{\text{approx}}\left[i\right] dθapprox[i]与dθ[i]的值相差很大,我们要做的就是查找不同的i值,看看是哪个导致 d θ approx [ i ] d\theta_{\text{approx}}\left[i\right] dθapprox[i] d θ [ i ] d\theta\left[i\right] dθ[i]的值相差这么多。举个例子,如果你发现,相对某些层或某层的 θ \theta θ d θ d\theta dθ的值相差很大,但是 dw [ l ] \text{dw}^{[l]} dw[l]的各项非常接近,注意 θ \theta θ的各项与 b b b w w w的各项都是一一对应的,这时,你可能会发现,在计算参数 b b b的导数 d b db db的过程中存在bug。反过来也是一样,如果你发现它们的值相差很大, d θ approx [ i ] d\theta_{\text{approx}}\left[i\right] dθapprox[i]的值与 d θ [ i ] d\theta\left[i\right] dθ[i]的值相差很大,你会发现所有这些项目都来自于 d w dw dw或某层的 d w dw dw,可能帮你定位bug的位置,虽然未必能够帮你准确定位bug的位置,但它可以帮助你估测需要在哪些地方追踪bug

第三点,在实施梯度检验时,如果使用正则化,请注意正则项。如果代价函数 J ( θ ) = 1 m ∑ L ( y ^ ( i ) , y ( i ) ) + λ 2 m ∑ ∣ ∣ W [ l ] ∣ ∣ 2 J(\theta) = \frac{1}{m}\sum_{}^{}{L(\hat y^{(i)},y^{(i)})} + \frac{\lambda}{2m}\sum_{}^{}{||W^{[l]}||}^{2} J(θ)=m1L(y^(i),y(i))+2mλ∣∣W[l]∣∣2,这就是代价函数 J J J的定义, d θ d\theta dθ等于与 θ \theta θ相关的 J J J函数的梯度,包括这个正则项,记住一定要包括这个正则项。

第四点,梯度检验不能与dropout同时使用,因为每次迭代过程中,dropout会随机消除隐藏层单元的不同子集,难以计算dropout在梯度下降上的代价函数 J ​ J​ J。因此dropout可作为优化代价函数 J ​ J​ J的一种方法,但是代价函数J被定义为对所有指数极大的节点子集求和。而在任何迭代过程中,这些节点都有可能被消除,所以很难计算代价函数 J ​ J​ J。你只是对成本函数做抽样,用dropout,每次随机消除不同的子集,所以很难用梯度检验来双重检验dropout的计算,所以我一般不同时使用梯度检验和dropout。如果你想这样做,可以把dropout中的keepprob设置为1.0,然后打开dropout,并寄希望于dropout的实施是正确的,你还可以做点别的,比如修改节点丢失模式确定梯度检验是正确的。实际上,我一般不这么做,我建议关闭dropout,用梯度检验进行双重检查,在没有dropout的情况下,你的算法至少是正确的,然后打开dropout

最后一点,也是比较微妙的一点,现实中几乎不会出现这种情况。当 w w w b b b接近0时,梯度下降的实施是正确的,在随机初始化过程中……,但是在运行梯度下降时, w w w b b b变得更大。可能只有在 w w w b b b接近0时,backprop的实施才是正确的。但是当 W W W b b b变大时,它会变得越来越不准确。你需要做一件事,我不经常这么做,就是在随机初始化过程中,运行梯度检验,然后再训练网络, w w w b b b会有一段时间远离0,如果随机初始化值比较小,反复训练网络之后,再重新运行梯度检验。

这就是梯度检验,恭喜大家,这是本周最后一课了。回顾这一周,我们讲了如何配置训练集,验证集和测试集,如何分析偏差和方差,如何处理高偏差或高方差以及高偏差和高方差并存的问题,如何在神经网络中应用不同形式的正则化,如 L 2 ​ L2​ L2​正则化和dropout,还有加快神经网络训练速度的技巧,最后是梯度检验。这一周我们学习了很多内容,你可以在本周编程作业中多多练习这些概念。祝你好运,期待下周再见。

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值