【翻译】pytorch中文文档(1.2.0)- Package Reference/torch.autograd

AUTOMATIC DIFFERENTIATION PACKAGE - TORCH.AUTOGRAD

torch.autograd提供了许多实现任意标量值函数自动求导的类和函数。它只需要对已有的代码最小的改动 —— 你只需要声明Tensor的关键词requires_grad=True表明梯度需要被计算。

torch.autograd.backward(tensors, grad_tensors=None, retain_graph=None, create_graph=False, grad_variables=None) [源码]

计算所给张量关于图的叶子节点的梯度的总和。
图通过链式法则求导。如果tensors是非标量(也就是data是超过一个元素)且需要梯度,然后雅克比向量积(jacobian vector product)将会被计算,这种情况下需要函数另外指定grad_tensors。它应当是一个匹配长度的序列,包含了雅克比向量积里的向量,通常是需要求导的函数关于相应张量的梯度(None对于不需要求导的张量也是可接受的值。
这个函数会累积函数到叶子节点,在调用前你可能需要清零。

参数:

  • tensor( tensor序列 ) :将要被计算导数的tensors
  • grad_tensors( tensor序列或None ) :雅克比向量积的向量,通常对相应张量的各元素求梯度。对于标量张量或无需求导的张量使用None值。如果一个None值对所有grad_tensors都是可接受的,那么这个参数是可选的。
  • retain_graph( _bool, 可选 ) :如果为False,用于计算grad的图将被释放。请注意,几乎在所有情况下,都不需要将此选项设置为True,而且通常可以以更有效的方式解决此问题。默认值为create_graph的值。
  • create_graph(bool, 可选 ) :如果为True,导数的图将会被构建,允许计算更高阶的导数。默认值为False

torch.autograd.grad(output,inputs, grad_outputs=None, retain_grad=None, create_graph=False,only_inputs=True,allow_unused=False) [源码]

计算和返回output关于inputs的梯度的和。
grad_outputs应当是长度和output相同的序列,包含了雅克比向量积中的向量,通常需要预计算关于每个outputs的梯度。如果output不需要grad,那么梯度可以是None
如果only_inputsTrue,函数将只返回一个关于指定inputs的梯度的列表。如果是False,那么剩余叶子节点的梯度也将会计算,并且将会被累积到它们的.grad属性。

参数:

  • output( tensor序列 ) :被导函数的输出
  • inputs( tensor序列 ) :关于的inputs,梯度会被返回,不会累积到.grad属性
  • grad_outputs( tensor序列 ) :雅克比向量积的向量。通常是关于每个输入的梯度。标量张量或不需要梯度的可用None指定。如果None对所有grad_tensors可接受,则此参数可选。默认为None。
  • retain_graph( _bool, 可选 ) :如果为False,用于计算grad的图将被释放。请注意,几乎在所有情况下,都不需要将此选项设置为True,而且通常可以以更有效的方式解决此问题。默认值为create_graph的值。
  • create_graph(bool, 可选) :如果为True,导数的图将会被构建,允许计算更高阶的导数。默认值为False
  • allow_unused( bool, 可选 ) :如果为False,当计算输出出错时(因此他们的梯度永远是0)指明不使用的inputs。默认为False

局部禁用梯度计算

CLASS torch.autograd.no_grad [源码]

禁用梯度计算的上下文管理器

当你确定不会调用 Tensor.backward() ,禁用梯度计算在推断时很有效。它将会减少计算带来的内存消耗。否则requires_grad = True

在这个模式下,即使输入是有requires_grad=True,也会是require_grad=False
的计算结果。

当使用enable_grad上下文管理器,这种模式将无效。

这种上下文管理器也可以是管理线程局部,它将会在其他线程失效。

也可以作为装饰器。

例如:

1
2
3
4
5
6
7
8
9
10
11
>>> x = torch.tensor([1], requires_grad = True)
>>> with torch.no_grad():
··· y = x * 2
>>> y.requires_grad
False
>>> @torch.no_grad()
··· def doubler(x):
··· return x * 2
>>> z = doubler(x)
>>> z.requires_grad
False

CLASS torch.autograd.enable_grad [源码]

启动梯度计算的上下文管理器

如果使用no_gradset_grad_enabled利用过的话,可以使用来启动梯度计算。

这种上下文管理器也可以是管理线程局部,它将会在其他线程失效。

也可以作为装饰器。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> x = torch.tensor([1], requires_grad = True)
>>> with torch.no_grad():
··· with torch.enable_grad():
··· y = x * 2
>>> y.requires_grad
True
>>> y.backward()
>>> x.grad
>>> @torch.enable_grad()
··· def doubler(x):
··· return x * 2
>>> with torch.no_grad()
··· z = doubler(x)
>>> z.requires_grad
True

CLASS torch.autograd.set_grad_enabled(mode)

设置是否进行梯度计算的上下文管理器。

set_grad_enabled将启动或禁用梯度,通过mode来确定。它可以被用作上下文管理器也可以是函数。

当使用enable_grad上下文管理器,set_grad_enable(False)将无效。

上下文管理器也可以管理线程局部,它将会在其他线程无效。

参数:

  • mode(bool):表示决定了梯度计算启动(True)或禁用(False)。这可以条件性地控制梯度计算的使用。

例如:

1
2
3
4
5
6
7
8
9
10
>>> x = torch.tensor([1], requires_grad=True)
>>> is_train = False
>>> with torch.set_grad_enabled(is_train):
··· y = x * 2
>>> y.requires_grad
False
>>> torch.set_grad_enabled(False)
>>> y = x * 2
>>> y.requires_grad
False

Tensors的In-place操作

在autograd中使用in-place操作是困难的事,并且我们在大多数情况下不鼓励使用。Autograd的缓存区积极地释放和重用非常高效,很少场合in-place操作能明显地降低内存的使用。如果不是你的操作在很大的内存压力下,你可能永远不会使用它们。

In-place正确性检查

所有Tensors记录应用于它们的in-place操作,并且如果执行过程检测张量为了反向传播而被保存在某个函数中,但是后来被in-place修改,一旦反向传播开始将会抛出错误。这确保如果你使用了in-place操作而没有看到任何错误,你会确定计算梯度是正确的。

Variable(弃用)

WARNING:

Variable API被弃用。Variables对张量自动求导没必要。自动求导把Tensors的requires_grad设为True会自动支持。

另外,现在构造用工厂方法像是torch.randn(),torch.zeros,torch.ones()来构造tensors(通过requires_grad=True),以及类似下面的:

1
autograd_tensor = torch.randn((2, 3, 4), requires_grad=True)

Tensor autograd 的函数

CLASS torch.Tensor

backward(gradient=None, retain_graph=None, create_graph=False) [源码]

计算关于叶子节点的当前张量的梯度。

图是通过链式法则求导。如果张量是非标量(也就是超过一个元素)并且需要梯度,函数需要另外指定gradient。它需要是匹配类型和位置的一个张量,这个张量包含了关于self的梯度。

这个函数会累积梯度到叶子节点 —— 你可能需要在调用它前清零梯度。

参数:

  • gradient( Tensor或None ):关于这个tensor的梯度。如果它是一个张量,除非create_graph为真,它将自动转换成一个不需要grad的张量。对于标量张量或不需要grad的张量,可以指定为None值。如果一个None值是可接受的,那么这个参数是可选的。
  • retain_graph( _bool, 可选 ) :如果为False,用于计算grad的图将被释放。请注意,几乎在所有情况下,都不需要将此选项设置为True,而且通常可以以更有效的方式解决此问题。默认值为create_graph的值。
  • create_graph(bool, 可选 ) :如果为True,导数的图将会被构建,允许计算更高阶的导数。默认值为False

detach()

返回一个从当前图分离出的张量。

结果不需要梯度。

注意:
返回的张量将和原来的张量共享内存。In-place对它们之一的修改将会被看到,而且可能触发正确性检查的错误。重要提示:从前,in-place对于size/stride/storage(像是resize_/resize_as_/set_/transpose_)会同时改变返回的向量和原始向量。现在,这种inplace不在会改变原始向量,并且相反会触发错误。并且对于稀疏张量也是如此。

detach_()

从已经创建过的图中分离张量,做成叶子节点。视图(views)不能分离。

grad

这个属性默认是None,当第一次调用backward()会计算self.的梯度变成张量。这个属性将包含被计算的梯度并且未来调用backward()将会累积到其中。

if_leaf

按照惯例所有requires_grad为False的张量都将是叶子节点(leaf)。

对于requires_grad为True的张量,如果它是被使用者创建的它将会也是叶子节点。这意思是它们不是某个操作的结果,所以grad_fn是None。

只有叶子节点的张量在调用backward()时填充它们的grad。为了填充非叶子节点的grad,你可以使用retain_grad()

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
>>> a = torch.rand(10, requires_grad = True)
>>> a.is_leaf
True
>>> b = torch.rand(10, requires_grad = True).cuda()
>>> b.is_leaf
False
# b是被从cpu移入cuda的操作创建的
>>> c = torch.rand(10, requires_grad = True) + 2
>>> c.is_leaf
False
# c被加法操作创建
>>> d = torch.rand(10).cuda()
>>> d.is_leaf
True
# d不需要梯度所以没有操作创建它(被autograd引擎追踪)
>>> e = torch.rand(10).cuda().requires_grad()
>>> e.is_leaf
True
# e需要梯度并且没有操作创建它
>>> f = torch.rand(10, requires_grad=True, device = "cuda")
>>> f.is_leaf
True
# f需要梯度,没有操作创建它

register_hook(hook) [源码]

注册一个反向传播hook

这个hook在每次求关于相应张量的导数时被调用。这个hook应当有下面的签名:

hook(grad) -> Tensor or None

这个hook不能修改它的变量,但是它能选择性地返回一个新的梯度,这个新的梯度可以用作代替grad

这个函数返回了一个handle,通过方法handle.remove()来从模块中移出hook。

例如:

1
2
3
4
5
6
7
8
9
>>> v = torch.tensor([0., 0., 0.], requires_grad = True)
>>> h = v.register_hook(lambda grad: grad * 2) # 加倍梯度
>>> v.backward(torch.tensor([1., 2., 3.]))
>>> v.grad

2
4
6
[torch.FloatTensor of size (3, )]

requires_grad

如果需要计算这个Tensor的梯度就设为True,否则为False

注意:

张量需要计算梯度这一事实并不意味着`grad`属性一定会被填充,详情请看`is_leaf`。

retain_grad() [源码]

启动非叶子节点张量的.grad属性。

函数

CLASS torch.autograd.Function [源码]

记录操作历史并且定义求导操作的公式。

每一次对Tensor进行计算,就创建一个新的函数对象,这个函数对象执行了计算并且记录了发生了什么。历史以函数的有向无环图(DAG)的形式保留下来,通过边缘来表示依赖关系(input <- output)。然后,当backward被调用时,图按照拓扑排序执行,通过调用每个Function对象的backward()方法,把返回的梯度传递给下一个Functions。

一般,使用者与functions交互的唯一方法就是创建子类和定义新的操作。这个是扩展torch.autograd的推荐方法。

每个函数对象只能使用一次(在一次前向传播中)。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
>>> class Exp(Function):
>>>
>>> @staticmethod
>>> def forward(ctx, i):
>>> result = i.exp()
>>> ctx.save_for_backward(result)
>>> return result
>>>
>>> @staticmethod
>>> def backward(ctx, grad_output):
>>> result = ctx.saved_tensors
>>> return grad_output * result

STATIC backward(ctx, *grad_outputs) [源码]

定义为求导计算定义公式

这个函数会被所有子类覆盖。

它必须接受一个上下文ctx作为第一个变量,跟着许多forward()的输出,并且它应当返回与forward()的输入相同的张量。每一个变量都是关于给定输出的梯度,每一个返回的值都应当是相应输入的梯度。

在前向传播时上下文被用作检索被保存的张量。它也有个属性ctx.needs_input_grad是个bool值的元组,表示每个输入是否需要梯度。例如,如果forward()的第一个输入需要计算关于输出的梯度,那么backward()将有ctx.needs_input_grad[0] = True。

STATIC forward(ctx, args, *kwargs) [源码]

执行操作。

这个函数会被所有子类覆盖。

它必须接受一个上下文ctx作为第一个变量,跟着任意数量的变量(tensors或其他类型)。

上下文被用作储存张量,这些张量将会在反向传播里被恢复。

数值梯度检查

torch.autograd.gradcheck(func, inputs, eps=1e-06,atol=1e-05,rtol=0.001,raise_exception=True, check_sparse_nnz=False,nondet_tol=0.0) [源码]

通过分析关于张量的梯度的有限差分来检查梯度计算

———————————————感谢阅读———————————————

欢迎收藏访问我的博客 知乎 掘金 简书 知乎

贰三 wechat
欢迎扫描二维码订阅我的公众号!