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

同一输入下torch.autograd.grad计算结果差异的原因探究

问题:torch.autograd.grad计算梯度结果不一致的原因

我尝试用torch.autograd.grad()计算一些点的梯度,代码如下:

for batch in data_loader:
    batch_coordinates = batch[0]
    out = model(batch_coordinates.requires_grad_())

    x1, y1 = batch_coordinates[:, 0].reshape(-1, 1), batch_coordinates[:, 1].reshape(-1, 1)

    y = custom_output(out, x1, y1)
    grad_1 = torch.autograd.grad(y.sum(), batch_coordinates, create_graph=True) # 计算梯度
    grad_2 = torch.autograd.grad(y.sum(), (x1, y1), create_graph=True) # 计算梯度

其中batch_coordinates是维度为torch.Size([n,2])的张量,n为点的数量;model是一个简单的三层神经网络;custom_output(out, x1, y1)是一个插值网络输出的函数,输入为点的x、y坐标和网络输出。

为什么grad_1和grad_2的计算结果存在差异(已经考虑了grad_2是列表的情况)?

输出结果如下:

GRAD MINIBATCH COORDINATES: 
(tensor([[-6.5256e-03,  1.5925e-03],
        [-6.1777e-03, -8.8977e-05],
        [-2.5146e-03,  3.1782e-03],
        [-4.3833e-03,  2.2729e-03],
        [-6.6386e-03,  3.9808e-04],
        [-5.9642e-03, -2.2408e-04],
        [ 1.0123e-03,  4.7309e-03],
        [ 3.8920e-02, -1.3823e-01],
        [-6.2750e+00,  1.4732e+00],
        [-5.8813e-03, -2.6810e-04]], grad_fn=<AddBackward0>),)
GRAD X1, Y1: 
(tensor([[ 0.0000e+00],
        [ 0.0000e+00],
        [ 0.0000e+00],
        [ 0.0000e+00],
        [-2.0982e-05],
        [ 0.0000e+00],
        [-1.5622e-04],
        [ 4.5191e-02],
        [-6.2711e+00],
        [ 0.0000e+00]], grad_fn=<AddBackward0>), tensor([[ 0.0000e+00],
        [ 0.0000e+00],
        [ 0.0000e+00],
        [ 0.0000e+00],
        [ 7.6683e-06],
        [ 0.0000e+00],
        [-2.7294e-05],
        [-1.3825e-01],
        [ 1.4730e+00],
        [ 0.0000e+00]], grad_fn=<AddBackward0>))

解答

核心原因是**x1、y1是batch_coordinates的视图而非独立张量**,PyTorch自动微分系统对视图张量的梯度追踪范围和原张量不同:

  • 对batch_coordinates求梯度时,PyTorch会完整追踪从batch_coordinates到y.sum()的全路径——包括model前向传播和custom_output的插值逻辑,所以grad_1是完整的梯度值。
  • x1、y1是原张量的切片/重塑视图,和原张量共享底层数据,但计算图中model的输入是batch_coordinates而非x1/y1,因此对x1/y1求梯度时,PyTorch只会计算custom_output中直接依赖x1/y1的部分梯度,忽略model内部的反向传播路径,这就导致大部分点的梯度为0,仅少数因custom_output直接用到坐标才产生非零值。

要让两者结果一致,需让x1、y1关联到完整的计算图。可以通过克隆原张量再拆分实现:

batch_clone = batch_coordinates.clone().requires_grad_()
x1, y1 = batch_clone[:, 0].reshape(-1, 1), batch_clone[:, 1].reshape(-1, 1)
out = model(batch_clone)
y = custom_output(out, x1, y1)
grad_1 = torch.autograd.grad(y.sum(), batch_clone, create_graph=True)
grad_2 = torch.autograd.grad(y.sum(), (x1, y1), create_graph=True)

此时x1、y1是克隆张量的视图,计算图会完整追踪所有路径,grad_2的结果会和grad_1的对应维度完全匹配。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 08:04:56