美文网首页
常见Optimizer

常见Optimizer

作者: 雪糕遇上夏天 | 来源:发表于2021-05-10 17:30 被阅读0次

    深度学习中的常用框架,无论是PyTorch还是TensorFlow,都封装了很多优化器。那么各优化器之间有什么优点和缺点呢。下面我们就回顾一下主流的优化算法。

    1. 前言

    当前大部分的优化算法,其本质都是梯度下降(Gradient Descent),只是不同的算法,对梯度下降进行了不同的优化。那么什么是梯度呢,梯度就是一个函数对其参数求一介偏导数。梯度的特性就是,函数在该点处沿着梯度的方向变化最快。因此梯度下降算法被用于求无约束凸函数的最小值。
    假设目标函数J(\theta),梯度下降算法流程如下:

    • 计算目标函数关于参数\theta的梯度:g_t = \bigtriangledown_{\theta_t}J(\theta)
    • 根据历史梯度计算一介动量和二阶动量:m_t = \phi(g_1, g_2, ... g_t), V_t = \psi(g_1, g_2, ... g_t)
    • 计算当前时刻的下降梯度:\bigtriangledown_t = \eta \times \frac{m_t}{\sqrt{V_t}}
    • 根据下降梯度,更新\theta\theta_{t+1} = \theta_t - \bigtriangledown_t

    2. Gradient Descent

    GD算法是最传统的梯度下降算法,他没有动量的概念,也就是说m_t = g_t, V_t = 1。参数更新方式为: \theta_{t+1} = \theta_t - \eta \times g_t
    沿着梯度的防线不断减小模型参数,从而最小化目标函数。如下图所示:

    梯度下降
    但是梯度下降也有一些不足:
    1. 训练速度慢,每次迭代都需要遍历所有样本,会使训练过程十分缓慢。
    2. 容易陷入局部最优,有些点梯度为0,导致参数不再发生变化,但不一定是目标函数的最优值(如鞍点)。
    3. 随着梯度的变小,参数更新很慢。

    3. Batch Gradient Descent (BGD)

    为了解决GD算法每输入一个样本就要更新一次参数,从而导致的效率低下的问题。BGD做了一些改进,不再是对每个样本都进行参数更新,而是对整体样本进行参数更新,假设现在有n各样本。BGD算法如下:
    \theta_{t+1} = \theta_t - \eta \times \frac{1}{n} \times \sum_{i=0}^n \bigtriangledown_{\theta_t}J(\theta, x_i, y_i)
    BGD的核心就是先算整体样本的梯度均值,在根据这个梯度均值进行参数更新。这样会大大加快参数更新速度,但还有更好的方法。

    4. Stochastic Gradient Descent(SGD)

    随机梯度下降,不再是用整体梯度的均值进行跟新了,而是从训练数据中选取一个样本进行参数更新:
    \theta_{t+1} = \theta_t - \eta \times\bigtriangledown_{\theta_t}J(\theta, x_i, y_i)
    从上边公式看跟GD算法一样,他们的主要区别是,SGD是从训练数据中随机选一个样本,而GD算法是所有训练数据都参与计算。SGD由于每次参数更新只需要一个样本,所以参数更新很快,但由于单个样本存在误差,不能很好代表整体数据,可能会导致梯度下降方向不是整体的最优方向,结果就是梯度下降的波动很大。
    SGD的优点就是能更快的收敛,虽然波动很大,会走很多弯路,但一般总能收敛,而且速度要快得多。
    但它依然没有解决局部最优的问题。

    5. Mini-batch Gradient Descent(MBGD)

    于是人们想到了一种办法,就是BGD和SGD的折中,选择一个mini_batch,batch_size为m:
    \theta_{t+1} = \theta_t - \eta \times \frac{1}{m} \times \sum_{i=x}^{x+m-1}\bigtriangledown_{\theta_t}J(\theta, x_i, y_i)
    MBGD即保证了训练速度,又保证了最优收敛的准确率。
    但是以上所有优化算法都存在一个问题,就是learning rate,如果选的太小会导致收敛很慢,太大会让loss function在极小值处来回震荡,错过极小值。

    6. Momentum

    momentum的核心思想,参数更新时在一定程度上保留之前的更新方向,同时又用当前batch的梯度微调最终的更新方向。也就是通过积累之前的动量来加速当前的梯度。从这个算法开始我们就要引入动量的概念了。其中动量为:
    m_{t+1} = \beta_1 \times m_t + (1-\beta_1) \times g_t
    其中\beta_1的经验值为0.9。参数更新公式为:
    \theta_{t+1} = \theta_t - m_{t+1}
    从以上公式中可以看出,t时刻下降的方向不仅跟当前点的梯度有关,而且跟之前积累的梯度相关。该方法可以缓解梯度波动较大的问题,加速收敛。

    7. Nesterov Accelerated Gradient

    NAG算法可以说是之前momentum算法的变种,他在梯度更新时做了一个矫正,具体做法是在当前的梯度上添加上上一时刻的动量\beta_1m_t。公式如下:
    m_{t+1} = \beta_1m_t + (1-\beta_1)\times\bigtriangledown_{\theta_t}J(\theta_t-\beta_1m_t) \\ \theta_{t+1} = \theta_t - m_{t+1}
    加上nesterov后,梯度在经过大的跳跃之后,会对下一步的梯度计算进行矫正(\theta_t - \beta_1m_t)。

    8. Adagrad

    Adaptive Gradient(自适应梯度),从这之后就会介绍一些自适应学习率的优化方法。AdaGrad其实是对学习率进行了一个约束,对于经常更新的参数,我们已经积累了足够的关于他的信息,不希望被单个样本影响太大,所以希望学习速率慢一些;对于不经常更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本中学习到更多的信息,因此希望学习速率高一些。在该方法中开始使用二介动量,标志着自适应学习率时代的到来。
    那么二介动量是个啥呢,他可以用来衡量历史更新频率,定义是迄今为止所有梯度值的平方和:V_t = \sum_{i=1}^{t}g_t^2,其中g_t为t时刻的梯度。根据前言中的公式(m_t=1):
    V_t = \sum_{i=1}^{t}g_t^2
    参数更新公式如下:
    \theta_{t+1} = \theta_t - \eta\frac{g_t}{\sqrt{V_t + \epsilon}}
    在梯度下降的基础上,对梯度增加了分母:梯度平方累积和的平方根。频繁更新的梯度,则累积的分母项逐渐偏大,那么更新的步长(stepsize)相对就会变小,而稀疏的梯度,则导致累积的分母项中对应值比较小,那么更新的步长则相对比较大。
    然而这种优化方法仍然需要定义超参数\eta,而且随着训练的增加会使参数更新量趋近0,导致训练提前结束,无法学习。

    9. Adadelta

    Adagrad的方式,参数更新量调整的方式过于激进,因此可以考虑调整二介动量的计算方式,使其变得平缓:不使用全部的历史梯度,而是使用过去一段时间窗口下的梯度,并且也不直接存储这些梯度值,仅仅是计算对应的平均值(滑动平均),从而避免二介动量持续累积,导致训练提前结束的问题出现。
    V_t = \beta_2 V_{t-1} + (1-\beta_2)(\bigtriangledown_{\theta_t}J(\theta_t))^2
    \theta_{t+1} = \theta_t - \eta \frac{g_t}{\sqrt{V_t + \epsilon }}
    从上面公式可以发现,参数更新还是需要提供learning rate的。作者在上边的基础上做了进一步处理:
    g_t = \bigtriangledown_{ \theta_t }J(\theta_t)
    E[g_t^2]_t = \rho ·E[g_t^2]_{t-1} + (1-\rho) · g_t^2
    \bigtriangledown_t = \frac{\sum_{i=1}^{t-1}\Delta\theta_r}{\sqrt{E[g_t^2]_t + \epsilon}}
    从上边公式可以看出,更新量\bigtriangledown_t不再以来learnging rate。

    • 训练初中期,加速效果不错,很快
    • 训练后期,反复在局部最小值附近抖动

    10. RMSprop

    RMSprop,将AdaGrad的梯度平方和累加修改为指数加权移动平均,可以是其在非凸设定下效果更好。
    g_t = \bigtriangledown_{\theta_t}J(\theta_t)
    E[g_t^2]_t = \rho ·E[g_t^2]_{t-1} + (1-\rho) · g_t^2
    \bigtriangledown_t = \frac{\eta · g_t}{\sqrt{E[g_t^2]_t + \epsilon}}
    根据经验,有一些超参数的设定可以参考,\eta=0.001, \rho=0.9, \epsilon=1e-9

    • RMSprop依然以来learning rate
    • RMSprop算是Adagrad的一种发展,和Adadelta的变体,效果趋于二者之间
    • 适合处理非平稳目标(包括季节性、周期性),对RNN比较友好。

    11. Adam

    Adaptive Moment Estimation,结合了前面一阶动量,二阶动量的方法。算法伪代码如下:

    Adam

    首先初始化m_0, v_0, t为0,\theta_0为初始化参数,然后循环执行如下步骤:
    m_{t+1} = \beta_1 m_t + (1-\beta_1)\bigtriangledown_{\theta_t}J(\theta_t)
    V_{t+1} = \beta_2 V_t + (1-\beta_2) (\bigtriangledown_{\theta_t}J(\theta_t))^2
    由于m,v都是0初始化的,根据上边公式,\beta_1默认0.9的话,会使m趋近于0,尤其是训练初期,因此对其进行处理:
    \hat{m}_{t+1} = \frac{m_{t+1}}{1-\beta_1^t}
    \hat{v}_{t+1} = \frac{v_{t+1}}{1-\beta_2^t}
    最终更新参数:
    \theta_{t+1} = \theta_t - \eta \frac{\hat{m}_{t+1}}{\sqrt{\hat{V}_{t+1} + \epsilon}}
    通常默认情况下,\beta_1=0.9, \beta_2=0.9999, \epsilon=10^{-8}。Adam对超参数的选择比较鲁棒,在很多情况下算作默认工作性能比较优秀的优化器。

    相关文章

      网友评论

          本文标题:常见Optimizer

          本文链接:https://www.haomeiwen.com/subject/hmyxrltx.html