1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 2-1 Coursera吴恩达《改善深度神经网络》 第一周课程笔记-深度学习的实践方面

2-1 Coursera吴恩达《改善深度神经网络》 第一周课程笔记-深度学习的实践方面

时间:2021-05-18 14:44:17

相关推荐

2-1 Coursera吴恩达《改善深度神经网络》 第一周课程笔记-深度学习的实践方面

记录吴恩达Andrew Ng深度学习专项课程笔记,方便之后回顾,共5门课。第一门课《神经网络与深度学习》(Neural Networks and Deep Learning)的4周课程笔记请见如下链接:

1-1 Coursera吴恩达《神经网络与深度学习》第一周课程笔记-深度学习概论

1-2 Coursera吴恩达《神经网络与深度学习》第二周课程笔记-神经网络基础

1-3 Coursera吴恩达《神经网络与深度学习》第三周课程笔记-浅层神经网络

1-4 Coursera吴恩达《神经网络与深度学习》第四周课程笔记-深层神经网络

今天开始介绍第二门课,这是第二门课《改善深度神经网络》(Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization)第一周机器学习策略的课程笔记,那我们开始吧。

目录

《1.1训练集/验证集/测试集》 Train/Dev/Test sets

《1.2偏差/方差》Bias/Variance

《1.3机器学习基础》Basic Recipe for Machine Learning

《1.4正则化》Regularization

《1.5为什么正则化可以减少过拟合?》Why regularization reduces overfitting

《1.6Dropout正则化》Dropout Regularization

《1.7理解Dropout》Understanding Dropout

《1.8其他正则化方法》Other regularization methods

《1.9正则化输入》 Normalizing inputs

《1.10梯度消失和梯度爆炸》Vanishing and Exploding gradients

《1.11神经网络的权重初始化》Weight Initialization for Deep Networks

《1.12梯度的数值逼近》Numerical approximation of gradients

《1.13梯度检验》Gradient checking

《1.14关于梯度检验实现的标记》 Gradient Checking Implementation Notes

Summary

《1.1训练集/验证集/测试集》 Train/Dev/Test sets

大家可能已经了解了如何构建神经网络,那么本周我们将继续学习如何有效运作神经网络。内容涉及超参数调优(hyperparameter tuning)、如何构建数据以及如何确保优化算法快速运行,从而时学习算法在合理时间内完成自我学习。第一周先说神经网络机器学习中的问题,然后是随机神经网络,还有一些确保神经网络正常运行的技巧。

在配置训练(train)、验证(devlopment)和测试(test)数据集的过程中做出正确决策在很大程度上会帮助大家创建高效的神经网络。训练神经网络时我们需要做很多决策,如神经网络的层数、每个隐藏层包含的隐藏单元、学习因子(学习速率)、各层激活函数的选择等。

一开始我们并不知道这些参数,实际上,应用型机器学习是一个高度迭代的过程。通常在项目启动时,先有一个初步想法(idea),比如构建一个含有特定层数、隐藏单元数量或者数据集个数等的神经网络,然后编码(code),并尝试运行这些代码,通过运行和测试得到该神经网络,或这些配置信息的运行结果;你可能根据结果重新完善自己的想法,改变策略,不断试验(experiment),或者找到更好的神经网络不断更新迭代自己的方案。如今,深度学习已经在自然语言处理(NLP),计算机视觉(CV),语音识别(Speech Recognition)以及结构化数据应用等众多领域取得巨大成功。就跨行业而言,Andrew认为最佳决策取决于你拥有的数据量,计算机配置中输入特征的数量,用GPU还是CPU训练,GPU和CPU的具体配置以及其他诸多因素。即使是最有经验的深度学习专家也很难第一次就找到最合适的参数。所以说,应用深度学习是一个反复迭代的过程,需要通过反复多次的循环训练得到最优化参数。因此,循环该过程的效率是决定项目进展速度的一个关键因素。而创建高质量的训练数据集、验证集和测试集也有助于提高循环效率。

