指数滑动平均Exponential Moving Average
这个概念经常在论文或者算法中看到,尤其是在随机梯度下降算法的改进算法中看到,就整理出来写一篇文章。
指数滑动平均,或者叫做指数加权平均(exponentially weighted moving average),可以看做一段时间内的历史加权均值。一般近期的数据拥有更高的权重。
假如有一个参数 ,在不同的epoch下具有如下取值。 。我们假定衰减率(衰减因子)是 ,则训练结束 的滑动平均值就是 。看到这个公式就知道Momentum和Adam的优化公式就用到了这个概念。
之所以叫指数滑动平均,是因为滑动窗口中的值求均值的时候前面的值是呈指数衰减的。因为权重的指数级别衰减,导致前面的值对后面的结果产生的影响减少,此时可以认为滑动均值只和最近的迭代有关系。通常衰减因子越大,前面的值衰减的就越缓慢,参数的更新就会越缓慢。如果对应sgd with momentum解释的话就是,如果当前的梯度和之前的梯度均值反向的话,就会前进的慢,如果和之前的梯度均值同向的话,就会前进的快,这样就可以抑制震荡。
一般认为,这个均值只和最近的 个值有关,而如果这些向量的方向全都相同的话,可以认为叠加之后速度提升的倍数是正比于 的,如果 ,带入计算可知 。
####pytroch代码实现
class EMA():
def __init__(self, decay):
self.decay = decay
# 用于保存上一次迭代计算出来的结果
self.shadow = {}
def register(self,name,val):
self.shadow[name] = val.clone()
def __call__(self,name,x):
assert name in self.shadow
new_average=self.decay*x+(1.0-self.decay)*self.shadow[name]
self.shadow[name]=new_average.clone()
return new_average
# 初始化
ema = EMA(0.999)
for name, param in model.named_parameters():
if param.requires_grad:
ema.register(name, param.data)
# 在batch中
for batch in batches:
optimizer.step()
for name,param in model.named_parameters():
if param.requires_grad:
param.data=ema(name,param.data)