1. 自动求导机制
pytorch会根据就算过程自动生成动态图,然后可以根据动态图的创建过程进行反向传播,计算得到每个节点的梯度。在创建张量的时候设置requires_grad=True可以将该张量加入到计算图中。torch.autograd为pytorch的自动求导包,有torch.autograd.backward函数和torch.autograd.grad函数,其中torch.autograd.backward函数通过传入根节点张量,以及初始梯度张量(形状和当前张量相同),可以计算产生该该根节点所有对应的叶子节点的梯度。
2. 自动求导机制实例
反向传播函数
t1 = torch.randn(3, 3, requires_grad=True)
print(t1)
print('=' * 50)
t2 = t1.pow(2).sum() # 计算张量的所有分量平方和
t2.backward() # 反向传播
print(t1.grad) # 梯度是张量原始分量的2倍
print('=' * 50)
t2 = t1.pow(2).sum() # 再次计算张量的所有分量平方和
t2.backward() # 再次反向传播
print(t1.grad) # 梯度累积
print('=' * 50)
print(t1.grad.zero_()) # 单个梯度清零
3. 梯度函数的使用
如果不需要求出当前张量对所有产生该张量的叶子节点的梯度,可以使用torch.autograd.grad函数。该函数的参数为两个张量,第一个张量是计算图的数据结果张量(或张量列表),第二个张量是需要对计算图求导的张量(或张量列表)。最后的输出结果是第一个张量对第二个张量求导的结果,且梯度会累加。
t1 = torch.randn(3, 3, requires_grad=True)
t2 = t1.pow(2).sum() # 根据t1张量计算t2张量
print(torch.autograd.grad(t2, t1)) # t2张量对t1张量求导
4. 计算图构建的启用和禁用
计算图的构建需要消耗内存和计算资源,但其并不是必要的,比如神经网络的推导。此时可以使用torch.no_grad上下文管理器,在这个管理器的作用域里进行的神经网络计算不会构建任何计算图。另外,对于一个张量,我们在反向传播的时候可能不需要让梯度通过这个张量的节点,也就是新建的计算图要和原来的计算图分离。此时就可以使用detach方法,通过调用这个方法返回一个新的张量,该张量会成为一个新的计算图的叶子节点,新的计算图和旧的计算图相互分离,互不影响。
t1 = torch.randn(3, 3, requires_grad=True)
t2 = t1.sum()
print(t2) # t2的计算构建了计算图,输出结果带有grad_fn
with torch.no_grad():
t3 = t1.sum()
print(t3) # t3的计算没有构建计算图,输出结果没有grad_fn
print(t1.sum()) # 保持原来的计算图
print(t1.sum().detach()) # 和原来的计算图分离