通常将所有的样本数据分成三个部分:Train/Dev/Test sets。训练集(Train sets)用来执行训练算法;验证集(Dev sets)简单交叉验证集选择最好的模型,经过充分验证不同算法的表现情况,选定了最终模型;测试集(Test sets)进行评估,用来测试最好算法的实际表现,作为该算法的无偏估计。

为了无偏评估算法的运行状况,小数据量时机器学习一般三七分,即70%训练集30%测试集。如果有验证集,则设置比例依次为60%、20%、20%。如果数量为100、1000或10000,这是比较科学的。但是在大数据时代,数据量是百万级的,那么验证集合测试集占总数据量的比例会趋向于变小。因为验证集的目标是用来比较验证不同算法的优劣,从而选择最好的1-2个算法模型。因此,通常不需要所有样本的20%这么多的数据来进行验证。对于100万的样本,往往只需要10000个样本来做验证就够了。测试集的主要目的是正确评估分类器的性能测试。所以如果是百万数据,只需要1000条。因此,对于百万级数据样本,Train/Dev/Test sets的比例通常可以设置为98%/1%/1%,对于数量过百万的应用,比例可以为99.5%/0.25%/0.25%,或者99.5%/0.4%/0.1%。因此,样本数据量越大,相应的Dev/Test sets的比例可以设置的越低一些。

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

深度学习的另一个趋势是在训练样本和测试样本分布不匹配的情况下进行训练,假如你要构建一个用户可以上传大量图片的应用程序(app),目的是找出并呈现出所有猫咪图片,训练集可能是网上下载的猫的图片,而验证集是用户在这个app上传的猫的图片,结果网页上的分辨率很高、制作精良,而用户上传的可能是手机随意拍摄的,像素低,比较模糊,这两类数据有所不同。根据经验,Andrew建议大家要确保验证集和测试集的数据来自同一分布,这个之后也会细讲。因为你们要用验证集来评估不同的模型,尽可能地优化性能。如果验证集和测试集来自同一个分布就会很好。

最后,数据没有测试集也没关系,测试集的目的是对所选定的神经网络系统做出无偏评估,如果不需要无偏评估,也可以不设置测试集,在验证集(test sets)上选择合适的模型。

《1.2偏差/方差》Bias/Variance

假设这是数据集,如果给这个数据集(图左)拟合一条直线,可能得到一个逻辑回归拟合,但它并不能很好地拟合该数据集,这是偏差高(high bias)的情况,称为欠拟合(underfit the data);相反地,如果我们拟合一个非常复杂的分类器,比如深度神经网络或者含有隐藏单元的神经网络,像这个数据集(图右),分类器方差较高(high variance),数据过度拟合(overfit the data);这两者之间,可能还有像(图中)一样的情况,复杂程度适中,数据拟合适度的分类器,这个看上起更为合理,称适度拟合(just right),是介于过拟合和欠拟合中间的一类。这是在二维的情况下,将偏差和方差可视化。多维通过绘制数据和可视化分割边界无法实现,但我们可以通过几个指标来研究偏差和方差。

沿用猫咪分类的例子。理解偏差和方差的两个关键数据是训练集误差(train set error)验证集误差(development set error)。假定Train set error为1%,而Dev set error为11%,即该算法模型对训练样本的识别很好,但是对验证集的识别却不太好。这说明了可能存在过拟合,某种程度上,验证集并没有充分利用交叉验证集的作用,模型泛化能力不强,导致验证集识别率低。我们称为高方差(high variance)。假设Train set error为15%,而Dev set error为16%,假设该案例中人的错误率几乎为0%,即人们浏览这些图片能分辨出是不是猫。算法并没有在训练集得到很好的训练,如果训练集的拟合度不高,就是欠拟合,即偏差较高(high bias)。相反,它对于验证集产生的结果却是合理的,只相差1%。

