指数滑动平均(ExponentialMovingAverage)EMA


EMA被广泛的应用在深度学习的BN层中,RMSprop,adadelta,adam等梯度下降方法


tf.train.ExponentialMovingAverage
函数定义
tensorflow中提供了tf.train.ExponentialMovingAverage来实现滑动平均模型,他使用指数衰减来计算变量的移动平均值。
tf.train.ExponentialMovingAverage.init(self, decay, num_updates=None, zero_debias=False, name="ExponentialMovingAverage"):
decay是衰减率在创建ExponentialMovingAverage对象时,需指定衰减率(decay),用于控制模型的更新速度。decay设置为接近1的值比较合理,通常为:0.999,0.9999。这里的一个trick是,

例如,

0.95^(20)=0.3584
1/e=0.3678
两者大概是近似相等的,也许这就是指数滑动平均中指数的含义吧。
影子变量的初始值与训练变量的初始值相同。当运行变量更新时,每个影子变量都会更新为:


num_updates是ExponentialMovingAverage提供用来动态设置decay的参数,当初始化时提供了参数,即不为none时,每次的衰减率是:

apply()方法添加了训练变量的影子副本,并保持了其影子副本中训练变量的移动平均值操作。在每次训练之后调用此操作,更新移动平均值。
average()和average_name()方法可以获取影子变量及其名称。


Tensorflow栗子:

import tensorflow as tf

# 定义一个32位浮点数的变量,初始值位0.0
v1 =tf.Variable(dtype=tf.float32, initial_value=0.)

# 衰减率decay,初始值位0.99
decay = 0.99

# 定义num_updates,同样,初始值位0
num_updates = tf.Variable(0, trainable=False)

# 定义滑动平均模型的类,将衰减率decay和num_updates传入。
ema = tf.train.ExponentialMovingAverage(decay=decay, num_updates=num_updates)

# 定义更新变量列表
update_var_list = [v1]

# 使用滑动平均模型
ema_apply = ema.apply(update_var_list)

# Tensorflow会话
with tf.Session() as sess:
    # 初始化全局变量
    sess.run(tf.global_variables_initializer())

    # 输出初始值
    print(sess.run([v1, ema.average(v1)]))      
    # [0.0, 0.0](此时 num_updates = 0 ⇒ decay = .1, ),
    # shadow_variable = variable = 0.

    # 将v1赋值为5
    sess.run(tf.assign(v1, 5))

    # 调用函数,使用滑动平均模型
    sess.run(ema_apply)

    # 再次输出
    print(sess.run([v1, ema.average(v1)]))     
    # 此时,num_updates = 0 ⇒ decay =0.1,  v1 = 5; 
    # shadow_variable = 0.1 * 0 + 0.9 * 5 = 4.5 ⇒ variable

    # 将num_updates赋值为10000
    sess.run(tf.assign(num_updates, 10000))

    # 将v1赋值为10
    sess.run(tf.assign(v1, 10))

    # 调用函数,使用滑动平均模型
    sess.run(ema_apply)

    # 输出
    print(sess.run([v1, ema.average(v1)]))      
    # decay = 0.99,shadow_variable = 0.99 * 4.5 + .01*10 ⇒ 4.555

    # 再次使用滑动平均模型
    sess.run(ema_apply)

    # 输出
    print(sess.run([v1, ema.average(v1)]))      
    # decay = 0.99,shadow_variable = .99*4.555 + .01*10 = 4.609
    for i in range(1000):
        sess.run(ema_apply)
        print(sess.run([v1,ema.average(v1)]))


### 滑动平均算法的实现与原理 滑动平均算法是一种常用的滤波方法,其核心思想是通过对一系列数据点进行平均处理,从而平滑掉数据中的噪声[^1]。具体而言,该算法的目标是在一个采样周期内寻找一个值 \( \overline{y} \),使得该值与各测量值 \( y(i) \) 之间的误差平方和最小化。 在实际应用中,滑动平均算法通常分为两种形式:**简单滑动平均**和**指数滑动平均**。 #### 简单滑动平均(Simple Moving Average, SMA) 简单滑动平均的基本公式为: \[ \overline{y}_n = \frac{1}{N} \sum_{i=1}^{N} y(i) \] 其中,\( \overline{y}_n \) 表示当前窗口内的平均值,\( N \) 是窗口大小,\( y(i) \) 是第 \( i \) 个采样值。这种方法通过计算固定窗口内所有采样值的算术平均来实现平滑效果[^1]。 以下是使用 Java 实现简单滑动平均的一个示例代码: ```java import java.util.LinkedList; import java.util.Queue; public class SimpleMovingAverage { private Queue<Double> window; private int size; private double sum; public SimpleMovingAverage(int size) { this.size = size; this.window = new LinkedList<>(); this.sum = 0.0; } public void addData(double data) { if (window.size() == size) { sum -= window.poll(); } window.offer(data); sum += data; } public double getAverage() { if (window.isEmpty()) return 0.0; return sum / window.size(); } public static void main(String[] args) { int windowSize = 5; SimpleMovingAverage sma = new SimpleMovingAverage(windowSize); for (int i = 0; i < 10; i++) { double data = Math.random() * 100.0; sma.addData(data); System.out.println("原始数据: " + data + ", 平均值: " + sma.getAverage()); } } } ``` #### 指数滑动平均Exponential Moving Average, EMA) 相比于简单滑动平均指数滑动平均赋予不同时间点的数据不同的权重,最近的数据点权重更大,而较早的数据点权重逐渐减小。其公式为: \[ Y_n = \alpha Y_{n-1} + (1 - \alpha) X_n \] 其中,\( Y_n \) 是本次滤波结果,\( Y_{n-1} \) 是上次滤波结果,\( X_n \) 是本次采样值,\( \alpha \) 是滤波系数,取值范围为 [0, 1]。较小的 \( \alpha \) 值表示更倾向于保留历史数据的影响,而较大的 \( \alpha \) 值则更关注当前数据的变化[^3]。 以下是一个 Python 实现指数滑动平均的示例代码: ```python class ExponentialMovingAverage: def __init__(self, alpha): self.alpha = alpha self.filtered_value = None def filter(self, value): if self.filtered_value is None: self.filtered_value = value else: self.filtered_value = self.alpha * self.filtered_value + (1 - self.alpha) * value return self.filtered_value # 示例运行 ema = ExponentialMovingAverage(alpha=0.9) for i in range(10): data = i ** 2 # 模拟输入数据 filtered_data = ema.filter(data) print(f"原始数据: {data}, 滤波结果: {filtered_data}") ``` ### 总结 滑动平均算法的核心在于通过对数据进行加权或非加权平均来减少噪声的影响。简单滑动平均适用于对等权重数据的场景,而指数滑动平均更适合需要动态调整权重的应用场合[^3]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值