x=torch.randn(3,requires_grad=True)
y=x+2 # will create a computational graph
print(y)
z=y*y*2
print(z)
z.backward() #dz/dx
print(x.grad)
tensor([2.0864, 1.2528, 1.2987], grad_fn=<AddBackward0>)
tensor([8.7058, 3.1389, 3.3733], grad_fn=<MulBackward0>)
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-6-3ff5c6c8f8ea> in <cell line: 8>()
6 print(z)
----> 8 z.backward() #dz/dx
9 print(x.grad)
2 frames
/usr/local/lib/python3.10/dist-packages/torch/autograd/__init__.py in _make_grads(outputs, grads, is_grads_batched)
115 if out.requires_grad:
116 if out.numel() != 1:
--> 117 raise RuntimeError(
118 "grad can be implicitly created only for scalar outputs"
119 )
RuntimeError: grad can be implicitly created only for scalar outputs
创建一个v,作为链式法则中的Jacobine矩阵
x=torch.randn(3,requires_grad=True)
y=x+2 # will create a computational graph
print(y)
z=y*y*2
print(z)
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float32)
z.backward(v) #dz/dx
print(x.grad)
当执行y.backward(v)
时,实际上进行的操作是计算向量y
相对于其输入张量x
的向量-雅可比乘积(vector-Jacobian product, VJP)。这个过程可以更清晰地理解backward
方法的工作原理以及v
的作用。假设我们有向量函数y=f(x)\mathbf{y} = f(\mathbf{x})y=f(x),其中x\mathbf{x}x和y\mathbf{y}y都是向量,x∈Rn\mathbf{x} \in \mathbb{R}^nx∈Rn,y∈Rm\mathbf{y} \in \mathbb{R}^my∈Rm。雅可比矩阵J\mathbf{J}J是fff相对于x\mathbf{x}x的导数的矩阵表示,其中每个元素Jij=∂yi∂xjJ_{ij} = \frac{\partial y_i}{\partial x_j}Jij=∂xj∂yi。
向量-雅可比乘积
当对y.backward(v)
进行操作,其中v∈Rm\mathbf{v} \in \mathbb{R}^mv∈Rm,实际上计算的是v⊤J\mathbf{v}^\top \mathbf{J}v⊤J。这个操作的结果是一个长度为nnn的向量,与x\mathbf{x}x的维度相同。具体地说,如果y\mathbf{y}y由函数f(x)f(\mathbf{x})f(x)得到,那么对于给定的向量v\mathbf{v}v,向量-雅可比乘积v⊤J\mathbf{v}^\top