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

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

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

1.1 训练,验证,测试集(Train / Dev / Test sets)

在这里插入图片描述

大家可能已经了解了,那么本周,我们将继续学习如何有效运作神经网络,内容涉及超参数调优,如何构建数据,以及如何确保优化算法快速运行,从而使学习算法在合理时间内完成自我学习。

第一周,我们首先说说神经网络机器学习中的问题,然后是随机神经网络,还会学习一些确保神经网络正确运行的技巧,带着这些问题,我们开始今天的课程。

在配置训练、验证和测试数据集的过程中做出正确决策会在很大程度上帮助大家创建高效的神经网络。训练神经网络时,我们需要做出很多决策,例如:

  1. 神经网络分多少层

  2. 每层含有多少个隐藏单元

  3. 学习速率是多少

  4. 各层采用哪些激活函数

在这里插入图片描述

创建新应用的过程中,我们不可能从一开始就准确预测出这些信息和其他超级参数。实际上,应用型机器学习是一个高度迭代的过程,通常在项目启动时,我们会先有一个初步想法,比如构建一个含有特定层数,隐藏单元数量或数据集个数等等的神经网络,然后编码,并尝试运行这些代码,通过运行和测试得到该神经网络或这些配置信息的运行结果,你可能会根据输出结果重新完善自己的想法,改变策略,或者为了找到更好的神经网络不断迭代更新自己的方案。

现如今,深度学习已经在自然语言处理,计算机视觉,语音识别以及结构化数据应用等众多领域取得巨大成功。结构化数据无所不包,从广告到网络搜索。其中网络搜索不仅包括网络搜索引擎,还包括购物网站,从所有根据搜索栏词条传输结果的网站。再到计算机安全,物流,比如判断司机去哪接送货,范围之广,不胜枚举。

我发现,可能有自然语言处理方面的人才想踏足计算机视觉领域,或者经验丰富的语音识别专家想投身广告行业,又或者,有的人想从电脑安全领域跳到物流行业,在我看来,从一个领域或者应用领域得来的直觉经验,通常无法转移到其他应用领域,最佳决策取决于你所拥有的数据量,计算机配置中输入特征的数量,用GPU训练还是CPUGPUCPU的具体配置以及其他诸多因素。

在这里插入图片描述

目前为止,我觉得,对于很多应用系统,即使是经验丰富的深度学习行家也不太可能一开始就预设出最匹配的超级参数,所以说,应用深度学习是一个典型的迭代过程,需要多次循环往复,才能为应用程序找到一个称心的神经网络,因此循环该过程的效率是决定项目进展速度的一个关键因素,而创建高质量的训练数据集,验证集和测试集也有助于提高循环效率。

在这里插入图片描述

假设这是训练数据,我用一个长方形表示,我们通常会将这些数据划分成几部分,一部分作为训练集,一部分作为简单交叉验证集,有时也称之为验证集,方便起见,我就叫它验证集(dev set),其实都是同一个概念,最后一部分则作为测试集。

接下来,我们开始对训练集执行算法,通过验证集或简单交叉验证集选择最好的模型,经过充分验证,我们选定了最终模型,然后就可以在测试集上进行评估了,为了无偏评估算法的运行状况。

在机器学习发展的小数据量时代,常见做法是将所有数据三七分,就是人们常说的70%训练集,30%测试集。如果明确设置了验证集,也可以按照60%训练集,20%验证集和20%测试集来划分。这是前几年机器学习领域普遍认可的最好的实践方法。

在这里插入图片描述

如果只有100条,1000条或者1万条数据,那么上述比例划分是非常合理的。

但是在大数据时代,我们现在的数据量可能是百万级别,那么验证集和测试集占数据总量的比例会趋向于变得更小。因为验证集的目的就是验证不同的算法,检验哪种算法更有效,因此,验证集只要足够大到能评估不同的算法,比如2个甚至10个不同算法,并迅速判断出哪种算法更有效。我们可能不需要拿出20%的数据作为验证集。

在这里插入图片描述

比如我们有100万条数据,那么取1万条数据便足以进行评估,找出其中表现最好的1-2种算法。同样地,根据最终选择的分类器,测试集的主要目的是正确评估分类器的性能,所以,如果拥有百万数据,我们只需要1000条数据,便足以评估单个分类器,并且准确评估该分类器的性能。假设我们有100万条数据,其中1万条作为验证集,1万条作为测试集,100万里取1万,比例是1%,即:训练集占98%,验证集和测试集各占1%。对于数据量过百万的应用,训练集可以占到99.5%,验证和测试集各占0.25%,或者验证集占0.4%,测试集占0.1%。

总结一下,在机器学习中,我们通常将样本分成训练集,验证集和测试集三部分,数据集规模相对较小,适用传统的划分比例,数据集规模较大的,验证集和测试集要小于数据总量的20%或10%。后面我会给出如何划分验证集和测试集的具体指导。

