loss不下降怎么办
本文最后更新于 2025年3月27日 晚上
Loss不下降怎么办
在训练神经网络时,如果发现 Loss 长时间不下降,可以从以下两个方面进行检查。
1. 检查参数设置
- 学习率(Learning Rate)是否合适:
- 过大可能导致 Loss 震荡甚至发散。
- 过小可能导致收敛速度过慢甚至停滞。
- 观察 Loss 变化趋势,并尝试调整学习率。
- 优化器(Optimizer)设置:
- 是否正确初始化优化器?
- 是否正确使用
zero_grad()
清除梯度? - 是否尝试了不同的优化器(AdamW、SGD 等)?
- Batch Size 影响:
- 过小的 batch size 可能导致梯度噪声较大。
- 过大的 batch size 可能导致泛化能力下降。
- 适当调整 batch size 观察效果。
- 数据是否正确:
- 目标值范围是否正确?
- 是否存在数据泄漏?
- 归一化或标准化是否一致?
2. 检查 param 和 param.grad
- param是否被正确初始化!!!:
- 检查param是否被初始化为0,如果有梯度初始化为0的层一定要注意!!!最后的loss看起来正常但是可能实际上在反传的时候是nan
1
2
3
4
5
6for name, param in self.named_parameters():
if (param == 0).all():
print(f"Parameter {name} is all zeros!")
if param.grad is not None:
self.log(f"grad_norm/{name}", param.grad.norm()) # 记录梯度范数
print(f"Layer {name} | Grad Norm: {param.grad.norm().item()}") - 如果检查到param初始化有0的,用别的初始化方法代替
1
2
3
4
5
6
7# 初始化参数为0的代码
param = nn.Parameter(torch.zeros(param_shape))
param.fill_(0)
# 初始化为正态分布
nn.init.normal_(param, mean=0.0, std=0.02)
# 如果param是2维的,可以用Xavier 初始化
nn.init.xavier_uniform_(param) # Xavier 初始化
- 检查param是否被初始化为0,如果有梯度初始化为0的层一定要注意!!!最后的loss看起来正常但是可能实际上在反传的时候是nan
- 梯度是否正确计算:
- 通过
on_after_backward()
或on_before_optimizer_step()
检查参数的梯度是否为None
。 - 可能原因:参数未注册、未计算梯度或梯度被截断。
- 通过
- 输入是否有
requires_grad=True
- 使用
input.requires_grad
检查输入是否可计算梯度。 - 如果
requires_grad=False
,则反向传播不会计算梯度。
- 使用
- 检查梯度是否过大或过小(Lightning PyTorch)
- 如果你使用的是lighting pytorch 包,可以在
on_after_backward()
里打印梯度范数:1
2
3
4
5def on_after_backward(self):
for name, param in self.named_parameters():
if param.grad is not None:
self.log(f"grad_norm/{name}", param.grad.norm())
print(f"Layer {name} | Grad Norm: {param.grad.norm().item()}") - 如果你在 DeepSpeed / FSDP / DDP 之类的分布式环境下训练,梯度可能在
on_after_backward 之外的地方被同步,导致 .grad 一直是
None,上面的方法会不适用。因此你可以用hook来检查
1
2
3
4
5
6def hook_fn(self, grad):
print(f"Gradient: {grad}")
# 在你的training_step中加入
for name, param in self.named_parameters():
if param.requires_grad:
param.register_hook(hook_fn)
- 如果你使用的是lighting pytorch 包,可以在
- 计算图是否正确构建
- 确保
loss
依赖于所有参数,否则loss.backward()
不会正确计算梯度。 - 检查
loss.requires_grad
是否为True
。 - 确保没有错误使用
.detach()
或torch.no_grad()
,否则会截断梯度。
- 确保
3. 其他可能原因
- 梯度裁剪(Gradient Clipping)
- 在梯度爆炸时使用
self.clip_gradients(optimizer, gradient_clip_val=1.0)
进行裁剪。
- 在梯度爆炸时使用
- 检查是否正确使用
manual_backward()
(Lightning)- 仅在
automatic_optimization=False
时,才需要手动调用manual_backward(loss)
。
- 仅在
如果按照这些步骤排查,应该能找到 Loss 不下降的原因并加以修正。
loss不下降怎么办
http://example.com/2025/03/27/loss不下降怎么办/