pytorch-梯度

2020年04月20日 31点热度 0人点赞 0条评论
import torch
x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn)
y = x + 2
print(y)
print(y.grad_fn)
z = y * y * 3
out = z.mean()
print(z, out)
out.backward() # 等价于 out.backward(torch.tensor(1.))
print(x.grad)

输出:

tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
None
tensor([[3., 3.],
        [3., 3.]], grad_fn=)

tensor([[27., 27.],
        [27., 27.]], grad_fn=) tensor(27., grad_fn=)
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

因为 out 是一个标量,所以调用 backward() 时不需要指定求导变量:

out.backward() # 等价于 out.backward(torch.tensor(1.))

可以看到最后求出的梯度:

tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])

验证下,我们令 out 为o , 因为

pytorch-梯度

所以
pytorch-梯度

所以上面的输出是正确的。
torch对torch求梯度时

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=)

现在 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.grad 是和 x 同形的张量。
再来看看中断梯度追踪的例子:

x = torch.tensor(1.0, requires_grad=True)
y1 = x ** 2
with torch.no_grad():
y2 = x ** 3
y3 = y1 + y2
print(x.requires_grad)
print(y1, y1.requires_grad) # True
print(y2, y2.requires_grad) # False
print(y3, y3.requires_grad) # True

输出

True
tensor(1., grad_fn=) True
tensor(1.) False
tensor(2., grad_fn=) True

可以看到,上面的 y2 是没有 grad_fn 而且 y2.requires_grad=False 的,而 y3 是有 grad_fn的。如果我们将 y3 对 x 求梯度的话会是多少呢?

y3.backward()
print(x.grad)

输出

tensor(2.)

为什么是2呢?不应该是5吗?事实上,由于y2的定义是被torch.no_grad(): 包裹的,所以与y2有关的梯度是不会回传的,只有与y1有关的梯度才会回传,即x*x对x的梯度。

上面提到, y2.requires_grad=False ,所以不能调用 y2.backward() ,会报错:

RuntimeError: element 0 of tensors does not require grad and does
not have a grad_fn

此外,如果我们想要修改 tensor 的数值,但是又不希望被 autograd 记录(即不会影响反向传播),那么我们可以对 tensor.data 进行操作。

x = torch.ones(1,requires_grad=True)
print(x.data) # 还是⼀一个tensor
print(x.data.requires_grad) # 但是已经是独⽴立于计算图之外
y = 2 * x
x.data *= 100 # 只改变了了值,不不会记录在计算图,所以不不会影响梯度传播
y.backward()
print(x) # 更更改data的值也会影响tensor的值
print(x.grad)

输出

tensor([1.])
False
tensor([100.], requires_grad=True)
tensor([2.])

pytorch官方文档
 

未经允许不得转载!pytorch-梯度

update

纸上得来终觉浅, 绝知此事须躬行。