Autograd 自动微分
深度学习的算法本质上是通过反向传播求导数,Pytorch的Autograd模块实现了此功能。在tensor上的所有操作,Autograd 都能自动求微分,避免了手动计算微分的过程。
其中,autograd.Variable.是Autograd中核心的类,它简单的封装了Tensor,支持所有tensor的操作。
tensor在被封装为Variable后,可以调用它的**.backward**实现反向传播,自动计算所有的梯度。Variable的数据结构如下图:
Variable主要包含三个属性:
1 data:保存Varible所包含的tensor
2 grad:保存data对应的梯度,注意,它这里也是一个Variable,而不是个tensor,与data形状一样。
3 gran_fn:指向一个Function对象,用来反向传播计算输入的梯度。
例子如下:
输入一个全为1的3*3的矩阵,为Variable类
import torch
from torch.autograd import Variable
a=torch.ones(3,3)
x = Variable(a,requires_grad = True)
print(x)
注意这里requires_grad=True表示该变量在自动计算梯度时会保留梯度值,为False则相反。默认为False
输出结果:
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]], requires_grad=True)
Varible几乎支持tensor的所有操作,如下:
y=x.sum()
print(y)
输出结果
tensor(9., grad_fn=<SumBackward0>)
查看x和y的grad_fn
print(x.grad_fn)
print(y.grad_fn)
输出结果:
None
<SumBackward0 object at 0x000002289C55CBA8>
可以看到,y是作为x的运算结果产生的,所以y有grad_fn。而x是直接创建的,所以没有
backward只能对一个标量求导或者 传入跟变量相关的梯度。
如果Variable是一个标量,无需对backward()指定任何参数,如下:
先看这个:
import torch
from torch.autograd import Variable
x = Variable(torch.ones(2, 2), requires_grad=True)
y = x + 2
z = y * y * 3
p = z.mean()
p.backward()
print(x.grad)
输出结果
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
但如果Varieble是一个向量,就需要指定一个和Variable中tensor的形状匹配的grad_output参数
如下:
这里,y.backward(weight1),weight1是对求导变量的一个权重,当y为标量的时候,该参数默认为1,就可以跟我们理解的一样,求y对x的导数。至于为什么有这个,参考知乎上的一文:PyTorch 的 backward 为什么有一个 grad_variables 参数?
import torch
from torch.autograd import Variable
x = Variable(torch.Tensor([1, 2, 3, 4, 5]), requires_grad=True) # 需要求导数
y = x * x
weights1 = torch.Tensor([5, 5, 5, 5, 5])
y.backward(weights1, retain_graph=True)
print(x.grad)
输出结果:
tensor([10., 20., 30., 40., 50.])
backward函数中还有retain_graph参数,使用这个参数时,再次求导的时候,会对之前的导数进行累加,所以每次反向传播前需要把梯度清零,如下,这在神经网络代码中会用到。
如下图:
import torch
from torch.autograd import Variable
x = Variable(torch.Tensor([1, 2, 3, 4, 5]), requires_grad=True) # 需要求导数
y = x * x
weights1 = torch.Tensor([5, 5, 5, 5, 5])
y.backward(weights1, retain_graph=True)
print(x.grad)
weights1 = torch.Tensor([5, 5, 5, 5, 5])
y.backward(weights1, retain_graph=True)
print(x.grad)
x.grad.data.zero_()# 清零
weights1 = torch.Tensor([5, 5, 5, 5, 5])
y.backward(weights1, retain_graph=True)
print(x.grad)
#输出结果
# tensor([10., 20., 30., 40., 50.])
# tensor([ 20., 40., 60., 80., 100.])
# tensor([10., 20., 30., 40., 50.])
上一篇: 深度学习的经验
下一篇: 深度学习(三):梯度计算