理解滑动平均(exponential moving average)

目录

1. 用滑动平均估计局部均值
2. TensorFlow中使用滑动平均来更新变量(参数)
3. 滑动平均为什么在测试过程中被使用?

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

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

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

(1)vt=βvt1+(1β)θt

  上式中,β[0,1)β=0 相当于没有使用滑动平均。

  假设起始 v0=0β=0.9,之后每个时刻,依次对变量 v 进行赋值,不使用滑动平均和使用滑动平均结果如下:

表 1  三种变量更新方式

t 不使用滑动平均模型,即给v直接赋值θ

使用滑动平均模型,
按照公式(1)更新v

使用滑动平均模型,
按照公式(2)更新v_biased

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]

图 1:三种变量更新方式

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

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

(2)vt=βvt1+(1β)θtv_biasedt=vt1βt

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

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

  滑动平均的好处:

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

 

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

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

  TensorFlow 提供了 tf.train.ExponentialMovingAverage 来实现滑动平均。在初始化 ExponentialMovingAverage 时,需要提供一个衰减率(decay),即公式(1)(2)中的 β。这个衰减率将用于控制模型的更新速度。ExponentialMovingAverage 对每一个变量(variable)会维护一个影子变量(shadow_variable),这个影子变量的初始值就是相应变量的初始值,而每次运行变量更新时,影子变量的值会更新为:

(3)shadow_variable=decayshadow_variable+(1decay)variable

公式(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 参数,那么每次使用的衰减率将是:

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

这一点其实和 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。

  

References

Course 2 Improving Deep Neural Networks by Andrew Ng

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

posted @   wuliytTaotao  阅读(65293)  评论(2编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示