现代深度学习的另一个趋势是越来越多的人在训练和测试集分布不匹配的情况下进行训练,假设你要构建一个用户可以上传大量图片的应用程序,目的是找出并呈现所有猫咪图片,可能你的用户都是爱猫人士,训练集可能是从网上下载的猫咪图片,而验证集和测试集是用户在这个应用上上传的猫的图片,就是说,训练集可能是从网络上抓下来的图片。而验证集和测试集是用户上传的图片。结果许多网页上的猫咪图片分辨率很高,很专业,后期制作精良,而用户上传的照片可能是用手机随意拍摄的,像素低,比较模糊,这两类数据有所不同,针对这种情况,根据经验,我建议大家要确保验证集和测试集的数据来自同一分布,关于这个问题我也会多讲一些。因为你们要用验证集来评估不同的模型,尽可能地优化性能。如果验证集和测试集来自同一个分布就会很好。

在这里插入图片描述

但由于深度学习算法需要大量的训练数据,为了获取更大规模的训练数据集,我们可以采用当前流行的各种创意策略,例如,网页抓取,代价就是训练集数据与验证集和测试集数据有可能不是来自同一分布。但只要遵循这个经验法则,你就会发现机器学习算法会变得更快。我会在后面的课程中更加详细地解释这条经验法则。

最后一点,就算没有测试集也不要紧,测试集的目的是对最终所选定的神经网络系统做出无偏估计,如果不需要无偏估计,也可以不设置测试集。所以如果只有验证集,没有测试集,我们要做的就是,在训练集上训练,尝试不同的模型框架,在验证集上评估这些模型,然后迭代并选出适用的模型。因为验证集中已经涵盖测试集数据,其不再提供无偏性能评估。当然,如果你不需要无偏估计,那就再好不过了。

在这里插入图片描述

在机器学习中,如果只有一个训练集和一个验证集,而没有独立的测试集,遇到这种情况,训练集还被人们称为训练集,而验证集则被称为测试集,不过在实际应用中,人们只是把测试集当成简单交叉验证集使用,并没有完全实现该术语的功能,因为他们把验证集数据过度拟合到了测试集中。如果某团队跟你说他们只设置了一个训练集和一个测试集,我会很谨慎,心想他们是不是真的有训练验证集,因为他们把验证集数据过度拟合到了测试集中,让这些团队改变叫法,改称其为“训练验证集”,而不是“训练测试集”,可能不太容易。即便我认为“训练验证集“在专业用词上更准确。实际上,如果你不需要无偏评估算法性能,那么这样是可以的。

在这里插入图片描述

所以说,搭建训练验证集和测试集能够加速神经网络的集成,也可以更有效地衡量算法地偏差和方差,从而帮助我们更高效地选择合适方法来优化算法。

1.2 偏差,方差(Bias /Variance)

我注意到,几乎所有机器学习从业人员都期望深刻理解偏差和方差,这两个概念易学难精,即使你自己认为已经理解了偏差和方差的基本概念,却总有一些意想不到的新东西出现。关于深度学习的误差问题,另一个趋势是对偏差和方差的权衡研究甚浅,你可能听说过这两个概念,但深度学习的误差很少权衡二者,我们总是分别考虑偏差和方差,却很少谈及偏差和方差的权衡问题,下面我们来一探究竟。

在这里插入图片描述

假设这就是数据集,如果给这个数据集拟合一条直线,可能得到一个逻辑回归拟合,但它并不能很好地拟合该数据,这是高偏差(high bias)的情况,我们称为“欠拟合”(underfitting)。

相反的如果我们拟合一个非常复杂的分类器,比如深度神经网络或含有隐藏单元的神经网络,可能就非常适用于这个数据集,但是这看起来也不是一种很好的拟合方式分类器方差较高(high variance),数据过度拟合(overfitting)。

在两者之间,可能还有一些像图中这样的,复杂程度适中,数据拟合适度的分类器,这个数据拟合看起来更加合理,我们称之为“适度拟合”(just right)是介于过度拟合和欠拟合中间的一类。

在这里插入图片描述

在这样一个只有 x 1 x_1 x1 x 2 x_2 x2两个特征的二维数据集中,我们可以绘制数据,将偏差和方差可视化。在多维空间数据中,绘制数据和可视化分割边界无法实现,但我们可以通过几个指标,来研究偏差和方差。

在这里插入图片描述

我们沿用猫咪图片分类这个例子,左边一张是猫咪图片,右边一张不是。理解偏差和方差的两个关键数据是训练集误差(Train set error)和验证集误差(Dev set error),为了方便论证,假设我们可以辨别图片中的小猫,我们用肉眼识别几乎是不会出错的。

假定训练集误差是1%,为了方便论证,假定验证集误差是11%,可以看出训练集设置得非常好,而验证集设置相对较差,我们可能过度拟合了训练集,在某种程度上,验证集并没有充分利用交叉验证集的作用,像这种情况,我们称之为“高方差”。

