PyTorch导数计算存疑:为何梯度输出为[6,6,6]而非[4,4,4]?
问题原因解析
你的计算偏差来自对PyTorch中backward()方法的理解误区,具体拆解如下:
1. 张量y的实际构成
你的代码中y = 3*x + x.sum()生成的是长度为3的张量,每个元素的表达式为:
- $y_0 = 3x_0 + (x_0+x_1+x_2) = 4x_0 + x_1 + x_2$
- $y_1 = 3x_1 + (x_0+x_1+x_2) = x_0 + 4x_1 + x_2$
- $y_2 = 3x_2 + (x_0+x_1+x_2) = x_0 + x_1 + 4x_2$
2. backward(torch.ones(3))的计算逻辑
当对非标量张量调用backward()时,传入的参数是梯度权重向量,PyTorch会计算雅可比向量积:即把权重向量与y对x的雅可比矩阵做乘积,最终得到x的梯度。
你传入的torch.ones(3)是[1,1,1],以$x_0$的梯度为例:
$$\text{grad}(x_0) = 1*\frac{\partial y_0}{\partial x_0} + 1*\frac{\partial y_1}{\partial x_0} + 1*\frac{\partial y_2}{\partial x_0} = 14 + 11 + 1*1 = 6$$
同理$x_1$和$x_2$的梯度也是6,最终得到[6,6,6]。
3. 如何得到你预期的[4,4,4]
如果你想让每个$x_i$对应$y_i$的偏导数(即4),有两种方式:
- 方式一:将
y转为标量后求导(本质是对所有y元素求和,此时权重默认是1):x = torch.arange(3,dtype=float) x.requires_grad_(True) y = (3*x + x.sum()).sum() # 转为标量 y.backward() print(x.grad) # 输出tensor([4., 4., 4.]) - 方式二:若要保留
y的张量形态,需明确你要计算的是每个y_i对x的梯度,但此时无法同时得到所有x_i对应y_i的4,只能单独计算单个y_i的梯度,比如:x = torch.arange(3,dtype=float) x.requires_grad_(True) y = 3*x + x.sum() y[0].backward() # 仅对y[0]求导 print(x.grad) # 输出tensor([4., 1., 1.])
内容的提问来源于stack exchange,提问作者Leosa99 _
相关产品推荐
相关产品推荐

