文章目录
局部最小值与鞍点 (Local Minimum & Saddle Point)
我们在做优化的时候经常会发现,随着参数不断更新,训练的损失不会再下降, 但是我们对这个损失仍然不满意.把深层网络(deep network)、线性模型和浅层网络(shallow network) 做比较,可以发现深层网络没有做得更好——深层网络没有发挥出它完整的力量,所以优化是有问题的.但有时候,模型一开始就训练不起来,不管我们怎么更新参数,损失都降不下去.
临界点及其种类
在优化过程中,优化到某个地方的损失关于参数的微分为零的时候,梯度下降就不能再更新参数了,训练就停下来了,损失不再下降.
当梯度为0时,我们最先想到的是到达了局部最小值,然而损失不是只在局部极小值的梯度是零,还有其他可能会让梯度是零的点,比如鞍点(saddle point).鞍点其实就是梯度是零且区别于局部极小值和局部极大值(local maximum)的点.
我们把梯度为零的点统称为临界点(critical point),损失没有办法再下降,也许是因为收敛在了 临界点,但不一定收敛在局部极小值,因为鞍点也是梯度为零的点.
判断临界值种类
判断一个临界点到底是局部极小值还是鞍点需要知道损失函数的形状.可是怎么知道损失函数的形状?网络本身很复杂,用复杂网络算出来的损失函数显然也很复杂.虽然无法完整 知道整个损失函数的样子,但是如果给定某一组参数,比如 θ θ θ,在 θ ′ θ^′ θ′附近的损失函数是有办法写出来的–利用泰勒级数近似:
L ( θ ) ≈ L ( θ ′ ) + ( θ − θ ′ ) T g + 1 2 ( θ − θ ′ ) T H ( θ − θ ′ ) L(θ)\approx L(θ^{′})+(θ-θ^{′})^{T}g+\frac{1}{2}(θ-θ^{′})^{T}H(θ-θ^{′}) L(θ)≈L(θ′)+(θ−θ′)Tg+21(θ−θ′)TH(θ−θ′)
其中g代表梯度,是一个向量,gi 是向 量 g 的第 i 个元素,就是L关于θ的第i个元素的偏导数, g i = δ L ( θ ′ ) δ θ i g_i=\frac{\delta L(θ^′)}{\delta θ_i} gi=δθiδL(θ′),弥补 L ( θ ′ ) L(θ^′) L(θ′)和 L ( θ ) L(θ) L(θ)之间的差距,有时会写成 ∇ L ( θ ′ ) \nabla L(θ^{′}) ∇L(θ′)
展开两项还不足以描述L(θ),H里面放的是L的二次微分,它第i行, 第j列的值Hij就是把θ的第 i 个元素对 L ( θ ′ ) L(θ^{′}) L(θ′)
作微分,再把θ的第j个元素二次微分,即 H i j = δ 2 δ θ i δ θ j L ( θ ′ ) H_{ij}=\frac{{\delta}^2}{\delta θ_i \delta θ_j} L(θ^{′}) Hij=δθiδθjδ2L(θ′).
在临界点,梯度g为0,因此第二项为0,我们可以根据第三项判断 θ ′ θ^′ θ′附近的误差表面,从而得知它是哪种类型,假设用向量v表示 ( θ − θ ′ ) , 令 (θ-θ^{′}),令 (θ−θ′),令 α = v T H v \alpha=v^{T}Hv α=vTHv,有如下三种情况:
- 对所有v有 α > 0 \alpha>0 α>0 局部最小值
- 对所有v有 α < 0 \alpha<0 α<0 局部最大值
- 有时大于零,有时小于零,代表是鞍点
当处于临界点,我们通过海森矩阵H收集了L的二次微分,对于某点,我们可以代入具体参数值,得到海森矩阵,通过特征值判断类型,例如特征值有正有负,就是鞍点,如果特征值都是正的(正定矩阵),就是局部最小值,负定矩阵同理.实际上H不仅可以判断类型,还指出了参数的更新方向
沿着 u 的方向更新 θ,损失就会变小.因为根据式 (3.10) 和式 (3.11),只要 θ = θ′ + u,沿着特征向量 u 的方向去更新参数,损失就会变小,所以虽然临界点的梯度为零,如果我们是 在一个鞍点,只要找出负的特征值,再找出这个特征值对应的特征向量.将其与 θ′ 相加,就 可以找到一个损失更低的点.
所以,鞍点并非什么大问题,但实际上,我们几乎不会真的把海森矩阵算出来,因为海森矩阵需要算二次微分,计算这个矩阵的运算量非常大,还要把它的特征值 跟特征向量找出来,所以几乎没有人用这个方法来逃离鞍点.还有一些其他逃离鞍点的方法的运算量都比要算海森矩阵小很多.
认识到鞍点其实没那么可怕,我们再回到老问题-局部最小值,我们在训练一个网络的时候,参数数量动辄达百万千万级,所以误差 表面其实有非常高的维度—— 参数的数量代表了误差表面的维度:
在一维中,我们认为自己遇到了局部最小值,实际上在二维中只不过是个鞍点,仍然有路可走(继续优化),那么如果维度足够高,实际上遇到局部最小值的情况很有限,因为一旦能找到临界点,如果其特征值有负,就可以继续梯度下降,只有全为正特征值,才意味着是局部最小值:
最小值比例 = 正特征值数量 总特征值数量 最小值比例=\frac{正特征值数量}{总特征值数量} 最小值比例=总特征值数量正特征值数量
实际上,我们几乎找不到所有特征值都为正的临界点,所以从经验上看起来,局部极小值并没有那么常见.多数的时候,我们训练到一个梯度很小的地方,参数不再更新,往往只是遇到了鞍点.
批量与动量(Batch & Momentum)
在计算梯度时,往往不会直接将所有数据集投入训练,而是将其分为多个批量,每个批量大小为B,训练时,取出B笔数据计算损失,并更新参数,当遍历完全部数据后,称为一个回合(epoch).事实上,每次进行分批量时,还会进行随机打乱(shuffle)
批量大小对梯度下降的影响
在实际训练时,具体的批量大小也作为一个超参数,为了理解这个超参数如何更好确定,取两个极端情况
- 不使用批量(批量大小即训练数据大小),这种使用全批量(full batch)的方法即批量梯度下降法(Batch Gradient Descent),这种方法需要把所有训练数据都查看完,才能够计算损失和梯度,进行一次参数更新
- 批量大小为1,这种方法即随机梯度下降法(Stochastic Gradient Descent),这意味着每取出一次,进行一次更新
理论上,BGD更新需要查看完所有数据,相比SGD可能需要更大的时间开销,每次更新相比SGD更慢,但更稳定.但实际上考虑并行计算,BGD花费的时间不一定比SGD更长(当然,GPU的并行计算能力存在极限).
以上讨论告诉我们在每次计算和更新时,并行计算的支持让批量大小可以尽可能增大,还需要考虑更新次数对时间的开销,当批量过小,单个回合所需要的参数更新次数更多,因此,考虑并行计算时,大批量的计算和更新反而更有效率.
大批量的更新更稳定,回合时间更短,计算时间虽然长但并行计算解决了这个问题,那么小批量的优势在哪?
由于小批量每次随机取一小部分进行计算更新,每次的更新方向是带有随机性的,即梯度方向有噪声(noisy),实际上有噪声的梯度反而可以帮助训练,这个优势体现在优化中.
批量梯度下降在更新参数的时候,沿着一个损失函数来更新参数,走到一个局部最小值点或鞍点显然就停下来了。梯度是零,如果不看海森矩阵,梯度下降就无法再更新参数 。但小批量梯度下降每次挑 一个批量计算损失,所以每一次更新参数的时候所使用的损失函数是有差异的.选到第一个 批量的时候,用 L1计算梯度;选到第二个批量的时候,用 L2计算梯度,在优化时,在某位置对于L1的梯度为0,优化停止,但对于L2,仍能继续优化,继续降低损失.
另外,由于对于局部最小值来说,平坦的最小值相较尖锐的最小值具有更高的稳定性,能够更好的适应损失函数的变化(损失函数变化时具体损失的变动不大),而小批量的随机性正好能让参数有机会脱离尖锐的最小值,找到更好的局部最小值,更具稳定性.
动量法
动量法是另外一个对抗鞍点和局部最小值点的方法
由于惯性,球会滚过鞍点,到达局部最小值,甚至翻过坡找到更好的局部最小值
一般的梯度下降(vanilla gradient descent)如图所示。初始参数为 θ0,计算完梯度后,往梯度的反方向去更新参数 θ1= θ0− ηg0。有了新的参数 θ1后,再计算与更新,直到临界点.
而引入动量后,每次在移动参数的时,不是只往梯度的反方向来移动参数,而是根据梯度的反方向加上前一步移动的方向决定移动方向,每一步的移动都用 m 来表示。m 其实可以写成之前所有计算的梯度的加权和。其中 η 是学习率,λ 是前一个方向的权重参数.可以从两个角度来理解动量法。一个角度是动量是梯度的反方向加上前一次移动的方向。另外一个角度是当加上动量的时候,更新的方向不是只考虑现在的梯度,而是考虑过去所有梯度的总和.
自适应学习率
综上,临界点其实不一定是训练网路时的最大困难,例如由于学习率设置较大,在优化的最后阶段,损失不再下降,但梯度仍不为0,无法到达局部最小值,像在山谷间不断震荡.
那么直接尽可能降低学习率是否可以解决问题?
事实上,学习率过大会出现震荡的情况,学习率过小会在梯度较平缓的非临界点的路上近乎停滞.所以,我们希望学习率在梯度大的地方小一些,在梯度小的地方大步前进,于是产生多种自适应学习率方法.
AdaGrad
AdaGrad(Adaptive Gradient)是典型的自适应学习率方法,其能够根据梯度大小自动调整学习率。AdaGrad可以做到梯度比较大的时候,学习率就减小,梯度比较小的时候,学习率就放大.
梯度下降更新某个参数 θ t i θ_t^i θti 的过程为
θ t + 1 i ← θ t i − η g t i θ_{t+1}^i \leftarrow θ_t^i-η g_t^i θt+1i←θti−ηgti
现在要有一个随着参数定制化的学习率,即把原来学习率 η 变成 η σ t i \frac {η}{σ_t^i} σtiη
θ t + 1 i ← θ t i − η σ t i g t i θ_{t+1}^i \leftarrow θ_t^i-\frac {η}{σ_t^i} g_t^i θt+1i←θti−σtiηgti
σ t i σ_t^i σti的上标i代表参数,下标t代表迭代次数,其定义为:
σ t i = 1 t + 1 ∑ j = 0 t ( g j i ) 2 {σ_t^i}=\sqrt{\frac{1}{t+1}\sum_{j=0}^t{(g_j^i)^2}} σti=t+11j=0∑t(gji)2
将 η σ t i \frac{η}{σ_t^i} σtiη作为新的学习率,当过去的梯度变大,σ变大,学习率就会变小,反之增大,自适应调整更新的步伐
RMSProp
AdaGrap仅考虑了某参数方向上梯度变化不大的情况,根据此调整步伐,实际上,同一个参数需要的学习率,也会随着时间而改变,同一个参数的同个方向,学习率也要动态调整,于是就有了新方法Root Mean Squared propagation.
σ的定义变为:
σ t i = α ( σ t − 1 i ) 2 + ( 1 − α ) ( g t i ) 2 {σ_t^i}=\sqrt{\alpha(σ_t-1^i)^2+(1-\alpha)(g_t^i)^2} σti=α(σt−1i)2+(1−α)(gti)2
通过 α \alpha α可以决定当前梯度的权重大还是过去梯度的影响大,动态决定是否"踩刹车"
Adam
最常用的优化的策略或者优化器(optimizer)是Adam(Adaptive moment estimation).Adam 可以看作 RMSprop 加上动量,其使用动量作为参数更新方向,并且能够自 适应调整学习率.
学习率调度
应用了自适应学习率,我们解决了更新步伐的问题,但是观察优化过程,又会发现新的问题
在梯度小的地方优化时,学习率( η σ t i \frac{η}{σ_t^i} σtiη)会不断增大,步伐的增大让虽然很小的梯度也产生极大的影响发生"爆炸",之后梯度增大,学习率减小,慢慢修正回来,如此往复.
通过学习率调度(learning rate scheduling)可以解决这个问题.之前的学习率调整方法中 η 是一个固定的值,而在学习率调度中 η 跟时间有关 η → η t η\rightarrowη_t η→ηt。学习率调度中最常见的策略是学习率衰减(learning rate decay),也称为学习率退火(learning rate annealing).随着参数的不断更新,让 η 越来越小
除了学习率下降以外,还有另外一个经典的学习率调度的方式———预热。预热的方法是让学习率先变大后变小,至于变到多大、变大的速度、变小的速度是超参数.在预热阶段,一开始学习率比较小是用来探索收集一些有关误差表面的情 报,先收集有关 σ 的统计数据,等 σ 统计得比较精准以后,再让学习率慢慢爬升,而预热完成后开始有效的优化,随着时间进行,逐渐到临界点,步伐也就放慢
优化总结
我们的更新公式进化到了当前版本
θ t + 1 i ← θ t i − η t σ t i m t i θ_{t+1}^i \leftarrow θ_t^i-\frac {η^t}{σ_t^i} m_t^i θt+1i←θti−σtiηtmti
这个版本里面有动量,其不是顺着某个时刻算出的梯度方向来更新参数,而是把过去所有算出梯度的方向做一个加权总和当作更新的方向。接下来的步伐大小为 $\frac {mi_t}{σi_t} $ 。最后通过 ηt来实现学习率调度。这个是目前优化的完整的版本,这种优化器除了 Adam 以外,还有各种变形,但其实各种变形是使用不同的方式来计算m或σ,或者是使用不同的学习率调度的方式