假设train set error为15%,而dev set error为30%,说明了该模型既存在高偏差(high bias)也存在高方差(high variance),这是深度学习中最坏的情况。再假设Train set error为0.5%,而Dev set error为1%,即低偏差(low bias)和低方差(low variance),是最好的情况。注意,上面的例子都是假设人眼辨别的错误率接近0%,即人类都能正确识别所有猫类图片。一般来说,最优误差(optimal error)也称为基本误差(base error),所以最优误差接近0。如果基本误差(base error)不同,例如图片很模糊,相应的train set error和dev set error会有所变化,那分析过程就要做出改变了。

总结,一般来说,Train set error体现了是否出现bias,Dev set error体现了是否出现variance(正确地说,应该是Dev set error与Train set error的相对差值)。以上分析前提都是假设基本误差(base error)很小(人类能正确识别猫类图片),训练集和验证集数据来自相同分布。

下面看一下high bias和 high variance的模型:(紫线)

模型既存在high bias也存在high variance,可以理解成某段区域是欠拟合的,某段区域是过拟合的。

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

《1.3机器学习基础》Basic Recipe for Machine Learning

在训练神经网络时,首先,如果碰到高偏差(欠拟合),通常是增加神经网络的隐藏层层数、神经元个数,训练时间延长,选择其它更复杂的NN模型等。你必须去尝试这些方法(如下图),可能有用可能没用,不过采用规模更大的网络通常都会有所帮助。Andrew会不断尝试这些方法,直到解决掉偏差问题,这是最低标准。在基础误差不高的情况下,一般都能通过这些方式有效降低和避免高偏差,至少在训练集上表现良好。其次,减少高方差(过拟合)的方法通常是增加训练样本数据,但有时无法获得更多的数据,进行正则化(Regularization)来减少过拟合,有时候我们不得不不断尝试,但有时能找到更合适的神经网络框架,可能会一箭双雕——同时减少方差和偏差。

注意到①处理高方差和高偏差的方法不一样,首先要通过验证集找到存在的问题,再对症下药,明确这一点有助于选出最有效的方法。②在机器学习的初级阶段,关于所谓的偏差方差权衡的探讨屡见不鲜,但是在当前的深度学习和大数据时代,只需要持续训练一个更大的网络,只要准备了更多的数据,同时减少方差和偏差不是没有可能。现在有工具可以做到降低一方而不增加另一方,Andrew认为这是深度学习对监督式学习大有裨益的一个原因,也是不必过于关注如何平衡偏差和方差的一个重要原因。我们下节课让大家更好理解如何实现神经网络的正则化。

《1.4正则化》Regularization

如果你怀疑神经网络过度拟合了数据,即出现了高方差(high variance),那么最先想到的可能是正则化(regularization),另一个方法是准备更多的数据(more data)。但获取更多样本的成本可能很高但正则化通常有助于避免过度拟合或减少网络误差。

下面用逻辑回归来实现这些设想。求成本函数(cost function)J的最小值。它是我们定义的成本函数,参数包含一些训练数据和不同数据中个体预测的损失,w和b逻辑回归的两个参数,w是一个多维度参数矢量,b是一个实数。实现正则化只需要添加参数λ(正则化参数),这种方法称为L2 regularization。先给出两种常见的正则化表达式:

L2 regularization的表达式为:

L1 regularization的表达式为:

具体解释我们看下图:

这里有个问题:为什么只对w进行正则化而加上b呢?其实也可以对b进行正则化。因为w一般是高维参数矢量,已经可以表达高方差问题。w可能含有很多参数,我们不可能拟合所有参数,而b只是单个数字。所以w几乎涵盖所有参数,当然,你加上之后也可以。当然你可能听过L1 regularization,它得到的w更加稀疏,因为w向量中很多零值。有人说这样有利于压缩模型。实际上,虽然L1得到的结果更稀疏,却没有降低太多存储空间,所以Andrew认为至少L1的主要目的不是为了压缩模型。在训练模型时,人们越来越倾向于使用L2。

