先说优化器的目标是啥,优化器的目标就是找到函数的最优解,例如现在有一个函数f(X),其中X=x1,x2....xn,如何找到这个函数的最小值,以及找到最小值时的X取值应该是啥,就是优化器要处理的问题。
常见的优化器
1. 梯度下降
梯度下降:GD/SGD/MiniBatch-SGD都是同一套,分别是全部数据、单条数据、若干条数据的梯度下降,是最基础的优化器,函数好比一座山(二元函数比较直观),现在站在山的某个某个位置,如果想要找整座山最低的那个山谷,要做的就两件事:
* 1. 方向:当前这个位置朝哪个方向走,可以以最快的速度下山
* 2. 速度/步长(单步距离):往这个方向走多远的距离比较合适(假设我是一个巨人,一步可以跨很远。。跨的太远有可能会把最低点跨过去)
SGD (Stochastic gradient descent), 随机梯度下降
为了解决方向和距离的问题,就引出梯度下降的方法
* 1. 方向:对于一个函数来说,导数的方向就是上山最快的方向,导数相反的方向就是下山最快的方向,所以这个时候求个导数就知道方向了。梯度下降说白了,就是对函数求导,直接拿梯度对应的方向用就行了。
* 2. 速度/步长(单步距离):这个就需要根据经验?来解决了,也就是梯度下降这个优化方法里唯一的一个参数:学学习率learning rate,也就是这个α
优缺点:
- 优点:实现简单,易于理解。
- 缺点:
- 方向上:收敛速度慢(SGD可能产生振荡),另外容易陷入局部最优解
- 速度上:学习率得自己定义,太大容易走偏(错过最优解),太小收敛速度太慢
因此接下来的所有优化基本都是在方向和速度两个方面进行的:
2. 动量优化器Momentum
严格来说应该叫gradient descent with momentum,带动量的梯度下降
虽然GD/SGD/MBSGD的大概原理类似,但是实际上还是有区别的,区别就在于,GD是真的全局的梯度,而SGD只是在那几个样本上的算出来的梯度,是一个估计值,这个估计值有可能和GroundTruth差不多也可能差很多。如图,左侧是理想的GD,右侧是可能的SGD,特别是在坡度比较明确和广阔的区域,就一直沿着某一方向走就好了,经常跳动很容易带来收敛速度的减缓。
为了解决振荡的问题(即一个mini-batch的梯度可能偏差很大的问题),解决mini-batch和全量SGD的之间GAP的方式,当然就是扩大mini-batch的batch_size,显然batch_size越大,两者就倾向于越接近,振荡也就越小。 但是扩大batch_size很多时候是受到资源限制的,那怎么办呢?所以能不能将每一步的batch加起来,例如将上一步算的梯度和这一步算的梯度合起来求个平均,这个时候batch_size就相当于扩大了一倍。但是将上一步的梯度(甚至更往前的梯度)和这一步的梯度直接合到一块儿,会产生什么效果呢?
首先,这意味着,多次累计的梯度的方向会产生趋势,而每一次的迭代,只是对趋势产生一部分的影响,而不是完全替换掉。
这个靠谱么?看两种情况:
* 1. 在离低谷比较远的时候:这种情况下,一般来说两次的梯度之间,方向上不应该差很多。所以引入前面的方向之后,会变的更平滑,缓解振荡,使得收敛速度更快
* 作为一种特例,在平坦的区域(梯度为0不一定意味着是低谷)也有助于可以穿越过去
* 2. 在离低谷比较近的时候:如果没有动量,每一次迭代步骤本身都容易跳过最低谷,然后在最低谷附近来回振荡,而无法真正的达到。加上动量之后,方向应该不会乱跳了,基本上可以朝正确的最低谷的方向走(但有可能会因步数大跳过去)。 另外由于动量的存在,到达低谷之后,大概率还会再往前冲几步,如果这个谷是一个小的低谷,可能就能冲出去,从而摆脱当前的这个低谷(可能是局部最优解,当然也可能miss掉了一个最优解。。),如果是个大谷,可能冲不出去,过了若干步又回来了。。。
定义动量变量:
其中,g(t) 是当前时间步的梯度,v(t) 是当前的动量,β是动量因子,通常设为0.9。
更新参数:
其中,θ是模型参数,α是学习率,这一步和SGD是一样的,其实就是第一步里面,计算方向的这一步在计算梯度的基础上,又加了个历史梯度,而且一般历史梯度占的权重远大于新的梯度。。。
还有有一点值得注意的是,梯度本身有个特点,就是在越陡峭的地方,梯度越大,从而使得下降的速度也会越快,因此利用累计梯度的话,会使得即使现在已经在不那么陡峭的地方了,但下降速度仍然很快,这一点有一个好处,就是这样也会使得下降更快(也就是说不光是方向上的稳定带来的收敛更快,在速度上带动量趋势也会加速收敛)。 但这也会带来一个弊端,就是真到了最低值的时候,其实应该慢点,否则有可能会因为跨的步子太大,从最低点越过去。。。
另外,在参数量上,因为为每个参数都维护了一个自己的动量,因此额外引入了一倍的参数量,即如果模型参数量是N,则又引入了一个N的参数量。
3.内斯特洛夫加速梯度 Nesterov’s Accelerated Gradient
这个方法名字比较多,有叫Nesterov Momentum等,这篇文章管这种方法叫做Nesterov Accelerated Gradient On The Importance Of Initialization And Momentum In Deep Learning 也简称NAG。
4. AdaGrad - Adaptive Gradient Algorithm
主要动机Why:主为了解决在机器学习和深度学习训练过程中,不同参数可能需要不同学习率的问题。
这里面应该是有两个假设:
1. 对梯度大的参数,需要相对小一点的学习率,因为太大的话会振荡?
2. 对梯度小的参数,需要相对大一点的学习率,因为太小会让收敛速度太慢?
但是问题是梯度大本来就表示可能离最优解还比较远,就得快点走啊。。。梯度小反过来。。当然Adagrad实际是用的累积梯度,不知道是不是累积的多就应该慢一点。。
所以如果两个参数,一个梯度很大,一个梯度很小,可能就分开走比较好。
核心思想和方法HOW:随着时间的推移
* 如果某个参数的梯度一直较大,注意是一直大,也就是梯度的累积比较大,那么它的学习率就让其减小得更快(因为担心走的太快,会振荡)
* 相反,如果某个参数的梯度较小,它的学习率减小得就慢。(因为担心走的太慢,收敛的太慢)
所以这里就是在原始的SGD梯度的基础上,除以了一个累加的梯度(ϵ是一个很小的数,如10−8,避免除以0),t表示更新的步数,i表示第i个参数,即每个参数有自己的梯度累积。gt=∇θf(θt−1)表示梯度
这个Gt就是所有历史梯度的平方和
优缺点:
- 优点:可以让快的慢一点,慢的快一点,自适应的调学习率
- 缺点:Gt是一个累加值,会越来越大,后面作为分母之后可能导致整个乘积项趋向于0,导致梯度消失,更新不动了。
另外需要注意的是,在参数量上,因为为每个参数都维护了一个自己的梯度累积值,因此额外引入了一倍的参数量,即如果模型参数量是N,则又引入了一个N的参数量。
5. RMSprop-Root Mean Square Propogation
动机:是由Geoffrey Hinton在2012年提出的一种自适应学习率的方法,它是AdaGrad的一个变体,主要为了解决AdaGrad在训练后期学习率下降过快的问题
方法:主要是引入了指数移动平均(exponential moving average, EMA)来估计梯度的平方根,而不是直接累积所有的历史梯度平方,从而提供了更加稳定的梯度尺度估计,避免了学习率过度减小
将Adagrad里的梯度累积公式,变成:
相当于在右侧两个加数之前,分别乘上了一个因子,累积的梯度一般占主导ρ一般设置为0.9
但事实上,因为分别乘了两个和为1的因子,已经不能算是严格意义上的梯度累积了。举个例子,如果更新了10次,每次梯度都是一样的话,每次得到的累积值其实也都是一样的。。。并没有真的累积起来,而如果最新的一次梯度很大,求得的累计值也会比上次大,如果最新的一次梯度很小,求得的累计值也会比上次小。。。
而如果不用历史累计值的话,那不如直接把公式第一个加数舍去,直接用最新这一步的偏导,扔到公式里,变成偏导的导数,再乘以偏导,结果变成了1(也可能是-1)。。。这样相当于梯度就算了个+/-号,具体的梯度大小没关系了。。直接变成以斜率更新。。。。
实际上现在这个公式,如果当前梯度和之前梯度”累积值”一样的话,就是这个效果,就算不一样,那也是当前梯度值大一点,那就以learning rate乘上一个大于1的数更新,当前梯度小一点及时learning rate乘上一个小于1的数更新。 也就是说这个时候梯度大的还是快一些,但是收到了一定程度的抑制,反之亦然。
6. Adam-Adaptive Moment Estimation
这个基本上可以理解为2.Momentum和5.RMSprop的结合版
对梯度(方向):
对学习率(步长):
上面这两个公式从形式上看很像,实际上一个是对梯度的一阶矩估计,另一个是对梯度的二阶矩估计,当然这两者的作用不太一样,梯度那个是直接替换掉SGD里的梯度,作为新的梯度直接使用;而二阶那个,是作为一个因子,开根号之后,用学习率除以这个值得到的新值。
但是这个地方有一个小问题,就是初始化的时候m0和v0都是0,会导致一开始算出来的初始值都非常小。。所以每一步算完m和v之后会除以一个比较大的数做一个扩大,分别是:
这里面β1和β2都是t次幂,步数多了之后这两个数都会趋近于0,分母就趋近于1,接近于不用优化了。
然后最终得到一个新的值,这个值从形式上看和前面的RMSprop等几个差不多。
7. AdamW - Adam with decoupled weight decay
AdamW其实就是在损失函数引入了L2正则项之后,对原始的Adam做了一下优化。
为了方式模型过拟合,通常会引入L2正则项,抑制权重:
这样形式的损失函数,用Adam进行优化就是下面红色框里的形式
AdamW对Adam进行的改造,本质上就是说在梯度下降的时候,只对原始的Loss函数进行方向和步长上的调整,而额外引入的L2正则项,按照正常的SGD的逻辑迭代,不加入到Adam的一阶矩、二阶矩的调整当中。
AdamW某种程度上是对含L2正则项的损失函数,在用Adam优化器优化的时候进行的一种修正,保证L2损失函数的本身可以高效和准确的发挥自身作用。
Backup:
在深度学习中,优化器(Optimizer)是用于更新模型参数以最小化损失函数的算法。以下是一些最常见的优化器:
-
SGD (Stochastic Gradient Descent):
- 这是最基本的优化器,逐个样本更新参数。
- 优点:实现简单,易于理解。
- 缺点:收敛速度慢,可能在局部最优解附近震荡。
-
Momentum:
- 是对SGD的一种改进,使用历史梯度来加速当前梯度的更新。
- 优点:可有效减少震荡,加快收敛。
- 缺点:需要选择合适的动量超参数。
-
Nesterov Accelerated Gradient (NAG):
- 在Momentum的基础上,使用了梯度的更新进行“预见”来调整参数。
- 优点:更进一步地减少震荡,提供更快的收敛速度。
-
AdaGrad:
- 根据参数的历史梯度自适应调整学习率,适合处理稀疏数据。
- 优点:对于频繁更新的参数,它会降低学习率,反之则增加。
- 缺点:学习率随着时间的推移而单调减小,可能导致训练过早停止。
-
RMSprop:
- 结合了AdaGrad的优点,使用指数衰减移动平均来计算梯度的平方。
- 优点:解决了AdaGrad学习率过早降低的问题。
- 常用于循环神经网络(RNN)等问题。
-
Adam (Adaptive Moment Estimation):
- 结合了Momentum和RMSprop的优点,维护一阶矩(均值)和二阶矩(方差)的移动平均。
- 优点:能够自适应调整学习率,适合大规模数据和高维空间。
- 是目前使用最广泛的优化器之一。
-
AdamW:
- 是Adam的变体,增加了权重衰减(L2正则化)的实现方式,以改善正则化效果。
- 优点:在训练过程中保持学习率的稳定性和正则化能力。
-
Nadam:
- 是Nesterov动量和Adam的结合,尝试获得两者的优点。
- 优点:能更快地收敛,适用于许多任务。
-
FTRL (Follow The Regularized Leader):
- 在大规模在线学习中常用,适合处理稀疏数据。
不同的任务、数据集和模型架构可能会对优化器的选择产生影响。在实践中,找到最适合特定问题的优化器通常需要实验和调优。
Reference: