- 只有叶子节点的梯度得到保留,中间变量的梯度默认不保留
- 叶子节点的值在求梯度前不允许更改,以及修改的方法
只有叶子节点的梯度得到保留,中间变量的梯度默认不保留,除非使用 retain_grad() 方法
# 叶子节点
a = torch.tensor(2.0, requires_grad=True)
b = a.exp()
b.backward()
a.grad
a
是叶子节点,b
不是叶子节点,当使用 b.backward()
求导时,只有叶子节点 a
的梯度 .grad
得到保留,非叶子节点 b
的 .grad
则没有,如果需要保留 b
的梯度,可以使用 b.retain_grad()
a = torch.tensor(2.0, requires_grad=True)
b = a.exp()
b.retain_grad()
b.backward()
b.grad
b.backward()
只能计算一次,因为执行一次 b.backward()
后,计算图的缓冲区已经被释放,再次执行将报如下错误:
RuntimeError: Trying to backward through the graph a second time, but the buffers have already been freed
叶子节点的值在求梯度前不允许更改
# a 是叶子节点
a = torch.tensor([10.,5.,2.,3.],requires_grad=True)
# 在求梯度前,叶子节点的值被修改
a[:] = 10
a.add_(10.)
loss = (a*a).mean()
loss.backward()
如上代码所示,叶子节点在反向传播前被修改,此时 a 已经不是叶子节点了,将报如下错误:
RuntimeError: leaf variable has been moved into the graph interior
如果需要在求梯度前修改,可以如下操作
一、使用 a.data.fill_() 方法
# 叶子节点
a = torch.tensor([10.,5.,2.,3.],requires_grad=True)
# 此时叶子节点的值被修改,但仍然是 叶子节点
a.data.fill_(5)
print(a, a.is_leaf)
# 可以正常求梯度
loss = (a*a).mean()
loss.backward()
print(a.grad)
二、使用 with torch.no_grad() 代码块
# 叶子节点
a = torch.tensor([10.,5.,2.,3.],requires_grad=True)
with torch.no_grad():
a[:] = 0
a.add_(5.)
# 此时可以继续求梯度
loss = (a*a).mean()
loss.backward()
print(a.grad)