我们来看最后一个细节,λ是正则化参数(超参数的一种),通过验证集或者交叉验证来配置这个参数,尝试各种各样的数据,选择最好的λ。要考虑训练集中的权衡,把参数设置为较小值,这样可以避免过拟合。在python中,lambda是保留字,所以编码时,使用lambd来表示lambda,以避免冲突。

在深度学习中如何实现正则化呢?(Frobenius范数——“弗罗贝尼乌斯范数”,用下标F表示)

首先写出成本函数J的表达式,这里加了惩罚项(如上图)。注意矩阵L2范数听起来更自然,但鉴于一些大家无须知道的特殊原因,按照惯例,我们称之为“弗罗贝尼乌斯范数”,它表示一个矩阵中所有元素的平方和。如何使用该范数实现梯度下降呢?用backprop计算dW的值,backprop会给出J对W的偏导数,实际上是W^[l],因为我们额外增加的正则化项,所以给dW加上(λ/m)*W^[l]这一项,然后定义这个更新项,使用新定义的dW^[l],它的定义含有相关参数代价函数导数和,以及最后添加的额外正则项,这也是L2正则化有时被称为“权重衰减”(weight decay)的原因。展开来写得到下面的表达式:

以上就是在神经网络中应用L2正则化的过程。你可能会问为什么正则化可以预防过拟合?下一视频讲,同时直观感受一下正则化是如何预防过拟合的。

《1.5为什么正则化可以减少过拟合?》Why regularization reduces overfitting

通过两个例子直观体会一下。还是之前那张图,从左到右,分别表示了欠拟合(underfit the data)刚好拟合(just right)过拟合(overfit the data)三种情况。

从成本函数J来看,直观上理解就是如果正则化λ设置得足够大,权重矩阵W被设置为接近于0的值,就是把多隐层单元的权重设为0,于是基本上消除了那些隐藏单元的许多影响。这种情况下,复杂神经网络就被简化成很小的网络,同时深度很大,它会使这个网络从过拟合的状态更接近于左图的高偏差状态。但是λ有个中间值,使得接近“just right”的中间状态。因此,选择合适大小的λ值,就能够同时避免高偏差(high bias)和高方差(high variance),得到最佳模型。

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

我们再来看一下,假设使用双曲线激活函数(tanh),用g(z)=tanh(z):

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

在之后的编程中会看到这些结果。Andrew建议在添加正则化项时,对成本函数J修改,添加一项,目的是预防权重过大,如果你使用的是梯度下降函数,在调试梯度下降时,其中一步是把J设计成这样一个函数,它代表梯度下降的调幅数量,一般J对梯度下降的每个调幅都单调递减。如果你使用正则化函数,注意J已经有一个全新的定义。如果你用的是原函数(第一个项正则化项),你可能看不到单调递减现象,为了调试梯度下降,请务必使用新定义的J函数,它包含第二个正则化项,否则J函数可能不会在所有调幅范围内都单调递减。L2正则化是Andrew在训练深度学习模型时最常用的一种方法。

回顾之前的tanh函数图像:

《1.6Dropout正则化》Dropout Regularization

除了L2 regularization之外,还有另外一种非常实用的正则化方法:Dropout(随机失活)。下面看工作原理。

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

这是网络节点精简后的一个样本,对于其它样本,我们照旧设置概率为0.5。对于每个训练样本,我们都将采用一个精简后神经网络来训练它(如上图右边),这种方法似乎有点怪,单纯遍历节点,编码也是随机的,可它真的有效。不过我们针对每个训练样本训练规模极小的网络,最后你可能会认识到为什么要正则化,因为我们在训练极小的网络。

