English interface selected · this article is currently written in Chinese.
训练为什么会不稳定:学习率、梯度累积与数值精度
English overview →具备清晰骨架、初步数学推导或工程验证,持续补充论据与实测。
数字花园
🌿 什么是数字花园与思想演进?
遵循 Maggie Appleton 与 Andy Matuschak 的常青笔记理念:这里不是按时间沉底的流水账,而是持续修剪打磨的知识生态。文章按成熟度经历:
- 🌱 萌芽 (Seedling): 发散灵感、读书摘录、开放猜想
- 🌿 演进 (Budding): 结构渐明、初步代码推导、积极修正
- 🌳 常青 (Evergreen): 逻辑闭环、持久经得起检验的基石
- 🔬 实验待证 (Speculative): 结合沙盒与仿真探针的理论探索
同一套数据和模型,换一个学习率,损失可能正常下降,也可能很快变成 NaN。把 batch 调小以后终于装进内存,训练又开始明显抖动。
这些现象不能都归结为“参数没调好”。有的来自目标或标签错误,有的来自一次更新使用的数据变了,还有的只是数字超出了计算格式能表达的范围。
本篇接着batch 与有效 token,从一次更新出发,解释常用控制项分别改变了什么。目标是遇到异常时能缩小原因范围,而不是记住一组似乎适用于所有模型的数值。
梯度给方向,学习率决定走多远
先看最简单的梯度下降:
是参数, 是当前目标对参数的梯度, 是学习率。梯度描述在当前位置附近,参数改变怎样影响目标;学习率决定沿这个方向移动多少。
用一个单参数例子看得更清楚。设 ,梯度就是 ,于是更新后为:
从 出发:
| 学习率 | 前几次参数 | 现象 |
|---|---|---|
| 0.5 | 2 → 1 → 0.5 → 0.25 | 幅度逐渐减小 |
| 1.5 | 2 → −1 → 0.5 → −0.25 | 来回越过零,但幅度减小 |
| 2.5 | 2 → −3 → 4.5 → −6.75 | 幅度越来越大 |
这个例子里, 才收敛。真实神经网络没有这么简单的统一范围,AdamW 也不是这条裸梯度下降公式。例子只说明:方向正确,并不保证步子迈得大也安全。
反过来,学习率非常小可以让曲线看起来平静,却可能在有限预算里几乎没学到东西。所以稳定性要与进展速度一起看。
AdamW 还会利用过去的梯度
Adam 对梯度及其平方维护指数移动平均,直观上分别记录近期方向与近期尺度。常见写法是:
这里的平方和后续运算按参数分量进行。初始化为零会使早期估计偏小,因此再进行偏差修正,得到 和 。更新使用类似 的量,而不是直接照搬原始梯度。Adam 论文
因此,“梯度范数翻倍”不能直接翻译成“Adam 参数更新距离翻倍”。历史状态、学习率和分量尺度都在参与计算。
AdamW 将权重衰减与梯度中的自适应缩放分开处理。概略地写为:
是权重衰减系数。原论文指出,对这类自适应优化器,把 L2 项加入目标与这种解耦处理不等价。Decoupled Weight Decay Regularization
具体实现还要说明哪些参数使用衰减、参数组学习率是否相同、采用哪些数值选项。PyTorch 的 AdamW 文档给出了其更新过程和接口选项;实验应记录实际版本与参数,而非只记“用了 AdamW”。PyTorch 2.9 AdamW
梯度累积减少的是同时处理的数据量
假设想让一次更新使用八条序列,但内存一次只能放两条,可以分四次前向和反向,累积梯度,最后更新一次参数。
在目标权重一致、累积期间参数不变等条件下,梯度求和能表达同一个大 batch 的梯度。但实际浮点顺序、随机 dropout 或跨样本操作可能使结果不完全一样;它也不等价于连续做四次参数更新。
最常见的误操作有两个:每个小批次后就更新了参数,或者每次反向前把此前累积的梯度清空了。前者改变更新频率,后者只留下最后一个小批次。
如果各小批次有效目标数不同,平均损失还要按有效数加权。上一篇已经推导过,不能始终机械地除以累积次数。
累积通常降低同时保留的激活需求,但模型参数、梯度和优化器状态仍然需要存放。一个模型若仅这些状态就放不下,继续增加累积次数并不会让它突然可行。
batch 变大,为什么不能机械放大学习率
更大的有效 batch 通常改变梯度估计的波动程度,也改变固定 token 预算下更新多少次。
假设总预算为一百万个有效目标。每次更新用一千个,就有约一千次更新;改成四千个,只有约二百五十次。若学习率调度仍按旧的“第几步”设计,整个训练过程的节奏也变了。
所以比较时至少同时报告:每次更新的有效目标、累计有效目标、更新次数,以及学习率随哪个计数变化。
某些设置下可以采用学习率随 batch 调整的经验规则,但它不是任意模型和预算下的定理。合理做法是在已稳定的基线附近做有限比较,并看固定预算下的验证结果,而不是把“线性放大”当成无需检验的配置公式。
warmup 解决早期节奏,不修复错误目标
warmup 是在训练初期逐渐把学习率升到预定水平。它可以缓和初期较激进的更新;之后还可以按既定规则降低学习率。
在教学设计里,假设前一百次更新做线性 warmup,最大值为 ,可以定义第 次更新使用:
这样第一次是最大值的百分之一,第一百次达到最大值。别忽略步数从零还是一开始,以及调度器是在更新前还是后推进,这些细节足以造成一位偏移。
如果改了有效 batch,同样一百次更新会消耗不同的 token 数。报告 warmup 只写百分比,也要说明百分比的分母是预定步数还是 token 预算。
warmup 不会修复错位标签、错误遮罩或大量重复验证样本。遇到曲线异常,应先确认任务和数值,再调整调度策略。
低精度节省资源,也改变数值边界
训练中的数字需要用有限位数表示。FP32、FP16、BF16 对可表示范围和精细程度作了不同取舍。BF16 的指数范围比 FP16 更宽,但不是所有数都表示得更精细。
混合精度也不等于把所有张量一律改成半精度。它通常根据算子安排计算类型,某些状态或归约仍使用更高精度;具体行为取决于设备、框架和实现。
FP16 训练中,较小梯度可能难以保留。loss scaling 的思路是先放大损失,让反向得到相应放大的梯度,再在更新前还原。它不是让实际学习率永久增大。
若采用梯度缩放,累积期间需要保持缩放约定一致,等累积完成再还原、检查和更新。PyTorch 的 AMP 示例明确说明了这一顺序,以及出现非有限梯度时可能跳过参数更新的行为。PyTorch AMP 示例
因此,日志里应区分“读过多少批次”和“真正执行多少次优化器更新”。若大量更新被跳过,却照常推进调度和预算,曲线解释就会混乱。
本文不预设某台设备上的最佳精度。首先建立可运行且数值有限的基线,再用相同样本与预算比较精度方案;不能把 FP32 也当作绝对正确的数学答案,它同样存在舍入误差。
梯度裁剪限制异常幅度,但不是万能保险
常见的全局范数裁剪可写成:
若范数不超过阈值 ,不改变梯度;超过时,把整组梯度按同一比例缩小。零梯度保持不变,实际代码要避免除零。
例如 ,范数为 5,阈值为 2,裁剪后就是 。方向不变,范数变成 2。这里说的是对所有被选参数合在一起计算的全局范数,不是每个分量单独截断。PyTorch 范数裁剪接口
若用了梯度缩放,应先还原再按真实阈值裁剪;否则阈值作用在被放大的数上。裁剪一般放在一次有效 batch 累积完成后。每个小批次先各自裁剪再相加,是另一个更新规则。
持续频繁裁剪值得检查:可能学习率或数据分布发生问题,也可能阈值本来就设得低。它不是自动证明存在梯度爆炸。已经出现 NaN 的梯度,也不能靠一个范数裁剪公式保证修好。
遇到异常,先保存能定位问题的证据
只记录一个平均 loss,通常不够。每次更新至少关联数据批次标识、有效目标数、学习率、损失、梯度范数和更新是否执行。范数最好说明记录于还原后、裁剪前还是裁剪后。
| 现象 | 优先检查 | 不宜立即下的结论 |
|---|---|---|
| 第一次就出现非有限值 | 输入、标签、空目标、logits 和损失计算 | 模型太大所以必然不稳定 |
| 某一批次突然尖峰 | 该批次长度、来源、目标数和异常文本 | 所有数据都需要重新清洗 |
| 训练损失下降,验证变差 | 过拟合、分布差异、评价口径 | 优化器失效 |
| 损失很平但几乎不降 | 梯度是否存在、参数是否更新、学习率 | 数据已经学完 |
| 换精度后频繁跳过更新 | 数值范围、缩放状态、相关算子 | 低精度一定不适合该任务 |
在发现异常的位置保存最近的有效检查点和批次信息,再用短范围重现。不要在同一轮里同时换数据、学习率、batch 和精度,否则即使好了,也不知道哪一项起作用。
一组可解释的比较怎样安排
先固定分词器、数据顺序、模型初始化、目标归一化和有效 batch,选择能稳定运行的基线。围绕一个问题比较,例如“当前学习率是否过大”。
可以选基线的一半、原值和两倍,在相同有效 token 预算下运行,提前约定停止条件:非有限数值、持续无更新,或资源超限。保存失败设置,不能只留下成功曲线。
学习率比较结束后,再单独研究精度或 batch。观察验证损失时,同时看达到该结果消耗的有效 token 和实际时间;单个随机种子的细微差异不足以证明稳定收益。
这是一份实验设计,不意味着这些配置已在本站运行。真正执行后的结论需要带上环境、日志和重复情况。
两个检查理解的问题
第一,把一个大 batch 拆成四个小批次,为什么应该只更新一次参数?如果各部分有效目标数不同,损失怎样加权?
第二,某次梯度范数从 2 变成 20,裁剪后仍为 1,损失随后恢复正常。仅凭这些日志,能否判断是数据异常、学习率过大,还是阈值太低?还缺哪些证据?
最后一篇将这些检查整理成可解释的小模型预训练实验,把“跑起来”逐步推进到“知道结果说明了什么”。
文章概念网络
从章节进入正文概念。实线表示所属层级,虚线连接跨章节重复出现的概念,不代表因果关系。
50 / 50 个节点 · 正文标记术语与关键词概念
训练为什么会不稳定:学习率、梯度累积与数值精度
回到原文 ↗最后更新于 2026-10-20
引用本文
@article{2026-10-20-llm-training-pretrain-05-optimization,
author = {枫语},
title = {训练为什么会不稳定:学习率、梯度累积与数值精度},
journal = {枫语},
year = {2026},
month = {oct},
url = {https://meiluosi.github.io/posts/2026-10-20-llm-training-pretrain-05-optimization/}
}