Geeks_Z の Blog Geeks_Z の Blog
首页
  • 学习笔记

    • 《HTML》
    • 《CSS》
    • 《JavaWeb》
    • 《Vue》
  • 后端文章

    • Linux
    • Maven
    • 汇编语言
    • 软件工程
    • 计算机网络概述
    • Conda
    • Pip
    • Shell
    • SSH
    • Mac快捷键
    • Zotero
  • 学习笔记

    • 《数据结构与算法》
    • 《算法设计与分析》
    • 《Spring》
    • 《SpringMVC》
    • 《SpringBoot》
    • 《SpringCloud》
    • 《Nginx》
  • 深度学习文章
  • 学习笔记

    • 《PyTorch》
    • 《ReinforementLearning》
    • 《MetaLearning》
  • 学习笔记

    • 《高等数学》
    • 《线性代数》
    • 《概率论与数理统计》
  • 增量学习
  • 哈希学习
GitHub (opens new window)

Geeks_Z

AI小学生
首页
  • 学习笔记

    • 《HTML》
    • 《CSS》
    • 《JavaWeb》
    • 《Vue》
  • 后端文章

    • Linux
    • Maven
    • 汇编语言
    • 软件工程
    • 计算机网络概述
    • Conda
    • Pip
    • Shell
    • SSH
    • Mac快捷键
    • Zotero
  • 学习笔记

    • 《数据结构与算法》
    • 《算法设计与分析》
    • 《Spring》
    • 《SpringMVC》
    • 《SpringBoot》
    • 《SpringCloud》
    • 《Nginx》
  • 深度学习文章
  • 学习笔记

    • 《PyTorch》
    • 《ReinforementLearning》
    • 《MetaLearning》
  • 学习笔记

    • 《高等数学》
    • 《线性代数》
    • 《概率论与数理统计》
  • 增量学习
  • 哈希学习
GitHub (opens new window)
  • Python

  • MLTutorials

    • 机器学习基础

    • 模型与算法

      • KNN
      • PCA
      • 奇异值分解SVD
      • K-means
      • 模型评估与选择
      • 正交普鲁克问题
      • 指数移动平均EDA
        • EMA的定义
        • 在深度学习的优化中的EMA
        • EMA的偏差修正
        • EMA为什么有效
        • PyTorch实现
        • References
      • 梯度提升GB
    • 模型优化

  • 卷积神经网络

  • 循环神经网络

  • Transformer

  • VisionTransformer

  • 扩散模型

  • 计算机视觉

  • PTM

  • MoE

  • LoRAMoE

  • LongTailed

  • 多模态

  • 知识蒸馏

  • PEFT

  • 对比学习

  • 小样本学习

  • 迁移学习

  • 零样本学习

  • 集成学习

  • Mamba

  • PyTorch

  • CL

  • CIL

  • 小样本类增量学习FSCIL

  • UCIL

  • 多模态增量学习MMCL

  • LTCIL

  • DIL

  • 论文阅读与写作

  • 分布外检测

  • GPU

  • 深度学习调参指南

  • AINotes
  • MLTutorials
  • 模型与算法
Geeks_Z
2024-12-25
目录

指数移动平均EDA

在深度学习中,经常会使用EMA(指数移动平均)这个方法对模型的参数做平均,以求提高测试指标并增加模型鲁棒。

EMA的定义

指数移动平均(Exponential Moving Average)也叫权重移动平均(Weighted Moving Average),是一种给予近期数据更高权重的平均方法。

假设我们有n 数据: [θ1,θ2,...,θn]

  • 普通的平均数: v―=1n∑i=1nθi
  • EMA: vt=β⋅vt−1+(1−β)⋅θt ,其中, vt 表示前 t 条的平均值 ( v0=0 ), β 是加权权重值 (一般设为0.9-0.999)。

Andrew Ng在Course 2 Improving Deep Neural Networks (opens new window)中讲到,EMA可以近似看成过去 1/(1−β) 个时刻 v 值的平均。

普通的过去 n 时刻的平均是这样的:

$v_t =\frac{(n-1)\cdot v_{t-1}+\theta_t}{n} $

类比EMA,可以发现当 β=n−1n 时,两式形式上相等。需要注意的是,两个平均并不是严格相等的,这里只是为了帮助理解。

实际上,EMA计算时,过去 1/(1−β) 个时刻之前的数值平均会decay到 1e 的加权比例,证明如下。