如何实施dropout呢?方法有几种,接下来讲的是最常用的方法,即inverted dropout(反向随机失活),出于完整性考虑,我们用一个三层网络来举例说明。

①首先要定义向量d(如上图),d^[3]表示一个三层的dropout向量,python代码如下:

d3 = np.random.rand(a3.shape[0],a3.shape[1]) < keep-prob

其中keep-prob是一个具体数字,它表示保留某个隐藏单元的概率,上个示例中它是0.5,而本例中它是0.8,这意味着消除任意一个隐藏单元的概率是0.2,它的作用就是生成随机矩阵,如果对进行因子分解,效果也是一样的。d^[3]是一个矩阵,每个样本和每个隐藏单元,其中对应值为1的概率都是0.8(对应为0的概率是0.2)。

②接着要做的是从第三层中获取激活函数a^[3],a^[3]等于上面的a^[3]乘以d^[3],python代码:

a3 = np.multiply(a3,d3) #a3 *= d3

上述d3是一个布尔型数组,值为true和false,而不是1和0,乘法运算依然有效,python算法会把true和false翻译为1和0。

③最后,向外拓展a^[3],用它除以keep-prob参数(0.8)。

a3 /= keep-prob

下面解释为什么要这样做?(上图)假设第三隐藏层上有50个单元(神经元),在一维上a^[3]是50,通过因子分解拆分为50*m维的,保留和删除它们的概率分别为80%和20%,这意味着最后被删除或归零的单元平均有10(50×20%=10)个。z^[4]=w^[4]*a^[3]+b^[4],a^[3]减少了20%,为了不影响z^[4]的期望值,将w^[4]*a^[3]除以0.8,它将会修正或弥补我们所需的那20%,a^[3]的期望值不变,划线部分(上图a3 /= keep-prob)就是所谓的dropout方法,这样使测试阶段变得更容易,因为它的数据扩展问题变少。它的功能是,不论keep-prop的值是多少0.8,0.9甚至是1,如果keep-prop设置为1,那么就不存在dropout,因为它会保留所有节点。反向随机失活(inverted dropout)方法通过除以keep-prob,保证a^[3]的期望值不变。

Dropout早期的迭代版本都没有除以keep-prob,所以在测试阶段,平均值会变得越来越复杂,不过那些版本已经不再使用了。不同的训练样本,清除不同的隐藏单元也不同。向量d用来决定第三层中哪些单元归零,无论用foreprop还是backprop,这里我们只介绍了foreprob。

我们在测试阶段不使用dropout函数,尤其像下列情况:

以此类推到最后一层,预测值为y帽。(如下图)

显然在测试阶段,我们并未使用dropout,自然也就不用抛硬币来决定失活概率,以及要消除哪些隐藏单元了,因为在测试阶段进行预测时,我们不期望输出结果是随机的,所有神经元都在工作,如果测试阶段应用dropout函数,预测会受到干扰。Inverted dropout函数在除以keep-prob时可以记住上一步的操作,目的是确保即使在测试阶段不执行dropout来调整数值范围,激活函数的预期结果也不会发生变化,所以没必要在测试阶段额外添加尺度参数,这与训练阶段不同。

这就是dropout,大家可以通过本周的编程练习来执行这个函数,亲身实践一下。为什么dropout会起作用呢?下节课我们将更加直观地了解dropout的具体功能。

《1.7理解Dropout》Understanding Dropout

Dropout可以随机删除网络中的神经单元,他为什么可以通过正则化发挥如此大的作用呢?更直观的理解一下,上节课中,对dropout随机删除网络中的神经单元有了一个直观了解,不要依赖于任何一个特征,因为该单元的输入可能随时被清除,因此该单元通过这种方式传播下去,并为单元的四个输入增加一点权重,通过传播所有权重好像每次迭代之后,神经网络都变得比以前更小,因此采用一个较小神经网络好像和使用正则化的效果是一样的。

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

