AI基础:优化算法
本文来源于吴恩达老师的深度学习课程[1]和深度学习课程[2]笔记部分。
作者:黄海广[3]
备注:笔记和作业(含数据、原始作业文件)、视频都在 github[4]中下载。
导语
在学习机器学习的过程中我们发现,大部分的机器学习算法的本质都是建立优化模型,通过最优化方法对目标函数(或损失函数)进行优化,从而训练出最好的模型,梯度下降是最基本的优化算法。本集对梯度下降和其他优化算法进行讲解。
目前我在编写AI基础系列,目前已经发布:
AI基础:数据可视化简易入门(matplotlib和seaborn)
后续持续更新
一 梯度下降(Gradient Descent)
1.1 梯度下降概述
梯度下降是一个用来求函数最小值的算法,我们将使用梯度下降算法来求出代价函数 的最小值。
梯度下降背后的思想是:开始时我们随机选择一个参数的组合,计算代价函数,然后我们寻找下一个能让代价函数值下降最多的参数组合。我们持续这么做直到找到一个局部最小值(local minimum),因为我们并没有尝试完所有的参数组合,所以不能确定我们得到的局部最小值是否便是全局最小值(global minimum),选择不同的初始参数组合,可能会找到不同的局部最小值。
想象一下你正站立在山的这一点上,站立在你想象的公园这座红色山上,在梯度下降算法中,我们要做的就是旋转360度,看看我们的周围,并问自己要在某个方向上,用小碎步尽快下山。这些小碎步需要朝什么方向?如果我们站在山坡上的这一点,你看一下周围,你会发现最佳的下山方向,你再看看周围,然后再一次想想,我应该从什么方向迈着小碎步下山?然后你按照自己的判断又迈出一步,重复上面的步骤,从这个新的点,你环顾四周,并决定从什么方向将会最快下山,然后又迈进了一小步,并依此类推,直到你接近局部最低点的位置。
1.2 批量梯度下降
批量梯度下降(batch gradient descent)算法的公式为:
其中是学习率(learning rate),它决定了我们沿着能让代价函数下降程度最大的方向向下迈出的步子有多大,在批量梯度下降中,我们每一次都同时让所有的参数减去学习速率乘以代价函数的导数。
在梯度下降算法中,还有一个更微妙的问题,梯度下降中,我们要更新和 ,当 和时,会产生更新,所以你将更新和。实现梯度下降算法的微妙之处是,在这个表达式中,如果你要更新这个等式,你需要同时更新和,我的意思是在这个等式中,我们要这样更新:
:= ,并更新:= 。
实现方法是:你应该计算公式右边的部分,通过那一部分计算出和的值,然后同时更新和。
进一步阐述这个过程:
在梯度下降算法中,这是正确实现同时更新的方法。这里不打算解释为什么你需要同时更新,同时更新是梯度下降中的一种常用方法。我们之后会讲到,同步更新是更自然的实现方法。当人们谈到梯度下降时,他们的意思就是同步更新。
如果你已经修过微积分课程,如果你熟悉偏导数和导数,这其实就是这个微分项:
,。
1.3 梯度下降的直观理解
我们更深入研究一下,更直观地感受一下这个算法是做什么的,以及梯度下降算法的更新过程有什么意义。梯度下降算法如下:
描述:对赋值,使得按梯度下降最快方向进行,一直迭代下去,最终得到局部最小值。其中是学习率(learning rate),它决定了我们沿着能让代价函数下降程度最大的方向向下迈出的步子有多大。
对于这个问题,求导的目的,基本上可以说取这个红点的切线,就是这样一条红色的直线,刚好与函数相切于这一点,让我们看看这条红色直线的斜率,就是这条刚好与函数曲线相切的这条直线,这条直线的斜率正好是这个三角形的高度除以这个水平长度,现在,这条线有一个正斜率,也就是说它有正导数,因此,我得到的新的,更新后等于减去一个正数乘以。
这就是我梯度下降法的更新规则:
让我们来看看如果太小或太大会出现什么情况:
如果太小了,即我的学习速率太小,结果就是只能这样像小宝宝一样一点点地挪动,去努力接近最低点,这样就需要很多步才能到达最低点,所以如果太小的话,可能会很慢,因为它会一点点挪动,它会需要很多步才能到达全局最低点。
如果太大,那么梯度下降法可能会越过最低点,甚至可能无法收敛,下一次迭代又移动了一大步,越过一次,又越过一次,一次次越过最低点,直到你发现实际上离最低点越来越远,所以,如果太大,它会导致无法收敛,甚至发散。
现在,我还有一个问题,当我第一次学习这个地方时,我花了很长一段时间才理解这个问题,如果我们预先把放在一个局部的最低点,你认为下一步梯度下降法会怎样工作?
假设你将初始化在局部最低点,在这儿,它已经在一个局部的最优处或局部最低点。结果是局部最优点的导数将等于零,因为它是那条切线的斜率。这意味着你已经在局部最优点,它使得不再改变,也就是新的等于原来的,因此,如果你的参数已经处于局部最低点,那么梯度下降法更新其实什么都没做,它不会改变参数的值。这也解释了为什么即使学习速率保持不变时,梯度下降也可以收敛到局部最低点。
我们来看一个例子,这是代价函数。
我想找到它的最小值,首先初始化我的梯度下降算法,在那个品红色的点初始化,如果我更新一步梯度下降,也许它会带我到这个点,因为这个点的导数是相当陡的。现在,在这个绿色的点,如果我再更新一步,你会发现我的导数,也即斜率,是没那么陡的。随着我接近最低点,我的导数越来越接近零,所以,梯度下降一步后,新的导数会变小一点点。然后我想再梯度下降一步,在这个绿点,我自然会用一个稍微跟刚才在那个品红点时比,再小一点的一步,到了新的红色点,更接近全局最低点了,因此这点的导数会比在绿点时更小。所以,我再进行一步梯度下降时,我的导数项是更小的,更新的幅度就会更小。所以随着梯度下降法的运行,你移动的幅度会自动变得越来越小,直到最终移动幅度非常小,你会发现,已经收敛到局部极小值。
回顾一下,在梯度下降法中,当我们接近局部最低点时,梯度下降法会自动采取更小的幅度,这是因为当我们接近局部最低点时,很显然在局部最低时导数等于零,所以当我们接近局部最低时,导数值会自动变得越来越小,所以梯度下降将自动采取较小的幅度,这就是梯度下降的做法。所以实际上没有必要再另外减小。
这就是梯度下降算法,你可以用它来最小化任何代价函数,不只是线性回归中的代价函数。
1.4 随机梯度下降法
如果我们一定需要一个大规模的训练集,我们可以尝试使用随机梯度下降法来代替批量梯度下降法。
在随机梯度下降法中,我们定义代价函数为一个单一训练实例的代价:
随机梯度下降算法为:首先对训练集随机“洗牌”,然后:Repeat (usually anywhere between1-10){
for {
(for )
} }
随机梯度下降算法在每一次计算之后便更新参数 ,而不需要首先将所有的训练集求和,在梯度下降算法还没有完成一次迭代时,随机梯度下降算法便已经走出了很远。但是这样的算法存在的问题是,不是每一步都是朝着”正确”的方向迈出的。因此算法虽然会逐渐走向全局最小值的位置,但是可能无法站到那个最小值的那一点,而是在最小值点附近徘徊。
1.5 小批量梯度下降
小批量梯度下降算法是介于批量梯度下降算法和随机梯度下降算法之间的算法,每计算常数次训练实例,便更新一次参数 。
Repeat {
for {
(for )
} }
通常我们会令 在 2-100 之间。这样做的好处在于,我们可以用向量化的方式来循环 个训练实例,如果我们用的线性代数函数库比较好,能够支持平行处理,那么算法的总体表现将不受影响(与随机梯度下降相同)。
二、优化算法 (Optimization algorithms)
2.1 Mini-batch 梯度下降(Mini-batch gradient descent)
本周将学习优化算法,这能让你的神经网络运行得更快。机器学习的应用是一个高度依赖经验的过程,伴随着大量迭代的过程,你需要训练诸多模型,才能找到合适的那一个,所以,优化算法能够帮助你快速训练模型。
其中一个难点在于,深度学习没有在大数据领域发挥最大的效果,我们可以利用一个巨大的数据集来训练神经网络,而在巨大的数据集基础上进行训练速度很慢。因此,你会发现,使用快速的优化算法,使用好用的优化算法能够大大提高你和团队的效率,那么,我们首先来谈谈mini-batch梯度下降法。
你之前学过,向量化能够让你有效地对所有个样本进行计算,允许你处理整个训练集,而无需某个明确的公式。所以我们要把训练样本放大巨大的矩阵当中去,,也是如此,,所以的维数是,的维数是,向量化能够让你相对较快地处理所有个样本。如果很大的话,处理速度仍然缓慢。比如说,如果是500万或5000万或者更大的一个数,在对整个训练集执行梯度下降法时,你要做的是,你必须处理整个训练集,然后才能进行一步梯度下降法,然后你需要再重新处理500万个训练样本,才能进行下一步梯度下降法。所以如果你在处理完整个500万个样本的训练集之前,先让梯度下降法处理一部分,你的算法速度会更快,准确地说,这是你可以做的一些事情。
你可以把训练集分割为小一点的子集训练,这些子集被取名为mini-batch,假设每一个子集中只有1000个样本,那么把其中的到取出来,将其称为第一个子训练集,也叫做mini-batch,然后你再取出接下来的1000个样本,从到,然后再取1000个样本,以此类推。
接下来我要说一个新的符号,把到称为,到称为,如果你的训练样本一共有500万个,每个mini-batch都有1000个样本,也就是说,你有5000个mini-batch,因为5000乘以1000就是5000万。
你共有5000个mini-batch,所以最后得到是
对也要进行相同处理,你也要相应地拆分的训练集,所以这是,然后从到,这个叫,一直到。
mini-batch的数量组成了和,这就是1000个训练样本,包含相应的输入输出对。
在继续课程之前,先确定一下我的符号,之前我们使用了上角小括号表示训练集里的值,所以是第个训练样本。我们用了上角中括号来表示神经网络的层数,表示神经网络中第层的值,我们现在引入了大括号来代表不同的mini-batch,所以我们有和,检查一下自己是否理解无误。
和的维数:如果是一个有1000个样本的训练集,或者说是1000个样本的值,所以维数应该是,的维数应该是,以此类推。因此所有的子集维数都是,而这些()的维数都是。
解释一下这个算法的名称,batch梯度下降法指的是我们之前讲过的梯度下降法算法,就是同时处理整个训练集,这个名字就是来源于能够同时看到整个batch训练集的样本被处理,这个名字不怎么样,但就是这样叫它。
相比之下,mini-batch梯度下降法,指的是我们在下一张幻灯片中会讲到的算法,你每次同时处理的单个的mini-batch 和,而不是同时处理全部的和训练集。
那么究竟mini-batch梯度下降法的原理是什么?在训练集上运行mini-batch梯度下降法,你运行for t=1……5000
,因为我们有5000个各有1000个样本的组,在for循环里你要做得基本就是对和执行一步梯度下降法。假设你有一个拥有1000个样本的训练集,而且假设你已经很熟悉一次性处理完的方法,你要用向量化去几乎同时处理1000个样本。
首先对输入也就是,执行前向传播,然后执行,之前我们这里只有,但是现在你正在处理整个训练集,你在处理第一个mini-batch,在处理mini-batch时它变成了,即,然后执行,之所以用大写的是因为这是一个向量内涵,以此类推,直到,这就是你的预测值。注意这里你需要用到一个向量化的执行命令,这个向量化的执行命令,一次性处理1000个而不是500万个样本。接下来你要计算损失成本函数,因为子集规模是1000,,说明一下,这()指的是来自于mini-batch和中的样本。
如果你用到了正则化,你也可以使用正则化的术语,,因为这是一个mini-batch的损失,所以我将损失记为上角标,放在大括号里()。
你也会注意到,我们做的一切似曾相识,其实跟之前我们执行梯度下降法如出一辙,除了你现在的对象不是,,而是和。接下来,你执行反向传播来计算的梯度,你只是使用和,然后你更新加权值,实际上是,更新为,对做相同处理,。这是使用mini-batch梯度下降法训练样本的一步,我写下的代码也可被称为进行“一代”(1 epoch)的训练。一代这个词意味着只是一次遍历了训练集。
使用batch梯度下降法,一次遍历训练集只能让你做一个梯度下降,使用mini-batch梯度下降法,一次遍历训练集,能让你做5000个梯度下降。当然正常来说你想要多次遍历训练集,还需要为另一个while循环设置另一个for循环。所以你可以一直处理遍历训练集,直到最后你能收敛到一个合适的精度。
如果你有一个丢失的训练集,mini-batch梯度下降法比batch梯度下降法运行地更快,所以几乎每个研习深度学习的人在训练巨大的数据集时都会用到,下一个视频中,我们将进一步深度讨论mini-batch梯度下降法,你也会因此更好地理解它的作用和原理。
2.2 理解mini-batch梯度下降法(Understanding mini-batch gradient descent)
在上周视频中,你知道了如何利用mini-batch梯度下降法来开始处理训练集和开始梯度下降,即使你只处理了部分训练集,即使你是第一次处理,本视频中,我们将进一步学习如何执行梯度下降法,更好地理解其作用和原理。
使用batch梯度下降法时,每次迭代你都需要历遍整个训练集,可以预期每次迭代成本都会下降,所以如果成本函数是迭代次数的一个函数,它应该会随着每次迭代而减少,如果在某次迭代中增加了,那肯定出了问题,也许你的学习率太大。
使用mini-batch梯度下降法,如果你作出成本函数在整个过程中的图,则并不是每次迭代都是下降的,特别是在每次迭代中,你要处理的是和,如果要作出成本函数的图,而只和,有关,也就是每次迭代下你都在训练不同的样本集或者说训练不同的mini-batch,如果你要作出成本函数的图,你很可能会看到这样的结果,走向朝下,但有更多的噪声,所以如果你作出的图,因为在训练mini-batch梯度下降法时,会经过多代,你可能会看到这样的曲线。没有每次迭代都下降是不要紧的,但走势应该向下,噪声产生的原因在于也许和是比较容易计算的mini-batch,因此成本会低一些。不过也许出于偶然,和是比较难运算的mini-batch,或许你需要一些残缺的样本,这样一来,成本会更高一些,所以才会出现这些摆动,因为你是在运行mini-batch梯度下降法作出成本函数图。
你需要决定的变量之一是mini-batch的大小,就是训练集的大小,极端情况下,如果mini-batch的大小等于,其实就是batch梯度下降法,在这种极端情况下,你就有了mini-batch 和,并且该mini-batch等于整个训练集,所以把mini-batch大小设为可以得到batch梯度下降法。
另一个极端情况,假设mini-batch大小为1,就有了新的算法,叫做随机梯度下降法,每个样本都是独立的mini-batch,当你看第一个mini-batch,也就是和,如果mini-batch大小为1,它就是你的第一个训练样本,这就是你的第一个训练样本。接着再看第二个mini-batch,也就是第二个训练样本,采取梯度下降步骤,然后是第三个训练样本,以此类推,一次只处理一个。
看在两种极端下成本函数的优化情况,如果这是你想要最小化的成本函数的轮廓,最小值在那里,batch梯度下降法从某处开始,相对噪声低些,幅度也大一些,你可以继续找最小值。
相反,在随机梯度下降法中,从某一点开始,我们重新选取一个起始点,每次迭代,你只对一个样本进行梯度下降,大部分时候你向着全局最小值靠近,有时候你会远离最小值,因为那个样本恰好给你指的方向不对,因此随机梯度下降法是有很多噪声的,平均来看,它最终会靠近最小值,不过有时候也会方向错误,因为随机梯度下降法永远不会收敛,而是会一直在最小值附近波动,但它并不会在达到最小值并停留在此。
实际上你选择的mini-batch大小在二者之间,大小在1和之间,而1太小了,太大了,原因在于如果使用batch梯度下降法,mini-batch的大小为,每个迭代需要处理大量训练样本,该算法的主要弊端在于特别是在训练样本数量巨大的时候,单次迭代耗时太长。如果训练样本不大,batch梯度下降法运行地很好。
相反,如果使用随机梯度下降法,如果你只要处理一个样本,那这个方法很好,这样做没有问题,通过减小学习率,噪声会被改善或有所减小,但随机梯度下降法的一大缺点是,你会失去所有向量化带给你的加速,因为一次性只处理了一个训练样本,这样效率过于低下,所以实践中最好选择不大不小的mini-batch尺寸,实际上学习率达到最快。你会发现两个好处,一方面,你得到了大量向量化,上个视频中我们用过的例子中,如果mini-batch大小为1000个样本,你就可以对1000个样本向量化,比你一次性处理多个样本快得多。另一方面,你不需要等待整个训练集被处理完就可以开始进行后续工作,再用一下上个视频的数字,每次训练集允许我们采取5000个梯度下降步骤,所以实际上一些位于中间的mini-batch大小效果最好。
用mini-batch梯度下降法,我们从这里开始,一次迭代这样做,两次,三次,四次,它不会总朝向最小值靠近,但它比随机梯度下降要更持续地靠近最小值的方向,它也不一定在很小的范围内收敛或者波动,如果出现这个问题,可以慢慢减少学习率,我们在下个视频会讲到学习率衰减,也就是如何减小学习率。
如果mini-batch大小既不是1也不是,应该取中间值,那应该怎么选择呢?其实是有指导原则的。
首先,如果训练集较小,直接使用batch梯度下降法,样本集较小就没必要使用mini-batch梯度下降法,你可以快速处理整个训练集,所以使用batch梯度下降法也很好,这里的少是说小于2000个样本,这样比较适合使用batch梯度下降法。不然,样本数目较大的话,一般的mini-batch大小为64到512,考虑到电脑内存设置和使用的方式,如果mini-batch大小是2的次方,代码会运行地快一些,64就是2的6次方,以此类推,128是2的7次方,256是2的8次方,512是2的9次方。所以我经常把mini-batch大小设成2的次方。在上一个视频里,我的mini-batch大小设为了1000,建议你可以试一下1024,也就是2的10次方。也有mini-batch的大小为1024,不过比较少见,64到512的mini-batch比较常见。
最后需要注意的是在你的mini-batch中,要确保和要符合CPU/GPU内存,取决于你的应用方向以及训练集的大小。如果你处理的mini-batch和CPU/GPU内存不相符,不管你用什么方法处理数据,你会注意到算法的表现急转直下变得惨不忍睹,所以我希望你对一般人们使用的mini-batch大小有一个直观了解。事实上mini-batch大小是另一个重要的变量,你需要做一个快速尝试,才能找到能够最有效地减少成本函数的那个,我一般会尝试几个不同的值,几个不同的2次方,然后看能否找到一个让梯度下降优化算法最高效的大小。希望这些能够指导你如何开始找到这一数值。
你学会了如何执行mini-batch梯度下降,令算法运行得更快,特别是在训练样本数目较大的情况下。不过还有个更高效的算法,比梯度下降法和mini-batch梯度下降法都要高效的多,我们在接下来的视频中将为大家一一讲解。
2.3 指数加权平均数(Exponentially weighted averages)
我想向你展示几个优化算法,它们比梯度下降法快,要理解这些算法,你需要用到指数加权平均,在统计中也叫做指数加权移动平均,我们首先讲这个,然后再来讲更复杂的优化算法。
虽然现在我生活在美国,实际上我生于英国伦敦。比如我这儿有去年伦敦的每日温度,所以1月1号,温度是40华氏度,相当于4摄氏度。我知道世界上大部分地区使用摄氏度,但是美国使用华氏度。在1月2号是9摄氏度等等。在年中的时候,一年365天,年中就是说,大概180天的样子,也就是5月末,温度是60华氏度,也就是15摄氏度等等。夏季温度转暖,然后冬季降温。
你用数据作图,可以得到以下结果,起始日在1月份,这里是夏季初,这里是年末,相当于12月末。
这里是1月1号,年中接近夏季的时候,随后就是年末的数据,看起来有些杂乱,如果要计算趋势的话,也就是温度的局部平均值,或者说移动平均值。
你要做的是,首先使,每天,需要使用0.9的加权数之前的数值加上当日温度的0.1倍,即,所以这里是第一天的温度值。
第二天,又可以获得一个加权平均数,0.9乘以之前的值加上当日的温度0.1倍,即,以此类推。
第二天值加上第三日数据的0.1,如此往下。大体公式就是某天的等于前一天值的0.9加上当日温度的0.1。
如此计算,然后用红线作图的话,便得到这样的结果。
你得到了移动平均值,每日温度的指数加权平均值。
看一下上一张幻灯片里的公式,,我们把0.9这个常数变成,将之前的0.1变成,即
由于以后我们要考虑的原因,在计算时可视大概是的每日温度,如果是0.9,你会想,这是十天的平均值,也就是红线部分。
我们来试试别的,将设置为接近1的一个值,比如0.98,计算,这就是粗略平均了一下,过去50天的温度,这时作图可以得到绿线。
这个高值要注意几点,你得到的曲线要平坦一些,原因在于你多平均了几天的温度,所以这个曲线,波动更小,更加平坦,缺点是曲线进一步右移,因为现在平均的温度值更多,要平均更多的值,指数加权平均公式在温度变化时,适应地更缓慢一些,所以会出现一定延迟,因为当,相当于给前一天的值加了太多权重,只有0.02的权重给了当日的值,所以温度变化时,温度上下起伏,当 较大时,指数加权平均值适应地更缓慢一些。
我们可以再换一个值试一试,如果是另一个极端值,比如说0.5,根据右边的公式(),这是平均了两天的温度。
作图运行后得到黄线。
由于仅平均了两天的温度,平均的数据太少,所以得到的曲线有更多的噪声,有可能出现异常值,但是这个曲线能够更快适应温度变化。
所以指数加权平均数经常被使用,再说一次,它在统计学中被称为指数加权移动平均值,我们就简称为指数加权平均数。通过调整这个参数(),或者说后面的算法学习,你会发现这是一个很重要的参数,可以取得稍微不同的效果,往往中间有某个值效果最好,为中间值时得到的红色曲线,比起绿线和黄线更好地平均了温度。
现在你知道计算指数加权平均数的基本原理,下一个视频中,我们再聊聊它的本质作用。
2.4 理解指数加权平均数(Understanding exponentially weighted averages)
上个视频中,我们讲到了指数加权平均数,这是几个优化算法中的关键一环,而这几个优化算法能帮助你训练神经网络。本视频中,我希望进一步探讨算法的本质作用。
回忆一下这个计算指数加权平均数的关键方程。
的时候,得到的结果是红线,如果它更接近于1,比如0.98,结果就是绿线,如果小一点,如果是0.5,结果就是黄线。
我们进一步地分析,来理解如何计算出每日温度的平均值。
同样的公式,
使,写下相应的几个公式,所以在执行的时候,从0到1到2到3,的值在不断增加,为了更好地分析,我写的时候使得的值不断减小,然后继续往下写。
首先看第一个公式,理解是什么?我们调换一下这两项(),。
那么是什么?我们就代入这个公式(),所以:
。
那么是什么?你可以用这个公式计算(),把公式代进去,所以:
。
以此类推,如果你把这些括号都展开,
所以这是一个加和并平均,100号数据,也就是当日温度。我们分析的组成,也就是在一年第100天计算的数据,但是这个是总和,包括100号数据,99号数据,97号数据等等。画图的一个办法是,假设我们有一些日期的温度,所以这是数据,这是,所以100号数据有个数值,99号数据有个数值,98号数据等等,为100,99,98等等,这就是数日的温度数值。
然后我们构建一个指数衰减函数,从0.1开始,到,到,以此类推,所以就有了这个指数衰减函数。
计算是通过,把两个函数对应的元素,然后求和,用这个数值100号数据值乘以0.1,99号数据值乘以0.1乘以,这是第二项,以此类推,所以选取的是每日温度,将其与指数衰减函数相乘,然后求和,就得到了。
结果是,稍后我们详细讲解,不过所有的这些系数(),相加起来为1或者逼近1,我们称之为偏差修正,下个视频会涉及。
最后也许你会问,到底需要平均多少天的温度。实际上大约为0.35,这大约是,e是自然算法的基础之一。大体上说,如果有,在这个例子中,,所以,约等于,大约是0.34,0.35,换句话说,10天后,曲线的高度下降到,相当于在峰值的。
又因此当的时候,我们说仿佛你在计算一个指数加权平均数,只关注了过去10天的温度,因为10天后,权重下降到不到当日权重的三分之一。
相反,如果,那么0.98需要多少次方才能达到这么小的数值?大约等于,所以前50天这个数值比大,数值会快速衰减,所以本质上这是一个下降幅度很大的函数,你可以看作平均了50天的温度。因为在例子中,要代入等式的左边,,所以为50,我们由此得到公式,我们平均了大约天的温度,这里代替了,也就是说根据一些常数,你能大概知道能够平均多少日的温度,不过这只是思考的大致方向,并不是正式的数学证明。
最后讲讲如何在实际中执行,还记得吗?我们一开始将设置为0,然后计算第一天,然后,以此类推。
现在解释一下算法,可以将,,等等写成明确的变量,不过在实际中执行的话,你要做的是,一开始将初始化为0,然后在第一天使,然后第二天,更新值,,以此类推,有些人会把加下标,来表示是用来计算数据的指数加权平均数。
再说一次,但是换个说法,,然后每一天,拿到第天的数据,把更新为。
指数加权平均数公式的好处之一在于,它占用极少内存,电脑内存中只占用一行数字而已,然后把最新数据代入公式,不断覆盖就可以了,正因为这个原因,其效率,它基本上只占用一行代码,计算指数加权平均数也只占用单行数字的存储和内存,当然它并不是最好的,也不是最精准的计算平均数的方法。如果你要计算移动窗,你直接算出过去10天的总和,过去50天的总和,除以10和50就好,如此往往会得到更好的估测。但缺点是,如果保存所有最近的温度数据,和过去10天的总和,必须占用更多的内存,执行更加复杂,计算成本也更加高昂。
所以在接下来的视频中,我们会计算多个变量的平均值,从计算和内存效率来说,这是一个有效的方法,所以在机器学习中会经常使用,更不用说只要一行代码,这也是一个优势。
现在你学会了计算指数加权平均数,你还需要知道一个专业概念,叫做偏差修正,下一个视频我们会讲到它,接着你就可以用它构建更好的优化算法,而不是简单直接的梯度下降法。
2.5 指数加权平均的偏差修正(Bias correction in exponentially weighted averages)
你学过了如何计算指数加权平均数,有一个技术名词叫做偏差修正,可以让平均数运算更加准确,来看看它是怎么运行的。
在上一个视频中,这个(红色)曲线对应的值为0.9,这个(绿色)曲线对应的=0.98,如果你执行写在这里的公式,在等于0.98的时候,得到的并不是绿色曲线,而是紫色曲线,你可以注意到紫色曲线的起点较低,我们来看看怎么处理。
计算移动平均数的时候,初始化,,但是,所以这部分没有了(),所以,所以如果一天温度是40华氏度,那么,因此得到的值会小很多,所以第一天温度的估测不准。
,如果代入,然后相乘,所以,假设和都是正数,计算后要远小于和,所以不能很好估测出这一年前两天的温度。
有个办法可以修改这一估测,让估测变得更好,更准确,特别是在估测初期,也就是不用,而是用,t就是现在的天数。举个具体例子,当时,,因此对第二天温度的估测变成了,也就是和的加权平均数,并去除了偏差。你会发现随着增加,接近于0,所以当很大的时候,偏差修正几乎没有作用,因此当较大的时候,紫线基本和绿线重合了。不过在开始学习阶段,你才开始预测热身练习,偏差修正可以帮助你更好预测温度,偏差修正可以帮助你使结果从紫线变成绿线。
在机器学习中,在计算指数加权平均数的大部分时候,大家不在乎执行偏差修正,因为大部分人宁愿熬过初始时期,拿到具有偏差的估测,然后继续计算下去。如果你关心初始时期的偏差,在刚开始计算指数加权移动平均数的时候,偏差修正能帮助你在早期获取更好的估测。
所以你学会了计算指数加权移动平均数,我们接着用它来构建更好的优化算法吧!
2.6 动量梯度下降法(Gradient descent with Momentum)
还有一种算法叫做Momentum,或者叫做动量梯度下降法,运行速度几乎总是快于标准的梯度下降算法,简而言之,基本的想法就是计算梯度的指数加权平均数,并利用该梯度更新你的权重,在本视频中,我们呢要一起拆解单句描述,看看你到底如何计算。
例如,如果你要优化成本函数,函数形状如图,红点代表最小值的位置,假设你从这里(蓝色点)开始梯度下降法,如果进行梯度下降法的一次迭代,无论是batch或mini-batch下降法,也许会指向这里,现在在椭圆的另一边,计算下一步梯度下降,结果或许如此,然后再计算一步,再一步,计算下去,你会发现梯度下降法要很多计算步骤对吧?
慢慢摆动到最小值,这种上下波动减慢了梯度下降法的速度,你就无法使用更大的学习率,如果你要用较大的学习率(紫色箭头),结果可能会偏离函数的范围,为了避免摆动过大,你要用一个较小的学习率。
另一个看待问题的角度是,在纵轴上,你希望学习慢一点,因为你不想要这些摆动,但是在横轴上,你希望加快学习,你希望快速从左向右移,移向最小值,移向红点。所以使用动量梯度下降法,你需要做的是,在每次迭代中,确切来说在第次迭代的过程中,你会计算微分,,我会省略上标,你用现有的mini-batch计算,。如果你用batch梯度下降法,现在的mini-batch就是全部的batch,对于batch梯度下降法的效果是一样的。如果现有的mini-batch就是整个训练集,效果也不错,你要做的是计算,这跟我们之前的计算相似,也就是,的移动平均数,接着同样地计算,,然后重新赋值权重,,同样,这样就可以减缓梯度下降的幅度。
例如,在上几个导数中,你会发现这些纵轴上的摆动平均值接近于零,所以在纵轴方向,你希望放慢一点,平均过程中,正负数相互抵消,所以平均值接近于零。但在横轴方向,所有的微分都指向横轴方向,因此横轴方向的平均值仍然较大,因此用算法几次迭代后,你发现动量梯度下降法,最终纵轴方向的摆动变小了,横轴方向运动更快,因此你的算法走了一条更加直接的路径,在抵达最小值的路上减少了摆动。
动量梯度下降法的一个本质,这对有些人而不是所有人有效,就是如果你要最小化碗状函数,这是碗的形状,我画的不太好。
它们能够最小化碗状函数,这些微分项,想象它们为你从山上往下滚的一个球,提供了加速度,Momentum项相当于速度。
想象你有一个碗,你拿一个球,微分项给了这个球一个加速度,此时球正向山下滚,球因为加速度越滚越快,而因为 稍小于1,表现出一些摩擦力,所以球不会无限加速下去,所以不像梯度下降法,每一步都独立于之前的步骤,你的球可以向下滚,获得动量,可以从碗向下加速获得动量。我发现这个球从碗滚下的比喻,物理能力强的人接受得比较好,但不是所有人都能接受,如果球从碗中滚下这个比喻,你理解不了,别担心。
最后我们来看具体如何计算,算法在此。
所以你有两个超参数,学习率以及参数,控制着指数加权平均数。最常用的值是0.9,我们之前平均了过去十天的温度,所以现在平均了前十次迭代的梯度。实际上为0.9时,效果不错,你可以尝试不同的值,可以做一些超参数的研究,不过0.9是很棒的鲁棒数。那么关于偏差修正,所以你要拿和除以,实际上人们不这么做,因为10次迭代之后,因为你的移动平均已经过了初始阶段。实际中,在使用梯度下降法或动量梯度下降法时,人们不会受到偏差修正的困扰。当然初始值是0,要注意到这是和拥有相同维数的零矩阵,也就是跟拥有相同的维数,的初始值也是向量零,所以和拥有相同的维数,也就是和是同一维数。
最后要说一点,如果你查阅了动量梯度下降法相关资料,你经常会看到一个被删除了的专业词汇,被删除了,最后得到的是。用紫色版本的结果就是,所以缩小了倍,相当于乘以,所以你要用梯度下降最新值的话,要根据相应变化。实际上,二者效果都不错,只会影响到学习率的最佳值。我觉得这个公式用起来没有那么自然,因为有一个影响,如果你最后要调整超参数,就会影响到和,你也许还要修改学习率,所以我更喜欢左边的公式,而不是删去了的这个公式,所以我更倾向于使用左边的公式,也就是有的这个公式,但是两个公式都将设置为0.9,是超参数的常见选择,只是在这两个公式中,学习率的调整会有所不同。
所以这就是动量梯度下降法,这个算法肯定要好于没有Momentum的梯度下降算法,我们还可以做别的事情来加快学习算法,我们将在接下来的视频中探讨这些问题。
2.7 RMSprop
你们知道了动量(Momentum)可以加快梯度下降,还有一个叫做RMSprop的算法,全称是root mean square prop算法,它也可以加速梯度下降,我们来看看它是如何运作的。
回忆一下我们之前的例子,如果你执行梯度下降,虽然横轴方向正在推进,但纵轴方向会有大幅度摆动,为了分析这个例子,假设纵轴代表参数,横轴代表参数,可能有,或者其它重要的参数,为了便于理解,被称为和。
所以,你想减缓方向的学习,即纵轴方向,同时加快,至少不是减缓横轴方向的学习,RMSprop算法可以实现这一点。
在第次迭代中,该算法会照常计算当下mini-batch的微分,,所以我会保留这个指数加权平均数,我们用到新符号,而不是,因此,澄清一下,这个平方的操作是针对这一整个符号的,这样做能够保留微分平方的加权平均数,同样,再说一次,平方是针对整个符号的操作。
接着RMSprop会这样更新参数值,,,我们来理解一下其原理。记得在横轴方向或者在例子中的方向,我们希望学习速度快,而在垂直方向,也就是例子中的方向,我们希望减缓纵轴上的摆动,所以有了和,我们希望会相对较小,所以我们要除以一个较小的数,而希望又较大,所以这里我们要除以较大的数字,这样就可以减缓纵轴上的变化。你看这些微分,垂直方向的要比水平方向的大得多,所以斜率在方向特别大,所以这些微分中,较大,较小,因为函数的倾斜程度,在纵轴上,也就是b方向上要大于在横轴上,也就是方向上。的平方较大,所以也会较大,而相比之下,会小一些,亦或平方会小一些,因此会小一些,结果就是纵轴上的更新要被一个较大的数相除,就能消除摆动,而水平方向的更新则被较小的数相除。
RMSprop的影响就是你的更新最后会变成这样(绿色线),纵轴方向上摆动较小,而横轴方向继续推进。还有个影响就是,你可以用一个更大学习率,然后加快学习,而无须在纵轴上垂直方向偏离。
要说明一点,我一直把纵轴和横轴方向分别称为和,只是为了方便展示而已。实际中,你会处于参数的高维度空间,所以需要消除摆动的垂直维度,你需要消除摆动,实际上是参数,等的合集,水平维度可能,等等,因此把和分开只是方便说明。实际中是一个高维度的参数向量,也是一个高维度参数向量,但是你的直觉是,在你要消除摆动的维度中,最终你要计算一个更大的和值,这个平方和微分的加权平均值,所以你最后去掉了那些有摆动的方向。所以这就是RMSprop,全称是均方根,因为你将微分进行平方,然后最后使用平方根。
最后再就这个算法说一些细节的东西,然后我们再继续。下一个视频中,我们会将RMSprop和Momentum结合起来,我们在Momentum中采用超参数,为了避免混淆,我们现在不用,而采用超参数以保证在Momentum和RMSprop中采用同一超参数。要确保你的算法不会除以0,如果的平方根趋近于0怎么办?得到的答案就非常大,为了确保数值稳定,在实际操练的时候,你要在分母上加上一个很小很小的,是多少没关系,是个不错的选择,这只是保证数值能稳定一些,无论什么原因,你都不会除以一个很小很小的数。所以RMSprop跟Momentum有很相似的一点,可以消除梯度下降中的摆动,包括mini-batch梯度下降,并允许你使用一个更大的学习率,从而加快你的算法学习速度。
所以你学会了如何运用RMSprop,这是给学习算法加速的另一方法。关于RMSprop的一个有趣的事是,它首次提出并不是在学术研究论文中,而是在多年前Jeff Hinton在Coursera的课程上。我想Coursera并不是故意打算成为一个传播新兴的学术研究的平台,但是却达到了意想不到的效果。就是从Coursera课程开始,RMSprop开始被人们广为熟知,并且发展迅猛。
我们讲过了Momentum,我们讲了RMSprop,如果二者结合起来,你会得到一个更好的优化算法,在下个视频中我们再好好讲一讲为什么。
2.8 Adam 优化算法(Adam optimization algorithm)
在深度学习的历史上,包括许多知名研究者在内,提出了优化算法,并很好地解决了一些问题,但随后这些优化算法被指出并不能一般化,并不适用于多种神经网络,时间久了,深度学习圈子里的人开始多少有些质疑全新的优化算法,很多人都觉得动量(Momentum)梯度下降法很好用,很难再想出更好的优化算法。所以RMSprop以及Adam优化算法(Adam优化算法也是本视频的内容),就是少有的经受住人们考验的两种算法,已被证明适用于不同的深度学习结构,这个算法我会毫不犹豫地推荐给你,因为很多人都试过,并且用它很好地解决了许多问题。
Adam优化算法基本上就是将Momentum和RMSprop结合在一起,那么来看看如何使用Adam算法。
使用Adam算法,首先你要初始化,,,,,在第次迭代中,你要计算微分,用当前的mini-batch计算,,一般你会用mini-batch梯度下降法。接下来计算Momentum指数加权平均数,所以(使用,这样就不会跟超参数混淆,因为后面RMSprop要用到),使用Momentum时我们肯定会用这个公式,但现在不叫它,而叫它。同样。
接着你用RMSprop进行更新,即用不同的超参数,,再说一次,这里是对整个微分进行平方处理,。
相当于Momentum更新了超参数,RMSprop更新了超参数。一般使用Adam算法的时候,要计算偏差修正,,修正也就是在偏差修正之后,
,
同样,
也使用偏差修正,也就是,。
最后更新权重,所以更新后是(如果你只是用Momentum,使用或者修正后的,但现在我们加入了RMSprop的部分,所以我们要除以修正后的平方根加上)。
根据类似的公式更新值,。
所以Adam算法结合了Momentum和RMSprop梯度下降法,并且是一种极其常用的学习算法,被证明能有效适用于不同神经网络,适用于广泛的结构。
本算法中有很多超参数,超参数学习率很重要,也经常需要调试,你可以尝试一系列值,然后看哪个有效。常用的缺省值为0.9,这是dW的移动平均数,也就是的加权平均数,这是Momentum涉及的项。至于超参数,Adam论文作者,也就是Adam算法的发明者,推荐使用0.999,这是在计算以及的移动加权平均值,关于的选择其实没那么重要,Adam论文的作者建议为,但你并不需要设置它,因为它并不会影响算法表现。但是在使用Adam的时候,人们往往使用缺省值即可,,和都是如此,我觉得没人会去调整,然后尝试不同的值,看看哪个效果最好。你也可以调整和,但我认识的业内人士很少这么干。
为什么这个算法叫做Adam?Adam代表的是Adaptive Moment Estimation,用于计算这个微分(),叫做第一矩,用来计算平方数的指数加权平均数(),叫做第二矩,所以Adam的名字由此而来,但是大家都简称Adam权威算法。
这就是关于Adam优化算法的全部内容,有了它,你可以更加快速地训练神经网络,在结束本周课程之前,我们还要讲一下超参数调整,以及更好地理解神经网络的优化问题有哪些。下个视频中,我们将讲讲学习率衰减。
2.9 学习率衰减(Learning rate decay)
加快学习算法的一个办法就是随时间慢慢减少学习率,我们将之称为学习率衰减,我们来看看如何做到,首先通过一个例子看看,为什么要计算学习率衰减。
假设你要使用mini-batch梯度下降法,mini-batch数量不大,大概64或者128个样本,在迭代过程中会有噪音(蓝色线),下降朝向这里的最小值,但是不会精确地收敛,所以你的算法最后在附近摆动,并不会真正收敛,因为你用的是固定值,不同的mini-batch中有噪音。
但要慢慢减少学习率的话,在初期的时候,学习率还较大,你的学习还是相对较快,但随着变小,你的步伐也会变慢变小,所以最后你的曲线(绿色线)会在最小值附近的一小块区域里摆动,而不是在训练过程中,大幅度在最小值附近摆动。
所以慢慢减少的本质在于,在学习初期,你能承受较大的步伐,但当开始收敛的时候,小一些的学习率能让你步伐小一些。
你可以这样做到学习率衰减,记得一代要遍历一次数据,如果你有以下这样的训练集,
你应该拆分成不同的mini-batch,第一次遍历训练集叫做第一代。第二次就是第二代,依此类推,你可以将学习率设为(decay-rate称为衰减率,epoch-num为代数,为初始学习率),注意这个衰减率是另一个你需要调整的超参数。
这里有一个具体例子,如果你计算了几代,也就是遍历了几次,如果为0.2,衰减率decay-rate为1,那么在第一代中,,这是在代入这个公式计算(),此时衰减率是1而代数是1。在第二代学习率为0.67,第三代变成0.5,第四代为0.4等等,你可以自己多计算几个数据。要理解,作为代数函数,根据上述公式,你的学习率呈递减趋势。如果你想用学习率衰减,要做的是要去尝试不同的值,包括超参数,以及超参数衰退率,找到合适的值,除了这个学习率衰减的公式,人们还会用其它的公式。
比如,这个叫做指数衰减,其中相当于一个小于1的值,如,所以你的学习率呈指数下降。
人们用到的其它公式有或者(为mini-batch的数字)。
有时人们也会用一个离散下降的学习率,也就是某个步骤有某个学习率,一会之后,学习率减少了一半,一会儿减少一半,一会儿又一半,这就是离散下降(discrete stair cease)的意思。
到现在,我们讲了一些公式,看学习率究竟如何随时间变化。人们有时候还会做一件事,手动衰减。如果你一次只训练一个模型,如果你要花上数小时或数天来训练,有些人的确会这么做,看看自己的模型训练,耗上数日,然后他们觉得,学习速率变慢了,我把调小一点。手动控制当然有用,时复一时,日复一日地手动调整,只有模型数量小的时候有用,但有时候人们也会这么做。
所以现在你有了多个选择来控制学习率。你可能会想,好多超参数,究竟我应该做哪一个选择,我觉得,现在担心为时过早。下一周,我们会讲到,如何系统选择超参数。对我而言,学习率衰减并不是我尝试的要点,设定一个固定的,然后好好调整,会有很大的影响,学习率衰减的确大有裨益,有时候可以加快训练,但它并不是我会率先尝试的内容,但下周我们将涉及超参数调整,你能学到更多系统的办法来管理所有的超参数,以及如何高效搜索超参数。
这就是学习率衰减,最后我还要讲讲神经网络中的局部最优以及鞍点,所以能更好理解在训练神经网络过程中,你的算法正在解决的优化问题,下个视频我们就好好聊聊这些问题。
2.10 局部最优的问题(The problem of local optima)
在深度学习研究早期,人们总是担心优化算法会困在极差的局部最优,不过随着深度学习理论不断发展,我们对局部最优的理解也发生了改变。我向你展示一下现在我们怎么看待局部最优以及深度学习中的优化问题。
这是曾经人们在想到局部最优时脑海里会出现的图,也许你想优化一些参数,我们把它们称之为和,平面的高度就是损失函数。在图中似乎各处都分布着局部最优。梯度下降法或者某个算法可能困在一个局部最优中,而不会抵达全局最优。如果你要作图计算一个数字,比如说这两个维度,就容易出现有多个不同局部最优的图,而这些低维的图曾经影响了我们的理解,但是这些理解并不正确。事实上,如果你要创建一个神经网络,通常梯度为零的点并不是这个图中的局部最优点,实际上成本函数的零梯度点,通常是鞍点。
也就是在这个点,这里是和,高度即成本函数的值。
但是一个具有高维度空间的函数,如果梯度为0,那么在每个方向,它可能是凸函数,也可能是凹函数。如果你在2万维空间中,那么想要得到局部最优,所有的2万个方向都需要是这样,但发生的机率也许很小,也许是,你更有可能遇到有些方向的曲线会这样向上弯曲,另一些方向曲线向下弯,而不是所有的都向上弯曲,因此在高维度空间,你更可能碰到鞍点。
就像下面的这种:
而不会碰到局部最优。至于为什么会把一个曲面叫做鞍点,你想象一下,就像是放在马背上的马鞍一样,如果这是马,这是马的头,这就是马的眼睛,画得不好请多包涵,然后你就是骑马的人,要坐在马鞍上,因此这里的这个点,导数为0的点,这个点叫做鞍点。我想那确实是你坐在马鞍上的那个点,而这里导数为0。
所以我们从深度学习历史中学到的一课就是,我们对低维度空间的大部分直觉,比如你可以画出上面的图,并不能应用到高维度空间中。适用于其它算法,因为如果你有2万个参数,那么函数有2万个维度向量,你更可能遇到鞍点,而不是局部最优点。
如果局部最优不是问题,那么问题是什么?结果是平稳段会减缓学习,平稳段是一块区域,其中导数长时间接近于0,如果你在此处,梯度会从曲面从从上向下下降,因为梯度等于或接近0,曲面很平坦,你得花上很长时间慢慢抵达平稳段的这个点,因为左边或右边的随机扰动,我换个笔墨颜色,大家看得清楚一些,然后你的算法能够走出平稳段(红色笔)。
我们可以沿着这段长坡走,直到这里,然后走出平稳段。
所以此次视频的要点是,首先,你不太可能困在极差的局部最优中,条件是你在训练较大的神经网络,存在大量参数,并且成本函数被定义在较高的维度空间。
第二点,平稳段是一个问题,这样使得学习十分缓慢,这也是像Momentum或是RMSprop,Adam这样的算法,能够加速学习算法的地方。在这些情况下,更成熟的优化算法,如Adam算法,能够加快速度,让你尽早往下走出平稳段。
因为你的网络要解决优化问题,说实话,要面临如此之高的维度空间,我觉得没有人有那么好的直觉,知道这些空间长什么样,而且我们对它们的理解还在不断发展,不过我希望这一点能够让你更好地理解优化算法所面临的问题。
参考资料
[1]机器学习课程: https://www.coursera.org/course/ml
[2]深度学习课程: https://mooc.study.163.com/university/deeplearning_ai
[3]黄海广: https://github.com/fengdu78
[4]github:
https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes
https://github.com/fengdu78/deeplearning_ai_books