【PyTorch入门】(二)自动求导(Autograd)

本系列介绍了入门PyTorch所需要了解的内容。本文主要参考文献:《Deep Learning with PyTorch: A 60 Minute Blitz》(PyTorch深度学习60分钟快速入门),更新于2019.06.12。

文章目录

PyTorch中所有神经网络的核心是autograd包,这个包提供所有在张量上进行自动求导的操作。这个过程是define-by-run的,也就是反向传播过程由代码运行方式定义,而且每次迭代都可以不同。

Tensor

torch.Tensor是这个包的重要类别。如果将其属性.requires_grad设成True,则会跟踪发生在这个张量上的所有操作。在计算结束后,可以通过调用.backward()进行梯度的自动计算。这个张量的梯度被积累在属性.grad中。

要停止一个张量参与反向传播,可以调用.detach()函数使其脱离反向传播计算过程。

如果要停止反向传播和内存利用,可以将整个代码用代码块torch.no_grad(),这个对于模型的评估格外有用,因为模型中可能存在可训练的参数(requires_grad=True),但是却不希望计算它们的梯度。

对于反向传播很重要的另一个类别时Function

TensorFunction之间是相互联系的,并且构建了一个非周期图(acyclic graph),记录了计算的完整历史。每个张量都有个.grad_fn属性来引用创造这个TensorFunction(除了由用户定义的张量,这些张量的grad_fn是·None`)。

可以通过调用Tensor上的.backward()实现求导。但是如果这个张量是标量(只有一个元素数据),不需要对backward()单独定义任何变量;但是元素很多的时候,需要制定gradient变量来保证张量的维度保持不变。

import torch

创建一个张量并设定requires_grad=True来跟踪实施在上面的计算:

x = torch.ones(2,2,requires_grad=True)
print(x)

在这里插入图片描述

进行一个张量操作:

y = x + 2
print(y)

在这里插入图片描述

y是通过某个操作定义的变量,因此具有grad_fn

print(y.grad_fn)

在这里插入图片描述

进一步对y进行操作:

z = y * y * 3
out = z.mean()

print(z.out)

在这里插入图片描述
requires_grad_( ... )可以in-place地改变已有张量的requires_grad标志。如果未指定,输入标志默认为False

a = torch.randn(2,2)
a = ((a* 3) / (a-1))
print(a.requires_grad)
a.requires_grad_(True)
print(a.requires_grad)
b = (a * a).sum()
print(b.grad_fn)

在这里插入图片描述

Gradients

现在开始反向传播。由于out包括的是一个标量,out.backward()等同于out.backward(torch.tensor(1.))

out.backward()

显示导数d(out)/dx:

print(x.grad)

在这里插入图片描述

这里应该得到4.5组成的矩阵。称out张量为o,可以得到
o = 1 4 ∑ i z i ,   z i = 3 ( x i + 2 ) 2 o=\frac{1}{4}\sum_iz_i,\ z_i=3(x_i+2)^2 o=41izi, zi=3(xi+2)2 z i ∣ x i = 1 = 27 z_i\vert_{x_i=1}=27 zixi=1=27

因此, ∂ o ∂ x i = 3 2 ( x i + 2 ) \frac{\partial o}{\partial x_i}=\frac{3}{2}(x_i+2) xio=23(xi+2),因此 ∂ o ∂ x i ∣ x i = 1 = 9 2 = 4.5 \frac{\partial o}{\partial x_i}\vert_{x_i=1}=\frac{9}{2}=4.5 xioxi=1=29=4.5

数学上,如果有一个值为向量的函数 y ⃗ = f ( x ⃗ ) \vec y = f(\vec x) y =f(x ) y ⃗ \vec y y x ⃗ \vec x x 的梯度是一个雅可比矩阵(Jacobian matrix)【在向量微积分中,雅可比矩阵是一阶偏导数以一定方式排列成的矩阵,其行列式称为雅可比行列式。】:

J = { ∂ y 1 ∂ x 1 ⋯ ∂ y 1 ∂ x n ⋮ ⋱ ⋮ ∂ y m ∂ x 1 ⋯ ∂ y m ∂ x n } J=\left\{\begin{matrix} \frac{\partial y_1}{\partial x_1} & \cdots & \frac{\partial y_1}{\partial x_n} \\ \vdots & \ddots & \vdots \\ \frac{\partial y_m}{\partial x_1} & \cdots & \frac{\partial y_m}{\partial x_n} \end{matrix}\right\} J=x1y1x1ymxny1xnym

整体而言,torch.autograd是一个用于计算向量-雅克比乘积的机器(an engine for computing vector-Jacobian product)。即给定任意向量 v = ( v 1 , v 2 , ⋯   , v m ) T v = (v_1, v_2, \cdots, v_m)^T v=(v1,v2,,vm)T,计算乘积 v T ⋅ J v^T\cdot J vTJ。如果 v v v恰好是一个标量函数 l = g ( y ⃗ ) l=g(\vec y) l=g(y )的梯度,即 v = ( ∂ l ∂ y 1 ⋯ ∂ l ∂ y m ) v=\left(\frac{\partial l}{\partial y_1}\cdots\frac{\partial l}{\partial y_m}\right) v=(y1lyml),那么根据chain rule,vector-Jacobian乘积应该是 l l l相对于 x ⃗ \vec x x 的梯度:
J T ⋅ v = ( ∂ y 1 ∂ x 1 ⋯ ∂ y m ∂ x 1 ⋮ ⋱ ⋮ ∂ y 1 ∂ x n ⋯ ∂ y m ∂ x n ) ( ∂ l ∂ y 1 ⋮ ∂ l ∂ y m ) = ( ∂ l ∂ x 1 ⋮ ∂ l ∂ x n ) J^T\cdot v=\left(\begin{matrix} \frac{\partial y_1}{\partial x_1} & \cdots & \frac{\partial y_m}{\partial x_1} \\ \vdots & \ddots & \vdots\\ \frac{\partial y_1}{\partial x_n} & \cdots & \frac{\partial y_m}{\partial x_n} \end{matrix}\right)\left(\begin{matrix} \frac{\partial l}{\partial y_1} \\ \vdots\\ \frac{\partial l}{\partial y_m}\\ \end{matrix}\right)=\left(\begin{matrix} \frac{\partial l}{\partial x_1}\\ \vdots\\ \frac{\partial l}{\partial x_n} \end{matrix}\right) JTv=x1y1xny1x1ymxnymy1lyml=x1lxnl

注意, v T ⋅ J v^T\cdot J vTJ是行向量,通过 J T ⋅ v J^T\cdot v JTv可以转换成列向量。

这个vector-Jacobian乘积使得将外部梯度送入一个没有标量输出的模型变得非常容易。

现在来具体看一个例子;

x = torch.randn(3,requires_grad=True)
y = x* 2
while y.data.norm() < 1000:
	y = y * 2

print(y)

终端结果:
在这里插入图片描述
此时,y已经不是一个标量了,torch.autograd没有办法直接计算完整的Jacobian,但是我们其实只需要vector-Jacobian乘积,那么简单地将向量以变量的形式反向传播就可以:

v = torch.tensor(p0.1, 1.0, 0.0001], dtype=torch.float)
y.backward(v)

print(x.grad)

终端结果:
在这里插入图片描述

也可以通过将代码块融入with torch.no_grad():中实现.requires_grad=True下的反向梯度传播:

print(x.requires_grad)
print((x ** 2).requires_grad)

with torch.no_grad():
	print((x ** 2).requires_grad)

终端结果:
在这里插入图片描述
代码总运行时间3.013秒。

辅助阅读材料:【文档学习】Pytorch——torch.autorgrad包

更多内容,欢迎加入星球讨论。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值