微积分
0. 环境介绍
环境使用 Kaggle 里免费建立的 Notebook
教程使用李沐老师的 动手学深度学习 网站和 视频讲解
小技巧:当遇到函数看不懂的时候可以按 Shift+Tab
查看函数详解。
0.1 求导结果
0.2 y 为标量,X 为向量
0.3 y 和 X 均为向量
1. 自动求导
假设我们想对函数
y
=
2
x
⊤
x
y=2x^{\top}x
y=2x⊤x 关于列向量
x
x
x 求导。
小细节:arange(4)
代表生成 4 个连续整型数,arange(4.0)
代表生成 4 个连续浮点数。
1.1 存储梯度
第一行代码设置与 x = torch.arange(4.0, requires_grad=True)
等价。
x.grad
默认为 None
。
1.2 计算 y y y
隐式构造计算图。
1.3 调用反向传播函数来自动计算 y y y 关于每个分量的梯度
内积是自己相乘,也就是
2
x
2
2x^2
2x2,求导后就是
4
x
4x
4x。
1.4 计算 y = s u m ( x ) y=sum(x) y=sum(x) 关于 x x x 的梯度
默认情况下,Pytorch 会累计梯度,我们需要清除之前的值。
如果注释掉 x.grad.zero_()
会导致每次 y.backward()
后 x.grad
的结果都是与之前的保留的梯度相加之和。
1.5 计算 y = s u m ( x ∗ x ) y=sum(x*x) y=sum(x∗x) 关于 x x x 的梯度
这里的 x * x
为 element-wise
的结果。
y.sum().backward()
等价于 y.backward(torch.ones(len(x)))
1.6 将某些计算移动到记录的计算图之外
y.detach()
将
y
y
y 设置为一个常数,命名为
u
u
u,
z
z
z 关于
x
x
x 的导数就是
u
u
u。这个操作可以用于固定参数。
1.7 即使构建函数的计算图需要通过 Python 控制流(例如,条件、循环或任意函数调用),我们仍然可以计算得到的变量的梯度。
调用
f
(
a
)
f(a)
f(a) 函数返回的值,是一个关于
a
a
a 的线性函数,所以
d
d
d 关于
a
a
a 的导数就是这个线性函数中
a
a
a 的系数
2. 练习
2.1 在运行反向传播函数之后,立即再次运行它,看看会发生什么。
会报错
RuntimeError: Trying to backward through the graph a second time (or directly access saved variables after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved variables after calling backward.
Pytorch构建的计算图是动态图,为了节约内存,所以每次一轮迭代完也即是进行了一次 backward
函数计算之后计算图就被在内存释放,因此如果你需要多次 backward
只需要在第一次反向传播时候添加一个 retain_graph=True
标识,让计算图不被立即释放。
2.2 在控制流的例子中,我们计算 d d d 关于 a a a 的导数,如果我们将变量 a a a 更改为随机向量或矩阵,会发生什么?
会报错
RuntimeError: grad can be implicitly created only for scalar outputs
因为默认是个标量,所以需要设置参数 torch.ones_like(d)
。