如果将这里的 vt 展开,可以得到:

$v_t = \alpha^n v_{t-n} + (1-\alpha)(\alpha^{n-1}\theta_{t-n+1}+ ... +\alpha^0\theta_t) $

其中, n=11−α ,代入可以得到 αn=α11−α≈1e 。

在深度学习的优化中的EMA

上面讲的是广义的ema定义和计算方法,特别的,在深度学习的优化过程中, θt 是t 刻的模型权重weights, vt 是t 刻的影子权重(shadow weights)。在梯度下降的过程中,会一直维护着这个影子权重,但是这个影子权重并不会参与训练。基本的假设是,模型权重在最后的n 内,会在实际的最优点处抖动,所以我们取最后n 的平均,能使得模型更加的鲁棒。

EMA的偏差修正

实际使用中,如果令 v0=0 ,且步数较少,ema的计算结果会有一定偏差。

理想的平均是绿色的,因为初始值为0,所以得到的是紫色的。

因此可以加一个偏差修正(bias correction):

$v_t = \frac{v_t}{1-\beta^t} $

显然,当t很大时,修正近似于1。

EMA为什么有效

网上大多数介绍EMA的博客,在介绍其为何有效的时候,只做了一些直觉上的解释,缺少严谨的推理,瓦砾在这补充一下,不喜欢看公式的读者可以跳过。

令第n时刻的模型权重(weights)为 vn ,梯度为 gn ,可得:

θn=θn−1−gn−1=θn−2−gn−1−gn−2=...=θ1−∑i=1n−1gi

令第n时刻EMA的影子权重为 vn ,可得:

vn=αvn−1+(1−α)θn=α(αvn−2+(1−α)θn−1)+(1−α)θn=...=αnv0+(1−α)(θn+αθn−1+α2θn−2+...+αn−1θ1)

代入上面 θn 的表达,令 v0=θ1 展开上面的公式,可得:

vn=αnv0+(1−α)(θn+αθn−1+α2θn−2+...+αn−1θ1)=αnv0+(1−α)(θ1−∑i=1n−1gi+α(θ1−∑i=1n−2gi)+...+αn−2(θ1−∑i=11gi)+αn−1θ1)=αnv0+(1−α)(1−αn1−αθ1−∑i=1n−11−αn−i1−αgi)=αnv0+(1−αn)θ1−∑i=1n−1(1−αn−i)gi=θ1−∑i=1n−1(1−αn−i)gi

对比两式:

θn=θ1−∑i=1n−1givn=θ1−∑i=1n−1(1−αn−i)gi

EMA对第i步的梯度下降的步长增加了权重系数 1−αn−i ,相当于做了一个learning rate decay。

PyTorch实现

class EMA():
    def __init__(self, model, decay):
        self.model = model
        self.decay = decay
        self.shadow = {}
        self.backup = {}

    def register(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                self.shadow[name] = param.data.clone()

    def update(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.shadow
                new_average = (1.0 - self.decay) * param.data + self.decay * self.shadow[name]
                self.shadow[name] = new_average.clone()

    def apply_shadow(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.shadow
                self.backup[name] = param.data
                param.data = self.shadow[name]

    def restore(self):
        for name, param in self.model.named_parameters():
            if param.requires_grad:
                assert name in self.backup
                param.data = self.backup[name]
        self.backup = {}

# 初始化
ema = EMA(model, 0.999)
ema.register()

# 训练过程中,更新完参数后,同步update shadow weights
def train():
    optimizer.step()
    ema.update()

# eval前,apply shadow weights;eval之后,恢复原来模型的参数
def evaluate():
    ema.apply_shadow()
    # evaluate
    ema.restore()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

References

  1. 机器学习模型性能提升技巧:指数加权平均(EMA) (opens new window)
  2. Exponential Weighted Average for Deep Neutal Networks (opens new window)
  3. 【炼丹技巧】指数移动平均(EMA)的原理及PyTorch实现 (opens new window)
上次更新: 2025/06/25, 11:25:50
正交普鲁克问题
梯度提升GB

← 正交普鲁克问题 梯度提升GB→

最近更新
01
帮助信息查看
06-08
02
常用命令
06-08
03
学习资源
06-07
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Geeks_Z | MIT License
京公网安备 11010802040735号 | 京ICP备2022029989号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式