指数滑动平均(EMA:exponential moving average)[转]

摘自:https://www.cnblogs.com/wuliytTaotao/p/9479958.html

参考:https://www.investopedia.com/terms/e/ema.asp

https://www.investopedia.com/terms/s/sma.asp

 

 

1. 用滑动平均估计局部均

  滑动平均(exponential moving average),或者叫做指数加权平均(exponentially weighted moving average),可以用来估计变量的局部均值,使得变量的更新与一段时间内的历史取值有关。

       变量vt时刻记为 为变量 vt 时刻的取值,即在不使用滑动平均模型时=,在使用滑动平均模型后,的更新公式如下:

, 其中FiltFreq为目标频率系数(具体叫法目前尚不清楚,有待深入研究),SampleFreq为信号采样频率,例如FiltFreq=20Hz, SampleFreq=16000Hz.

 

  上式中,β∈[0,1)。β=0相当于没有使用滑动平均。假设起始 ==0,β=0.9,之后每个时刻,依次对变量 v进行赋值,不使用滑动平均和使用滑动平均结果如下:

                             表 1  三种变量更新方式

https://img2018.cnblogs.com/blog/1351564/201906/1351564-20190615000526560-254363648.png

                   图 1:三种变量更新方式

 

  Andrew Ng在Course 2 Improving Deep Neural Networks中讲到,t时刻变量 v 的滑动平均值大致等于过去 1/(1−β) 个时刻 θ 值的平均。这个结论在滑动平均起始时相差比较大,所以有了Bias correction,将 vt 除以 (1−βt)修正对均值的估计。

加入了Bias correction后,v_biasedt的更新公式如下:

 

t越大,1 - 越接近 1,则公式(1)和(2)得到的结果 (和v_biase)将越来越近,如图 1 所示。

  当 β越大时,滑动平均得到的值越和 θ 的历史值相关。如果 β=0.9,则大致等于过去 10 个 θ 值的平均;如果 β=0.99,则大致等于过去 100 个 θ值的平均。

  滑动平均的好处:占内存少,不需要保存过去10个或者100个历史 θ值,就能够估计其均值。(当然,滑动平均不如将历史值全保存下来计算均值准确,但后者占用更多内存和计算成本更高)。

 

2. TensorFlow中使用滑动平均来更新变量(参数

  滑动平均可以看作是变量的过去一段时间取值的均值,相比对变量直接赋值而言,滑动平均得到的值在图像上更加平缓光滑,抖动性更小,不会因为某次的异常取值而使得滑动平均值波动很大,如图 1所示。

  TensorFlow 提供了 tf.train.ExponentialMovingAverage 来实现滑动平均。在初始化 ExponentialMovingAverage 时,需要提供一个衰减率(decay),即公式(1)(2)中的 β

。这个衰减率将用于控制模型的更新速度。ExponentialMovingAverage 对每一个变量(variable)会维护一个影子变量(shadow_variable),这个影子变量的初始值就是相应变量的初始值,而每次运行变量更新时,影子变量的值会更新为:

 

shadow_variable=decay⋅shadow_variable+(1−decay)⋅variable             (3)

 

公式(3)中的 shadow_variable 就是公式(1)中的 vt,公式(3)中的 variable 就是公式(1)中的 θt,公式(3)中的 decay 就是公式(1)中的 β

公式(3)中,decay 决定了影子变量的更新速度,decay 越大影子变量越趋于稳定。在实际运用中,decay一般会设成非常接近 1 的数(比如0.999或0.9999)。为了使得影子变量在训练前期可以更新更快,ExponentialMovingAverage 还提供了 num_updates 参数动态设置 decay 的大小。如果在初始化 ExponentialMovingAverage 时提供了 num_updates 参数,那么每次使用的衰减率将是:

 

min{decay,1+num_updates10+num_updates}              (4)

 

这一点其实和 Bias correction 很像。

TensorFlow 中使用 ExponentialMovingAverage 的例子:code 

(如果 GitHub 无法加载 .ipynb 文件,则将 .ipynb 文件的 URL 复制到网站 https://nbviewer.jupyter.org/

 

3. 滑动平均为什么在测试过程中被使用

  滑动平均可以使模型在测试数据上更健壮(robust)。“采用随机梯度下降算法训练神经网络时,使用滑动平均在很多应用中都可以在一定程度上提高最终模型在测试数据上的表现。” 

  对神经网络边的权重 weights 使用滑动平均,得到对应的影子变量 shadow_weights。在训练过程仍然使用原来不带滑动平均的权重 weights,不然无法得到 weights 下一步更新的值,又怎么求下一步 weights 的影子变量 shadow_weights。之后在测试过程中使用 shadow_weights 来代替 weights 作为神经网络边的权重,这样在测试数据上效果更好。因为 shadow_weights 的更新更加平滑,对于随机梯度下降而言,更平滑的更新说明不会偏离最优点很远;对于梯度下降 batch gradient decent,我感觉影子变量作用不大,因为梯度下降的方向已经是最优的了,loss 一定减小;对于 mini-batch gradient decent,可以尝试滑动平均,毕竟 mini-batch gradient decent 对参数的更新也存在抖动。

设 decay=0.999,一个更直观的理解,在最后的 1000 次训练过程中,模型早已经训练完成,正处于抖动阶段,而滑动平均相当于将最后的 1000 次抖动进行了平均,这样得到的权重会更加 robust。

 

 

Python实例:

# -*- coding: utf-8 -*-
"""
Created on Sun Apr  8 22:16:57 2018
"""
import numpy as np
from matplotlib import pyplot as plt
#from scipy.signal import medfilt

#%% Generage data
N = 10000
w = 501 # median filter window size

sigma = 0.1
data = np.random.random(N)*sigma + 1
#data[0] += sigma # make the first point biased

break_idx = int(N/2)
data[break_idx] += -sigma
data[break_idx:] += 1

#%% median filter
def medfilt(data, w):
    # one-sided median filter for 1-D array
    # w - windows size, needs to be odd
   
    assert(w%2 == 1)
    L = len(data)
    data_filtered = np.zeros(L)
   
    startp = 0
    endp = 0
    for i in range(L):
        if i - w + 1 < 0:
            startp = 0
        else:
            startp = i - w + 1
        endp = i+1
        data_filtered[i] = np.median(data[startp:endp])
    return data_filtered
   
#%% Exponentially weighted average with bias correction
beta = 1 - 1.0/w
data_filtered = np.zeros(len(data) + 1)
data_filtered_corrected = np.copy(data_filtered)
bias_correction_idx = 0

data_filtered[0] = 0
for i in range(N):
    if (data[i] - data[i-1]) > 0.5:
        data_filtered[i+1] = 0 + (1 - beta) * data[i]
        bias_correction_idx = i
    else:
        data_filtered[i+1] = beta * data_filtered[i] + (1 - beta) * data[i]
    # bias correction   
    data_filtered_corrected[i+1] = data_filtered[i+1] / (1 - beta ** (i+1 - bias_correction_idx))

data_median = medfilt(data, w)

plt.plot(data, label = 'raw')
#plt.plot(data_filtered[1:], label = 'filtered')
plt.plot(data_filtered_corrected[1:], label = 'filtered corrected')
plt.plot(data_median, label = 'median filter')
plt.legend()
plt.show()

生成的图形如下:

  

References

Course 2 Improving Deep Neural Networks by Andrew Ng

《TensorFlow实战Google深度学习框架》 4.4.3

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值