本站原创文章,转载请说明来自《老饼讲解-深度学习》www.bbbdata.com
在pytorch中使用自动求梯度时,往往需要反复backward
本文讲解如何反复backward以及多次backward时需要注意清空梯度
本节指出pytorch中backward默认是一次性的,以及如何实现多次backward
pytorch的计算图是动态图,它在每次调用backward后就会释放,
也就是默认情况下backward是一次性的,再次backward会报错
示例如下:
import torch
x = torch.tensor([1,2],dtype=(float),requires_grad=True) # 定义参数x
A = torch.tensor([2,3],dtype=(float)) # 常量A,不需梯度
y = A@(x*x) # 定义y
y.backward() # 向后传播,更新梯度
#-----再次传播------------------------
y.backward() # 再次向后传播,会报错
运行结果报错如下:
RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed).
Saved intermediate values of the graph are freed when you call .backward() or autograd.grad().
Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.
如果要让pytroch的backward反复使用,必须在backward时使用retain_graph=True来保留计算图,
在本次backward时使用了retain_graph=True,下次就可以继续使用backward,实现多次反复backward
示例如下:
import torch
x = torch.tensor([1,2],dtype=(float),requires_grad=True) # 定义参数x
A = torch.tensor([2,3],dtype=(float)) # 常量A,不需梯度
y = A@(x*x) # 定义y
y.backward(retain_graph=True) # 向后传播,并保留计算图
y.backward() # 再次向后传播
可以看到,示例中共运行了两次backward,但不会报错
本节指出反复backward时,需要注意清空梯度
在将backward设置为retain_graph=True后,可以实现多次重复backward
但必须注意的是,每次backward时梯度都是累加的
示例如下:
import torch
x = torch.tensor([1,2],dtype=(float),requires_grad=True) # 定义参数x
A = torch.tensor([2,3],dtype=(float)) # 常量A,不需梯度
y = A@(x*x) # 定义y
y.backward(retain_graph=True) # 向后传播,并保留计算图
print('x.grad:',x.grad) # 打印x的梯度
#-----多次传播------------------------
y.backward(retain_graph=True) # 再次向后传播
print('x.grad:',x.grad) # 打印x的梯度
y.backward(retain_graph=True) # 再再次向后传播
print('x.grad:',x.grad) # 打印x的梯度
运行结果如下:
x.grad: tensor([ 4., 12.], dtype=torch.float64)
x.grad: tensor([ 8., 24.], dtype=torch.float64)
x.grad: tensor([12., 36.], dtype=torch.float64)
可以看到,在多次backward时,每一次都是把自变量的梯度累加到自变量的原有梯度上
因此,在pytorch中,如果需要多次backward,且每次计算的是当前梯度,则需要先用grad.zero_()把梯度进行清空
示例如下:
import torch
x = torch.tensor([1,2],dtype=(float),requires_grad=True) # 定义参数x
A = torch.tensor([2,3],dtype=(float)) # 常量A,不需梯度
y = A@(x*x) # 定义y
y.backward(retain_graph=True) # 向后传播,并保留计算图
print('x.grad:',x.grad) # 打印x的梯度
#-----多次传播------------------------
x.grad.zero_() # 清空x的梯度
y.backward(retain_graph=True) # 再次向后传播
print('x.grad:',x.grad) # 打印x的梯度
x.grad.zero_() # 清空x的梯度
y.backward(retain_graph=True) # 再再次向后传播
print('x.grad:',x.grad) # 打印x的梯度
运行结果如下:
x.grad: tensor([ 4., 12.], dtype=torch.float64)
x.grad: tensor([ 4., 12.], dtype=torch.float64)
x.grad: tensor([ 4., 12.], dtype=torch.float64)
从结果可以看到,使用grad.zero_()把梯度清空后,每次backward后得到的梯度值才是当前的梯度值
好了,以上就是pytorch中求导时如何反复backward以及需要注意梯度累加性,需要清零梯度的全部内容了~
End