Pytorch CNN训练时loss.backward触发AddmmBackward返回nan值报错
你遇到的AddmmBackward返回NaN的错误,本质是反向传播过程中全连接层的矩阵乘加运算产生了数值溢出,结合你输出的梯度存在1e16量级的异常值和大量NaN,属于典型的梯度爆炸或数值计算非法问题,可按以下步骤排查修复:
- 校验数据集合法性
先排查自定义数据集的输入张量、标签是否存在NaN/inf值,同时确认标签格式符合负对数似然损失(NLLLoss)的要求:标签必须是类别索引(非onehot编码),取值范围在[0, 类别数-1]区间内,可添加以下断言做校验:assert not torch.isnan(inputs).any(), "输入张量存在NaN" assert not torch.isnan(targets).any(), "标签存在NaN" assert targets.min() >= 0 and targets.max() < num_classes, "标签取值超出类别范围" - 修复损失计算逻辑
负对数似然损失要求输入是LogSoftmax的输出,若LogSoftmax的输出存在接近0的值,取对数后会得到-inf,反向传播就会生成NaN,可对输出做下限裁剪避免非法值:out = F.log_softmax(out, dim=1) out = torch.clamp(out, min=-100) # 避免出现负无穷 loss = F.nll_loss(out, targets) - 添加梯度裁剪抑制爆炸
你观测到的e16量级梯度已经属于梯度爆炸范畴,在反向传播后、优化器更新参数前添加梯度裁剪即可解决:loss.backward() # 裁剪梯度,max_norm可根据实际场景调整为1、5、10等值 torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5) optimizer.step() - 调整训练超参数
降低Adam优化器的初始学习率,默认1e-3可能对你的数据集过大,可尝试下调到1e-4、1e-5级别;同时确认输入数据已做归一化处理,输入数值范围过大也会导致逐层计算后数值溢出。 - 定位异常样本
先将batch size调整为1,逐样本跑训练流程,如果单样本训练报错,优先排查模型结构和损失逻辑的错误;如果单样本正常、批量训练报错,说明batch内存在异常样本,可进一步定位脏数据。
内容的提问来源于stack exchange,提问作者user14924
相关产品推荐
相关产品推荐

