torch.Tensor
的属性.requires_grad
设置为True
,它将记录自身所有的操作.当计算完成后可以调用.backward()
函数来计算梯度.梯度将会存放在.grad
属性里面.
通过.detach()
方法可以停止tensor记录历史,也可以停止未来的计算.
Tensor
和Function
是紧密相连的.每一个tensor
都有一个.grad_fn
属性,他对应了一个创建Tensor
的Function
.
autograd提供了自动微分操作.
import torch
# 创建一个tensor
x = torch.ones(2, 2, requires_grad=True)
print(x)
# 对tensor进行操作
y = x + 2
print(y)
# y是计算的结果,所以他会有`grad_fn`
print(y.grad_fn)
# 对y进行更多的操作
z = y * y * 3
out = z.mean()
print(z, out)
# `.requires_grad_(...)`用来指定一个tensor的`requires_grad`标志, 默认是`False`
a = torch.randn(2, 2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)
接下来计算反向传播.因为out
只包含了一个值,所以out.backward()
等价于out.backward(torch.tensor(1.))
,也就是说如果结果是矩阵的话,要在backward
方法里指明维度.
out.backward()
print(x.grad)
输出的结果是
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
为什么会得到这个结果?回想刚才我们的计算公式:
x = torch.ones(2, 2, requires_grad=True)
y = x + 2
z = y * y * 3
out = z.mean()
转换为数学公式为:
o = 1 4 ∑ i z i o = \frac{1}{4}\sum_i z_i o=41∑izi
z i = 3 ( x i + 2 ) 2 z_i = 3(x_i+2)^2 zi=3(xi+2)2
我们得到,当x=1时:
z i ∣ x i = 1 = 27 z_i\bigr\rvert_{x_i=1} = 27 zi∣∣xi=1=27
因此,得到在x=1那个点的斜率为:
∂ o ∂ x i = 3 2 ( x i + 2 ) \frac{\partial o}{\partial x_i} = \frac{3}{2}(x_i+2) ∂xi∂o=23(xi+2)
∂ o ∂ x i ∣ x i = 1 = 9 2 = 4.5 \frac{\partial o}{\partial x_i}\bigr\rvert_{x_i=1} = \frac{9}{2} = 4.5 ∂xi∂o∣∣xi=1=29=4.5
如果最后输出的y,不是一个值而是一个向量,则:
x = torch.randn(3, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)
v = torch.tensor([0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)
print(x.grad)
print(x.requires_grad)
print((x ** 2).requires_grad)
with torch.no_grad():
print((x ** 2).requires_grad)
参考文献:
https://pytorch.apachecn.org/#/docs/3
https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html#sphx-glr-beginner-blitz-autograd-tutorial-py