实验数据:
x1 = torch.tensor([1, 2], dtype=torch.float, requires_grad=True)
x2 = torch.tensor([3, 4], dtype=torch.float, requires_grad=True)
x3 = torch.tensor([5, 6], dtype=torch.float, requires_grad=True)
y = (torch.pow(x1, 3) + torch.pow(x2, 2) + x3).sum()
y.backward()
x4 = x2.clone()
print(x1.grad, x2.grad, x3.grad, x4.grad)
# 梯度分别是 3x^2, 2x, 1, None
# tensor([ 3., 12.]) tensor([6., 8.]) tensor([1., 1.]) None
求导是通过backward()
来实现的,最后对象一定是一个scalar,比如y.backward()
。这里的y是一个和一些需要求导的tensor相关的数值。
则可以通过x.grad
去查看tensor x的梯度。
tensor有一个属性requires_grad,决定是否求梯度。
可以通过detach()
或者detach_()
放弃求导。注意,在pytorch中_
代表是否修改自身。比如x.detach()
只是返回一个放弃求导的tensor,x本身并没有放弃。但是需要注意下文所说的浅拷贝问题,即使y=x.detach()
返回了一个放弃求导的tensor,此时x可求导y不可求,但是对y做修改仍然会影响到x。
注意python中的=
是浅拷贝,如果用a = b
去构造a的话,a的变化会在b上面进行修改。
x2.detach_()
print(x2) # x2本身不可求导了 tensor([3., 4.])
x5 = x3.detach()
print(x3, x5) # 一个可求导一个不可 tensor([5., 6.], requires_grad=True) tensor([5., 6.])
x5[0] = 100
print(x3, x5) # 浅拷贝 还是会影响彼此 tensor([100., 6.], requires_grad=True) tensor([100., 6.])
所以如果想构造一个相同的tensor,可以通过clone()
来实现,如a = b.clone()
。需要注意的是,clone出来的tensor的requires_grad始终为True,并且不会复制原来的tensor的grad,并且丢失自己原来的grad。
# 原来的x3和x1都有梯度值
x3 = x1.clone()
print(x3, x3.grad) # tensor([1., 2.], grad_fn=<CloneBackward>) None # 可以看到x3可求导,但是梯度值清空为None了,丢失了原来的梯度
对于求出来的梯度grad是不清空的,如果多次求导,梯度会累加。如果想清空某个tensor的梯度,可以使用grad.zero()
,比如x.grad.zero()
举例:
x2.grad.zero_() # 清空梯度
z = (torch.pow(x1, 3) + torch.pow(x2, 2) + x3).sum()
z.backward()
print(x1.grad, x2.grad, x3.grad, x4.grad)
# 注意此时除了x2之外其他tensor梯度是原来梯度的两倍,因为其他都累加了一次新的,而x2梯度清空了
# tensor([ 6., 24.]) tensor([12., 16.]) tensor([2., 2.]) None
标签:tensor,梯度,x2,pytorch,求导,x3,grad
From: https://www.cnblogs.com/ReflexFox/p/16881562.html