pytorch autograd 非叶子节点的梯度会保留么?

  • 只有叶子节点的梯度得到保留,中间变量的梯度默认不保留
  • 叶子节点的值在求梯度前不允许更改,以及修改的方法

只有叶子节点的梯度得到保留,中间变量的梯度默认不保留,除非使用 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)

你可能感兴趣的:(深度学习)