PyTorch损失不下降主因常是学习率错误或浅层梯度消失:学习率过大(如SGD+momentum=0.9时lr=0.1)致loss发散为inf/nan;浅层梯度趋零而末层正常,多因torch.no_grad()、.detach()或.requires_grad=False截断计算图,需用backward_hook定位衰减点。

损失函数不下降,八成不是模型不行,而是学习率设错了,或者梯度根本没传到前面几层——这两类问题在 PyTorch 实操中高频共存,且相互掩盖。
学习率太大导致 loss 飞天或震荡
lr=0.1 时 loss 突然变成 inf 或 nan,不是数据炸了,是优化器一步跨过山谷摔下悬崖。尤其当你用 SGD 搭配默认 momentum=0.9,初始梯度稍大就会滚雪球式发散。
- 先关掉所有正则项(
weight_decay=0)、关掉BatchNorm的 running stats 更新(model.train()时设bn.eval()临时隔离干扰) - 用极小 batch(如
batch_size=1)跑 5 轮,观察loss.item()是否稳定下降:如果还跳变,直接换ReduceLROnPlateau调度器,patience=2、factor=0.5开始压 - 别信“别人用 0.01 效果好”——你的
model.parameters()的参数量、初始化方式、损失尺度都不同,lr必须重估
梯度在浅层消失,loss 停滞但不报错
训练几十轮后,loss 卡在某个值不动,optimizer.step() 确实在执行,但 model.layer1.weight.grad 几乎为 0,而最后一层梯度正常——这是典型的梯度消失信号,和 sigmoid/tanh 无关,Kaiming 初始化 + ReLU 也救不了它,只要链路里有任意一环断掉。
- 检查是否误用了
torch.no_grad()包裹了部分前向逻辑(比如自定义 loss 计算里调了.detach()后又反向) - 确认所有中间变量都参与计算图:打印
output.requires_grad,必须是True;若为False,往上查哪一步用了.item()、.numpy()、.cpu().detach().numpy() - 对关键层手动注入梯度探针:
hook = lambda grad: print(f"layerX grad norm: {grad.norm().item():.4f}"),用layer.register_backward_hook(hook)定位衰减断点
loss 不下降却显示梯度非零的隐藏陷阱
你看到 loss.backward() 后 param.grad 有值,就以为梯度通了?错。常见假阳性场景:loss 是标量但计算路径被截断、多 loss 加权时权重为 0、criterion 返回的是 mean 而你误当 sum 用。
立即学习“Python免费学习笔记(深入)”;
-
criterion = nn.CrossEntropyLoss(reduction='sum')和reduction='mean'对应的梯度尺度差一个 batch size 倍,混用会导致 optimizer 实际步长偏差数十倍 - 多任务 loss 合并时写成
total_loss = loss_a + 0 * loss_b,表面看loss_b没参与,但它内部的requires_grad=True变量仍会构建计算图,拖慢 backward 且可能污染梯度流 - 自定义 loss 中用了
torch.where(condition, a, b)但condition是 bool tensor 且未 detach,容易因广播引发隐式梯度泄漏
真正卡住的地方,往往不在 loss 公式本身,而在你没意识到的归一化方式、隐藏状态生命周期、或某次 .detach() 的位置——这些细节不会报错,只会让梯度静默蒸发。


















