概念
-
滑动平均(
exponential moving average
),或者叫做指数加权平均(exponentially weighted moving average
),可以用来估计变量的局部均值,使得变量的更新与一段时间内的历史取值有关。 -
加权移动平均法,是对观察值分别给予不同的权数,按不同权数求得移动平均值,并以最后的移动平均值为基础,确定预测值的方法。采用加权移动平均法,是因为观察期的近期观察值对预测值有较大影响,它更能反映近期变化的趋势。
-
指数移动加权平均法,是指各数值的加权系数随时间呈指数式递减,越靠近当前时刻的数值加权系数就越大。
-
指数移动加权平均较传统的平均法来说,一是不需要保存过去所有的数值;二是计算量显著减小。
公式理解
其实指数滑动平均法相当于加权滑动平均法的变体,主要区别在于,指数滑动平均法的权重是随时间推移呈指数衰减。指数滑动平均法的公式如下:
v t = β ⋅ v t − 1 + ( 1 − β ) ⋅ θ t ( 1 ) v_t = β \cdot v_{t-1} + (1 - β) \cdot θ_t \qquad \qquad (1) vt=β⋅vt−1+(1−β)⋅θt(1)
变量 v v v 在t时刻记为 v t v_t vt, θ t θ_t θt为变量 v v v在t时刻的取值,即在不使用滑动平均模型时 v t = θ t v_t = θ_t vt=θt
上式中, β ∈ [ 0 , 1 ) β ∈ [0, 1) β∈[0,1), β β β其实就是衰减权重,一般来说初始化设置为0.9, β = 0 β=0 β=0相当于没有使用平滑。
如果还不理解的话,也可以这样看:
将 v t v_t vt 看做预测值 记作 p t p_t pt, v t − 1 v_{t-1} vt−1看做观测值 记作 x t x_t xt,那么公式(1)也可以表示为:
p t = β ⋅ x t + ( 1 − β ) ⋅ p t − 1 p_t = β \cdot x_t + (1 - β) \cdot p_{t-1} pt=β⋅xt+(1−β)⋅pt−1
前面说了,指数滑动平均的权重是随着时间推移呈指数衰减的,那么上面的这个递推公式体现在哪里呢?我们把公式(1)进行延伸:
θ t = v t − 1 = β ⋅ v t − 2 + ( 1 − β ) ⋅ θ t − 1 ( 2 ) θ_t = v_{t-1} = β \cdot v_{t-2} + (1 - β) \cdot θ_{t-1} \qquad \qquad (2) θt=vt−1=β⋅vt−2+(1−β)⋅θt−1(2)
将(1)和(2)联立,可得:
v t = β ⋅ v t − 1 + ( 1 − β ) ⋅ ( β ⋅ v t − 2 + ( 1 − β ) ⋅ θ t − 1 ) ( 3 ) v_t = β \cdot v_{t-1} + (1-β) \cdot (β \cdot v_{t-2} + (1-β) \cdot θ_{t-1}) \qquad \qquad (3) vt=β⋅vt−1+(1−β)⋅(β⋅vt−2+(1−β)⋅θt−1)(3)
发现没有,在(3)中 v t v_t vt和 θ t − 1 θ_{t-1} θt−1的关系是 ( 1 − β ) 2 (1-β)^2 (1−β)2倍,而在(1)中 v t v_t vt和 θ t θ_{t} θt的关系是 ( 1 − β ) (1-β) (1−β)倍,呈指数衰减关系。
根据吴恩达的视频公开课中提到的,t时刻变量v的滑动平均值大致等于过去 1 1 − β \frac{1}{1-β} 1−β1这个时刻θ值得平均。这个结论在滑动平均起始时相差比较大,所以有了偏差修正,将 v t v_t vt除以 ( 1 − β t ) (1-β^t) (1−βt)修正对均值的估计。
加入偏差修正后, v t v_t vt和 v b i a s e d t v_{biased_t} vbiasedt的更新公式如下:
v t = β ⋅ v t − 1 + ( 1 − β ) ⋅ θ t v b i a s e d t = v t 1 − β t ( 4 ) v_t = β \cdot v_{t-1} + (1-β) \cdot θ_t \\ v_{biased_t} = \frac{v_t}{1-β^t} \qquad \qquad (4) vt=β⋅vt−1+(1−β)⋅θtvbiasedt=1−βtvt(4)
假设起始 v 0 v_0 v0 = 0, β β β=0.9,之后每个时刻,依次对变量 v v v进行赋值,不使用滑动平均和使用滑动平均的结果如下:
t | 不使用滑动平均模型,即给𝑣直接赋值𝜃 | 使用滑动平均模型,按照公式(1)更新𝑣 | 使用滑动平均模型,按照公式(4)更新𝑣_𝑏𝑖𝑎𝑠𝑒𝑑 |
---|---|---|---|
0, 1, 2, … , 35 | [0, 10, 20, 10, 0, 10, 20, 30, 5, 0, 10, 20, 10, 0, 10, 20, 30, 5, 0, 10, 20, 10, 0, 10, 20, 30, 5, 0, 10, 20, 10, 0, 10, 20, 30, 5] | [0, 1.0, 2.9, 3.61, 3.249, 3.9241, 5.5317, 7.9785, 7.6807, 6.9126, 7.2213, 8.4992, 8.6493, 7.7844, 8.0059, 9.2053, 11.2848, 10.6563, 9.5907, 9.6316, 10.6685, 10.6016, 9.5414, 9.5873, 10.6286, 12.5657, 11.8091, 10.6282, 10.5654, 11.5089, 11.358, 10.2222, 10.2, 11.18, 13.062, 12.2558] | [0, 10.0, 15.2632, 13.321, 9.4475, 9.5824, 11.8057, 15.2932, 13.4859, 11.2844, 11.0872, 12.3861, 12.0536, 10.4374, 10.3807, 11.592, 13.8515, 12.7892, 11.2844, 11.1359, 12.145, 11.9041, 10.5837, 10.5197, 11.5499, 13.5376, 12.6248, 11.2844, 11.1489, 12.0777, 11.8608, 10.6276, 10.5627, 11.5365, 13.4357, 12.5704] |
t越大, 1 − β t 1-β^t 1−βt越接近1,则 v t v_t vt 和 v b i a s e d t v_{biased_t} vbiasedt将越来越接近,如上图所示
当 β β β越大时,滑动平均得到的值越和 θ θ θ的历史值相关。如果 β = 0.9 β=0.9 β=0.9,则大致等于过去10个 θ θ θ的均值,如果 β = 0.99 β=0.99 β=0.99,则大致等于过去100个 θ θ θ的均值
引入吴恩达视频课的例子
例子为美国一年内每天的温度分布情况,具体如下图所示:
EWMA 的表达式如下:
v t = β ⋅ v t − 1 + ( 1 − β ) ⋅ θ t v_t = β \cdot v_{t-1} + (1 - β) \cdot θ_t vt=β⋅vt−1+(1−β)⋅θt
上式中 θ t θ_t θt为时刻t的实际温度,系数 β β β表示加权下降的速率,其值越小下降的越快, v t v_t vt为t时刻的EWMA值。
在上图中有两条不同颜色的线,分别对应着不同的 β β β值。
当 β = 0.9 β=0.9 β=0.9时,有 v t = 0.9 ⋅ v t − 1 + 0.1 ⋅ θ t v_t=0.9 \cdot v_{t-1} + 0.1 \cdot θ_t vt=0.9⋅vt−1+0.1⋅θt,对应着图中的红线,虽然曲线有些波动,但总体拟合真实数据。
当 β = 0.98 β=0.98 β=0.98时,有 v t = 0.98 ⋅ v t − 1 + 0.02 ⋅ θ t v_t=0.98 \cdot v_{t-1} + 0.02 \cdot θ_t vt=0.98⋅vt−1+0.02⋅θt,对应着图中的绿线,此时曲线较平,但却有所偏离真实数据。
在t=0时刻,一般初始化 v 0 = 0 v_0=0 v0=0,对EWMA的表达式进行归纳可以将t时刻的表达式写成:
v t = ( 1 − β ) ⋅ ( θ t + β ⋅ θ t − 1 + . . . + β t − 1 ⋅ θ 1 ) v_t = (1-β) \cdot (θ_t + β \cdot θ_{t-1} + ... + β^{t-1} \cdot θ_1) vt=(1−β)⋅(θt+β⋅θt−1+...+βt−1⋅θ1)
从上面式子中可以看出,数值的加权系数随着时间呈指数下降。在数学中一般会以 1 e \frac{1}{e} e1作为一个临界值,小于该值得加权系数的值不作考虑,接着来分析 β = 0.9 β=0.9 β=0.9和 β = 0.98 β=0.98 β=0.98的情况。
当
β
=
0.9
β=0.9
β=0.9时,
0.
9
1
0
0.9^10
0.910约等于
1
e
\frac{1}{e}
e1,因此认为此时是近10个数值的加权平均。
当
β
=
0.98
β=0.98
β=0.98时,
0.
9
50
0.9^{50}
0.950约等于
1
e
\frac{1}{e}
e1,因此认为此时是近50个数值的加权平均。这种情况也是正式移动平均的来源。
偏差修正:
在初始化
𝑣
0
=
0
𝑣_0=0
v0=0 时实际上会存在一个问题。具体的如下图所示:
从上图中可以看出有一条绿色和紫色的曲线,都是对应于 β = 0.98 β=0.98 β=0.98 时的曲线。理想状况下应该是绿色的曲线,但当初始化 𝑣 0 = 0 𝑣_0=0 v0=0 时却会得到紫色的曲线,这是因为初始化的值太小,导致初期的数值都偏小,而随着时间的增长,初期的值的影响减小,紫色的曲线就慢慢和绿色的曲线重合。
v t = β ⋅ v t − 1 + ( 1 − β ) ⋅ θ t v b i a s e d t = v t 1 − β t v_t = β \cdot v_{t-1} + (1-β) \cdot θ_t \\ v_{biased_t} = \frac{v_t}{1-β^t} vt=β⋅vt−1+(1−β)⋅θtvbiasedt=1−βtvt
当 𝑡 很小时,分母可以很好的放大当前的数值;当 𝑡 很大时,分母的数值趋于1,对当前数值几乎没有影响。
EWMA 主要是被应用在动量优化算法中,比如Adam算法中的一阶矩和二阶矩都采用了上面修改后的EWMA算法。
滑动平均为什么在测试过程中被使用
滑动平均可以使模型在测试数据上更健壮(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
对参数的更新也存在抖动。
设 d e c a y = 0.999 decay=0.999 decay=0.999, 一个更直观的理解,在最后的 1000 次训练过程中,模型早已经训练完成,正处于抖动阶段,而滑动平均相当于将最后的 1000 次抖动进行了平均,这样得到的权重会更加 robust。
代码实现
下面是我的实现,需要可以根据需求自行修改
# 指数加权移动平均
class ExpMovAvg(object):
def __init__(self, decay=0.9):
self.shadow = 0
self.decay = decay
self.first_time = True
def update(self, data, t, is_biased=False):
t = t[t['ecpm'] == data]['counter'].values[0]
if self.first_time:
self.shadow = data
self.first_time = False
return data
else:
self.shadow = self.decay * self.shadow + (1 - self.decay) * data
if is_biased: # 偏差修正
return self.shadow / 1 - self.decay ** t
else: # 不做偏差修正
return self.shadow