from torch.autograd import Variable
x = Variable(torch.ones(1, 2),requires_grad=True)
x += 1 #或者调用x.add_(1) #注意add_下划线
报错:RuntimeError: a leaf Variable that requires grad has been used in an in-place operation.
下面通过torch.no_grad()进行运算
from torch.autograd import Variable
x = Variable(torch.ones(1, 2),requires_grad=True)
print(id(x)) #输出:140655195757952
print(x) #输出 :tensor([[1., 1.]], requires_grad=True)
with torch.no_grad():
x += 1 #或者调用x.add_(1) #注意add_下划线
print(id(x)) #输出:140655195757952 id没有改变
print(x)# 输出:tensor([[2., 2.]], requires_grad=True) 梯度还未True
x =x + 1
print(id(x)) #输出: 140655195756800 id改变
print(x) #输出:tensor([[3., 3.]], grad_fn=) 没有requires_grad=True状态
从输出中可以看到:x += 1
没有改变id,requires_grad
,但是执行x =x + 1
后id改变,且后边状态为grad_fn=
,记录了加法状态AddBackward0
,但是,这样之后执行backword()
后求梯度为变为None
,也就是普通赋值(非原地操作)不能对计算梯度的,如果想不用torch.no_grad()
,可以利用x.data
修改内容。如果:
from torch.autograd import Variable
import torch
x = Variable(torch.ones(1, 2),requires_grad=True)
y = x**2
c = x + 1 ##假如此处换为 x = x + 1,最后结果会输出什么?
z = y**2
z.sum().backward()
print(z.grad) ## 输出:None
print(y.grad) ##输出:None
print(x.grad) ##输出:tensor([[4., 4.]])
print(x) ##输出:tensor([[1., 1.]], requires_grad=True
print(y) ##:tensor([[1., 1.]], grad_fn=
print(z) ##:输出:tensor([[1., 1.]], grad_fn=)
print(c) ##:输出:tensor([[2., 2.]], grad_fn=)
从输出可以看到,只有requires_grad=True
状态的tensor才有梯度,如果将c = x + 1
替换为x = x + 1
后,x.grad
也会变为None
,打印x
为tensor([[2., 2.]], grad_fn=
,所以,梯度输出为None
,其实,最开始的x
还是存在梯度。一旦tensor的requires_grad
不为True
时候,就能够随意原地操作了,没有梯度限制。
from torch.autograd import Variable
import torch
x = Variable(torch.ones(1, 10),requires_grad=True)
y1 = (x)**2
y2 = (x)**2
z = y1**2 + y2**2
z.sum().backward()
print(x.grad) ## 输出:tensor([[8., 8., 8., 8., 8., 8., 8., 8., 8., 8.]])
print(z) ##输出:tensor([[2., 2., 2., 2., 2., 2., 2., 2., 2., 2.]], grad_fn=)
x = Variable(torch.ones(1, 10),requires_grad=True)
y1 = (x)**2
with torch.no_grad():
y2 = (x)**2
z = y1**2 + y2**2
z.sum().backward()
print(x.grad) ##输出:tensor([[4., 4., 4., 4., 4., 4., 4., 4., 4., 4.]])
print(z)##输出:tensor([[2., 2., 2., 2., 2., 2., 2., 2., 2., 2.]], grad_fn=)
x = Variable(torch.ones(1, 10),requires_grad=True)
with torch.no_grad():
x += 1
y2 = (x)**2
y1 = (x)**2
z = y1**2 + y2**2
z.sum().backward()
print(x.grad)##输出tensor([[32., 32., 32., 32., 32., 32., 32., 32., 32., 32.]])
print(z)##输出tensor([[32., 32., 32., 32., 32., 32., 32., 32., 32., 32.]],grad_fn=)
第一次通过y1
和y2
的梯度全部计算;第二次仅仅计算了通过y1
的梯度,y2
没有传递梯度;第三次仅仅计算通过y1
的梯度,但是x
值改变导致y1
的导数和y1
改变,所以梯度为32
。
from torch.autograd import Variable
import torch
x = Variable(torch.ones(1, 10),requires_grad=True)
y1 = (x)**2
with torch.no_grad():
x += 1
y2 = (x)**2
z = y1**2 + y2**2
z.sum().backward() ##这里会报错,报错内容见后面
print(x.grad)
print(z)
报错:RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [1, 10]] is at version 1; expected version 0 instead. Hint: enable anomaly detection to find the operation that failed to compute its gradient, with torch.autograd.set_detect_anomaly(True)
意思是需要求梯度的tensor已经进行原地操作,进行了改变,(之前的x
不存在了)不能求梯度,将y1 = (x)**2
放在z = y1**2 + y2**2
之前(with torch.no_grad():
之外),则没问题。
optimizer.zero_grad()
的原因from torch.autograd import Variable
import torch
x = Variable(torch.ones(1, 2),requires_grad=True)
x.sum().backward()
print(x.grad) #输出:tensor([[1., 1.]])
x.sum().backward()
print(x.grad)#输出:tensor([[2., 2.]])
x.sum().backward()
print(x.grad)#输出:tensor([[3., 3.]])
从输出中可以看出,每执行一次backward()
,对应tensor的梯度都会自加1
,即梯度自动累加,所以需要每个batch_size
都执行梯度清零.zero_grad()
操作。