文章目录
- 引言
- Mini-batch梯度下降算法
- 理解小批量梯度下降法
- 指数加权平均
- 理解指数加权平均
- 指数加权平均的偏差修正
- 动量梯度下降法
- RMSprop
- Adam优化算法
- 学习率衰减
- 局部最优的问题
- 参考
引言
本文是吴恩达深度学习第二课:改善深层网络的笔记。这次内容包括深度学习的实用技巧、提高算法运行效率、超参数调优。
第二课有以下三个部分,本文是第二部分。
- 深度学习的实用指南
- 提高算法运行效率
- 超参数调优
Mini-batch梯度下降算法
我们知道,向量化能让我们高效的对 m m m个样本进行计算,但如果 m = 5 , 000 , 000 m=5,000,000 m=5,000,000呢。
在对整个训练数据集进行批量梯度下降法时,每下降一步都需要处理整个训练集。当样本总数有500万,或者5000万以上时,批量梯度下降法会非常慢。
如果把训练集分成小一点的部分,每次只根据这一小部分进行梯度下降,这一小部分子集叫做Mini-batch。假设每一子集中只有1000个样本,这个1000叫做批次大小(batch size)
一般需要在划分子集之前对整个训练集进行洗牌操作
这样就有5000个mini-bacth,对 Y Y Y也要进行同样的处理。
Mini-batch t t t包含 { X { t } , Y { t } } \{X^{\{t\}},Y^{\{t\}}\} {X{t},Y{t}}
这里我们用花括号 { t } \{t\} {t}来表示不同的mini-batch。
我们来看下它们的维数, X X X的维数是 ( n x , m ) (n_x,m) (nx,m),那么每个mini-bacth X { t } X^{\{t\}} X{t}的维数是 ( n x , 1000 ) (n_x,1000) (nx,1000) (因为这里刚好能平均分,如果不能均分的话,最后一个小批次可能没有批次大小那么多)
同样 Y { t } Y^{\{t\}} Y{t}的维数是 ( 1 , 1000 ) (1,1000) (1,1000)
批量梯度下降法(Batch Gradient descent)就是我们之前将的梯度下降法,就是会一次处理整个数据集,这个名字可能会有点误解;小批量梯度下降法(Mini-batch Gradient descent)每次处理的是单个小批量的 X { t } , Y { t } X^{\{t\}},Y^{\{t\}} X{t},Y{t}。
下面看下小批量梯度下降法的算法过程:
当我们的数据量比较大是,使用小批量梯度下降法运行的比批量梯度下降发更快,在深度学习中几乎都会用到,因为一般深度学习的数据量是很庞大的。
理解小批量梯度下降法
在批量梯度下降法中,每次迭代要遍历整个训练集,可以预期每次迭代的成本都会下降。
而小批量梯度下降法中,如果每个小批量都绘制损失函数之的话,那么就有可能得到上面的图像。
一个要考虑的因素是批次大小,如果批次大小就是整个数据集大小的话,那么就是批量梯度下降法,这个算法的缺点是单次迭代耗时太长。
如果批次大小取个极端值 1 1 1的话,那么就是随机梯度下降法(Stochastic Gradient Descent),这个算法会更加快,每个样本都可以移动一步,但是不一定每次都是梯度下降的方向,但是最终还是能到达最小值附近,虽然可能不会达到最小值,但是其实也不差,如上图紫线。还有一个缺点是无法利用向量化带来的加速优势。
如果批次大小介于上面两者之间的话,就是小批量梯度下降法,它能达到学习率最快的效果,同时也能利用向量化。也不需要等待整个训练数据集遍历完才去下降一步,只要遍历完一个小批次就可以移动一步。 如上图绿线,它也无法保证每次朝梯度下降的方向移动,但是比随机梯度下降法要更持续地靠近最小值的方向。
那么如果采用小批量梯度下降法,这个批次大小要如何选择呢。
如果样本量很小,比如小于2000,那么可以直接使用批量梯度下降法;
否则常用的批次大小有64,128,256,512,1024。
实际上这个批次大小也是一个超参数,需要尝试不同的值,才能找到最有效地减少成本函数的那个。
实际有还有一些优化算法比梯度下降法要快,要理解这些算法,需要用到指数加权平均,我们先来看下指数加权平均。
指数加权平均
指数加权(移动)平均只取最近的N次数据进行局部的平均值计算。下面来看一个例子:
假设这是一个温度与时间(日)关系的趋势图。从每年的1月1日开始到年末。
我们看下如何计算趋势,即温度的局部平均值或移动平均值。
每天需要用0.9的加权值乘以之前的值加上0.1乘以当天的温度。比如上面是第一天的计算式子。
计算第二天的累计值也是一样,0.9乘以前一天的累计值加上0.1乘以当天的温度。以此类推:
这样就得到了每天的指数加权平均值,如果用红线画图的话,就得到下面的图像:
我们再来看下上面的公式,用 β \beta β表示上面的0.9。
在计算时,可以把 V t V_t Vt看成大概是 1 1 − β \frac{1}{1-\beta} 1−β1的每日温度。
如果 β = 0.9 \beta=0.9 β=0.9就是10天的平均值,我们来看下其他值,假如 β = 0.98 \beta=0.98 β=0.98,那么 1 1 − 0.98 = 50 \frac{1}{1-0.98} = 50 1−0.981=50,就是50天的平均值。
作图时就可以得到上面的绿线,可以看到更加的平缓。当 β = 0.98 \beta=0.98 β=0.98相当于给之前的值加了太多权值,而只给当天值增加0.02的权重,所以当 β \beta β较大时,指数加权平均值适应地更慢一些,比如红线已经下来了,但是绿线还在上面。
我们还可以试另一个极端的值,比如 β = 0.5 \beta=0.5 β=0.5,相当于只平均了两天的值。那么得到的图像肯定是很抖动的,如下图黄线:
但是这个曲线能更快的适应温度的变化。
理解指数加权平均
我们进一步分析来理解如何计算出每日温度的平均值,当 β = 0.9 \beta=0.9 β=0.9时,
我们自顶向下的来分析这个式子。
v 100 v_{100} v100可以改写成什么呢
把 v 99 v_{99} v99这个式子代入到 v 100 v_{100} v100中就得到:
同样,替换 v 98 v_{98} v98的式子,可以进一步地写成:
把 θ \theta θ的值写出来得:
这就是一个加权平均。比如我们分析 v 100 v_{100} v100的组成,这个值包括100天的温度加上99天的数据,98天的数据…
画图的一个办法是,我们有日期的温度,从右到左分别是100天的温度,99天的温度,98天的温度…
然后我们构建一个指数衰减函数
从0.1开始,到0.9乘以0.1,到0.9的平方乘以0.1,
所以就有了上面这个指数衰减函数图像,然后计算 v 100 v_{100} v100是通过把两个函数对应的元素相乘,然后求和
比如100天的温度乘以0.1 + 99天的温度乘以 0.1 × 0.9 0.1\times 0.9 0.1×0.9 …
θ \theta θ前面的这些系数之和加起来会逼近 1 1 1,称为偏差修正。下节会讲到。
那到底平均多少天的温度呢,实际上 0. 9 10 ≈ 0.35 ≈ 1 e 0.9^{10} \approx 0.35 \approx \frac{1}{e} 0.910≈0.35≈e1
大体上说,如果有 1 − ε 1 - \varepsilon 1−ε,这个例子中 ε = 0.1 \varepsilon = 0.1 ε=0.1,
如果 ( 1 − ε ) 1 ε = 1 e (1-\varepsilon)^{\frac{1}{\varepsilon}} = \frac{1}{e} (1−ε)ε1=e1,也就是10天后曲线的高度,下降到原来的三分之一,由于时间越往前推移 θ \theta θuanzhogn越小,所以相当于说:我们每次只考虑最近 N = 1 1 − β N = \frac{1}{1 - \beta} N=1−β1天的数据来来计算当前时刻的指数加权移动平均,这也是移动
平均的来源。
因此当 β = 0.9 \beta=0.9 β=0.9时,我们说在计算一个指数加权平均数,只关注了过去10天的温度,权重下降到不到当日权重的三分之一。相反如果 β = 0.98 \beta=0.98 β=0.98,那么0.98需要多少次方才能达到这么小的数值,是50次, 0.9 8 50 = 1 e 0.98^{50}=\frac{1}{e} 0.9850=e1。可以看成是平均了50天的温度,因此我们就得到了约等于平均 1 1 − β \frac{1}{1 - \beta} 1−β1天的温度。这里用 ε = 1 − β \varepsilon = 1- \beta ε=1−β。
这样就大概知道能平均多少天的温度。
如果编码实现呢,给出上面的式子
先初始化 v θ = 0 v_\theta = 0 vθ=0
然后得到 θ t \theta_t θt的值,通过 β v θ + ( 1 − β ) θ t \beta v_\theta + (1 - \beta)\theta_t βvθ+(1−β)θt来更新 v θ v_\theta vθ的值即可。
可以看到这个算法是很高效的。
其实它并不是最好的,也不是最精准的计算平均数的方法,如果要计算移动窗,直接算出过去10天的总和或过去50天的总和,然后除以10或50就好了,这样可以得到更好的估测值,但缺点是保留了所有最近(10/50天)的值,占用了更多内存。
指数加权平均的偏差修正
在上个视频中,红色曲线对应 β \beta β的值为0.9,绿色曲线对应的 β \beta β值为0.98.
但实际上,在 β = 0.98 \beta=0.98 β=0.98时,我们得到的是紫色曲线。
它的起点比真实的要低很多,不能很好的估计起始位置的温度,此问题称为:冷启动问题,这是由于 v 0 = 0 v_0=0 v0=0造成的。
比如来看下 v 1 v_1 v1,我们先写出 v 1 v_1 v1的公式,根据公式 v 1 = 0.02 θ 1 v_1 = 0.02 \theta_1 v1=0.02θ1,如果第一天的温度 θ 1 \theta_1 θ1是40华氏度,那么得到温度就是8度,因此得到的值要小得多。
v 2 v_2 v2也是一样,也会小于实际第2天的温度,有个方法可以修改这一估测,叫修正偏差。
就是把所有时刻的 v t v_t vt除以 1 − β t 1 - \beta^t 1−βt
比如当 t = 2 t=2 t=2时, 1 − β 2 1 - \beta^2 1−β2 = 0.0396
那么 v 2 1 − β 2 \frac{v_2}{1 - \beta^2} 1−β2v2就等于
你会发现随着 t t t的增加, β t \beta^t βt越接近于 0 0 0,因此当 t t t很大时,修正偏差几乎没起作用。
从上面的图像也可以看出,当 t t t很大时,紫线和绿线重合了,但是在开始阶段,偏差修正能更好的预测温度。
动量梯度下降法
动量梯度下降法(Momentum)运行速度几乎总是比标准的梯度下降法要快。
它的基本想法就是计算梯度的指数加权平均数,然后更新权重。
假设你要优化一个函数形状如图的成本函数:
红点是最小值位置,
如果用标准的梯度下降法可能会得到上面这种产生上下波动的图像,这种上下波动会减慢梯度下降法的速度,同时无法使用更大的学习率,不然会偏移函数的范围,像紫线一样:
因此只能选择一个较小的学习率,从而导致速度变慢。
在纵轴上我们希望学习慢一点,因为从纵轴来看,高度不高;而横轴上我们希望学习快一点,因为比较狭长。
此时就可以使用动量梯度下降法。
动量梯度下降法基于批量梯度下降法或小批量梯度下降法得到的 d W , d b dW,db dW,db计算指数加权平均数,具体的是:
就像我们上小节计算温度的式子一样,这样就可以减缓某个方向上梯度下降的速度。
比如上面的例子中,在纵轴方向上下摆动,在平均过程中,微分的正负数相互抵消,所以平均值接近于零。
但在横轴方向,所有的微分都指向横轴方向,因此横轴方向的平均值仍然较大。
所以最终动量梯度下降法可能走的是上面这条红色的更加快捷的路径。
一般 β \beta β会稍小于 1 1 1,动量就是物理学里面的惯性,相当于有一个加速度,加速度就是上面后面那个式子。
初始值 v d W = 0 , v d b = 0 v_{dW} = 0,v_{db} = 0 vdW=0,vdb=0
上面就是动量梯度下降法的实现,有两个超参数:学习率 α \alpha α和控制指数加权平均数的 β \beta β。
常用的 β = 0.9 \beta=0.9 β=0.9,就是平均了前十次迭代的速度。
关于偏差修正,实际上一般不会对动量梯度下降法进行偏差修正。因为只要十次迭代后就不再是一个具有偏差的预测。
RMSprop
还有一种叫RMSprop(root mean square prop)的算法,它也可以加速梯度下降。
我们还是以上小节的例子说明,这里假设纵轴是参数 b b b,横轴是参数 w w w。我们想要减小纵轴方向上的速度,加快横轴方向上的速度。
RMSprop算法可以实现这一点,来看下它的实现细节:
上面的 d W 2 dW^2 dW2代码中就是dW ** 2
,所以这种方法也可以看成是基于指数加权平均的。
在横轴方向 W W W,我们希望学习速度快,而在纵轴方向 b b b,我们希望学习慢。
所以我们希望 S d W S_{dW} SdW是一个较小的数,而 S d b S_{db} Sdb是一个较大的数。
我们来看微分的话(比如看下面这条线的微分),垂直方向的微分远大于水平方向的微分。
所以 b b b方向上的导数 d b db db非常大,而 d W dW dW较小。
也可以这么理解,如果某个方向上梯度震荡很大,应该减小其步长;而震荡大,则这个方向的 S S S也较大,更新参数时除完 S \sqrt{S} S 后,可以看成学习率(或梯度)变小了,速度就慢了;反之,如果某个方向上梯度震荡很小,应该增大其步长;而震荡小,则这个方向的 S S S也较小,除完之后就大了。
RMSprop的路径可能是上图绿线这样,还有个好处是,可以使用较大的学习率。
值得说明的一点是,这里用了 w w w和 b b b两个参数只会为了简化,实际上会有很多个参数, d W , d b dW,db dW,db是一个高维的参数向量。
这就是RMSprop(root mean square,均方根),因为会将微分进行平方(均方根里的方),然后使用平方根(均方根里的根)。
我们再Momentum中采用超参数 β \beta β,为了避免混淆,我们现在不用 β \beta β,而用超参数 β 2 \beta_2 β2,同时为了确保不会除零,加上一个很小的值 ε \varepsilon ε,通常取 ε = 1 0 − 8 \varepsilon = 10^{-8} ε=10−8
Adam优化算法
Adam算法基本就是将Momentum和RMSprop结合在一起。
这里面有多超参数, β \beta β参数都有经验值, α \alpha α需要调。
有了Adam算法我们可以更加快速的训练神经网络。
学习率衰减
加快学习算法的一个办法就是随时间慢慢减少学习率,通常称为学习率衰减(learning reate decay)。
下面以一个例子来说明为什么要梯度衰减。
假设我们用mini-batch 梯度下降法,将一个批次大小设为128,在迭代过程中可能会有噪音,它们会向最小值的方向移动,但是不会精确地收敛(可能不会达到最小值)。
因为学习率是固定的,而不同的小批次中有噪音,但是在训练的初期学习率可以较大,这样能快速的学习,但到了后期,尤其是上图最里面那个等高线里面,学习率应该变小,使得步伐也变小。所以最后可以在更接近最小值附近摆动,如绿线所示:
每次学习完整个训练集叫一次epoch。学习率应该随着epoch的增多而减少。
这里的衰减率是另一个超参数,当初始 α 0 = 0.2 \alpha_0 = 0.2 α0=0.2,衰减率为1时。学习率随着迭代次数的增加是下面这样的:
除了这个学习率衰减的方法,还有其他的方法。
局部最优的问题
以这个图为例,在这个损失函数图像中,分布着很多局部最优点,而只有一个全局最优,梯度下降法可能会困在一个局部最优中。
而人们的直接往往会被这些低维图像所误导,如果你在训练一个神经网络,代价函数中大部分梯度为零的点实际上并不是想上面这样的局部最优,而是鞍点(像马鞍一点最低的那个点)
对于一个高维空间的函数,如果梯度为零,则在每个方向上可能是凸函数,或者是凹函数。
假设在一个20000维的空间中,如果一个点要称为局部最优,则需要在所有的2万个方向上都像下面这样(凸函数图像或凹函数图像这样):
因此这个概率非常低,更可能的是遇到下面这种鞍点:
如果局部最优点不是问题,那么问题是什么呢,真正的问题是停滞区(plateaus,指的是导数长时间接近于零的一段区域)。
比如说慢慢接近于停滞区的红点,然后因为左右侧的随机扰动,算法最终能离开这个停滞区。
- 所以实际上如果参数很多的话,不太可能会陷入局部最优点。
- 停滞区会让学习过程变得相当慢,这也是上面介绍的那些算法可以改善学习算法的地方。
比如Adam算法可以加快沿停滞区向下移动的速度,并且加快离开停滞区的速度。
参考
- 吴恩达深度学习 专项课程