通过查看训练集误差和验证集误差,我们便可以诊断算法是否具有高方差。也就是说衡量训练集和验证集误差就可以得出不同结论。

假设训练集误差是15%,我们把训练集误差写在首行,验证集误差是16%,假设该案例中人的错误率几乎为0%,人们浏览这些图片,分辨出是不是猫。算法并没有在训练集中得到很好训练,如果训练数据的拟合度不高,就是数据欠拟合,就可以说这种算法偏差比较高。相反,它对于验证集产生的结果却是合理的,验证集中的错误率只比训练集的多了1%,所以这种算法偏差高,因为它甚至不能拟合训练集,这与上一张幻灯片最左边的图片相似。

再举一个例子,训练集误差是15%,偏差相当高,但是,验证集的评估结果更糟糕,错误率达到30%,在这种情况下,我会认为这种算法偏差高,因为它在训练集上结果不理想,而且方差也很高,这是方差偏差都很糟糕的情况。

再看最后一个例子,训练集误差是0.5%,验证集误差是1%,用户看到这样的结果会很开心,猫咪分类器只有1%的错误率,偏差和方差都很低。

有一点我先在这个简单提一下,具体的留在后面课程里讲,这些分析都是基于假设预测的,假设人眼辨别的错误率接近0%,一般来说,最优误差也被称为贝叶斯误差,所以,最优误差接近0%,我就不在这里细讲了,如果最优误差或贝叶斯误差非常高,比如15%。我们再看看这个分类器(训练误差15%,验证误差16%),15%的错误率对训练集来说也是非常合理的,偏差不高,方差也非常低。

在这里插入图片描述

当所有分类器都不适用时,如何分析偏差和方差呢?比如,图片很模糊,即使是人眼,或者没有系统可以准确无误地识别图片,在这种情况下,最优误差会更高,那么分析过程就要做些改变了,我们暂时先不讨论这些细微差别,重点是通过查看训练集误差,我们可以判断数据拟合情况,至少对于训练数据是这样,可以判断是否有偏差问题,然后查看错误率有多高。当完成训练集训练,开始使用验证集验证时,我们可以判断方差是否过高,从训练集到验证集的这个过程中,我们可以判断方差是否过高。

在这里插入图片描述

以上分析的前提都是假设基本误差很小,训练集和验证集数据来自相同分布,如果没有这些假设作为前提,分析过程更加复杂,我们将会在稍后课程里讨论。

上一张幻灯片,我们讲了高偏差和高方差的情况,大家应该对优质分类器有了一定的认识,偏差和方差都高是什么样子呢?这种情况对于两个衡量标准来说都是非常糟糕的。

在这里插入图片描述

我们之前讲过,这样的分类器,会产生高偏差,因为它的数据拟合度低,像这种接近线性的分类器,数据拟合度低。

在这里插入图片描述

但是如果我们稍微改变一下分类器,我用紫色笔画出,它会过度拟合部分数据,用紫色线画出的分类器具有高偏差和高方差,偏差高是因为它几乎是一条线性分类器,并未拟合数据。

在这里插入图片描述

这种二次曲线能够很好地拟合数据。

在这里插入图片描述

这条曲线中间部分灵活性非常高,却过度拟合了这两个样本,这类分类器偏差很高,因为它几乎是线性的。

在这里插入图片描述

而采用曲线函数或二次元函数会产生高方差,因为它曲线灵活性太高以致拟合了这两个错误样本和中间这些活跃数据。

这看起来有些不自然,从两个维度上看都不太自然,但对于高维数据,有些数据区域偏差高,有些数据区域方差高,所以在高维数据中采用这种分类器看起来就不会那么牵强了。

总结一下,我们讲了如何通过分析在训练集上训练算法产生的误差和验证集上验证算法产生的误差来诊断算法是否存在高偏差和高方差,是否两个值都高,或者两个值都不高,根据算法偏差和方差的具体情况决定接下来你要做的工作,下节课,我会根据算法偏差和方差的高低情况讲解一些机器学习的基本方法,帮助大家更系统地优化算法,我们下节课见。

1.3 机器学习基础(Basic Recipe for Machine Learning)

上节课我们讲的是如何通过训练误差和验证集误差判断算法偏差或方差是否偏高,帮助我们更加系统地在机器学习中运用这些方法来优化算法性能。

下图就是我在训练神经网络用到的基本方法:(尝试这些方法,可能有用,可能没用)

在这里插入图片描述

这是我在训练神经网络时用到地基本方法,初始模型训练完成后,我首先要知道算法的偏差高不高,如果偏差较高,试着评估训练集或训练数据的性能。如果偏差的确很高,甚至无法拟合训练集,那么你要做的就是选择一个新的网络,比如含有更多隐藏层或者隐藏单元的网络,或者花费更多时间来训练网络,或者尝试更先进的优化算法,后面我们会讲到这部分内容。你也可以尝试其他方法,可能有用,也可能没用。

