【DL-CV】正则化,Dropout<前篇---后篇>【DL-CV】浅谈GoogLeNet(咕咕net)
原版SGD的问题
原味版的SGD(以下称SGD)是通过死跟负梯度方向来对参数进行更新的,也就是走一步、停下确定方向、再走一步,如此循环。非常简单,非常老实的走法不是麽?但是SGD这个相对简单的算法在实际使用中还是会产生不少的问题,下面我们来看看最主要的几个
1️⃣SGD 一旦陷入损失的局部最小值或鞍点(既不是最大值也不是最小值的临界点)训练将变得缓慢:
作为问题的引入我们先考虑参数只有一个的情况下损失关于该参数的图(如上,x轴是该参数,y轴是损失)
- 当SGD遇到局部最小值时,因为梯度为0,参数不会更新,最终就卡在局部最小值这个点了
- 当SGD遇到或接近鞍点时,同样梯度为0或非常小,参数也几乎不会更新,于是也卡在该鞍点
这是一维的情况,在高维的情况下(上千上万个参数),局部最小值意味着所有参数无论往哪个方向走损失都会增大,这其实是非常罕见的事情。而高维情况下的鞍点可以这样理解,即在该点下某些方向会使损失增大,某些方向会使损失减少;所以在高维情况下遇到鞍点将会是非常常见的事情,在鞍点附近训练速度将会变得缓慢。
2️⃣SGD 对所有参数更新时应用同样的学习率:
梯度由许多偏导数组成,对应着各个参数的更新。对于偏导数大的,我们希望配个小的学习率给他;对于偏导数小的,我们希望配个大的学习率给他,这样各个参数都能获得大致相同的更新幅度,提高网络的健壮性。可惜SGD固定死的学习率不能满足我们的要求
3️⃣SGD 在遇到噪声时,训练将变得缓慢:
SGD 是通过随机抽取小批量样本进行训练的,是对每次损失和梯度的估计(不像批量学习一样全部训练样本全往里塞获得真实的损失和估计),当估计中存在噪音,参数更新的方向会受到影响而偏离,导致训练时间延长
综上,使用原版的SGD进行参数更新带来的体验并不是那么好(需要更新换代啦)。还好的是,伟大的研究人员,或是对原版SGD进行了各种各样的魔改,或是灵光一闪提出新的更新算法,现在已经有多种更高级的参数更新的方法啦,下面就来看一下
普通动量更新
该方法的关键是引入一个速度的概念。速度这个量将对历次求得的梯度进行累加,在每次累加时会有一参数$\gamma$对原速度进行衰减处理后再进行累加。参数更新时,我们不在根据当前的负梯度方向进行更新,而是根据当前速度方向更新。这样引入速度之后 SGD卡在局部最小值和鞍点的问题 会得到有效解决,从而加速训练。
上面的说明不懂没关系,看了下面的比喻你便会豁然开朗
- 想象有一座高山,其高度代表损失值;有一个小球代表着参数,在山的不同点有不同的值;我们的目标是让小球滚到山底取得最优参数(下山的过程就是训练的过程)。在这种想象下,负梯度就相当于重力在斜面上的分力使得小球有下降的趋势,小球在下降的过程中因为重力做正功速度会增加;也因为这个速度的存在,小球会安然越过小山谷(对应局部最小值)或平原(对应鞍点)继续下山。当小球真正接近“U型”山底时,小球会在山底来回摆动,最后因为阻力(对应参数$\gamma$)而停在山底(参数训练完成)。
懂了下面就放公式,顺便比较SGD和魔改后的SGD,公式中的t代表第t次迭代更新
SGD | SGD + 动量 | |
---|---|---|
公式(x是待更新参数) | $$x_{t+1}=x_t-\alpha\nabla_xL(x_t)$$ | $$v_{t+1}=\gamma v_t+\alpha\nabla_xL(x_t)$$$$x_{t+1}=x_t-v_{t+1}$$ |
代码实现 |
至于参数$\gamma$,其存在相当于摩擦力,可使使速度衰减。如果没有$\gamma$,小球到达最后的“U型”山底就不会停下来,训练时参数可能就收敛不了。$\gamma$常为[0.5,0.9,0.95,0.99]中的一个,并且通常为0.9。$\gamma$也可以随着训练的进行而逐渐上升,如刚开始将$\gamma$设为0.5而在后面的多个epoch中慢慢提升到0.99
Nesterov动量
Nesterov动量与普通动量原理上有些许不同(Nesterov动量可以说是普通动量的小升级)。在理论上对于凸函数Nesterov动量能得到更好的收敛,在实践中也确实比普通动量表现更好一些。
使用Nesterov动量时,不会计算当前点的梯度,而是先往速度方向步进到下一点,计算这“下一点”的梯度,然后回到原点把这“下一点”的梯度加到速度上,再用累加后的速度在原点上进行步进。这个看似多此一举的操作并不是无意义的,计算“下一点”的梯度可以看作是对未来位置梯度的预测从而提前对速度方向进行修正,从而进一步加快训练速度。下面来对比一下普通动量和Nesterov动量:
普通动量 | Nesterov动量 | |
---|---|---|
图示 | ||
公式 | $$v_{t+1}=\gamma v_t+\alpha\nabla_xL(x_t)$$$$x_{t+1}=x_t-v_{t+1}$$ | $$v_{t+1}=\gamma v_t + \alpha \nabla_xL(x_t - \gamma v_t)$$$$x_{t+1} = x_t-v_{t+1}$$ |
这两个动量更新方法都有效解决了SGD的问题1️⃣
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。