例:下列x.grad的值是如何计算的?
>>> x = torch.arange(4.0)
>>> x
tensor([0., 1., 2., 3.])
>>> x.requires_grad_(True)
tensor([0., 1., 2., 3.], requires_grad=True)
>>> x.grad
>>> y = 2 * torch.dot(x, x)
>>> y
tensor(28., grad_fn=<MulBackward0>)
>>> y.backward()
>>> x.grad
tensor([ 0., 4., 8., 12.])
解析:
要理解 x.grad 的计算结果,核心是自动微分(反向传播)的数学原理 + PyTorch的梯度计算逻辑,下面分步骤拆解:
步骤1:明确变量关系与数学表达式
首先梳理代码中的变量定义:
x是张量[0., 1., 2., 3.],且开启了梯度追踪(requires_grad=True);y = 2 * torch.dot(x, x):torch.dot(x, x)是向量内积(点积),数学上等价于 x02+x12+x22+x32x_0^2 + x_1^2 + x_2^2 + x_3^2x02+x12+x22+x32,因此:
y=2×(x02+x12+x22+x32) y = 2 \times (x_0^2 + x_1^2 + x_2^2 + x_3^2) y=2×(x02+x12+x22+x32)
步骤2:梯度的数学定义(偏导数)
x.grad 存储的是 y 对 x 每个元素的偏导数(∂y∂xi\frac{\partial y}{\partial x_i}∂xi∂y),这是反向传播的核心。
先对 yyy 求关于 xix_ixi 的偏导数:
∂y∂xi=∂∂xi[2×(x02+x12+x22+x32)]=2×2xi=4xi \frac{\partial y}{\partial x_i} = \frac{\partial}{\partial x_i} \left[ 2 \times (x_0^2 + x_1^2 + x_2^2 + x_3^2) \right] = 2 \times 2x_i = 4x_i ∂xi∂y=∂xi∂[2×(x02+x12+x22+x32)]=2×2xi=4xi
步骤3:代入x的具体值计算梯度
根据上面的偏导数公式 ∂y∂xi=4xi\frac{\partial y}{\partial x_i} = 4x_i∂xi∂y=4xi,代入 xxx 的每个元素:
| xix_ixi | ∂y∂xi=4xi\frac{\partial y}{\partial x_i} = 4x_i∂xi∂y=4xi | 对应 x.grad 结果 |
|---|---|---|
| x0=0x_0=0x0=0 | 4×0=04 \times 0 = 04×0=0 | 0.0 |
| x1=1x_1=1x1=1 | 4×1=44 \times 1 = 44×1=4 | 4.0 |
| x2=2x_2=2x2=2 | 4×2=84 \times 2 = 84×2=8 | 8.0 |
| x3=3x_3=3x3=3 | 4×3=124 \times 3 = 124×3=12 | 12.0 |
最终得到 x.grad = tensor([0., 4., 8., 12.]),和代码运行结果完全一致。
补充:PyTorch的计算逻辑验证
torch.dot(x, x)的梯度:
点积 x⋅x=∑i=03xi2x \cdot x = \sum_{i=0}^3 x_i^2x⋅x=∑i=03xi2,其对 xix_ixi 的偏导数是 2xi2x_i2xi;- 乘以系数2后的梯度:
y=2×(x⋅x)y = 2 \times (x \cdot x)y=2×(x⋅x),根据导数的“常数倍法则”,梯度也会乘以2,即 2×2xi=4xi2 \times 2x_i = 4x_i2×2xi=4xi; y.backward()的作用:
触发反向传播,从y开始,沿着计算图(MulBackward0→DotBackward)回溯,将每个 xix_ixi 的梯度计算结果存入x.grad。
关键总结
x.grad 的值本质是标量 y 对张量 x 每个元素的偏导数,计算过程遵循基本的微分法则(幂函数求导、常数倍法则),PyTorch只是自动完成了这一数学计算并将结果存入 x.grad 属性中。
411

被折叠的 条评论
为什么被折叠?



