梯度下降优化算法

原文:An overview of gradient descent optimization algorithms

梯度下降算法

梯度下降算法(Gradient Descent Optimization)是神经网络模型训练最常用的优化算法。详见:梯度下降

梯度下降算法的原理:

  • 目标函数 J(θ)J(\theta) 关于参数 θ\theta 的梯度将是损失函数(loss function)上升最快的方向。

  • 要最小化 loss,只需要将参数沿着梯度相反的方向前进一个步长,就可以实现目标函数(loss function)的下降。这个步长 η\eta 又称为学习速率。

  • 参数更新公式如下:

    θθηJ(θ)\theta\leftarrow \theta-\eta \cdot \nabla J(\theta)

  • 其中 J(θ)\nabla J(\theta) 是参数的梯度。

根据计算目标函数采用数据量的不同,梯度下降算法又可以分为:

  • 批量梯度下降算法(Batch Gradient Descent,BGD)

    J(θ)J(\theta) 是在整个训练集上计算的,如果数据集比较大,可能会面临内存不足问题,而且收敛速度一般比较慢。

  • 随机梯度下降算法(Stochastic Gradient Descent,SGD)

    又称为在线学习,即得到了一个样本,就可以执行一次参数更新。所以其收敛速度会快一些,但是有可能出现目标函数值震荡现象,因为高频率的参数更新导致了高方差。

  • 小批量梯度下降算法(Mini-batch Gradient Descent,MBGD)。

    是折中方案,选取训练集中一个小批量样本(一般是2的倍数,如32,64,128等)计算,这样可以保证训练过程更稳定,而且采用批量训练方法也可以利用矩阵计算的优势,是目前最常用的梯度下降算法。

问题与挑战:

  • 选择一个合适的学习率可能是困难的。学习率太小会导致收敛的速度很慢,学习率太大会妨碍收敛,导致损失函数在最小值附近震荡甚至发散。

  • 虽然可以通过退火等方法调整学习率,但策略和阈值需要预先设定好,因此无法适应数据集的特点。

  • 另一方面,SGD 不易处理鞍点处的梯度。由于鞍点周围的误差相同,梯度在所有方向都接近于0,导致 SGD 很难脱离鞍点。

Momentum

  • SGD(指上面的三种方法)的参数更新完全依赖于当前的 batch,容易出现震荡现象

  • 动量(Momentum optimization) 通过将当前时刻的梯度 ηθJ(θ)\eta \nabla_\theta J( \theta),与前一时刻的梯度 vt1v_{t-1} 按照动量的系数 γγ 进行加权,使得当前的更新方向包括当前梯度的方向与之前时刻梯度的方向,来增加更新的稳定性,同时抑制 SGD 的震荡现象。

vt=γvt1+ηθJ(θ)v_t = \gamma v_{t-1} + \eta \nabla_\theta J( \theta)

θ=θvt\theta = \theta - v_t

  • 动量的系数 γγ 表示保留原来方向的程度,通常设置为 0.9 左右。

  • 当梯度指向收敛方向时,动量加快更新速度;当梯度改变方向时,动量降低更新速度。从而在保证收敛更快的同时,减弱震荡现象。

NAG

  • NAG 即 Nesterov accelerated gradient 涅斯捷罗夫梯度加速。相比于momentum,NAG 增加了一个将要去哪里的指示,因而在曲面上升时,能够降低更新速度。

  • NAG 在计算参数的梯度时,在损失函数中减去了动量项,即计算 θJ(θγνt1)\nabla_{\theta}J(\theta-\gamma \nu_{t-1}),这种方式预估了下一次参数所在的近似位置。即:

νt=γνt1+ηθJ(θγνt1)\nu_t=\gamma\nu_{t-1}+\eta \cdot \nabla_{\theta}J(\theta-\gamma \nu_{t-1})

θ=θνt\theta=\theta-\nu_t

  • 动量系数 γγ 通常设置为 0.9 左右。

  • 在 Momentum 中,首先计算当前梯度项(小蓝色向量),然后加上动量项,这样便得到了大的跳跃(大蓝色的向量)。

  • NAG 首先进行一个大的跳跃(动量项)(棕色向量),然后加上一个小的使用了动量计算的当前梯度(红色向量)进行修正得到绿色的向量,避免更新过猛。

