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_inputs
是True
,函数将只返回一个关于指定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 | 1], requires_grad = True) x = torch.tensor([ |
CLASS torch.autograd.enable_grad [源码]
启动梯度计算的上下文管理器
如果使用no_grad
或set_grad_enabled
利用过的话,可以使用来启动梯度计算。
这种上下文管理器也可以是管理线程局部,它将会在其他线程失效。
也可以作为装饰器。
例如:
1 | 1], requires_grad = True) x = torch.tensor([ |
CLASS torch.autograd.set_grad_enabled(mode)
设置是否进行梯度计算的上下文管理器。
set_grad_enabled
将启动或禁用梯度,通过mode
来确定。它可以被用作上下文管理器也可以是函数。
当使用enable_grad
上下文管理器,set_grad_enable(False)
将无效。
上下文管理器也可以管理线程局部,它将会在其他线程无效。
参数:
- mode(bool):表示决定了梯度计算启动(True)或禁用(False)。这可以条件性地控制梯度计算的使用。
例如:
1 | 1], requires_grad=True) x = torch.tensor([ |
Tensors的In-place操作
在autograd中使用in-place操作是困难的事,并且我们在大多数情况下不鼓励使用。Autograd的缓存区积极地释放和重用非常高效,很少场合in-place操作能明显地降低内存的使用。如果不是你的操作在很大的内存压力下,你可能永远不会使用它们。
In-place正确性检查
所有Tensor
s记录应用于它们的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 | 10, requires_grad = True) a = torch.rand( |
register_hook(hook) [源码]
注册一个反向传播hook
这个hook在每次求关于相应张量的导数时被调用。这个hook应当有下面的签名:
hook(grad) -> Tensor or None
这个hook不能修改它的变量,但是它能选择性地返回一个新的梯度,这个新的梯度可以用作代替grad
。
这个函数返回了一个handle,通过方法handle.remove()
来从模块中移出hook。
例如:
1 | 0., 0., 0.], requires_grad = True) v = torch.tensor([ |
requires_grad
如果需要计算这个Tensor的梯度就设为True
,否则为False
。
注意:
张量需要计算梯度这一事实并不意味着`grad`属性一定会被填充,详情请看`is_leaf`。
retain_grad() [源码]
启动非叶子节点张量的.grad属性。
函数
CLASS torch.autograd.Function [源码]
记录操作历史并且定义求导操作的公式。
每一次对Tensor
进行计算,就创建一个新的函数对象,这个函数对象执行了计算并且记录了发生了什么。历史以函数的有向无环图(DAG)的形式保留下来,通过边缘来表示依赖关系(input
<- output
)。然后,当backward被调用时,图按照拓扑排序执行,通过调用每个Function
对象的backward()
方法,把返回的梯度传递给下一个Function
s。
一般,使用者与functions交互的唯一方法就是创建子类和定义新的操作。这个是扩展torch.autograd的推荐方法。
每个函数对象只能使用一次(在一次前向传播中)。
例如:
1 | class Exp(Function): |
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) [源码]
通过分析关于张量的梯度的有限差分来检查梯度计算