Autograd: 自动微分
autograd包中是PyTorch中所有神经网络的核心。
该autograd软件包为Tensors上的所有操作提供自动区分。它是一个逐个运行的框架,这意味着backprop由自己的代码运行方式定义,并且每个迭代都可以不同
张量
torch.Tensor
是包的核心类。如果将其属性设置.requires_grad
为True
,则会开始跟踪其上的所有操作。完成计算后,可以调用.backward()
并自动计算所有渐变。该张量的梯度将累计到.grad()
属性中。
要阻止张量跟踪历史记录,可以调用.detach()
将它从计算历史记录中分离出来,并防止将来的计算被跟踪
要防止跟踪历史记录(和使用内存),还可以将代码块包装在其中。这在评估模型时尤其有用,因为模型可能具有可训练的参数,但我们不需要梯度。with torch.no_grad():requires_grad=True
还有一个类对于autograd实现非常重要 -a Function
Tensor和Function互相连接并构建一个非循环图,它编码完整的计算历史。每一个张量都有.grad_fn
属性,该属性引用Function已创建的属性Tensor。.grad_fn is None
如果你想计算任何导数,可以调用.backward
a Tensor。如果Tensor是标量(即它包含一个元素数据),则不需要指定任何参数backward()
,但是如果他有更多的额元素,则需要指定一个gradient
匹配形状的张量的参数。
1 | x = torch.ones(2, 2, requires_grad=True) # 创建一个张量并设置requires_grad为跟踪计算 |
注意: requires_grad_(...)
requires_grad
就地改变现有的Tensor旗帜。如果没有的话,就默认为False。
1 | a = torch.randn(2, 2) |
Gradient
Let’s backprop now! 因为out包含的是一个标量,所以out.backward()
和out.backward(torch.tensor(1.))
是等价的
1 | out.backward() |
torch.autograd.backgrad(variables, grad_variables=None, retain_graph = None, create_graph=None, retain_variables=None)
-
grad_variable
:形状与variable一致,对于y.backward()
,grad_variable
相当于链式法则:dz/dx = dz/dy * dy/dx
中的dz/dy
。grad_variables也可以是tensor或序列 -
retain_graph
:反向传播需要缓存一些中间结果,反向传播之后,这些缓存就会被清空,可通过指定这个参数不清空缓存,用来多次反向传播。 -
create_graph:对反向传播过程再次构建计算图,可通过backward of backward实现求高阶导数
注意:variables和grad_variables都可以是sequence。对于scalar(标量,一维向量)来说可以不用填写grad_variables参数,若填写的话就相当于系数。若variables非标量则必须填写grad_variables参数。
通式: 对于此式,x的梯度
-
scalar标量:注意参数requires_grad=True让其成为一个叶子节点,具有求导功能。
1
2
3
4
5
6
7
8
9
10
11
12import torch as t
from torch.autograd import Variable as v
a = v(t.FloatTensor([2, 3]), requires_grad=True)
b = a + 3
c = b * b * 3
out = c.mean()
out.backward(retain_graph=True)
print(a.grad.data)
"""
output:
tensor([15., 18.])
"""手工求解过程
我们对其求导也很简单:
和上面的求解一致
还可以通过.requires_grad=True
with torch.no_grad()
包装代码来停止在Tensor上跟踪历史记录的autograd。
1 | print(x.requires_grad) |
例:
y =w * x + b
y.backgrad()
如果需要计算dy / dw
w.grad()
**注意:**torch.normal()
返回一个张量,张量里面的随机数是从相互独立的正态分布中随机产生的。神经网络中的初始weight用normal生成可能效果会比较好。
nn.CrossEntropyLoss() 和 NLLLoss()
NLLLoss的输入时一个对数概率向量和一个目标标签,他不会为我们计算对数概率,适合网络的最后一层时log_softmax,损失函数nn.CrossEntropyLoss()与NLLLoss()相同,唯一的不同是他为我们去做softmax