自动求梯度
前言
神经网络就是寻求一个拟合函数,但是因为参数过多,所以不得不借助每一点的梯度来一点一点的接近最佳的LOSS值,pytorch拥有动态的计算图,存储记忆对向量的每一个函数操作,最后通过反向传播来计算梯度,这可以说是pytorch的核心。
所以深入了解如果利用pytorch进行自动梯度计算非常重要。
深度学习模型的训练就是不断更新权值,权值的更新需要求解梯度。
PyTorch提供的
autograd
包能够根据输⼊
和前向传播过程自动构建计算图,并执行反向传播。
本节将介绍如何使⽤用autograd
包来进行自动求梯度的有关操作。
概念
上一节介绍的 Tensor
是这个包的核心类,如果将其属性 .requires_grad
设置为 True
,它将开始追
踪(track)在其上的所有操作(这样就可以利用链式法则进行梯度传播了)。
完成计算后,可以调用 .backward()
来完成所有梯度计算。此 Tensor 的梯度将累积到 .grad
属性中。
如果不想要被继续追踪,可以调用 .detach()
将其从追踪记录中分离出来,这样就可以防止将来的计算被追踪,这样梯度就传不过去了。
此外,还可以用 with torch.no_grad()
将不想被追踪的操作代码块包裹起来,这种方法在评估模型的时候很常用,因为在评估模型时,我们并不需要计算可训练参数
( requires_grad=True
)的梯度。
Function
是另外一个很重要的类。 Tensor
和 Function
互相结合就可以构建一个记录有整个计算过程的有向无环图(DAG)。
每个 Tensor
都有一个 .grad_fn
属性,该属性即创建该 Tensor
的Function
, 就是说该 Tensor
是不是通过某些运算得到的,若是,则 grad_fn
返回一个与这些运算相关的对象,否则是None
。
下面通过⼀些例子来理解这些概念。
Tensor
创建⼀一个 Tensor
并设置 requires_grad=True
:
x = torch.ones(2, 2, requires_grad=True)
print(x)
print(x.grad_fn)
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
None
再做一下运算操作:
y = x + 2
print(y)
print(y.grad_fn)
输出:
tensor([[3., 3.],
[3., 3.]], grad_fn=<AddBackward>)
<AddBackward object at 0x1100477b8>
注意x是直接创建的,所以它没有
grad_fn
, ⽽而y是通过一个加法操作创建的,所以它有一个为
<AddBackward>
的grad_fn
。
像x这种直接创建的称为叶子节点,叶子节点对应的 grad_fn
是 None
。
print(x.is_leaf, y.is_leaf) # True False
关于复杂度运算操作:
z = y * y * 3
out = z.mean()
print(z, out)
输出:
tensor([[27., 27.],
[27., 27.]], grad_fn=<MulBackward>) tensor(27., grad_fn=
<MeanBackward1>
通过 .requires_grad_()
来用in-place(就地操作)的方式改变 requires_grad
属性:
a = torch.randn(2, 2) # 缺失情况下默认 requires_grad = False
a = ((a * 3) / (a - 1))
print(a.requires_grad) # False
a.requires_grad_(True)
print(a.requires_grad) # True
b = (a * a).sum()
print(b.grad_fn)
输出:
False
True
<SumBackward0 object at 0x118f50cc0>
梯度
因为 out
是一个标量,所以调用 backward()
时不需要指定求导变量:
out.backward() # 等价于 out.backward(torch.tensor(1.))
我们来看看 out
关于 x
的梯度d(out)dx\frac{d(o u t)}{d x}dxd(out):
print(x.grad)
输出:
tensor([[4.5000, 4.5000],
[4.5000, 4.5000]])
我们令 out
为ooo , 因为
o=14∑i=14zi=14∑i=143(xi+2)2 o=\dfrac{1}{4}\sum_{i=1}^4z_i=\dfrac{1}{4}\sum_{i=1}^43(x_i+2)^2\quad\quad o=41i=1∑4zi=41i=1∑43(xi+2)2
所以
∂o∂xi∣xi=1=92=4.5 \quad\left.\dfrac{\partial o}{\partial x_i}\right|_{x_i=1}=\dfrac{9}{2}=4.5 ∂xi∂o
x