Adagrad

  • Adagrad 即 Adaptive Gradient Algorithm 自适应梯度算法。

  • 上面的方法在参数更新过程中,使用了固定的学习率。Adagrad 则是让学习率适应参数。

  • 对于出现次数较少的特征,对其采用更大的学习率,对于出现次数较多的特征,对其采用较小的学习率。因而适用于处理稀疏数据。

  • gt,ig_{t, i} 为在 tt 时刻目标函数关于参数 θi\theta_i 的梯度:

    gt,i=θJ(θi)g_{t, i} = \nabla_\theta J( \theta_i )

  • 通常,在 tt 时刻,对参数 θi\theta_i 的更新过程为:

    θt+1,i=θt,iηgt,i\theta_{t+1, i} = \theta_{t, i} - \eta \cdot g_{t, i}

  • 使用 Adagrad 时,在 tt 时刻,基于对 θi\theta_i 计算过的历史梯度,对每一个参数 θi\theta_i 的学习率进行了修正:

    θt+1,i=θt,iηGt,ii+ϵgt,i\theta_{t+1, i} = \theta_{t, i} - \dfrac{\eta}{\sqrt{G_{t, ii} + \epsilon}} \cdot g_{t, i}

  • 其中,GtRd×dG_{t} \in \mathbb{R}^{d \times d} 是一个对角矩阵。

  • ii 行的对角元素 eiie_{ii} 为第 ii 个参数 θi\theta_i 的历史梯度的平方和。

  • ϵ\epsilon 是一个平滑参数,为了使得分母不为 0 (通常 ϵ\epsilone8e−8 )。

  • 另外如果分母不开根号,算法性能会很糟糕。

  • 再进一步,将所有 Gt,ii,gt,iG_{t,ii},g_{t,i} 的元素写成向量 Gt,gtG_t,g_t , Adagrad 算法参数更新的矩阵形式如下:

θt+1=θtηGt+ϵgt\theta_{t+1} = \theta_{t} - \frac{\eta}{\sqrt{G_{t}+\epsilon}} \odot g_{t}

  • 其中 ⊙ 为点乘,即矩阵对应元素相乘。

  • Adagrad 的优点是无需手动调整学习率。在大多数的应用场景中,通常采用常数0.01。

  • Adagrad的缺点是它在分母中累加梯度的平方,在整个训练过程中,累加的和会持续增长,导致学习率最终变得无限小,无法学习到新的特征。

Adadelta

  • Adadelta 是 Adagrad 的一种扩展算法,以处理 Adagrad 学习速率单调递减的问题。

  • Adadelta 只计算窗口大小为 ww 的最近历史梯度,同时,并不存储历史平方梯度值,而是将梯度的平方递归地表示成所有历史梯度平方的均值。

  • tt 时刻的均值 E[g2]tE[g^2]_t 只取决于先前的均值和当前的梯度(分量γγ 类似于动量项):

    E[g2]t=γE[g2]t1+(1γ)gt2E[g^2]_t = \gamma E[g^2]_{t-1} + (1 - \gamma) g^2_t

  • 在 Adagrad 中梯度更新值为:

    Δθt=ηGt+ϵgt\Delta \theta_t = - \dfrac{\eta}{\sqrt{G_{t} + \epsilon}} \odot g_{t}

  • 在 Adadelta 中梯度更新值为:

    Δθt=ηE[g2]t+ϵgt\Delta \theta_t = - \dfrac{\eta}{\sqrt{E[g^2]_t + \epsilon}} g_{t}

  • 由于分母仅仅是梯度的均方根(root mean squared,RMS)误差,可以简写为:

    Δθt=ηRMS[g]tgt\Delta \theta_t = - \dfrac{\eta}{RMS[g]_{t}} g_t

  • 将上面公式改成关于 θtθ_t 的:

    E[Δθ2]t=γE[Δθ2]t1+(1γ)Δθt2E{{\left[ \Delta {{\theta }^{2}} \right]}_{t}}=\gamma E{{\left[ \Delta {{\theta }^{2}} \right]}_{t-1}}+(1-\gamma )\Delta \theta _{t}^{2}

  • 参数更新的均方根误差为:

    RMS[Δθ]t=E[Δθ2]t+ϵRMS[\Delta \theta]_{t} = \sqrt{E[\Delta \theta^2]_t + \epsilon}

  • 由于 RMS[Δθ]tRMS[\Delta \theta]_{t} 未知,使用之前时刻的 RMS 值 RMS[Δθ]t1RMS[\Delta \theta]_{t-1} 替换先前的更新规则中的学习率 ηη。最终的 Adadelta 更新公式为:

    Δθt=RMS[Δθ]t1RMS[g]tgt\Delta \theta_t = - \dfrac{RMS[\Delta \theta]_{t-1}}{RMS[g]_{t}} g_{t}

    θt+1=θt+Δθt\theta_{t+1} = \theta_t + \Delta \theta_t

  • 使用 Adadelta 算法,无需设置默认的学习率,因为更新规则中已经移除了学习率。