总结一下,事实证明,dropout被正式地作为一种正则化的替代形式,与L2正则化不同的是,被应用的方式不同,dropout也会有所不同,甚至更适用于不同的输入范围。L2对不同权重的衰减是不同的,它取决于倍增的激活函数的大小。

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

总之,对于有可能出现过拟合,且含有诸多参数的层,我们可以把keep-prob设置成比较小的值,以便应用更强大的dropout,有点像L2正则化的正则化参数。从技术上讲,我们也可以对输入层应用dropout,但现实中一般不这么做。

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

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

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

《1.8其他正则化方法》Other regularization methods

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

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

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

对于光学字符识别,我们还可以通过添加数字,随意旋转或扭曲数字来扩增数据,把这些数字添加到训练集,它们仍然是数字。为了方便说明,Andrew对字符做了强变形处理,实际操作时轻微变形就好。

②另外一种常用的方法叫作early stopping,运行梯度下降时,我们可以绘制训练误差,或只绘制成本函数J的优化过程,在训练集上用0-1记录分类误差次数。呈单调下降趋势,如下图。还可以绘制验证集误差,它可以是验证集上的分类误差,或验证集上的代价函数,逻辑损失和对数损失等,你会发现,验证集误差通常会先呈下降趋势,然后在某个节点处开始上升。

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

下面谈谈early stopping的缺点。机器学习的其中一步是选择一个算法来优化代价函数J,常用工具有梯度下降,Momentum,RMSprop和Adam等。同时,也不想出现过拟合,解决工具如正则化,扩增数据等

在重点优化成本函数J时,你只需要留意w和b,J(w,b)的值越小越好,你只需要想办法减小这个值,其它的不用关注。然后,预防过拟合还有其他任务,换句话说就是减少方差,这一步我们用另外一套工具来实现,这个原理有时被称为“正交化”(Orthogonalization)。而early stopping的主要缺点就是你不能独立地处理这两个问题(优化J和预防过拟合)。

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

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

这节课我们讲了如何使用数据扩增,以及如何使用early stopping降低神经网络中的方差或预防过拟合。下节课我们会讲一些配置优化问题的方法,来提高训练速度。

《1.9正则化输入》 Normalizing inputs

训练神经网络,其中一个加速训练的方法就是归一化输入(normalizing inputs)。假设我们有个训练集,它有两个输入特征,所以输入特征x是二维的,这是数据集的散点图。归一化输入需要两个步骤,第一步是零均值化

是一个向量,X等于每个训练数据x减去u,意思是移动训练集,直到它完成零均值化。

第二步是归一化方差,注意特征x1的方差比x2大得多。

这是节点y的平方,是一个向量,它的每个特征都有方差。由于已经完成了零均值化,把所有数据除以σ平方。这样x1和x2的方差都等于1。提示一下,如果你用它来调整训练数据,那么用相同的均值和方差来归一化测试集。们希望不论是训练数据还是测试数据,都是通过相同μ和σ^2定义的相同数据转换,其中μ和σ^2是由训练集数据计算得来的。

我们为什么要这么做呢?为什么我们想要归一化输入特征,回想一下右上角所定义的成本函数J。如下图:

如果你使用非归一化的输入特征,成本函数J会像左上方,是一个非常细长狭窄的成本函数。假如特征x1取值范围从1到1000,x2的取值范围从0到1,结果是参数w1和w2值的范围或比率将会非常不同,这些数据轴应该是w1和w2,但直观理解,这里标记为w和b,成本函数就有点像狭长的碗一样,如果你能画出该函数的部分轮廓,它会是这样一个狭长的函数(左下方)。在这样的成本函数J上运行梯度下降法,必须使用一个非常小的学习率。而且梯度下降法可能需要多次迭代过程,直到最后找到最小值。但如果进行归一化处理,函数是一个更圆的球形轮廓(右上方),那么不论从哪个位置开始,梯度下降法都能够更直接地找到最小值,也可以使用较大步长,而不需要像在左图中那样反复执行。

