自动求导

我们来逐步分析代码,并解释为什么 b.grad[3.]

代码分析 Link to heading

import torch

w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)

a = torch.add(w, x)  # a = w + x
b = torch.add(w, 1)  # b = w + 1
y = torch.mul(a, b)  # y = a * b

b.retain_grad()  # 保留 b 的梯度
y.backward()     # 反向传播计算梯度

print(w.grad)    # 打印 w 的梯度
print(b.grad)    # 打印 b 的梯度

1. 计算图 Link to heading

  • a = w + xawx 的和。
  • b = w + 1bw 和常数 1 的和。
  • y = a * byab 的乘积。

计算图如下:

w ────┐
      ├── a = w + x ───┐
x ────┘                │
                       y = a * b
w ────┐                │
      ├── b = w + 1 ───┘
1 ────┘

2. 计算值 Link to heading

  • w = [1.], x = [2.]
  • a = w + x = [1.] + [2.] = [3.]
  • b = w + 1 = [1.] + [1.] = [2.]
  • y = a * b = [3.] * [2.] = [6.]

3. 反向传播 Link to heading

反向传播的目的是计算 y 对各个变量的梯度。根据链式法则:

  • y = a * b,所以:

    • $\frac{\partial y}{\partial a} = b = [2.]$
    • $\frac{\partial y}{\partial b} = a = [3.]$
  • a = w + x,所以:

    • $\frac{\partial a}{\partial w} = 1$
    • $\frac{\partial a}{\partial x} = 1$
  • b = w + 1,所以:

    • $\frac{\partial b}{\partial w} = 1$

4. 计算梯度 Link to heading

  • yb 的梯度:

    $$ \frac{\partial y}{\partial b} = a = [3.] $$

    因此,b.grad = [3.]

  • yw 的梯度:

    $$ \frac{\partial y}{\partial w} = \frac{\partial y}{\partial a} \cdot \frac{\partial a}{\partial w} + \frac{\partial y}{\partial b} \cdot \frac{\partial b}{\partial w} $$

    代入值:

    $$ \frac{\partial y}{\partial w} = [2.] \cdot 1 + [3.] \cdot 1 = [5.] $$

    因此,w.grad = [5.]

结果 Link to heading

  • b.grad = [3.],因为 yb 的梯度是 a = [3.]
  • w.grad = [5.],因为 yw 的梯度是 [5.]

总结 Link to heading

b.grad[3.],因为 yb 的偏导数是 a = [3.]。这是通过链式法则和反向传播计算得出的结果。