一会儿我们会看到许多不同的神经网络架构,或许你能找到一个更合适解决此问题的新的网络架构,加上括号,因为其中一条就是你必须去尝试,可能有用,也可能没用,不过采用规模更大的网络通常都会有所帮助,延长训练时间不一定有用,但也没什么坏处。训练学习算法时,我会不断尝试这些方法,直到解决掉偏差问题,这是最低标准,反复尝试,直到可以拟合数据为止,至少能够拟合训练集。

如果网络足够大,通常可以很好的拟合训练集,只要你能扩大网络规模,如果图片很模糊,算法可能无法拟合该图片,但如果有人可以分辨出图片,如果你觉得基本误差不是很高,那么训练一个更大的网络,你就应该可以……至少可以很好地拟合训练集,至少可以拟合或者过拟合训练集。一旦偏差降低到可以接受的数值,检查一下方差有没有问题,为了评估方差,我们要查看验证集性能,我们能从一个性能理想的训练集推断出验证集的性能是否也理想,如果方差高,最好的解决办法就是采用更多数据,如果你能做到,会有一定的帮助,但有时候,我们无法获得更多数据,我们也可以尝试通过正则化来减少过拟合,这个我们下节课会讲。有时候我们不得不反复尝试,但是,如果能找到更合适的神经网络框架,有时它可能会一箭双雕,同时减少方差和偏差。如何实现呢?想系统地说出做法很难,总之就是不断重复尝试,直到找到一个低偏差,低方差的框架,这时你就成功了。

有两点需要大家注意:

第一点,高偏差和高方差是两种不同的情况,我们后续要尝试的方法也可能完全不同,我通常会用训练验证集来诊断算法是否存在偏差或方差问题,然后根据结果选择尝试部分方法。举个例子,如果算法存在高偏差问题,准备更多训练数据其实也没什么用处,至少这不是更有效的方法,所以大家要清楚存在的问题是偏差还是方差,还是两者都有问题,明确这一点有助于我们选择出最有效的方法。

第二点,在机器学习的初期阶段,关于所谓的偏差方差权衡的讨论屡见不鲜,原因是我们能尝试的方法有很多。可以增加偏差,减少方差,也可以减少偏差,增加方差,但是在深度学习的早期阶段,我们没有太多工具可以做到只减少偏差或方差却不影响到另一方。但在当前的深度学习和大数据时代,只要持续训练一个更大的网络,只要准备了更多数据,那么也并非只有这两种情况,我们假定是这样,那么,只要正则适度,通常构建一个更大的网络便可以,在不影响方差的同时减少偏差,而采用更多数据通常可以在不过多影响偏差的同时减少方差。这两步实际要做的工作是:训练网络,选择网络或者准备更多数据,现在我们有工具可以做到在减少偏差或方差的同时,不对另一方产生过多不良影响。我觉得这就是深度学习对监督式学习大有裨益的一个重要原因,也是我们不用太过关注如何平衡偏差和方差的一个重要原因,但有时我们有很多选择,减少偏差或方差而不增加另一方。最终,我们会得到一个非常规范化的网络。从下节课开始,我们将讲解正则化,训练一个更大的网络几乎没有任何负面影响,而训练一个大型神经网络的主要代价也只是计算时间,前提是网络是比较规范化的。

今天我们讲了如何通过组织机器学习来诊断偏差和方差的基本方法,然后选择解决问题的正确操作,希望大家有所了解和认识。我在课上不止一次提到了正则化,它是一种非常实用的减少方差的方法,正则化时会出现偏差方差权衡问题,偏差可能略有增加,如果网络足够大,增幅通常不会太高,我们下节课再细讲,以便大家更好理解如何实现神经网络的正则化。

1.4 正则化(Regularization)

深度学习可能存在过拟合问题——高方差,有两个解决方法,一个是正则化,另一个是准备更多的数据,这是非常可靠的方法,但你可能无法时时刻刻准备足够多的训练数据或者获取更多数据的成本很高,但正则化通常有助于避免过拟合或减少你的网络误差。

如果你怀疑神经网络过度拟合了数据,即存在高方差问题,那么最先想到的方法可能是正则化,另一个解决高方差的方法就是准备更多数据,这也是非常可靠的办法,但你可能无法时时准备足够多的训练数据,或者,获取更多数据的成本很高,但正则化有助于避免过度拟合,或者减少网络误差,下面我们就来讲讲正则化的作用原理。

我们用逻辑回归来实现这些设想,求成本函数 J J J的最小值,它是我们定义的成本函数,参数包含一些训练数据和不同数据中个体预测的损失, w w w b b b是逻辑回归的两个参数, w w w是一个多维度参数矢量, b b b是一个实数。在逻辑回归函数中加入正则化,只需添加参数λ,也就是正则化参数,一会儿再详细讲。

