梯度爆炸的典型现象是训练时loss突变为nan或参数梯度突变为inf/极大值(如1e8以上),判断依据是监控各层梯度范数是否出现持续指数增长或跨量级跳变,而非单纯数值大。

梯度爆炸的典型现象和判断依据
训练时 loss 突然变成 nan,或者某次 backward 后模型参数突变为 inf 或极大绝对值(如 1e8 以上),基本可以确认梯度爆炸。但更早发现问题的方式是监控每层权重的梯度范数——如果某一层的 torch.norm(param.grad) 在前几个 epoch 就飙升到 >100,甚至 >1000,而其他层还在 0.1 附近,那它大概率是爆炸源头。
注意:不是所有大梯度都代表爆炸。RNN、Transformer 的某些层(如 embedding、decoder 最后一层)在小 batch 下天然梯度偏大,关键看**是否持续指数增长**或**跨量级跳变**。
如何在 backward 后逐层获取梯度范数
PyTorch 不自动保存中间梯度,必须在 loss.backward() 之后、optimizer.step() 之前插入钩子或遍历。最轻量的做法是直接遍历模型参数:
for name, param in model.named_parameters():
if param.grad is not None:
grad_norm = torch.norm(param.grad).item()
print(f"{name}: {grad_norm:.3f}")
常见陷阱:
-
param.grad在zero_grad()后为None,务必确保在backward()之后、step()之前执行 - BN 层的
weight和bias通常有梯度,但running_mean等 buffer 没有,别误判 - 使用
torch.nn.DataParallel时,named_parameters()返回的是 module 内部参数,没问题;但DistributedDataParallel下需确保在 rank 0 上打印,避免重复输出
用 register_hook 实现细粒度梯度监控
如果想在每次 backward 时自动记录、不侵入训练主循环,可用 register_hook:
grad_norms = {}
for name, param in model.named_parameters():
if param.requires_grad:
grad_norms[name] = []
param.register_hook(lambda grad, n=name: grad_norms[n].append(torch.norm(grad).item()))
但要注意:
- 钩子接收的是原始
grad张量,不是副本,别在钩子里做 in-place 修改(如grad.clamp_())否则影响后续计算 - 钩子在反向传播过程中触发,顺序与计算图相反,所以
grad_norms中列表末尾不一定是最后一层——需配合name字段识别层级 - 若模型含
torch.cuda.amp混合精度,grad是 float16,torch.norm默认转 float32 计算,无问题;但若手动 cast 成 float16 再求范数,可能下溢为 0
梯度裁剪不是万能解,得知道裁哪一层
torch.nn.utils.clip_grad_norm_ 常被当成“防爆开关”,但它对所有参数一视同仁。实际中,爆炸常集中在特定结构:
- LSTM 的
weight_hh_l0(隐藏到隐藏权重)容易因长序列累积误差
- Transformer decoder 的
layers.5.self_attn.out_proj.weight 在生成任务中梯度方差极大
- 带残差连接的深层 CNN 中,浅层(如
conv1.weight)梯度可能比深层小 2–3 个数量级,全局裁剪会过度压制它们
weight_hh_l0(隐藏到隐藏权重)容易因长序列累积误差layers.5.self_attn.out_proj.weight 在生成任务中梯度方差极大conv1.weight)梯度可能比深层小 2–3 个数量级,全局裁剪会过度压制它们建议做法:先用前述方法跑 1–2 个 batch,找出梯度范数持续 >50 的层,再针对性裁剪:
torch.nn.utils.clip_grad_norm_(model.layer5.parameters(), max_norm=10.0)
真正难的不是监控,而是区分「该大的梯度」和「失控的梯度」——比如 attention score 的梯度在 softmax 后本就稀疏且局部极大,此时看 L1 范数比 L2 更稳定;而全连接层更适合看 L2。这个细节,多数人调参时会忽略。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











