第 02 章 / 第 04 课

训练为什么会不稳定:激活与梯度

通过激活分布和梯度范数,区分饱和、梯度过小、学习率过大与数据问题。

中文讲解 · 约 3 分钟两道自测 · 可重复作答附官方视频 · 英文第 4 / 15 课
这一课,你会学到
  • 认识激活饱和与梯度传播
  • 记录参数、梯度和激活的分布
  • 一次只改变一个实验条件
术语速查与实践准备
反向传播
沿计算依赖反向应用链式法则并累加梯度。
BPE
反复合并相邻 token 对以构造词表的方法。
BatchNorm
使用批次/运行统计对激活做规范化的层;训练和评估行为不同。

浏览器概念实验可以直接做。运行文中的 PyTorch 代码前,按官方安装说明准备独立环境;完整模型训练的时间与内存按实际数据、模型和硬件测量。

模型结构写对之后,训练仍可能失败。损失不降、突然变成 NaN、梯度接近零,背后不一定是同一个原因。我们先学习怎样观察,而不是遇到问题就同时改十个参数。

激活尺度怎样影响梯度

例如 tanh 的输出被限制在 −1 到 1。输入绝对值很大时,输出接近边界,导数接近零。若许多隐藏单元长期处于这种饱和区域,误差信号很难穿过它们回到前面的参数。

输入尺度、权重初始化、层数和激活函数都可能影响这种现象。梯度很小也可能来自任务本身或模型已经接近局部平坦区,所以不能只凭一张直方图下结论。

给训练加三个观察点

在固定的一批数据上,记录隐藏层激活的均值和标准差、各层参数的梯度范数、更新量相对参数量的大小。这些记录帮助你回答:问题从哪个位置开始?更新到底太小还是太大?

# h 是某层的激活;在 loss.backward() 之后检查梯度。
print("activation", h.detach().mean().item())
print("activation std", h.detach().std().item())

for name, parameter in model.named_parameters():
    if parameter.grad is not None:
        print(name, parameter.grad.detach().norm().item())

代码片段要放入已有训练程序,其中 h 和 model 来自你的模型。记录多步趋势比只截取单步更有价值。检查时还要确认数据里没有非法值、标签没有越界。

归一化并不是万能修复

BatchNorm 在训练时利用当前批次统计,在评估时通常使用累计统计。因此 train() 和 eval() 会改变相关层的行为。Transformer 常见的 LayerNorm 则按不同维度归一化,不应把两者的统计方式混为一谈。

加入归一化后,仍要检查初始化、学习率、损失计算和数据划分。不要为了让曲线看起来平滑,就把验证损失混入训练曲线,或直接删除表现较差的批次。

怎样做一个有解释力的对照

保留同一数据顺序、模型结构与随机种子,只改变初始化尺度。记录改变前后的激活统计、梯度范数和留出损失。若实验有随机波动,可以用多个种子重复,并报告范围。

这一课的产出是一份诊断记录。下一课手动推导梯度,让你知道观察到的数值来自哪一步计算;随后再进入分词和 GPT,而不是把不稳定的训练循环一路复制下去。

读完之后,给理解一次反馈。

在同一个小 MLP 上记录隐藏层激活均值/标准差与梯度范数,再只改变初始化尺度做对照。

本课参考资料

文章、例子与练习为本站原创讲解;官方视频与延伸资料保留作者来源。

核对日期 2026-10-14
核对实验结果,再留下完成记录。

完成记录与自测结果分别保存,不自动推断掌握程度。