Variable是PyTorch中的另一个变量类型。一旦张量被转换成Variable类型便可以实现自动求导。
Variable对象和Tensor对象之间的转换
>>> import torch
>>> from torch.autograd import Variable
>>> a = torch.FloatTensor([4])
>>> print(Variable(a)) # 将张量转换成Variable对象
tensor([4.])
>>> print(Variable(a,requires_grad=True)) # 将张量转换成支持梯度计算的Variable对象
tensor([4.], requires_grad=True)
>>> a.data
tensor([4.])
# 在使用requires_grad时,必须要求张量的值是浮点型,pytorch不支持对整数类型进行梯度运算。
控制梯度计算的方法
torch.no_grad()
# no_grad()会使其作用域中的Variable()对象的requires_grad属性失效
# 用no_grad()函数配合with语句限制requires_grad属性的作用域
x = torch.ones(2,2,requires_grad=True)
# tensor.ones()是一个相对上层的函数,支持requires_grad参数,该函数可以直接生成
# Variable对象,使用torch.tensor也可以支持参数设置,但是torch.Tensor()不支持参数设置
with torch.no_grad():
y=x*2
print(y.requires_grad) # 输出为False
# 使用函数装饰器限制requires_grad()函数的作用域
@torch.no_grad()
def doubles(x):
return x * 2
z = doubles(x)
print(z.requires_grad) # 输出:False
函数enable_grad()和no_grad()的嵌套
# 在函数torch.enable_grad()作用域中使用with限制requires_grad的作用域
import torch
x = torch.ones(2,2,requires_grad=True)
with torch.no_grad(): # 梯度计算属性失效
with torch.enable_grad(): # 梯度计算属性生效
y = x * 2
print(y.requires_grad) # 输出:True
#################################################################
# 同样torch.enable_grad()也可以使用装饰器进行修饰
# 当torch.enable_grad()作用在没有requires_grad属性的Variable对象时,将会失效
用set_grad_enable()函数统一管理梯度计算
# 很多时候并不是调用enable_grad()和no_grad()来控制梯度计算,而是调用set_grad_enabled()函数对
# 梯度计算进行统一管理。
torch.set_grad_enabled(False)
Variable对象的属性
# grad_fn和is_leaf属性分别表示计算图中的节点和叶子节点属性
# 如果Variable对象不是通过计算生成的,那么grad_fn属性为None,is_leaf属性为True,反之亦然
>>> x = torch.tensor([1.,2.,3.],requires_grad=True)
>>> x.grad_fn
>>> print(x.grad_fn)
None
>>> x.is_leaf
True
>>> m=x+1
>>> print(m.grad_fn)
<AddBackward0 object at 0x7fbaab616e20>
>>> print(m.is_leaf)
False
# pytorch通过backward()方法实现了自动求导的功能
# 当带有需求梯度计算的张量经过一系列计算最终生成一个标量,便可以使用该标量的backward()方法进行
# 自动求导,一定要在当前变量内容时标量的情况下使用,否则会报错
>>> f=m.mean()
>>> f.backward()
>>> print(f)
tensor(3., grad_fn=<MeanBackward0>)
>>> print(x.grad)
tensor([0.3333, 0.3333, 0.3333])
>>> f=m.sum()
>>> f.backward()
>>> f
tensor(9., grad_fn=<SumBackward0>)
>>> x.grad
tensor([1.3333, 1.3333, 1.3333])
# 使用detach()方法将Variable对象分离成叶子节点
# 对张量取值时,需要求梯度的Variable对象无法直接被转换为Numpy对象,可以利用detach()方法将
# Variable对象分离成叶子节点
>>> from torch.autograd import Variable
>>> x = Variable(torch.ones(2,2),requires_grad=True)
>>> x.numpy
<built-in method numpy of Tensor object at 0x7fbb0cc42580>
>>> x.numpy()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: Can't call numpy() on Tensor that requires grad. Use tensor.detach().numpy() instead.
# 该方法会将Variable对象从创建它的graph中分离出来,之后在进行Numpy对象的转换
>>> x.detach().numpy()
array([[1., 1.],
[1., 1.]], dtype=float32)
# 该代码会返回一个从当前计算图中分离出的Variable对象,并使他成为叶子节点
# 实际应用中,还可以使用detach()方法来计算指定模型中参数的梯度
# 例如:模型A和B,若只计算B中参数的梯度,不想计算A中模型参数的梯度,可以用detach()方法来处理
y = A(x)
z = B(y.detach())
z.backward()
y = A(x)
y.detach_()
z = B(y)
z.backward()