梯度保留
Q(question):pytorch autograd 非叶子节点的梯度会保留么?
A(answer):
1. 只有叶子节点的梯度得到保留,中间变量的梯度默认不保留
2. 叶子节点的值在求梯度前不允许更改
示例
>>> a = torch.tensor(2.0, requires_grad=True)
>>> b = torch.tensor(3.0)
>>> c=a*a*5
>>> d=c*c*b
>>> d.backward()
>>> a.grad
tensor(2400.)
注:复制完代码请删去>>>和输出结果再运行,建议手打一遍,这样更能加深理解
默认创建的张量(tensor)为常量
,常量无法计算,需要设置requires_grad=True才能计算梯度,所以a
,c
,d
可以计算梯度,b
不可以计算梯度。反向传播后,只有叶子节点可以保留梯度,所以这里只有a
的梯度会保留,如果需要保留c
,d
的梯度,需要使用retain_grad()函数
注:大家可以尝试一下计算图的可视化,我这里暂时就不加了,有空补上
>>> a = torch.tensor(2.0, requires_grad=True)
>>> b = torch.tensor(3.0)
>>> c=a*a*5
>>> d=c*c*b
>>> c.retain_grad()
>>> d.retain_grad()
>>> d.backward()
>>> a.grad #求导后2*b*c*10*a,把c用a*a*5来代,即2*b*a*a*5*10*a为2400
tensor(2400.)
>>> c.grad #求导后2*b*c,把c用a*a*5来代,即2*b*a*a*5为120
tensor(120.)
>>> d.grad
tensor(1.)
注:复制完代码请删去>>>
和输出结果
再运行,建议手打一遍,这样更能加深理解
d.backward()
只能计算一次,因为执行一次 d.backward()
后,计算图的缓冲区已经被释放,再次执行将报如下错误:
RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed).
如果需要再次使用,则需要在前一次执行backward()时加上retain_graph=True
,此时会对之前求到的梯度进行叠加
a = torch.tensor(2.0, requires_grad=True)
b = torch.tensor(3.0)
c=a*a*5
d=c*c*b
c.retain_grad()
d.retain_grad()
d.backward(retain_graph=True)
print(a.grad)
print(c.grad)
print(d.grad)
'''
输出
tensor(2400.)
tensor(120.)
tensor(1.)
'''
d.backward()
print(a.grad)
print(c.grad)
print(d.grad)
'''
输出
tensor(4800.)
tensor(240.)
tensor(2.)
'''
原文链接:
https://blog.csdn.net/liangjiu2009/article/details/106980762
https://blog.csdn.net/go___on/article/details/124294061
https://blog.csdn.net/weixin_43479947/article/details/126989990
梯度清零
在PyTorch中,对模型参数的梯度置0时通常使用两种方式:model.zero_grad()和optimizer.zero_grad()。二者在训练代码都很常见,那么二者的区别在哪里呢?
model.zero_grad()
model.zero_grad()的作用是将所有模型参数的梯度置为0。其源码如下:
for p in self.parameters():
if p.grad is not None:
p.grad.detach_()
p.grad.zero_()
optimizer.zero_grad()
optimizer.zero_grad()的作用是清除所有可训练的torch.Tensor的梯度。其源码如下:
for group in self.param_groups:
for p in group['params']:
if p.grad is not None:
p.grad.detach_()
p.grad.zero_()
总结
1.因此,当使用optimizer=optim.Optimizer(net.parameters())设置优化器时,此时优化器中的param_groups等于模型中的parameters(),此时,二者是等效的,从二者的源码中也可以看出来。
2.当多个模型使用同一个优化器时,二者是不同的,此时需要根据实际情况选择梯度的清除方式。
梯度分离
detach()函数,返回一个新的tensor,是从当前计算图中分离下来的,但是仍指向原变量的存放位置,其grad_fn=None
且requires_grad=False
,得到的这个tensor永远不需要计算其梯度,不具有梯度grad,即使之后重新将它的requires_grad置为true,它也不会具有梯度grad。
注意:返回的tensor和原始的tensor共享同一内存数据。in-place函数修改会在两个tensor上同时体现(因为它们共享内存数据)
,此时当要对其调用backward()时可能会导致错误。
原文链接:https://blog.csdn.net/qq_36605433/article/details/120617031
梯度累加
原文链接 https://blog.csdn.net/ltochange/article/details/123629686
原文链接:https://www.cnblogs.com/lart/p/11628696.html