RMSprop

  • RMSprop 未发表,但是也是自适应学习率的算法,由Geoff Hinton提出。

  • RMSprop 和 Adadelta 在相同的时间里被独立的提出,都起源于对Adagrad 的极速递减的学习率问题的求解。

  • 实际上,RMSprop 是 Adadelta 的第一个更新向量的特例:

    E[g2]t=0.9E[g2]t1+0.1gt2E[g^2]_t = 0.9 E[g^2]_{t-1} + 0.1 g^2_t

    θt+1=θtηE[g2]t+ϵgt\theta_{t+1} = \theta_{t} - \dfrac{\eta}{\sqrt{E[g^2]_t + \epsilon}} g_{t}

  • 同样,RMSprop 将学习率分解成一个平方梯度的指数衰减的平均。Hinton 建议将 γγ 设置为 0.9,对于学习率 ηη,一个好的固定值为0.001。

Adam

  • Adam 即 Adaptive Moment Estimation 自适应矩估计,是另一种自适应学习率的算法,Adam对每一个参数都计算自适应的学习率。

  • 除了像 Adadelta 和 RMSprop一样存储一个指数衰减的历史平方梯度的平均 vtv_t,Adam 同时还保存一个历史梯度的指数衰减均值 mtm_t,类似于动量:

    mt=β1mt1+(1β1)gtm_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t

    vt=β2vt1+(1β2)gt2v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2

  • mtm_tvtv_t 分别是对梯度的一阶矩(均值)和二阶矩(非确定的方差)的估计,正如该算法的名称。

  • Adam 的作者发现当衰减率(decay rate)很小时(β1β_1β2β_2 接近于 1),mtm_tvtv_t 最终都趋于0,因而Adam算法最终对一阶矩和二阶矩进行校正(β1β_1β2β_2 的上标 tt 代表 tt 次方):

    m^t=mt1β1t\hat{m}_t = \dfrac{m_t}{1 - \beta^t_1}

    v^t=vt1β2t\hat{v}_t = \dfrac{v_t}{1 - \beta^t_2}

  • 最终 Adam 的更新规则为:

    θt+1=θtηv^t+ϵm^t\theta_{t+1} = \theta_{t} - \dfrac{\eta}{\sqrt{\hat{v}_t} + \epsilon} \hat{m}_t

  • 作者建议 $β_1 取默认值为 0.9, β2β_2 为0.999,ϵϵ10810^{−8}

算法的选择

  • 如果输入数据是稀疏的,选择任一自适应学习率算法可能会得到最好的结果。选用这类算法的另一个好处是无需调整学习率,选用默认值就可能达到最好的结果。

  • RMSprop 是 Adagrad 的扩展形式,用于处理在 Adagrad 中急速递减的学习率。

  • RMSprop 与 Adadelta 相同,所不同的是 Adadelta 在更新规则中使用参数的均方根进行更新。

  • Adam 是将偏差校正和动量加入到 RMSprop 中。

  • 在这样的情况下,RMSprop、Adadelta 和 Adam 是很相似的算法并且在相似的环境中性能都不错。在优化后期由于梯度变得越来越稀疏,偏差校正能够帮助Adam微弱地胜过 RMSprop。

  • 综合看来,Adam可能是最佳的选择。

  • 有趣的是,最近许多论文中采用不带动量的 SGD 和一种简单的学习率的退火策略。通常 SGD 能够找到最小值点,但是比其他优化的 SGD 花费更多的时间,与其他算法相比,SGD 更加依赖鲁棒的初始化和退火策略,同时,SGD 可能会陷入鞍点,而不是局部极小值点。

  • 因此,如果想要快速收敛和训练一个深层的或者复杂的神经网络,可以选择一个自适应学习率的方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章