1.Variable三要素:
data,是一个Tensor
grad,保存data的梯度,是个Variable
grad_fn,还不懂
Variable的构造函数需要传入tensor,同时有两个可选参数:
requires_grad (bool)
:是否需要对该variable进行求导volatile (bool)
:意为”挥发“,设置为True,则构建在该variable之上的图都不会求导,专为推理阶段设计- 变量的
requires_grad
属性默认为False,如果某一个节点requires_grad被设置为True,那么所有依赖它的节点requires_grad
都是True。这其实很好理解,对于,x.requires_grad = True,当需要计算时,根据链式法则,,自然也需要求,所以y.requires_grad会被自动标为True. volatile=True
是另外一个很重要的标识,它能够将所有依赖于它的节点全部都设为volatile=True
,其优先级比requires_grad=True
高。volatile=True
的节点不会求导,即使requires_grad=True
,也无法进行反向传播。对于不需要反向传播的情景(如inference,即测试推理时),该参数可实现一定程度的速度提升,并节省约一半显存,因其不需要分配空间计算梯度。在反向传播过程中非叶子节点的导数计算完之后即被清空。若想查看这些变量的梯度,有两种方法:
- 使用autograd.grad函数
- 使用hook
# 第一种方法:使用grad获取中间变量的梯度 x = V(t.ones(3), requires_grad=True) w = V(t.rand(3), requires_grad=True) y = x * w z = y.sum() # z对y的梯度,隐式调用backward() t.autograd.grad(z, y)
# 第二种方法:使用hook # hook是一个函数,输入是梯度,不应该有返回值 def variable_hook(grad): print('y的梯度: \r\n',grad) x = V(t.ones(3), requires_grad=True) w = V(t.rand(3), requires_grad=True) y = x * w # 注册hook hook_handle = y.register_hook(variable_hook) z = y.sum() z.backward() # 除非你每次都要用hook,否则用完之后记得移除hook hook_handle.remove()
2.计算图
算子:+,-,*,\等运算方式
变量:分为叶子节点、根节点;叶子节点是用户自己创建的,根节点是计算目标,比如y=f(x),x是叶子节点,y是根节点,利用链式法则很容易求得各个叶子节点的梯度。