λ 2 m \frac{\lambda}{2m} 2mλ乘以 w w w范数的平方,其中 ∥ w ∥ 2 2 \left\| w \right\|_2^2 w22 w w w的欧几里德范数的平方,等于 w j w_{j} wj j j j 值从1到 n x n_{x} nx)平方的和,也可表示为 w T w w^{T}w wTw,也就是向量参数 w w w 的欧几里德范数(2范数)的平方,此方法称为 L 2 L2 L2正则化,因为这里用了欧几里德范数,被称为向量参数 w w w L 2 L2 L2范数。

在这里插入图片描述

为什么只正则化参数 w w w?为什么不再加上参数 b b b 呢?你可以这么做,只是我习惯省略不写,因为 w w w通常是一个高维参数矢量,已经可以表达高偏差问题, w w w可能包含有很多参数,我们不可能拟合所有参数,而 b b b只是单个数字,所以 w w w几乎涵盖所有参数,而不是 b b b,如果加了参数 b b b,其实也没太大影响,因为 b b b只是众多参数中的一个,所以我通常省略不计,如果你想加上这个参数,完全没问题。

在这里插入图片描述

L 2 L2 L2正则化是最常见的正则化类型,你们可能听说过 L 1 L1 L1正则化, L 1 L1 L1正则化,加的不是 L 2 L2 L2范数,而是正则项 λ m \frac{\lambda}{m} mλ乘以 ∑ j = 1 n x ∣ w ∣ \sum_{j= 1}^{n_{x}}{|w|} j=1nxw ∑ j = 1 n x ∣ w ∣ \sum_{j =1}^{n_{x}}{|w|} j=1nxw也被称为参数 w w w向量的 L 1 L1 L1范数,无论分母是 m m m还是 2 m 2m 2m,它都是一个比例常量。

在这里插入图片描述

如果用的是 L 1 L1 L1正则化, w w w最终会是稀疏的,也就是说 w w w向量中有很多0,有人说这样有利于压缩模型,因为集合中参数均为0,存储模型所占用的内存更少。实际上,虽然 L 1 L1 L1正则化使模型变得稀疏,却没有降低太多存储内存,所以我认为这并不是 L 1 L1 L1正则化的目的,至少不是为了压缩模型,人们在训练网络时,越来越倾向于使用 L 2 L2 L2正则化。

我们来看最后一个细节, λ \lambda λ是正则化参数,我们通常使用验证集或交叉验证集来配置这个参数,尝试各种各样的数据,寻找最好的参数,我们要考虑训练集之间的权衡,把参数设置为较小值,这样可以避免过拟合,所以λ是另外一个需要调整的超级参数,顺便说一下,为了方便写代码,在Python编程语言中, λ \lambda λ是一个保留字段,编写代码时,我们删掉 a a a,写成 l a m b d lambd lambd,以免与Python中的保留字段冲突,这就是在逻辑回归函数中实现 L 2 L2 L2正则化的过程,如何在神经网络中实现 L 2 L2 L2正则化呢?

在这里插入图片描述

神经网络含有一个成本函数,该函数包含 W [ 1 ] W^{[1]} W[1] b [ 1 ] b^{[1]} b[1] W [ l ] W^{[l]} W[l] b [ l ] b^{[l]} b[l]所有参数,字母 L L L是神经网络所含的层数,因此成本函数等于 m m m个训练样本损失函数的总和乘以 1 m \frac{1}{m} m1,正则项为 λ 2 m ∑ 1 L ∣ W [ l ] ∣ 2 \frac{\lambda }{2m}{{\sum\nolimits_{1}^{L}{| {{W}^{[l]}}|}}^{2}} 2mλ1LW[l]2,我们称 ∣ ∣ W [ l ] ∣ ∣ 2 {||W^{\left[l\right]}||}^{2} ∣∣W[l]∣∣2为范数平方,这个矩阵范数 ∣ ∣ W [ l ] ∣ ∣ 2 {||W^{\left[l\right]}||}^{2} ∣∣W[l]∣∣2(即平方范数),被定义为矩阵中所有元素的平方求和,

在这里插入图片描述

我们看下求和公式的具体参数,第一个求和符号其值 i i i从1到 n [ l − 1 ] n^{[l - 1]} n[l1],第二个其 J J J值从1到 n [ l ] n^{[l]} n[l],因为 W W W是一个 n [ l ] × n [ l − 1 ] n^{[l]}\times n^{[l-1]} n[l]×n[l1]的多维矩阵, n [ l ] n^{[l]} n[l]表示 l l l 层单元的数量, n [ l − 1 ] n^{[l-1]} n[l1]表示第 l − 1 l-1 l1层隐藏单元的数量。

在这里插入图片描述

