1 . torch.autograd
为方便用户使用而专门开发的一套自动求导引擎,它能够根据输入和前向传播过程自动构建计算图,并执行反向传播。
1 2 3 4 5 6 7 8 9
| import torch as t
a = t.randn(3, 4, requires_grad=True)
a = t.randn(3, 4).requires_grad_()
a = t.randn(3, 4) a.requires_grad=True
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| b = t.zeros(3, 4).requires_grad_()
c = a.add(b)
d = c.sum() d.backward() print(d.requires_grad)
print(a.requires_grad, b.requires_grad, c.requires_grad)
print(a.is_leaf, b.is_leaf, c.is_leaf)
print(c.grad is None)
|
2 . 验证 autograd 的计算结果与利用公式手动计算的结果一致。
$y=x^2 \cdot e^x$ 的导函数是:$\frac{d_{y}}{d_{x}}=2x \cdot e^x + x^2 \cdot e^x$,来看看 autograd 的计算结果与手动求导的计算结果是否有误差。
Input:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import torch as t
def f(x): y = x ** 2 * t.exp(x) return y
def gradf(x): '''手动求导函数''' dx = 2 * x * t.exp(x) + x ** 2 * t.exp(x) return dx
x = t.randn(3, 4, requires_grad=True) y = f(x)
y.backward(t.ones(y.size())) print(x.grad) print(gradf(x))
|
Output:
3 . 每一个前向传播操作的函数都有与之对应的反向传播函数用来计算输入的各个 variable 的梯度,这些函数的函数名通常以 Backward 结尾。
Input:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| import torch as t
x = t.ones(1) b = t.rand(1, requires_grad=True) w = t.rand(1, requires_grad=True) y = w * x z = y + b
print(x.requires_grad, b.requires_grad, w.requires_grad)
print(z.grad_fn)
print(z.grad_fn.next_functions) print(z.grad_fn.next_functions[0][0] == y.grad_fn)
print(y.grad_fn.next_functions)
print(w.grad_fn, x.grad_fn)
|
Output:
计算 $w$ 的梯度的时候,需要用到 $x$ 的数值($\frac{\partial y}{\partial w}=x$),这些数值在前向过程中会保存成 buffer,在计算完梯度之后会自动清空,为了能够多次反向传播需要指定 retain_graph
来保留这些 buffer。
1 2 3 4 5 6
| z.backward(retain_graph=True) print(w.grad)
z.backward() print(w.grad)
|
4 . PyTorch 使用的是动态图,它的计算图在每次前向传播时都是从头开始构建。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import torch as t
def abs(x): if x.data[0] > 0: return x else: return -x
x = t.ones(1, requires_grad=True) y = abs(x) y.backward() print(x.grad)
x = -1 * t.ones(1) x = x.requires_grad_() y = abs(x) y.backward() print(x.grad)
|
变量的 requires_grad
属性默认 False
,如果某一个节点 requires_grad
被设置为 True
,那么所有依赖它的节点 requires_grad
都是 True
。
5 . 有时候可能不希望 autograd 对 tensor 求导,因为求导需要缓存许多中间结构,增加额外的内存/显存开销,同时降低运行速度,那么我们可以关闭自动求导,譬如在模型训练完毕转而进行测试推断的时候。
1 2 3 4 5 6 7 8 9
| import torch as t
with t.no_grad(): x = t.ones(1) w = t.rand(1, requires_grad=True) y = x * w
print(x.requires_grad, w.requires_grad, y.requires_grad)
|
关闭自动求导后可以使用 t.set_grad_enable(True)
恢复设置。
笔记来源:《pytorch-book》