pytorch 梯度计算相关内容总结

Posted mazinkaiser1991

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pytorch 梯度计算相关内容总结相关的知识,希望对你有一定的参考价值。

一、梯度计算准备工作

调用backward()函数前,叶子/非叶子节点的grad属性均为none,无论是否设置了requires_grad=True(叶子节点),或者调用了retain_grad()(非叶子节点),非叶子节点不能设置requires_grad=True,否则会报错:“RuntimeError: you can only change requires_grad flags of leaf variables.”)。

叶子/非叶子节点定义:

1.叶子节点:

  • 所有requires_grad为false的tensor都是叶子节点,也即is_leaf属性返回true。
  • 若tensor的requires_grad为true,同时是由用户创建,则该tensor为叶子节点。也即不是operation结果的tensor,叶子节点的grad_fn为none。
  • 由requires_grad为false的节点通过operation产生的节点还是叶子节点,此时设置requires_grad为true,不影响是否为叶子节点,但会影响后续节点是否为叶子节点。猜想这么设计的原因是:由于无法判断是否是由operation产生的节点,因此通过设置requires_grad也就无法更新是否为叶子节点。

示例如下:

>>> a = torch.randn((3, 4))
>>> a
tensor([[-1.0351, -0.2712,  2.4718,  0.4248],
        [ 0.9309,  0.7676, -0.1888, -0.0586],
        [-0.4290,  0.2478, -0.0056,  0.8502]])
>>> b = torch.randn((3, 4))
>>> b
tensor([[ 0.5519,  0.3557,  0.2577, -0.6338],
        [ 1.2905,  2.1761, -0.1334, -1.3477],
        [ 0.8308,  0.1957,  0.1915,  0.1244]])
>>> c = a + b
>>> c.requires_grad
False
>>> c.is_leaf
True
>>> c.requires_grad = True
>>> c.is_leaf
True
// c的requires_grad为true,同时是由operation产生,但是仍为叶子节点,说明requires_grad状态的改变并不能影响是否为叶子节点。

2.非叶子节点

  • 由requires_grad为true的节点通过operation产生,同时operation是可以求导的操作,否则仍为叶子节点。此处对于多元operation,有一个输入是requires_grad为true的节点即可获得非叶子节点。

示例如下:

>>> c
tensor([[-0.4832,  0.0846,  2.7295, -0.2089],
        [ 2.2214,  2.9437, -0.3222, -1.4063],
        [ 0.4018,  0.4435,  0.1859,  0.9746]], requires_grad=True)
>>> g = c > 0
>>> g
tensor([[False,  True,  True, False],
        [ True,  True, False, False],
        [ True,  True,  True,  True]])
>>> g.is_leaf
True
>>> c
tensor([[-0.4832,  0.0846,  2.7295, -0.2089],
        [ 2.2214,  2.9437, -0.3222, -1.4063],
        [ 0.4018,  0.4435,  0.1859,  0.9746]], requires_grad=True)
>>> g = c.sum()
>>> g
tensor(7.5644, grad_fn=<SumBackward0>)
>>> g.is_leaf
False

叶子/非叶子节点获得grad的方法:

1.叶子节点

  • 设置requires_grad为true

2.非叶子节点

  • 调用retain_grad()。

仅叶子节点,调用backward()后,存在grad。

若某个节点的输入节点的requires_grad为True,则该节点的grad_fn必不为none,该节点的梯度就可以通过调用backward()自动计算。loss计算梯度依据的条件同样如此。

二、梯度计算相关内容

1.使用backward()计算梯度

调用backward()函数后,

  • 对于叶子节点,若设置了requires_grad为true,则可以获得梯度,否则梯度为none。
  • 对于非叶子节点,若调用了retain_grad(),则可以获得梯度,否则梯度也为none。

若计算图中没有一个节点设置了requires_grad为true,则经过loss函数计算的结果仅包含计算结果,grad_fn为none,此时调用backward()函数会出错,错误提示信息如下:

“RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn”

解决方法:将计算图中任意一个节点,设置为requires_grad为true,或者调用retain_grad(),并重新计算loss。

若仅设置requires_grad为true,或者调用retain_grad(),不重新计算loss,loss的grad_fn还是none,此时调用backward(),还是会出现上面的错误。

2.调用backward()函数需要注意的问题:

  • 仅标量可以通过backward()计算梯度,若为非标量调用backward(),会出现以下错误:“RuntimeError: grad can be implicitly created only for scalar outputs”
  • 在调用backward()函数时需要将retain_graph设置为True,否则梯度只能计算一次,第二次再调用backward时,会出现如下错误:“RuntimeError: Trying to backward through the graph a second time, but the saved intermediate results have already been freed. Specify retain_graph=True when calling backward the first time.”
  • 对于tensor可以使用.grad.zero_()对梯度清零。
  • 在使用torch.tensor()初始化tensor时需要保证数据为float或者为复数类型,否则无法设置requires_grad为True。错误提示如下:“RuntimeError: Only Tensors of floating point and complex dtype can require gradients”。
  • 在初始化tensor时如果是使用torch.Tensor初始化则没有requires_grad参数,torch.Tensor是一个类,是torch.FloatTensor的别名,因此默认初始化数据为float32类型,但是requires_grad需要单独设置。如果使用torch.tensor初始化,则可以直接设置requires_grad这一参数,但需要注意使用float类型数据,torch.tensor是一个函数。

 

 

 

以上是关于pytorch 梯度计算相关内容总结的主要内容,如果未能解决你的问题,请参考以下文章

自动求梯度(pytorch版本)——2.20

Pytorch学习之梯度计算backward函数

PyTorch中的backward [转]

梯度的计算公式是啥?

实践·pytorch梯度计算

pytorch中反向传播,梯度保留,梯度分离,梯度清零,梯度累加等相关问题解析