该矩阵范数被称作“弗罗贝尼乌斯范数”,用下标 F F F标注”,鉴于线性代数中一些神秘晦涩的原因,我们不称之为“矩阵 L 2 L2 L2范数”,而称它为“弗罗贝尼乌斯范数”,矩阵 L 2 L2 L2范数听起来更自然,但鉴于一些大家无须知道的特殊原因,按照惯例,我们称之为“弗罗贝尼乌斯范数”,它表示一个矩阵中所有元素的平方和。

在这里插入图片描述

该如何使用该范数实现梯度下降呢?

backprop计算出 d W ​ dW​ dW的值,backprop会给出 J J J对​ W W W的偏导数,实际上是​$ W{[l]}$,把​$W{[l]} 替换为​ 替换为​ 替换为W^{[l]} 减去学习率乘以​ 减去学习率乘以​ 减去学习率乘以dW$。

在这里插入图片描述

这就是之前我们额外增加的正则化项,既然已经增加了这个正则项,现在我们要做的就是给 d W dW dW加上这一项 λ m W [ l ] \frac {\lambda}{m}W^{[l]} mλW[l],然后计算这个更新项,使用新定义的 d W [ l ] dW^{[l]} dW[l],它的定义含有相关参数代价函数导数和,以及最后添加的额外正则项,这也是 L 2 L2 L2正则化有时被称为“权重衰减”的原因。

在这里插入图片描述

我们用$ dW{[l]}$的定义替换此处的$dW{[l]} ,可以看到, ,可以看到, ,可以看到,W{[l]}$的定义被更新为$W{[l]} 减去学习率 减去学习率 减去学习率\alpha$ 乘以backprop 再加上 λ m W [ l ] \frac{\lambda}{m}W^{[l]} mλW[l]

在这里插入图片描述

该正则项说明,不论 W [ l ] W^{[l]} W[l]是什么,我们都试图让它变得更小,实际上,相当于我们给矩阵W乘以 ( 1 − α λ m ) (1 - \alpha\frac{\lambda}{m}) (1αmλ)倍的权重,矩阵 W W W减去 α λ m \alpha\frac{\lambda}{m} αmλ倍的它,也就是用这个系数 ( 1 − α λ m ) (1-\alpha\frac{\lambda}{m}) (1αmλ)乘以矩阵 W W W,该系数小于1,因此 L 2 L2 L2范数正则化也被称为“权重衰减”,因为它就像一般的梯度下降, W W W被更新为少了 α \alpha α乘以backprop输出的最初梯度值,同时 W W W也乘以了这个系数,这个系数小于1,因此 L 2 L2 L2正则化也被称为“权重衰减”。

在这里插入图片描述

我不打算这么叫它,之所以叫它“权重衰减”是因为这两项相等,权重指标乘以了一个小于1的系数。

以上就是在神经网络中应用 L 2 L2 L2正则化的过程,有人会问我,为什么正则化可以预防过拟合,我们放在下节课讲,同时直观感受一下正则化是如何预防过拟合的。

1.5 为什么正则化有利于预防过拟合呢?(Why regularization reduces overfitting?)

为什么正则化有利于预防过拟合呢?为什么它可以减少方差问题?我们通过两个例子来直观体会一下。

在这里插入图片描述

在这里插入图片描述

左图是高偏差,右图是高方差,中间是Just Right,这几张图我们在前面课程中看到过。

在这里插入图片描述

现在我们来看下这个庞大的深度拟合神经网络。我知道这张图不够大,深度也不够,但你可以想象这是一个过拟合的神经网络。这是我们的代价函数 J J J,含有参数 W W W b b b。我们添加正则项,它可以避免数据权值矩阵过大,这就是弗罗贝尼乌斯范数,为什么压缩 L 2 L2 L2范数,或者弗罗贝尼乌斯范数或者参数可以减少过拟合?

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

但是 λ \lambda λ会存在一个中间值,于是会有一个接近“Just Right”的中间状态。

直观理解就是 λ \lambda λ增加到足够大, W W W会接近于0,实际上是不会发生这种情况的,我们尝试消除或至少减少许多隐藏单元的影响,最终这个网络会变得更简单,这个神经网络越来越接近逻辑回归,我们直觉上认为大量隐藏单元被完全消除了,其实不然,实际上是该神经网络的所有隐藏单元依然存在,但是它们的影响变得更小了。神经网络变得更简单了,貌似这样更不容易发生过拟合,因此我不确定这个直觉经验是否有用,不过在编程中执行正则化时,你实际看到一些方差减少的结果。

在这里插入图片描述

我们再来直观感受一下,正则化为什么可以预防过拟合,假设我们用的是这样的双曲线激活函数。

在这里插入图片描述

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

在这里插入图片描述

现在你应该摒弃这个直觉,如果正则化参数λ很大,激活函数的参数会相对较小,因为代价函数中的参数变大了,如果 W W W很小,

