常见Optimizer
深度学习中的常用框架,无论是PyTorch还是TensorFlow,都封装了很多优化器。那么各优化器之间有什么优点和缺点呢。下面我们就回顾一下主流的优化算法。
1. 前言
当前大部分的优化算法,其本质都是梯度下降(Gradient Descent),只是不同的算法,对梯度下降进行了不同的优化。那么什么是梯度呢,梯度就是一个函数对其参数求一介偏导数。梯度的特性就是,函数在该点处沿着梯度的方向变化最快。因此梯度下降算法被用于求无约束凸函数的最小值。
假设目标函数,梯度下降算法流程如下:
- 计算目标函数关于参数的梯度:
- 根据历史梯度计算一介动量和二阶动量:
- 计算当前时刻的下降梯度:
- 根据下降梯度,更新:
2. Gradient Descent
GD算法是最传统的梯度下降算法,他没有动量的概念,也就是说。参数更新方式为: 。
沿着梯度的防线不断减小模型参数,从而最小化目标函数。如下图所示:
但是梯度下降也有一些不足:
- 训练速度慢,每次迭代都需要遍历所有样本,会使训练过程十分缓慢。
- 容易陷入局部最优,有些点梯度为0,导致参数不再发生变化,但不一定是目标函数的最优值(如鞍点)。
- 随着梯度的变小,参数更新很慢。
3. Batch Gradient Descent (BGD)
为了解决GD算法每输入一个样本就要更新一次参数,从而导致的效率低下的问题。BGD做了一些改进,不再是对每个样本都进行参数更新,而是对整体样本进行参数更新,假设现在有n各样本。BGD算法如下:
BGD的核心就是先算整体样本的梯度均值,在根据这个梯度均值进行参数更新。这样会大大加快参数更新速度,但还有更好的方法。
4. Stochastic Gradient Descent(SGD)
随机梯度下降,不再是用整体梯度的均值进行跟新了,而是从训练数据中选取一个样本进行参数更新:
从上边公式看跟GD算法一样,他们的主要区别是,SGD是从训练数据中随机选一个样本,而GD算法是所有训练数据都参与计算。SGD由于每次参数更新只需要一个样本,所以参数更新很快,但由于单个样本存在误差,不能很好代表整体数据,可能会导致梯度下降方向不是整体的最优方向,结果就是梯度下降的波动很大。
SGD的优点就是能更快的收敛,虽然波动很大,会走很多弯路,但一般总能收敛,而且速度要快得多。
但它依然没有解决局部最优的问题。
5. Mini-batch Gradient Descent(MBGD)
于是人们想到了一种办法,就是BGD和SGD的折中,选择一个mini_batch,batch_size为m:
MBGD即保证了训练速度,又保证了最优收敛的准确率。
但是以上所有优化算法都存在一个问题,就是learning rate,如果选的太小会导致收敛很慢,太大会让loss function在极小值处来回震荡,错过极小值。
6. Momentum
momentum的核心思想,参数更新时在一定程度上保留之前的更新方向,同时又用当前batch的梯度微调最终的更新方向。也就是通过积累之前的动量来加速当前的梯度。从这个算法开始我们就要引入动量的概念了。其中动量为:
其中的经验值为0.9。参数更新公式为:
从以上公式中可以看出,t时刻下降的方向不仅跟当前点的梯度有关,而且跟之前积累的梯度相关。该方法可以缓解梯度波动较大的问题,加速收敛。
7. Nesterov Accelerated Gradient
NAG算法可以说是之前momentum算法的变种,他在梯度更新时做了一个矫正,具体做法是在当前的梯度上添加上上一时刻的动量。公式如下:
加上nesterov后,梯度在经过大的跳跃之后,会对下一步的梯度计算进行矫正()。
8. Adagrad
Adaptive Gradient(自适应梯度),从这之后就会介绍一些自适应学习率的优化方法。AdaGrad其实是对学习率进行了一个约束,对于经常更新的参数,我们已经积累了足够的关于他的信息,不希望被单个样本影响太大,所以希望学习速率慢一些;对于不经常更新的参数,我们了解的信息太少,希望能从每个偶然出现的样本中学习到更多的信息,因此希望学习速率高一些。在该方法中开始使用二介动量,标志着自适应学习率时代的到来。
那么二介动量是个啥呢,他可以用来衡量历史更新频率,定义是迄今为止所有梯度值的平方和:,其中为t时刻的梯度。根据前言中的公式():
参数更新公式如下:
在梯度下降的基础上,对梯度增加了分母:梯度平方累积和的平方根。频繁更新的梯度,则累积的分母项逐渐偏大,那么更新的步长(stepsize)相对就会变小,而稀疏的梯度,则导致累积的分母项中对应值比较小,那么更新的步长则相对比较大。
然而这种优化方法仍然需要定义超参数,而且随着训练的增加会使参数更新量趋近0,导致训练提前结束,无法学习。
9. Adadelta
Adagrad的方式,参数更新量调整的方式过于激进,因此可以考虑调整二介动量的计算方式,使其变得平缓:不使用全部的历史梯度,而是使用过去一段时间窗口下的梯度,并且也不直接存储这些梯度值,仅仅是计算对应的平均值(滑动平均),从而避免二介动量持续累积,导致训练提前结束的问题出现。
从上面公式可以发现,参数更新还是需要提供learning rate的。作者在上边的基础上做了进一步处理:
从上边公式可以看出,更新量不再以来learnging rate。
- 训练初中期,加速效果不错,很快
- 训练后期,反复在局部最小值附近抖动
10. RMSprop
RMSprop,将AdaGrad的梯度平方和累加修改为指数加权移动平均,可以是其在非凸设定下效果更好。
根据经验,有一些超参数的设定可以参考,。
- RMSprop依然以来learning rate
- RMSprop算是Adagrad的一种发展,和Adadelta的变体,效果趋于二者之间
- 适合处理非平稳目标(包括季节性、周期性),对RNN比较友好。
11. Adam
Adaptive Moment Estimation,结合了前面一阶动量,二阶动量的方法。算法伪代码如下:
Adam首先初始化为0,为初始化参数,然后循环执行如下步骤:
由于m,v都是0初始化的,根据上边公式,默认0.9的话,会使m趋近于0,尤其是训练初期,因此对其进行处理:
最终更新参数:
通常默认情况下,。Adam对超参数的选择比较鲁棒,在很多情况下算作默认工作性能比较优秀的优化器。