梯度下降
李宏毅
梯度下降
解决下面的最优化问题:
:lossfunction(损失函数) :parameters(参数)
这里的parameters是复数,即
我们要找一组参数
假设
然后分别计算初始点处,两个参数对
叫做Learning rates(学习速率)
上图举例将梯度下降法的计算过程进行可视化。
Tip1:调整学习速率
小心翼翼地调整学习率
举例:
上图左边黑色为损失函数的曲线,假设从左边最高点开始,如果学习率调整的刚刚好,比如红色的线,就能顺利找到最低点。如果学习率调整的太小,比如蓝色的线,就会走的太慢,虽然这种情况给足够多的时间也可以找到最低点,实际情况可能会等不及出结果。如果 学习率调整的有点大,比如绿色的线,就会在上面震荡,走不下去,永远无法到达最低点。还有可能非常大,比如黄色的线,直接就飞出去了,更新参数的时候只会发现损失函数越更新越大。
虽然这样的可视化可以很直观观察,但可视化也只是能在参数是一维或者二维的时候进行,更高维的情况已经无法可视化了。
解决方法就是上图右边的方案,将参数改变对损失函数的影响进行可视化。比如学习率太小(蓝色的线),损失函数下降的非常慢;学习率太大(绿色的线),损失函数下降很快,但马上就卡住不下降了;学习率特别大(黄色的线),损失函数就飞出去了;红色的就是差不多刚好,可以得到一个好的结果。
自适应学习率
举一个简单的思想:随着次数的增加,通过一些因子来减少学习率
通常刚开始,初始点会距离最低点比较远,所以使用大一点的学习率
update好几次参数之后呢,比较靠近最低点了,此时减少学习率
比如
, 是次数。随着次数的增加, 减小
学习率不能是一个值通用所有特征,不同的参数需要不同的学习率
Adagrad 算法
Adagrad 是什么?
每个参数的学习率都把它除上之前微分的均方根。解释:
普通的梯度下降为:
是一个参数
Adagrad 可以做的更好:
:之前参数的所有微分的均方根,对于每个参数都是不一样的。
Adagrad举例
下图是一个参数的更新过程
将 Adagrad 的式子进行化简:
Adagrad 存在的矛盾?
在 Adagrad 中,当梯度越大的时候,步伐应该越大,但下面分母又导致当梯度越大的时候,步伐会越小。
下图是一个直观的解释:
下面给一个正式的解释:
比如初始点在
这样可以认为如果算出来的微分越大,则距离最低点越远。而且最好的步伐和微分的大小成正比。所以如果踏出去的步伐和微分成正比,它可能是比较好的。
结论1-1:梯度越大,就跟最低点的距离越远。
这个结论在多个参数的时候就不一定成立了。
多参数下结论不一定成立
对比不同的参数
上图左边是两个参数的损失函数,颜色代表损失函数的值。如果只考虑参数
所以结论1-1是在没有考虑跨参数对比的情况下,才能成立的。所以还不完善。
之前说到的最佳距离
所以最好的步伐应该是:
即不止和一次微分成正比,还和二次微分成反比。最好的step应该考虑到二次微分:
Adagrad 进一步的解释
再回到之前的 Adagrad
对于
Tip2:随机梯度下降法
之前的梯度下降:
而随机梯度下降法更快:
损失函数不需要处理训练集所有的数据,选取一个例子
此时不需要像之前那样对所有的数据进行处理,只需要计算某一个例子的损失函数Ln,就可以赶紧update 梯度。
对比:
常规梯度下降法走一步要处理到所有二十个例子,但随机算法此时已经走了二十步(每处理一个例子就更新)
Tip3:特征缩放
比如有个函数:
两个输入的分布的范围很不一样,建议把他们的范围缩放,使得不同输入的范围是一样的。
为什么要这样做?
上图左边是
坐标系中是两个参数的error surface(现在考虑左边蓝色),因为
上图右边是两个参数scaling比较接近,右边的绿色图就比较接近圆形。
对于左边的情况,上面讲过这种狭长的情形不过不用Adagrad的话是比较难处理的,两个方向上需要不同的学习率,同一组学习率会搞不定它。而右边情形更新参数就会变得比较容易。左边的梯度下降并不是向着最低点方向走的,而是顺着等高线切线法线方向走的。但绿色就可以向着圆心(最低点)走,这样做参数更新也是比较有效率。
怎么做缩放?
方法非常多,这里举例一种常见的做法:
上图每一列都是一个例子,里面都有一组特征。
对每一个维度
然后用第
梯度下降的理论基础
问题
当用梯度下降解决问题:
每次更新参数
上述结论正确吗?
结论是不正确的。。。
数学理论
比如在
接下来就是如果在小圆圈内快速的找到最小值?
泰勒展开式
先介绍一下泰勒展开式
定义
若
当
举例:
图中3条蓝色线是把前3项作图,橙色线是
多变量泰勒展开式
下面是两个变量的泰勒展开式
利用泰勒展开式简化
回到之前如何快速在圆圈内找到最小值。基于泰勒展开式,在
将问题进而简化为下图:
不考虑s的话,可以看出剩下的部分就是两个向量
然后将u和v带入。
发现最后的式子就是梯度下降的式子。但这里用这种方法找到这个式子有个前提,泰勒展开式给的损失函数的估算值是要足够精确的,而这需要红色的圈圈足够小(也就是学习率足够小)来保证。所以理论上每次更新参数都想要损失函数减小的话,即保证式1-2 成立的话,就需要学习率足够足够小才可以。
所以实际中,当更新参数的时候,如果学习率没有设好,是有可能式1-2是不成立的,所以导致做梯度下降的时候,损失函数没有越来越小。
式1-2只考虑了泰勒展开式的一次项,如果考虑到二次项(比如牛顿法),在实际中不是特别好,会涉及到二次微分等,多很多的运算,性价比不好。
梯度下降的限制
容易陷入局部极值 还有可能卡在不是极值,但微分值是0的地方 还有可能实际中只是当微分值小于某一个数值就停下来了,但这里只是比较平缓,并不是极值点
Vanishing / Exploding gradients
训练神经网络,尤其是深度神经所面临的一个问题就是梯度消失或梯度爆炸,也就是你训练神经网络的时候,导数或坡度有时会变得非常大,或者非常小,甚至于以指数方式变小,这加大了训练的难度。
这节课,你将会了解梯度消失或梯度爆炸的真正含义,以及如何更明智地选择随机初始化权重,从而避免这个问题。
假设你正在训练这样一个极深的神经网络,为了节约幻灯片上的空间,我画的神经网络每层只有两个隐藏单元,但它可能含有更多,但这个神经网络会有参数
所有这些矩阵数据传递的协议将给出
假设每个权重矩阵
相反的,如果权重是0.5,
我希望你得到的直观理解是,权重
在深度神经网络中,激活函数将以指数级递减,虽然我只是讨论了激活函数以与
对于当前的神经网络,假设
总结一下,我们讲了深度神经网络是如何产生梯度消失或爆炸问题的,实际上,在很长一段时间内,它曾是训练深度神经网络的阻力,虽然有一个不能彻底解决此问题的解决方案,但是已在如何选择初始化权重问题上提供了很多帮助。
Weight Initialization for Deep NetworksVanishing / Exploding gradients
上节课,我们学习了深度神经网络如何产生梯度消失和梯度爆炸问题,最终针对该问题,我们想出了一个不完整的解决方案,虽然不能彻底解决问题,却很有用,有助于我们为神经网络更谨慎地选择随机初始化参数,为了更好地理解它,我们先举一个神经单元初始化地例子,然后再演变到整个深度网络。
我们来看看只有一个神经元的情况,然后才是深度网络。
单个神经元可能有4个输入特征,从
结果,如果你是用的是Relu激活函数,而不是
我提到了其它变体函数,刚刚提到的函数是Relu激活函数,一篇由Herd等人撰写的论文曾介绍过。对于几个其它变体函数,如tanh激活函数,有篇论文提到,常量1比常量2的效率更高,对于tanh函数来说,它是
实际上,我认为所有这些公式只是给你一个起点,它们给出初始化权重矩阵的方差的默认值,如果你想添加方差,方差参数则是另一个你需要调整的超级参数,可以给公式
希望你现在对梯度消失或爆炸问题以及如何为权重初始化合理值已经有了一个直观认识,希望你设置的权重矩阵既不会增长过快,也不会太快下降到0,从而训练出一个权重或梯度不会增长或消失过快的深度网络。我们在训练深度网络时,这也是一个加快训练速度的技巧。
Numerical approximation of gradients
在实施backprop时,有一个测试叫做梯度检验,它的作用是确保backprop正确实施。因为有时候,你虽然写下了这些方程式,却不能100%确定,执行backprop的所有细节都是正确的。为了逐渐实现梯度检验,我们首先说说如何计算梯度的数值逼近,下节课,我们将讨论如何在backprop中执行梯度检验,以确保backprop正确实施。
我们先画出函数
我们写一下数据算式,图中绿色三角形上边的点的值是
这是一些你可能比较熟悉的微积分的理论,如果你不太明白我讲的这些理论也没关系,导数的官方定义是针对值很小的
对于一个非零的
如果你不理解上面两条结论,所有公式都在这儿,不用担心,如果你对微积分和数值逼近有所了解,这些信息已经足够多了,重点是要记住,双边误差公式的结果更准确,下节课我们做梯度检验时就会用到这个方法。
今天我们讲了如何使用双边误差来判断别人给你的函数
Gradient checking
梯度检验帮我们节省了很多时间,也多次帮我发现backprop实施过程中的bug,接下来,我们看看如何利用它来调试或检验backprop的实施是否正确。
假设你的网络中含有下列参数,
同样的,把
这就是实施梯度检验的过程,英语里通常简称为“grad check”,首先,我们要清楚
只对
从上节课中我们了解到这个值(
具体来说,如何定义两个向量是否真的接近彼此?我一般做下列运算,计算这两个向量的距离,
如果它的值在
如果左边这个方程式结果是
在实施神经网络时,我经常需要执行foreprop和backprop,然后我可能发现这个梯度检验有一个相对较大的值,我会怀疑存在bug,然后开始调试,调试,调试,调试一段时间后,我得到一个很小的梯度检验值,现在我可以很自信的说,神经网络实施是正确的。
现在你已经了解了梯度检验的工作原理,它帮助我在神经网络实施中发现了很多bug,希望它对你也有所帮助。
Gradient Checking Implementation Notes
这节课,分享一些关于如何在神经网络实施梯度检验的实用技巧和注意事项。
首先,不要在训练中使用梯度检验,它只用于调试。我的意思是,计算所有
第二点,如果算法的梯度检验失败,要检查所有项,检查每一项,并试着找出bug,也就是说,如果
第三点,在实施梯度检验时,如果使用正则化,请注意正则项。如果代价函数
第四点,梯度检验不能与dropout同时使用,因为每次迭代过程中,dropout会随机消除隐藏层单元的不同子集,难以计算dropout在梯度下降上的代价函数
最后一点,也是比较微妙的一点,现实中几乎不会出现这种情况。当
这就是梯度检验,恭喜大家,这是本周最后一课了。回顾这一周,我们讲了如何配置训练集,验证集和测试集,如何分析偏差和方差,如何处理高偏差或高方差以及高偏差和高方差并存的问题,如何在神经网络中应用不同形式的正则化,如
BGD(Batch gradient descent)
Theory
假设
无约束最优化问题。
由于
其中,
第
其中,
梯度下降算法:
输入:目标函数$f \left( x \right)
输出:$f \left( x \right)
取初值
,置 计算
计算梯度
,当$| g_{k} | < \varepsilon x^{*}=x^{\left(k\right)} p_{k}=-g\left(x^{\left(k\right)}\right) \lambda_{k}$,使
置
,计算
当$| f \left( x^{\left(k+1\right)} \right) - f \left( x^{\left(k\right)} \right) | < \varepsilon| x^{\left(k+1\right)} - x^{\left(k\right)} | < \varepsilon x^{*}=x^{k+1}$ 否则,置
,转3.
Summary
- BGD(批量梯度下降):更新每一参数都用所有样本更新。
- 优点:每次迭代都需要把所有样本都送入,这样的好处是每次迭代都顾及了全部的样本,能保证做的是全局最优化。
- 缺点:由于这种方法是在一次更新中,就对整个数据集计算梯度,所以计算起来非常慢,遇到很大量的数据集也会非常棘手,而且不能投入新数据实时更新模型。