Adam优化器详解

最近在实验室搞的和某公司的校企合作面试中被问到有关Adam优化器的问题。笔者之前也总结过PyTorch中的几种常见优化器的接口和用法,但没有对原理进行详解。于是抽出时间对Adam优化器的细节进行了仔细的学习。

Adam的发展

Adam于2014年12月Kingma和Lei Ba两位学者提出,结合了AdaGrad和RMSProp的优点,对梯度的均值和方差进行综合考虑,计算更新的步长。

AdaGrad

我们都知道在一般的SGD算法中,参数每个维度都是依据相同的人为设定的梯度进行优化。

事实证明这种方法很多时候不能满足需要,这是由于不同维度上的梯度值并不一致。采取相同的学习率很多时候会造成某些梯度大的维度过早出现发散。

AdaGrad根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题。

AdaGrad优化器维护一个变量s_t, 并用这个变量来控制学习率的变化。如果用x表示参数,g表示梯度,则s_t的更新公式如下:

s_t = s_(t-1) + g_t⊙g_t 

其中⊙表示逐个元素相乘,实际上就是得到了梯度的平方数值。很明显随着迭代次数的增加,s_t不断增加。

参数的更新公式如下:

x_t = x_(t-1) + [η / √(s_t + ε)] ⊙ g_t

其中η表示超参数基准学习率,ε通常设置为一个常数值,是为了保证数值的稳定,以及防止分母出现负值。该更新公式会随着迭代次数的增加不断降低学习率,同时由于s_t是一个长度为参数个输的向量,每个参数的学习率下降程度都是动态调整的。

通过pytorch进行一个简单的实现:

import torch
import torch.nn as nn

model = nn.Parameter(torch.randn(10, 1))

# 特征数量为10,10个样本。
x = torch.randn(10, 10)
y = torch.randn(10)
eta = 0.01
s = torch.zeros(10, 1)
for epoch in range(100):
    f = y - x.mm(model)
    f.backward()
    g = model.weight.grad
    model.weight = model.weight - (eta / torch.sqrt(s + 1)) * g
    s = s + g * g

adagrad主要缺点在于当梯度较大的时候,s_t会迅速变大,从而导致η迅速减小。这可能使得模型的训练停滞不前,寻找不到最佳的结果。

RMSProp

RMSProp和AdaGrad十分类似,区别在于为了避免学习率过早地降得太低,采用了一个超参数γ来控制梯度数值对于s_t的影响:

s_t = γ · s_(t-1) + (1 - γ) ` (g_t⊙g_t)

当γ值较大的时候,s_t的变化也会较小,从而模型可以以比较均匀的速度优化。当γ值较小的时候,s_t变化比较剧烈,从而学习率也会迅速减小,模型可以放慢优化速度以寻找最优解。

γ的引入使得使用者可以更加方便地控制学习率移动的幅度, 这种方法被称为指数加权移动平均(exponentially weighted moving average)。

AdaDelta

另一种进行指数加权移动平均的算法是AdaDelta算法。在RMSProp的基础上,该算法不再需要提供η这个基础学习率超参数。而是对参数的实际变化值进行指数加权移动平均。如下所示:

x_t = x_(t-1) + [√(Δx + ε) / √(s_t + ε)] ⊙ g_t

Δx初始化为0,然后通过下式进行迭代更新:

x_t = ρ · x_(t-1) + (1 - ρ) g' ⊙ g'

其中g'是经过学习率调整后的实际参数变化值。ρ和γ通常取相同的值。

Adam算法具体思路和实现

Adam(Adaptive moment estimation)算法是综合了RMSProp中的指数加权平均和SGD中的动量法思路。Adam采用两个不同的超参数β1和β2来控制动量以及RMSP中s_t的更新。

v_t = β1 · v_(t-1) + (1 - β1) · g_t
s_t = β2 · s_(t-1) + (1 - β2) · (g_t⊙g_t)

此外通过计算设计者发现在t时刻,各时刻动量的权值之和为1 - β1^t。为了保证在t较小时该值也能接近1,Adam算法会进行一次梯度修正。即:

v_t = v_t / (1 - β1^t)
s_t = s_t / (1 - β2^t)

每一轮实际梯度为

g_t' = η · v_t / (√s_t + ε)

Adam综合了动量法和指数加权平均的办法。从而也就综合了两者的优点。前者是参考了物理学中动量的概念,使得过去的梯度下降结果对本次梯度产生一定的影响,后者则是一定程度上避免了参数更新的发散。

最后更新于