当然,实际上是w一个高维向量,因此用二维绘制w并不能正确地传达并直观理解,但总的理解是成本函数会更圆一些,而且更容易优化,前提是特征都在相似范围内,而不是从1到1000,0到1的范围,而是在-1到1范围内或相似偏差,这使得成本函数优化起来更简单快速。所以如果输入特征处于不同范围内,那么归一化特征值就非常重要了。如果特征值处于相似范围内,那么归一化就不是很重要了。执行这类归一化并不会产生什么危害,Andrew通常会做归一化处理,虽然不确定它能否提高训练或算法速度。

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

《1.10梯度消失和梯度爆炸》Vanishing and Exploding gradients

训练神经网络,尤其是深度神经所面临的一个问题就是梯度消失或梯度爆炸(vanishing and exploding gradients),也就是你训练神经网络的时候,导数或坡度有时会变得非常大,或者非常小,甚至于以指数方式变小,这加大了训练的难度。这节课,你将会了解梯度消失或梯度爆炸的真正含义,以及如何更明智地选择随机初始化权重,从而避免这个问题。

假设你正在训练这样一个极深的神经网络,为了节约幻灯片上的空间,神经网络每层只有两个隐藏单元:

参数W^[1],W^[2],W^[3],...W^[l],使用激活函数g(z)=z(线性激活函数),假设b^[l]=0,输出为:

假设每个权重矩阵为

每个元素都大于1,则

y帽等于1.5^(L-1)x。L越大,y帽越大,呈指数型增长,也称爆炸式增长。相反,如果权重矩阵W的元素都小于1,如0.5,L越大,y帽正比于0.5^L,呈指数型减小,称为数值消失。当各层权重W都大于1或者小于1,当层数很大时,出现数值爆炸或消失。

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

《1.11神经网络的权重初始化》Weight Initialization for Deep Networks

上节课,我们学习了深度神经网络如何产生梯度消失和梯度爆炸问题,最终针对该问题,我们想出了一个不完整的解决方案,通过例子来理解。先看只有一个神经元的情况,单个神经元可能有4个输入特征,从x1到x4,如下图:

经过a=g(z)处理,最终得到y帽。

因为b=0,先忽略b,为了预防z值过大或者过小,你可以看到n越大,你希望w_i越小,最合理的方法是设置为w_i = 1/n,n表示神经元的输入特征数量。设置第l层权重矩阵为:

其中,n^[l-1]是第l-1层神经元的数量。

相应的python伪代码为:

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

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

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

这里,Andrew用的是n^[l-1],因为本例中,逻辑回归的特征是不变的。但一般情况下第l层上的每个神经元都有个n^[l-1]输入。如果激活函数的输入特征被零均值和标准方差化,方差是1,也会调整到相似范围,这就没解决问题(梯度消失和爆炸问题)。但它确实降低了梯度消失和爆炸问题,因为它给权重矩阵W设置了合理值,你也知道,它不能比1大很多,也不能比1小很多,所以梯度没有爆炸或消失过快。

刚刚提到的函数是Relu激活函数,一篇由Herd等人撰写的论文曾介绍过。对于几个其它变体函数,如tanh激活函数,它是1/n^[l-1],被称为Xavier初始化。Yoshua Bengio和他的同事还提出另一种方法,你可能在一些论文中看到过,它们使用的是公式:

代码如下:

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

总之,如果激活函数是tanh,一般选择上面的初始化方法,方差为1/n。如果激活函数是ReLU,权重w的初始化一般令其方差为2/n。

实际上,Andrew认为所有这些公式只是给你一个起点,它们给出初始化权重矩阵的方差的默认值,至于选择哪种初始化方法因人而异。如果你想添加方差,方差参数则是另一个你需要调整的超级参数,可以给公式np.sqrt(2/n[l-1]) 添加一个乘数参数,调优作为超级参数激增(hyperparameter surge)一份子的乘子参数(multiplier)。有时调优该超级参数效果一般,Andrew通常把它的优先级放得比较低。至于选择哪种初始化方法因人而异,可以根据不同的激活函数选择不同方法。另外,我们可以对这些初始化方法中设置某些参数,作为超参数,通过验证集进行验证,得到最优参数,来优化神经网络。

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

《1.12梯度的数值逼近》Numerical approximation of gradients

在实施backprop时,有一个测试叫做梯度检验(gradient checking),它的作用是确保backprop正确实施。因为有时候,你虽然写下了这些方程式,却不能100%确定,执行backprop的所有细节都是正确的。为了逐渐实现梯度检验,我们首先说说如何计算梯度的数值逼近。(Andrew通过计算单边误差和双边误差,引入导数的定义,如果导数部分很熟悉,可以跳过。)

导数的官方定义是针对值很小的ε(无限趋近于0),

右侧极限。

《1.13梯度检验》Gradient checking

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

假设你的网络中有下列参数,梯度检验首先要做的是W^[1],b^[1],...,W^[L],b^[L]这些矩阵构造成一维向量,然后将这些一维向量组合起来构成一个更大的一维向量θ。这样cost function J(W^[1],b^[1],...,W^[L],b^[L])就可以表示成J(θ)。然后将反向传播过程通过梯度下降算法得到的dW^[1],db^[1],...,dW^[L],db^[L] 按照一样的顺序构造成一个一维向量 dθ。 dθ的维度与 θ一致。具体分析如下图:

为了实施梯度检验,你要做的就是循环执行,从而对每个i也就是对每个θ组成元素计算的值,这里使用双边误差,也就是:

从上节课中我们了解到这个值应该逼近dθ[i]=偏J/偏θ_i(成本函数J的偏导数),你需要对i的每个值都执行这个运算,得到两个向量,验证这些向量是否彼此接近。

如何定义两个向量是否真的接近彼此?计算两个向量的欧式距离

分母只是用于预防这些向量太小或太大,分母使得这个方程式变成比率,我们执行这个方程式,ε可能为10^-7,如果你发现上面方程式得到的值为或更小,这就很好,这就意味着导数逼近很有可能是正确的,它的值非常小。如果这个值在10^-5范围内,就要小心了,表明梯度计算可能有问题,需要再次检查这个向量的所有项,确保没有一项误差过大,可能这里有bug。如果这个值为10^-3,或者更大,这时应该仔细检查所有θ项,经过一些调试,最终结果会是非常小的值。

《1.14关于梯度检验实现的标记》 Gradient Checking Implementation Notes

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

首先,不要在训练中使用梯度检验,它只用于调试。为了实施梯度下降,你必须使用W和b反向传播来计算dθ,只有调试的时候才会计算它。

第二点,如果算法的梯度检验失败,要检查所有项,检查每一项,并试着找出bug。注意θ的各项与b和w的各项都是一一对应的。

第三点,在实施梯度检验时,如果使用正则化,请注意正则项。

第四点,梯度检验不能与dropout同时使用,因为每次迭代过程中,dropout会随机消除隐藏层单元的不同子集,难以计算dropout在梯度下降上的代价函数J。

最后一点,也是比较微妙的一点,现实中几乎不会出现这种情况,随机初始化时运行梯度检查。

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

Summary

本周课主要讲解了深度学习的实践方面的内容。主要包括构建数据集,引入偏差和方差评估神经网络拟合情况,介绍正则化、dropout等解决高方差(过拟合)问题,对神经网络进行权重初始化来解决梯度消失和梯度爆炸,以及使用梯度检验方法来调试bug。

说明:记录学习笔记,如果错误欢迎指正!转载请联系我。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。