任务描述
本关任务:
本关提供了一个张量变量tensor ,根据所给的张量创建 Variable 变量v,同时要求同学们掌握 Variable 的相关属性,例如如何获得 Variable 的 data 属性。
相关知识
之前我们学习” Pytorch 之 Tensor “中提过, Pytorch和 Numpy 有很多相似之处,而 Pytorch 与其最不同的地方在于 Pytorch 提供了自动求导功能,也就是可以自动计算出用户所需的参数的梯度,这个操作由另外一个基本元素提供——Variable。
本质上Variable和Tensor没有区别,多数情况下,将Tensor替换为Variable,代码一样会正常的工作。不过Variabel会放入一个计算图(computational graph),这个图将所有的计算步骤 (节点) 都连接起来,进行前向传播,反向传播以及自动求导。在最后进行误差反向传递时,一次性将所有 Variable 里面的梯度都计算出来,而Tensor 就没有这个能力啦。
autograd.Variable 是这个包中最核心的类。 它包装了一个 Tensor,并且几乎支持所有定义在其上的操作。一旦完成了运算,用户可以调用 .backward()来自动计算出所有的梯度,可以通过属性 .data 来访问原始的Tensor,而关于Variable的梯度则集中于 .grad 属性中。
创建 Variable
在创建之前,首先要引入相应的包,如下列代码所示:
import torch
from torch.autograd import Variable
基本形式:
Variable(data, requires_grad=True)
参数说明:
data: 任意的 tensor 类
requires_grad:是否参与误差反向传播, 是否计算计算梯度
应用示例:
tensor = torch.FloatTensor([[1,2],[3,4]])
variable = Variable(tensor, requires_grad=True)
输出结果:
Variable containing:
1 2
3 4
[torch.FloatTensor of size 2x2]
Variable 数据
利用variable.data可获取 Variable 中的张量。
应用示例:
print(variable.data)
输出结果:
1 2
3 4
[torch.FloatTensor of size 2x2]
任务描述
本关要求掌握Variable 的基本属性及其意义,如requires_grad属性标记着该Variable 是否需要求导。
本关任务:
本关提供了一个32位浮点型的张量 x,要求同学们根据 x创建一个Variable类型的变量 y, y是由 x 的平方计算得到,并输出y的Requires Gradiet属性和Gradient属性。
相关知识
Variable 形式的数据, 在很多时候是用不了的( 比如想要用 plt 画图 ), 所以我们要转换一下, 将它变成 tensor 形式。
Variable 数据
之前我们学习了利用.data访问 Variable 的 Tensor,可以在此基础上利用 numpy() 转换为 numpy 类型。
应用示例:
print(variable.data.numpy())
输出结果:
[[ 1. 2.]
[ 3. 4.]]
grad_fn属性
PyTorch采用动态图设计,可以很方便地查看中间层的输出,动态的设计计算图结构。autograd根据用户对Variable的操作构建其计算图。其中,对变量的操作抽象为Function。
在 autograd 包中,还有一个对其实现非常重要的类——Function。Variable 和Function是相互关联的,并建立一个非循环图,从而完成完整的计算过程。
variable和function它们是彼此不分开的,先上图:
如图,假设我们有一个输入变量input,input是用户输入的,所以其创造者creator为null值,input经过第一个数据操作operation1(比如加减乘除运算)得到output1变量,这个过程中会自动生成一个function1的变量,而output1的创造者就是这个function1。随后,output1再经过一个数据操作生成output2,这个过程也会生成另外一个Function实例function2,output2的创造者creator为function2。
在这个向前传播的过程中,function1和function2记录了数据input的所有操作历史,当output2运行其backward函数时,会使得function2和function1自动反向计算input的导数值并存储在grad属性中。
若把整个操作流看成是一张图(Graph),那么像input这种creator为null的被称之为图的叶子(graph leaf),它不是任何函数(Function)的输出,而是由用户创建的节点,只有叶子节点才能被autograd,返回导数。而creator 非null的变量比如output1和output2,是不能被返回导数的,它们的grad均为None。
应用示例:
x = Variable(torch.ones(2, 2), requires_grad=True)
#在 x 基础上进行运算
y = x + 2
print(x.grad_fn)
print(y.grad_fn)
y是作为运算的结果产生的,所以y有grad_fn,而x是直接创建的,所以x没有grad_fn。
输出结果:
None
<AddBackward0 object at 0x111413898>
相关属性
Variable 的主要属性如下所示:
.data
任意类型的封装好的张量。
.grad
保存与 data类型和位置相匹配的梯度,此属性难以分配并且不能重新分配。
.requires_grad
标记变量是否已经由一个需要调用到此变量的子图创建的 bool值。只能在叶子变量上进行修改。默认为 False,叶子节点指定 True后,依赖节点都被置为 True。
is_leaf
标记变量是否是子图叶子节点(如由用户创建的变量)的 bool值。
.volatile
标记变量是否能在推理模式下应用的 bool值。只能在叶子变量上更改。
应用示例:
print('Requires Gradient : %s ' % (variable.requires_grad))
print('Volatile : %s ' % (variable.volatile))
print('Gradient : %s ' % (variable.grad))
输出结果:
Requires Gradient : True
Volatile : False
Gradient : None
特别地,变量的requires_grad和volatile标记的运算就相当于or。 如下列所示:
x = Variable(torch.randn(5, 5))
y = Variable(torch.randn(5, 5))
z = Variable(torch.randn(5, 5), requires_grad=True)
a = x + y # x, y的 requires_grad的标记都为false, 所以输出的变量requires_grad也为false
print(a.requires_grad)
#False
b = a + z
#a ,z 中,有一个 requires_grad 的标记为True,那么输出的变量的 requires_grad为True
print(b.requires_grad)
#True
注意: volatile =True相当于 requires _grad=False。但是在纯推断模式的时候,只要是输入 volatile =True,那么输出 Variable的 volatile必为 True。这就比使用 requires _grad=False方便多了。
NOTE:在使用 volatile =True的时候,变量是不存储 creator属性的,这样也减少了内存的使用。
background()
基本形式:
torch.autograd.backward(variables, grad_variables=None, retain_graph=None, create_graph=None, retain_variables=None)
用途:用以计算当前变量的梯度
参数说明:
variables (sequence of Variable):将要计算导数的变量
grad_variables (sequence of (Tensor, Variable or None))
相应变量的每个元素的梯度
Tensor:将自动转换为变量,当 create_graph为True时计算梯度
Variable:计算变量的梯度
None:被指定为标量梯度或不需要计算梯度的值
retain_graph (bool, optional)
False:用于计算梯度的图形将被释放
create_graph (bool, optional)
True:图形的梯度将被计算,允许计算更高阶的导数
默认为False。
retain_variable
False: 反向传播之后这个计算图的内存会被释放
True : 反向传播之后这个计算图的内存不会被释放,可进行第二次进行第二次反向传播
该计算图使用链式规则进行求导。如果任何变量是非标量的(即它们的数据具有多于一个元素)并且需要梯度,则该函数另外需要指定grad_variables。
应用示例:
# Create tensors.
x = Variable(torch.Tensor([3]), requires_grad=True)
w = Variable(torch.Tensor([2]), requires_grad=True)
# Build a computational graph.
y = w * x + 4 # y =w * x + 4
# Compute gradients.
y.backward(retain_graph=True)
# Print out the gradients.
print(x.grad)
print(w.grad)
其中,对 y 的反向传播求解过程如下所示:
输出结果:
# x.grad = 2 对 y 式中的 x 求导
Variable containing:
2
[torch.FloatTensor of size 1]
# w.grad = 3 对 y 式中的 w 求导
Variable containing:
3
[torch.FloatTensor of size 1]
background()进阶
使用Variable.backward()求Variable的梯度的时候,Variable.grad是累加的。
应用示例:
y.backward()
# Print out the gradients.
print(x.grad)
print(w.grad)
输出结果:
Variable containing:
4
[torch.FloatTensor of size 1]
Variable containing:
6
[torch.FloatTensor of size 1]
既然累加的话,那我们如何置零呢?在上式的末尾添加以下语句,输出结果如下所示:
应用示例:
x.grad.data.zero_()
print(x.grad)
输出结果:
Variable containing:
0
[torch.FloatTensor of size 1]
通过上面的方法,就可以将grad置零。
当要对矩阵求导时,backward需要传入一个参数,这个参数的维度必须是跟叶子结点的那个变量维度一致且元素值为1。比如叶子结点是2x2的矩阵,对backward传一个tensor.ones(2,2)即可。比如上式的y.backward()等价于y.backward(torch.Tensor([1.0]))。
torch.autograd.grad
基本语法:
torch.autograd.grad(outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=None, only_inputs=True, allow_unused=False)
用途:计算并返回输入的输出梯度的总和。
参数说明:
outputs(可变序列)
差分函数的输出。
inputs(可变序列)
输入将返回梯度的积分(并不积累.grad)。
grad_outputs(Tensor 或Variable的序列)
每个输出的梯度。任何张量将被自动转换为volatile,除非create_graph为True。
retain_graph(bool,可选)
如果为 False,则用于计算 grad的图形将被释放。
请注意,在几乎所有情况下,将此选项设置为 True不是必需的,通常可以以更有效的方式解决。
默认值为create_graph。
create_graph(bool,可选)
如果为True,则构造导数的图形,允许计算高阶衍生产品。
默认为False,除非grad_variables包含至少一个非易失性变量。
only_inputs(bool,可选)
为True,则渐变 wrt离开是图形的一部分,但不显示inputs不会被计算和累积。
默认为True
allow_unused(bool, 可选)
默认为False.
属性相关说明:
grad_outputs是匹配包含每个输出的预先计算的梯度的长度序列。如果输出不需要 grad,则梯度可以是None。
如果only_inputs为True,该函数将仅返回指定输入的梯度列表。如果它是False,则仍然计算所有剩余叶子的梯度,并累积到输入的.grad 属性中。
应用示例:
x=torch.FloatTensor([1,2,3])
x = Variable(x, requires_grad=True)
y = x * x
print(y)
dy_dx = torch.autograd.grad(y, x, grad_outputs=torch.ones(1,3))
print(dy_dx)
输出结果:
Variable containing:
1
4
9
[torch.FloatTensor of size 3]
(Variable containing:
2 4 6
[torch.FloatTensor of size 1x3]
,)