动手学深度学习_2.2_autograd
Tensor
import torch x = torch.ones(2, 2, requires_grad=True) # 将其属性.requires_grad设置为True,它将开始追踪(track)在其上的所有操作。完成计算后,可以调用.backward()来完成所有梯度计算 print(x) print(x.grad_fn) # 每个Tensor都有一个.grad_fn属性,该属性即创建该Tensor的Function(除非用户创建的Tensors时设置了grad_fn=None)
# tensor([[1., 1.],
# [1., 1.]], requires_grad=True) # None
y = x + 2 print(y) print(y.grad_fn) # tensor([[3., 3.], # [3., 3.]], grad_fn=<AddBackward0>) # <AddBackward0 object at 0x7fecef6f5320>
attension: x是直接创建的,所以他没有grad_fn,而y通过一个加法操作创建的,所以它有一个的grad_fn
# x这种直接创建的称为叶⼦节点,叶⼦节点对应的 grad_fn 是 None print(x.is_leaf, y.is_leaf) # True False
z = y * y * 3 out = z.mean() print(z, out) # tensor([[27., 27.], # [27., 27.]], grad_fn=<MulBackward0>) tensor(27., grad_fn=<MeanBackward0>)
# 通过.requires_grad_()来用in-place的方式改变requires_grad属性 a = torch.randn(2, 2) # 缺失情况下默认requires_grad=False 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) # False # True # <SumBackward0 object at 0x7fecef6d17b8>
梯度
# 因为out是一个标量,所以调用backward()时不需要指定求导变量 out.backward() # 等价于out.backward(torch.tensor(1.)) print(x.grad) # tensor([[4.5000, 4.5000], # [4.5000, 4.5000]])
# 再来一次反向传播,注意 grad 是累加的 out2 = x.sum() out2.backward() print(x.grad) out3 = x.sum() x.grad.data.zero_() out3.backward() print(x.grad) # tensor([[5.5000, 5.5000], # [5.5000, 5.5000]]) # tensor([[1., 1.], # [1., 1.]])
# y.backward(w) 求的不是 y 对 x 的导数,而是 l = torch.sum(y*w) 对 x 的导数。 x = torch.tensor([1.0, 2.0, 3.0, 4.0], requires_grad=True) y = 2 * x z = y.view(2, 2) print(z) # tensor([[2., 4.], # [6., 8.]], grad_fn=<ViewBackward>)
现在y不是一个标量,所以在调用backward时需要传入一个和y同行的权重向量进行甲醛求和得到一个标量
v = torch.tensor([[1.0, 0.1], [0.01, 0.001]], dtype=torch.float) z.backward(v) print(x.grad) # tensor([2.0000, 0.2000, 0.0200, 0.0020])
# 中断梯度追踪 x = torch.tensor(1.0, requires_grad=True) y1 = x ** 2 with torch.no_grad(): # 与y2有关的梯度是不会回传的,只有与y1有关的梯度才会回传 y2 = x ** 3 y3 = y1 + y2 print(x, x.requires_grad) print(y1, y1.requires_grad) print(y2, y2.requires_grad) # False,所以不能调用y2.backward() print(y3, y3.requires_grad) # tensor(1., requires_grad=True) True # tensor(1., grad_fn=<PowBackward0>) True # tensor(1.) False # tensor(2., grad_fn=<AddBackward0>) True
y3.backward() print(x.grad) # tensor(2.)
想修改tensor的数值,但又不希望被autograd记录(即不影响反向传播),那么可对tensor.data操作
x = torch.ones(1, requires_grad=True) print(x.data) print(x.data.requires_grad) y = 2 * x x.data *= 100 y.backward() print(x) print(x.grad) # tensor([1.]) # False # tensor([100.], requires_grad=True) # tensor([2.])