参考:
PyTorch 学习笔记汇总
PyTorch中backward函数详解
1 动态图
PyTorch 采用的是动态图机制(Dynamic Computational Graph),而 Tensorflow 采用的是静态图机制。(Static Computational Graph)
动态图运算和搭建同时进行,也就是可以先计算前面的节点值,再根据这些值搭建后面的计算图。而静态图需要先搭建图,然后再输入数据进行运算。
PyTorch 动态图的优点是灵活,易调节,且使用简单方便。(类似 Python 库)但是其效率相对 Tensorflow 的静态图要低不少。
2.1 计算动态图
计算图是用来描述运算的有向无环图,有两个主要元素:节点 (Node) 和边 (Edge)。节点表示数据,如向量、矩阵、张量。边表示运算,如加减乘除卷积等。
一个简单的例子 ,该式子用计算图表示为:
,其中 ,。
2.2 求导
对于上式,分别求 在 时,关于 、 的导数:
同理:
PyTorch中,torch.backward()
会提供求导的功能,代码如下(注意,当计算图中的根不是标量时,即因变量为一个向量时,会构建出多个计算图对该向量中的每个元素分别进行求导,详见 pytorch中backward()函数详解 ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import torch m = torch.tensor([2.], requires_grad=True) n = torch.tensor([3.], requires_grad=True)
a = torch.add(m, n) b = torch.add(m, -n) y = torch.mul(a, b)
y.backward()
print('m的梯度:', m.grad) print('n的梯度', n.grad) print('m is_leaf:', m.is_leaf) print('n is_leaf:', n.is_leaf) print('a is_leaf:', a.is_leaf) print('b is_leaf:', b.is_leaf) print('y is_leaf:', y.is_leaf)
|
1 2 3 4 5 6 7
| m的梯度: tensor([4.]) n的梯度 tensor([-6.]) m is_leaf: True n is_leaf: True a is_leaf: False b is_leaf: False y is_leaf: False
|
并且由打印可知,可以看出 和 的 is_leaf 属性为 true,这是由于、、 是依赖 和 的,故、为叶子节点。叶子节点的概念主要是为了节省内存,在计算图中的一轮反向传播结束之后,非叶子节点的梯度是会被释放的,所以直接访问非叶子节点的梯度是为空的。但是如果在反向传播结束之后仍然需要保留非叶子节点的梯度,可以对节点使用retain_grad()
方法。
张量Tensor中,属性grad_fn记录了创建该张量时使用的方法(函数),故而可以在调用torch.backward()
时自动求导。
2 线性回归
线性回归是分析一个变量y与另外一 (多) 个变量x之间的关系的方法。一般可以写成 线性回归的目的就是求解参数,。其主要步骤:
① 确定模型(实际使用中,可能是一个隐函数):;
② 选择损失函数,一般使用均方误差MSE(mean square error):。其中是预测值,是真实值;
③ 使用梯度下降法求解梯度,并根据学习率 更新参数,以此来最小化损失函数。
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import torch import matplotlib.pyplot as plt torch.manual_seed(10)
lr = 0.05
x = torch.rand(20, 1) * 10
y = 2*x + (5 + torch.randn(20, 1))
w = torch.randn((1), requires_grad=True) b = torch.zeros((1), requires_grad=True)
for iteration in range(100):
wx = torch.mul(w, x) y_pred = torch.add(wx, b)
loss = (0.5 * (y - y_pred) ** 2).mean()
loss.backward()
b.data.sub_(lr * b.grad) w.data.sub_(lr * w.grad)
w.grad.zero_() b.grad.zero_()
if iteration % 5 == 0:
plt.scatter(x.data.numpy(), y.data.numpy()) plt.plot(x.data.numpy(), y_pred.data.numpy(), 'r-', lw=5) plt.text(2, 20, 'Loss=%.4f' % loss.data.numpy(), fontdict={'size': 20, 'color': 'red'}) plt.xlim(1.5, 10) plt.ylim(8, 28) plt.title("Iteration: {}\nw: {} b: {}".format(iteration, w.data.numpy(), b.data.numpy())) plt.pause(0.5)
if loss.data.numpy() < 1: break
|