在大语言模型训练中,显存往往无法容纳理想规模的批次。梯度累积通过连续处理多个微批次、暂存其梯度,并在达到指定次数后统一更新参数,让有限显存也能模拟更大的批量训练。不过,梯度累积步数并非越大越好,它会同时改变有效批量规模、参数更新频率、训练吞吐量和收敛行为。
梯度累积如何扩大有效批量规模
设单张设备每次前向与反向传播处理的微批量为 B,梯度累积步数为 G,数据并行设备数为 N,那么按样本数计算的有效批量规模通常为:
有效批量规模 = B × G × N
例如,每张 GPU 的微批量为 4,使用 8 张 GPU,累积 4 步后更新一次参数,则有效批量规模为 4 × 4 × 8,也就是 128。需要注意,这里的“步”可能指微批次处理次数,也可能指优化器更新次数。阅读训练日志时应先确认框架对 global step、iteration 和 optimizer step 的具体定义。
梯度累积的核心价值是降低单次计算所需的激活显存,而不是降低模型参数、优化器状态或梯度本身占用的显存。Hugging Face Accelerate 的梯度累积文档也将其描述为:在多个批次上累积梯度,达到指定次数后再执行优化器更新。
为什么相同有效批量不一定具有相同速度
从理想数学形式看,在样本顺序、损失归一化和随机因素一致的前提下,微批量为 8、累积 4 步,与直接使用批量 32 的梯度结果可以非常接近。但二者的运行效率通常不同。直接批量 32 只需完成一次较大的前向与反向传播,而梯度累积需要执行四轮较小计算,因此会增加循环调度、算子启动和数据加载等开销。
当微批量过小时,GPU 的并行计算能力可能无法充分利用,吞吐量随之下降。因此,在显存允许的情况下,通常应优先提高微批量,再用适量梯度累积补足目标有效批量。Hugging Face 社区关于批量大小与梯度累积的讨论也指出,梯度累积主要用于突破显存限制,若大批量能够直接运行,通常会有更好的执行效率。
累积步数如何影响收敛速度
这里需要区分两种“速度”。第一种是按优化器更新次数衡量的收敛速度。累积步数增加后,每次更新综合了更多样本,梯度噪声通常会减小,更新方向可能更稳定,但单位训练样本对应的参数更新次数也会减少。第二种是按实际时间衡量的收敛速度。即使达到同一损失所需的样本量相近,更多的小微批次循环也可能延长实际训练时间。
有效批量增大并不保证模型更快达到更好的验证指标。较大的批量可以平滑梯度波动,却可能降低参数更新频率。如果保持学习率、预热步数和训练轮数完全不变,优化过程实际上已经发生变化。特别是训练计划按 optimizer step 配置时,提高累积步数会减少每个 epoch 内的更新次数,学习率调度器也可能更慢或更快地进入下一阶段,具体取决于代码在微步还是更新步上调用调度器。
实现错误会破坏理论等价性
最常见的问题是损失缩放。若每个微批次的损失采用平均值归约,通常需要在反向传播前除以累积步数,或者交给训练框架自动处理。否则,累积后的梯度可能被额外放大。除此之外,梯度裁剪应在完成累积之后、优化器更新之前执行,不能在每个微步上分别裁剪。
对于变长文本,简单地平均各微批次损失还可能产生偏差。若不同微批次包含的有效 token 数差异较大,更严谨的做法是根据非填充 token 总数进行归一化,而不是先计算每个微批次均值再取平均。否则,小批次与长序列批次可能获得不恰当的相同权重。
分布式训练还要关注梯度同步。如果每个微步都触发一次跨设备同步,累积虽然节省了显存,却可能产生不必要的通信开销。成熟框架通常会在非更新微步暂缓同步,并在真正执行 optimizer step 前完成聚合。Accelerate 的官方操作指南提供了自动管理累积与同步的方式。
如何选择合适的梯度累积步数
- 先确定可运行的最大微批量:在目标序列长度、精度模式和并行配置下逐步测试,并保留一定显存余量,避免偶发长序列导致溢出。
- 再确定目标有效批量:结合已有训练方案、优化器设置和验证集表现计算所需累积步数,不要单纯追求更大的数字。
- 同步调整训练计划:检查学习率、预热比例、总更新步数、日志间隔、评估间隔和保存间隔是否基于 optimizer step。
- 比较端到端指标:同时观察每秒 token 数、显存峰值、梯度范数、训练损失与验证损失,而不只看单步耗时。
- 优先做小规模对照:固定有效批量,比较不同微批量与累积步数组合,以实际吞吐量和验证效果选择配置。
总结
梯度累积用更多微步换取更大的有效批量,是训练 LLM 时解决显存不足的重要工具。增加累积步数可以扩大有效批量并平滑梯度,但也会降低参数更新频率,增加循环与通信开销,并影响学习率调度和实际收敛时间。合理策略不是盲目提高累积步数,而是在显存允许范围内尽量增大微批量,再以适度累积达到目标有效批量,同时正确处理损失归一化、梯度同步、裁剪时机和训练步数统计。