2023年11月29日发(作者:)

深度学习Adam优化算法理论知识和学习率的变化

在最近学习中,⽤Adam作为优化器,在训练时打印学习率发现学习率并没有改变。这好像与之前理解的⾃适应的学习率有所⽭盾?

Adam的理论知识

问题1 指数滑动平均是什么?

Exponential Moving Average (EMA) 指数滑动平均指各数值的加权系数随时间呈指数式递减,越靠近当前时刻的数值加权系数就越⼤。

为例,从上⾯的推导可以看到,越远离时刻t,其梯度所占的⽐重就越⼩,在梯度在不断的更新的过程中,虽然使⽤了历史梯度,但是

m

t

在不同时刻的梯度对当前贡献不同,离时刻t越近,对的影响就越⼤,离时刻t越远,对的影响就越⼩。

mmm

ttt

问题2 为什么需要进⾏修正?

1)通俗解释:

当对不进⾏修正时():

mβ=0.9

t1

m

0

=0

mβm+(1β)g0.1g

110111

==

m0.90.1g+0.1g0.09g+0.1g

21212

==

m0.081g+0.09g+0.1g3

312

=

依次类推,我们可以看到由于=0,导致,均向0进⾏偏置,也会离越来越远。

mmg

0tt

2)理论公式解释:

从上⾯的更新公式可以看出来,相当于是梯度⼀阶距估计,所以我们计算的期望:

mmgm

tttt

从上⾯的公式可以看到,需要将修正为 ,才能近似认为为梯度的⽆偏距估计。同样的思路可以解释的修正。

mm/(1β)mgv

tt1ttt

t

问题3 学习率是如何变化的?

在Adam论⽂中指出可以将下⾯三⾏公式:

等价替换成:

在pytorch源代码中也是按照上述这种写法(附在最后⾯)。

t

那这样写是不是说明学习率的变化是由来决定呢,那这样还能称之为⾃适应的学习率吗?

α/(1β)

1β

2

1

t

我们知道梯度下降法的定义公式:

按照梯度下降法的定义公式,我们可以将参数更新公式写成:

θ=θ

t

t−1t

α

v^

t

+ε

m^

^v

t

+ε

可以看作在t时刻,参数 的学习率。从上述公式也可以看出来,对于不同的参数,在每其中,将视为梯度的⼀阶距估计,那么

θmg

ttt

α

⼀时刻都会有不同的学习率,所以很难对其进⾏可视化。

最后附上Adam源码

我通过pytorch1.2/lib/python3.7/site-packages/torch/optim/找到⽂件,下⾯是代码:

def step(self, closure=None):

loss = None

if closure is not None:

loss = closure()

for group in self.param_groups:

for p in group['params']:

if p.grad is None:

continue

grad = p.grad.data

if grad.is_sparse:

raise RuntimeError('Adam does not support sparse gradients, please consider SparseAdam instead')

amsgrad = group['amsgrad']

state = self.state[p]

# State initialization

if len(state) == 0:

state['step'] = 0

# Exponential moving average of gradient values

state['exp_avg'] = torch.zeros_like(p.data)

# Exponential moving average of squared gradient values

state['exp_avg_sq'] = torch.zeros_like(p.data)

if amsgrad:

# Maintains max of all exp. moving avg. of sq. grad. values

state['max_exp_avg_sq'] = torch.zeros_like(p.data)

exp_avg, exp_avg_sq = state['exp_avg'], state['exp_avg_sq']

if amsgrad:

max_exp_avg_sq = state['max_exp_avg_sq']

beta1, beta2 = group['betas']

state['step'] += 1

if group['weight_decay'] != 0:

grad.add_(group['weight_decay'], p.data)

# Decay the first and second moment running average coefficient

exp_avg.mul_(beta1).add_(1 - beta1, grad)

exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad)

if amsgrad:

# Maintains the maximum of all 2nd moment running avg. till now

torch.max(max_exp_avg_sq, exp_avg_sq, out=max_exp_avg_sq)

# Use the max. for normalizing running avg. of gradient

denom = max_exp_avg_sq.sqrt().add_(group['eps'])

else:

denom = exp_avg_sq.sqrt().add_(group['eps'])

bias_correction1 = 1 - beta1 ** state['step']

bias_correction2 = 1 - beta2 ** state['step']

step_size = group['lr'] * math.sqrt(bias_correction2) / bias_correction1

p.data.addcdiv_(-step_size, exp_avg, denom)

return loss

以上均是我个⼈的理解,如果各位有更好的想法可以留⾔,共同学习进步!