You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch添加自定义损失后autograd失效、训练损失无变化排查

PyTorch混合损失训练时损失值固定问题排查

核心错误点

你的代码一共两处破坏autograd梯度链路的问题,直接导致模型参数无法更新,损失全程不变:

  • 自定义损失完全脱离计算图
    my_custom_loss中调用.detach().cpu().numpy()将PyTorch张量转为NumPy数组,后续所有正弦、求和计算都是NumPy操作,完全脱离PyTorch的自动微分追踪范围,返回的square_sum是和模型参数毫无关联的普通浮点数,反向传播时这部分不会产生任何梯度。从你的打印日志也能验证:正常的loss1带grad_fn=<MseLossBackward0>标记,而loss2直接输出无梯度标记的浮点数34.6672。
  • 多余的Variable操作彻底切断梯度链
    损失求和后执行的loss = torch.autograd.Variable(loss, requires_grad=True)是完全错误的操作:PyTorch 0.4版本后Variable已和Tensor合并,这种写法会新建一个独立的叶子张量,彻底断开和前序计算图、模型参数的关联,反向传播时梯度根本无法回传到模型参数,参数自然全程不更新。

修复代码

首先重写自定义损失,全程使用PyTorch原生算子,保留计算图,同时修正原实现中角度未转弧度的逻辑错误(三角函数默认输入为弧度值,原NumPy实现直接传入角度值计算结果是错的):

import torch

def my_custom_loss(preds, label):
    angle_diff = preds - label
    half_angle_diff = angle_diff / 2
    # 如果你的标签角度是角度制,保留下面这行转弧度;如果是弧度制则删除
    half_angle_diff = torch.deg2rad(half_angle_diff)
    sine_diff = torch.sin(half_angle_diff)
    square_sum = torch.nansum(sine_diff ** 2)
    return square_sum

然后删除多余的Variable包装,修正损失计算逻辑:

mse_loss = torch.nn.MSELoss()
# 前向传播得到preds、label后
loss1 = mse_loss(preds[:, (0,1,3)], label[:, (0,1,3)])
loss2 = my_custom_loss(preds[:, 2], label[:, 2])
# 直接求和即可,不需要额外包装
loss = loss1 + loss2
# 正常执行反向传播
loss.backward()
# 后续执行优化器step、梯度清零等常规操作即可

修复后可以通过打印验证:loss2会成为带grad_fn标记的可微分张量,最终的loss也会保留完整的计算图链路,模型参数可以正常接收梯度更新。

内容的提问来源于stack exchange,提问作者fariadantes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 09:42:23