梯度累计原理:数学可行性与PyTorch实现

目录

为啥梯度能"累计"?

梯度相加为什么数学上是可行的?

[backward() 里到底发生什么?](#backward() 里到底发生什么?)

[为什么需要手动 zero_grad?](#为什么需要手动 zero_grad?)

组合在一起:梯度累计的流程

[backward 结束后,梯度和优化器 step 的关系又是什么?](#backward 结束后,梯度和优化器 step 的关系又是什么?)

一句总结


为啥梯度能"累计"?

在标准训练里,你做的流程是:

前向计算 → backward算梯度 → 用优化器更新参数。

它隐含了一个默认假设:你一个 batch 的数据已经足够代表真实分布,因此一次梯度就能用来更新参数。

但你可能没那么大的显存,没法用你理想的 batch_size 128、256......你可能只能塞 batch_size = 4 或 8。这样会让梯度噪声很大,模型更新得像喝了咖啡的蚂蚁一样跳跃。

这里就需要梯度累计:
你通过多次前向+反向,把多个小 batch 的梯度加起来,模拟一个"大 batch"。然后再更新一次参数。

这相当于你把"更新"这步延迟,反向的梯度会在参数的 .grad 里不断累加,直到你觉得"好了,累够了",再让 optimizer.step() 一次。


梯度相加为什么数学上是可行的?

反向传播得到的梯度,本质上是损失函数对参数的偏导数。

多批数据的总损失 L = L₁ + L₂ + ... + Lₙ。

对参数 w 的梯度是:

∂L/∂w = ∂(L₁ + L₂ + ... + Lₙ)/∂w

= ∂L₁/∂w + ∂L₂/∂w + ... + ∂Lₙ/∂w

也就是说:独立 batch 的梯度可以直接相加,这就是数学的允许证书。

这也是为什么你做 4 次 backward,.grad 就累计了 4 个 batch 的梯度,你再 step,一次性更新。


backward() 里到底发生什么?

你可以把 backward 理解为"沿着计算图倒着求导,并把结果塞到对应参数的 .grad 上"。

具体来说:

  1. PyTorch 构建一个动态计算图,把每个操作都记录下来:加法、矩阵乘法、卷积......

  2. 调用 backward() 后,它沿着计算图做链式求导。

  3. 求出的梯度会加到每个需要梯度的 tensor.grad 上。

    注意是 加上去(+=),不是替换!

举个例子:

复制代码
loss.backward()

内部发生的是:

  • 遍历计算图,把每一层对 loss 的梯度算出来

  • 如果 parameter.grad 原来不是 None,就做

    复制代码
    parameter.grad += grad_from_backprop
  • 直到所有参数都获得了自己的梯度

也就是说,它天然支持"累积"。


为什么需要手动 zero_grad?

因为 PyTorch 的默认行为是"累加梯度"。

如果你不手动清空 .grad,下一次 backward 会继续往上叠。

这刚好与梯度累计是一对好搭子:

累计时,你故意不清 grad;

更新后,你必须清 grad。


组合在一起:梯度累计的流程

复制代码
optimizer.zero_grad()

for i, (x, y) in enumerate(dataloader):
    out = model(x)
    loss = criterion(out, y)
    loss = loss / accumulation_steps      # 可选:把 loss 平均一下

    loss.backward()                       # 梯度累加到了 param.grad

    if (i+1) % accumulation_steps == 0:
        optimizer.step()                  # 更新权重
        optimizer.zero_grad()             # 清空梯度,准备下一轮

这样就实现了"小 batch 训练大 batch 的效果"。


backward 结束后,梯度和优化器 step 的关系又是什么?

你可以把它想象成两个阶段:

  • backward:负责算梯度并把它放到 param.grad

  • optimizer.step:负责用 param.grad 来真正修改参数

优化器做的是:

w = w - learning_rate * w.grad

当你累计梯度时,是把多个梯度加到 w.grad 上,再由 optimizer 一次性使用它。


一句总结

梯度累计能生效,是因为反向传播会把梯度累加在 .grad 上,而多个 batch 的梯度在数学上可以直接相加;优化器只在你调用 step() 时使用累积结果更新一次参数,从而实现"大 batch 训练"的效果。

相关推荐
科创致远几秒前
科创致远 ESOP 系统深度评测:从参数解析到 ROI 实战验证
大数据·人工智能·制造·精益工程
CAIE研习社4 分钟前
从“会聊天”到能落地:光伏、风电运维里的AI怎么用?
大数据·人工智能
TAN-90°-6 分钟前
Deep Learning for Computer Vision——Generative Models 2
人工智能·深度学习·神经网络·算法·目标检测·机器学习·计算机视觉
洞见新研社10 分钟前
豆包手机发售,AI代理进入“终端”竞赛
人工智能·ai
benchmark_cc16 分钟前
策略临时需要一批股票的最新价格,先查行情还是先建股票池?——从量化策略执行逻辑看数据获取顺序
python·数据分析·pandas·量化交易·股票数据·quantdash
成为深度学习高手17 分钟前
XLinear:用一个轻量 MLP,带外生变量做长期时间序列预测
python·深度学习·时序数据库
QC777LX21 分钟前
中文专业在AI行业的新岗位:从Prompt到人文训练
人工智能
知几蜗牛24 分钟前
2.8万亿参数上云之后,Kimi K3的门槛变低了吗
人工智能
sarasuki26 分钟前
工具设计的坏味道:什么样的定义会让模型乱调
人工智能·agent·设计
jingli928 分钟前
微信自动回复怎么设置?重复问题怎么自动回答——私域FAQ自动应答搭建全流程(关键词匹配+知识库+语义AI,2026实操版)
人工智能·自动化·用户运营