在这里插入图片描述

如果 W W W很小,相对来说, z z z也会很小。

在这里插入图片描述

特别是,如果 z z z的值最终在这个范围内,都是相对较小的值, g ( z ) g(z) g(z)大致呈线性,每层几乎都是线性的,和线性回归函数一样。

在这里插入图片描述

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

在这里插入图片描述

总结一下,如果正则化参数变得很大,参数 W W W很小, z z z也会相对变小,此时忽略 b b b的影响, z z z会相对变小,实际上, z z z的取值范围很小,这个激活函数,也就是曲线函数 t a n h tanh tanh会相对呈线性,整个神经网络会计算离线性函数近的值,这个线性函数非常简单,并不是一个极复杂的高度非线性函数,不会发生过拟合。

大家在编程作业里实现正则化的时候,会亲眼看到这些结果,总结正则化之前,我给大家一个执行方面的小建议,在增加正则化项时,应用之前定义的代价函数 J J J,我们做过修改,增加了一项,目的是预防权重过大。

在这里插入图片描述

如果你使用的是梯度下降函数,在调试梯度下降时,其中一步就是把代价函数 J J J设计成这样一个函数,在调试梯度下降时,它代表梯度下降的调幅数量。可以看到,代价函数对于梯度下降的每个调幅都单调递减。如果你实施的是正则化函数,请牢记, J J J已经有一个全新的定义。如果你用的是原函数 J J J,也就是这第一个项正则化项,你可能看不到单调递减现象,为了调试梯度下降,请务必使用新定义的 J J J函数,它包含第二个正则化项,否则函数 J J J可能不会在所有调幅范围内都单调递减。

这就是 L 2 L2 L2正则化,它是我在训练深度学习模型时最常用的一种方法。在深度学习中,还有一种方法也用到了正则化,就是dropout正则化,我们下节课再讲。

1.6 dropout 正则化(Dropout Regularization)

除了 L 2 L2 L2正则化,还有一个非常实用的正则化方法——“Dropout(随机失活)”,我们来看看它的工作原理。

在这里插入图片描述

假设你在训练上图这样的神经网络,它存在过拟合,这就是dropout所要处理的,我们复制这个神经网络,dropout会遍历网络的每一层,并设置消除神经网络中节点的概率。假设网络中的每一层,每个节点都以抛硬币的方式设置概率,每个节点得以保留和消除的概率都是0.5,设置完节点概率,我们会消除一些节点,然后删除掉从该节点进出的连线,最后得到一个节点更少,规模更小的网络,然后用backprop方法进行训练。

在这里插入图片描述

在这里插入图片描述

这是网络节点精简后的一个样本,对于其它样本,我们照旧以抛硬币的方式设置概率,保留一类节点集合,删除其它类型的节点集合。对于每个训练样本,我们都将采用一个精简后神经网络来训练它,这种方法似乎有点怪,单纯遍历节点,编码也是随机的,可它真的有效。不过可想而知,我们针对每个训练样本训练规模小得多的网络,最后你可能会认识到为什么要正则化网络,因为我们在训练规模小得多的网络。

在这里插入图片描述

如何实施dropout呢?方法有几种,接下来我要讲的是最常用的方法,即inverted dropout(反向随机失活),出于完整性考虑,我们用一个三层( l = 3 l=3 l=3)网络来举例说明。编码中会有很多涉及到3的地方。我只举例说明如何在某一层中实施dropout

首先要定义向量 d d d d [ 3 ] d^{[3]} d[3]表示网络第三层的dropout向量:

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

然后看它是否小于某数,我们称之为keep-probkeep-prob是一个具体数字,上个示例中它是0.5,而本例中它是0.8,它表示保留某个隐藏单元的概率,此处keep-prob等于0.8,它意味着消除任意一个隐藏单元的概率是0.2,它的作用就是生成随机矩阵,如果对 a [ 3 ] a^{[3]} a[3]进行因子分解,效果也是一样的。 d [ 3 ] d^{[3]} d[3]是一个矩阵,每个样本和每个隐藏单元,其中 d [ 3 ] d^{[3]} d[3]中的对应值为1的概率都是0.8,对应为0的概率是0.2,随机数字小于0.8。它等于1的概率是0.8,等于0的概率是0.2。

接下来要做的就是从第三层中获取激活函数,这里我们叫它 a [ 3 ] a^{[3]} a[3] a [ 3 ] a^{[3]} a[3]含有要计算的激活函数, a [ 3 ] a^{[3]} a[3]等于上面的 a [ 3 ] a^{[3]} a[3]乘以 d [ 3 ] d^{[3]} d[3]a3 =np.multiply(a3,d3),这里是元素相乘,也可写为 a 3 ∗ = d 3 a3*=d3 a3=d3,它的作用就是让 d [ 3 ] d^{[3]} d[3]中所有等于0的元素(输出),而各个元素等于0的概率只有20%,乘法运算最终把 d [ 3 ] d^{\left\lbrack3 \right]} d[3]中相应元素输出,即让 d [ 3 ] d^{[3]} d[3]中0元素与 a [ 3 ] a^{[3]} a[3]中相对元素归零。

