torch.autograd
提供了类和函数用来对任意标量函数
进行求导。要想使用自动求导,只需要对已有的代码进行微小的改变。只需要将所有的tensor
包含进Variable
对象中即可。
torch.autograd.backward(variables, grad_variables, retain_variables=False)
给定图的叶子节点
variables, 计算图中变量的梯度和。
注意:我们需要在调用此函数之前将leaf variable的梯度置零。叶子节点和Variable是两个概念,叶子节点是说用户创建的变量,可以保存梯度以进行反向传播;Variable只是对tensor的包装,当设置Variable的required_grad=True时,可以计算梯度,但如果不是叶子节点的话,在反向传播之前会释放梯度。
参数说明:
class torch.autograd.Variable
包装一个Tensor
,它同时保存着Variable的梯度
和创建这个Variable的Function
的引用。这个引用可以用来追溯创建这个Variable的整条链。如果Variable是用户创建
的,那么它的creator是None,我们称这种对象为 leaf Variables
。
由于autograd只支持标量值的反向求导
(即:y是标量),梯度的大小总是和数据的大小匹配。同时,仅仅给leaf variables分配梯度,其他Variable的梯度总是为0.
变量:
属性:
所包含的方法:
当前Variable
对leaf variable
求偏导。
计算图可以通过链式法则求导。如果Variable是 非标量(non-scalar)的,且requires_grad=True。那么此函数需要指定gradient,它的形状应该和Variable的长度匹配,里面保存了Variable的梯度。
此函数累积leaf variable的梯度。你可能需要在调用此函数之前将Variable的梯度置零。
参数:
gradient (Tensor) – 其他函数对于此Variable的导数。仅当Variable不是标量的时候使用,类型和位形状应该和self.data一致。gradient的作用是可以简单地理解成在求梯度时的权重,因为可能不同值的梯度对结果影响程度不同,所以pytorch弄了个这种接口,而没有固定为全是1。具体gradients参数的作用参考Pytorch autograd,backward详解。
retain_variables (bool) – True, 计算梯度所必要的buffer在经历过一次backward过程后不会被释放。如果你想多次计算某个子图的梯度的时候,设置为True。在某些情况下,使用autograd.backward()效率更高。
detach()
返回一个新的Variable,从当前图中分离下来的。
返回的Variable requires_grad=False
,如果输入 volatile=True
,那么返回的Variable volatile=True
。
注意:返回的Variable和原始的Variable公用同一个data tensor。in-place修改会在两个Variable上同时体现(因为它们共享data tensor),可能会导致错误。
将一个Variable
从创建它的图中分离,并把它设置成leaf variable
。
参考:Torch Autograd详解
实现autograd依赖于Variable和Function这两种数据类型。Variable是Tensor的外包装
,Varibale和Tensor基本一致,区别在于多了下面几个属性。
variable类型变量的data属性存储着Tensor数据,grad属性存储关于该变量的导数,creator是代表该变量的创造者。
Variable和Function它们是彼此不分开的,如下图所示,是数据向前传输和向后传输生成导数的过程。
如图,假设我们有一个输入变量input(数据类型为Variable),input是用户输入的,所以其创造者creator为null值,input经过第一个数据操作operation1(比如加减乘除运算)得到output1变量(数据类型仍为Variable),这个过程中会自动生成一个function1的变量(数据类型为Function的一个实例),而output1的创造者就是这个function1。随后,output1再经过一个数据操作生成output2,这个过程也会生成另外一个实例function2,output2的创造者creator为function2。
在这个向前传播的过程中,function1和function2记录了数据input的所有操作历史,当output2运行其backward函数时,会使得function2和function1自动反向计算input的导数值并存储在grad属性中。
creator为null的变量才能被返回导数,比如input,若把整个操作流看成是一张图(Graph),那么像input这种creator为null的被称之为图的叶子(graph leaf)。而creator非null的变量比如output1和output2,是不能被返回导数的,它们的grad均为0。所以只有叶子节点才能被autograd。
例子: 参考PyTorch教程之Autograd
创建变量x
import torch
from torch.autograd import Variable
x = Variable(torch.ones(2, 2), requires_grad=True)
print(x)
输出结果:
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
在x基础上进行运算:
y = x + 2
print(y)
输出结果:
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward0>)
查看x的grad_fn
:
None
查看y的grad_fn
:
print(y.grad_fn)
输出结果:
<AddBackward0 object at 0x0000027B00384C48>
可以看到y是作为运算的结果产生的,所以y有grad_fn,而x是直接创建的,所以x没有grad_fn。
在y基础上进行运算:
z = y * y * 3
out = z.mean()
print(z)
print(out)
输出结果:
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward0>)
tensor(27., grad_fn=<MeanBackward0>)
如果Variable是一个标量(例如它包含一个单元素数据),你无需对backward()指定任何参数.
out.backward()等价于out.backward(torch.Tensor([1.0])).
out.backward()
print(x.grad)
输出结果:
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
如果它有更多的元素(矢量),你需要指定一个和tensor的形状匹配的grad_output参数(y在指定方向投影对x的导数)
x = torch.randn(3)
x = Variable(x, requires_grad=True)
y = x * 2
while y.data.norm() < 1000:
y = y * 2
print(y)
输出结果:
tensor([ 396.7552, 1183.1866, 862.6874], grad_fn=<MulBackward0>)
不传入参数:
y.backward()
print(x.grad)
输出结果:
RuntimeError: grad can be implicitly created only for scalar outputs
传入参数:
gradients = torch.FloatTensor([0.1, 1.0, 0.0001])
y.backward(gradients)
print(x.grad)
输出结果:
tensor([5.1200e+01, 5.1200e+02, 5.1200e-02])
具体gradients参数的作用参考Pytorch autograd,backward详解