指数滑动平均(Exponential Moving Average)

指数滑动平均Exponential Moving Average


  这个概念经常在论文或者算法中看到,尤其是在随机梯度下降算法的改进算法中看到,就整理出来写一篇文章。
  指数滑动平均,或者叫做指数加权平均(exponentially weighted moving average),可以看做一段时间内的历史加权均值。一般近期的数据拥有更高的权重。
  假如有一个参数 θ \theta ,在不同的epoch下具有如下取值。 θ 1 , θ 2 , . . . θ t , \theta_1,\theta_2,...\theta_t, 。我们假定衰减率(衰减因子)是 β \beta ,则训练结束 θ \theta 的滑动平均值就是 θ t = β × θ t 1 + ( 1 β ) × θ t \overline \theta_t=\beta×\overline \theta_{t-1}+(1-\beta)×\theta_t 。看到这个公式就知道Momentum和Adam的优化公式就用到了这个概念。
  之所以叫指数滑动平均,是因为滑动窗口中的值求均值的时候前面的值是呈指数衰减的。因为权重的指数级别衰减,导致前面的值对后面的结果产生的影响减少,此时可以认为滑动均值只和最近的迭代有关系。通常衰减因子越大,前面的值衰减的就越缓慢,参数的更新就会越缓慢。如果对应sgd with momentum解释的话就是,如果当前的梯度和之前的梯度均值反向的话,就会前进的慢,如果和之前的梯度均值同向的话,就会前进的快,这样就可以抑制震荡。
  一般认为,这个均值只和最近的 1 1 β \frac1{1-\beta} 个值有关,而如果这些向量的方向全都相同的话,可以认为叠加之后速度提升的倍数是正比于 1 1 β \frac1{1-\beta} 的,如果 β = 0.9 \beta=0.9 ,带入计算可知 1 1 β = 10 \frac1{1-\beta}=10

####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)

发布了36 篇原创文章 · 获赞 4 · 访问量 47万+

猜你喜欢

转载自blog.csdn.net/m0_38065572/article/details/104578482
今日推荐