在这里插入图片描述

如果用python实现该算法的话, d [ 3 ] d^{[3]} d[3]则是一个布尔型数组,值为truefalse,而不是1和0,乘法运算依然有效,python会把truefalse翻译为1和0,大家可以用python尝试一下。

最后,我们向外扩展 a [ 3 ] a^{[3]} a[3],用它除以0.8,或者除以keep-prob参数。

在这里插入图片描述

下面我解释一下为什么要这么做,为方便起见,我们假设第三隐藏层上有50个单元或50个神经元,在一维上 a [ 3 ] a^{[3]} a[3]是50,我们通过因子分解将它拆分成 50 × m 50×m 50×m维的,保留和删除它们的概率分别为80%和20%,这意味着最后被删除或归零的单元平均有10(50×20%=10)个,现在我们看下 z [ 4 ] z^{\lbrack4]} z[4] z [ 4 ] = w [ 4 ] a [ 3 ] + b [ 4 ] z^{[4]} = w^{[4]} a^{[3]} + b^{[4]} z[4]=w[4]a[3]+b[4],我们的预期是, a [ 3 ] a^{[3]} a[3]减少20%,也就是说 a [ 3 ] a^{[3]} a[3]中有20%的元素被归零,为了不影响 z [ 4 ] z^{\lbrack4]} z[4]的期望值,我们需要用 w [ 4 ] a [ 3 ] / 0.8 w^{[4]} a^{[3]}/0.8 w[4]a[3]/0.8,它将会修正或弥补我们所需的那20%, a [ 3 ] a^{[3]} a[3]的期望值不会变,划线部分就是所谓的dropout方法。

在这里插入图片描述

它的功能是,不论keep-prop的值是多少0.8,0.9甚至是1,如果keep-prop设置为1,那么就不存在dropout,因为它会保留所有节点。反向随机失活(inverted dropout)方法通过除以keep-prob,确保 a [ 3 ] a^{[3]} a[3]的期望值不变。

事实证明,在测试阶段,当我们评估一个神经网络时,也就是用绿线框标注的反向随机失活方法,使测试阶段变得更容易,因为它的数据扩展问题变少,我们将在下节课讨论。

据我了解,目前实施dropout最常用的方法就是Inverted dropout,建议大家动手实践一下。Dropout早期的迭代版本都没有除以keep-prob,所以在测试阶段,平均值会变得越来越复杂,不过那些版本已经不再使用了。

现在你使用的是 d d d向量,你会发现,不同的训练样本,清除不同的隐藏单元也不同。实际上,如果你通过相同训练集多次传递数据,每次训练数据的梯度不同,则随机对不同隐藏单元归零,有时却并非如此。比如,需要将相同隐藏单元归零,第一次迭代梯度下降时,把一些隐藏单元归零,第二次迭代梯度下降时,也就是第二次遍历训练集时,对不同类型的隐藏层单元归零。向量 d d d d [ 3 ] d^{[3]} d[3]用来决定第三层中哪些单元归零,无论用foreprop还是backprop,这里我们只介绍了foreprob

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

z [ 1 ] = w [ 1 ] a [ 0 ] + b [ 1 ] z^{[1]} = w^{[1]} a^{[0]} + b^{[1]} z[1]=w[1]a[0]+b[1]

a [ 1 ] = g [ 1 ] ( z [ 1 ] ) a^{[1]} = g^{[1]}(z^{[1]}) a[1]=g[1](z[1])

z [ 2 ] =   w [ 2 ] a [ 1 ] + b [ 2 ] z^{[2]} = \ w^{[2]} a^{[1]} + b^{[2]} z[2]= w[2]a[1]+b[2]

a [ 2 ] = … a^{[2]} = \ldots a[2]=

以此类推直到最后一层,预测值为 y ^ \hat{y} y^

在这里插入图片描述

显然在测试阶段,我们并未使用dropout,自然也就不用抛硬币来决定失活概率,以及要消除哪些隐藏单元了,因为在测试阶段进行预测时,我们不期望输出结果是随机的,如果测试阶段应用dropout函数,预测会受到干扰。理论上,你只需要多次运行预测处理过程,每一次,不同的隐藏单元会被随机归零,预测处理遍历它们,但计算效率低,得出的结果也几乎相同,与这个不同程序产生的结果极为相似。

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

l = k e e p − p r o b l=keep-prob l=keepprob

这就是dropout,大家可以通过本周的编程练习来执行这个函数,亲身实践一下。

为什么dropout会起作用呢?下节课我们将更加直观地了解dropout的具体功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值