乐趣区

关于机器学习:小白学PyTorch-动态图与静态图的浅显理解

文章来自公众号【机器学习炼丹术】,回复“炼丹”即可取得海量学习材料哦!

本章节缕一缕 PyTorch 的动态图机制与 Tensorflow 的动态图机制(最新版的 TF 也反对动态图了仿佛)。

1 动态图的初步推导

  • 计算图是用来形容运算的 有向无环图
  • 计算图有两个次要元素:结点(Node)和边(Edge);
  • 结点示意数据,如向量、矩阵、张量;
  • 边示意运算,如加减乘除卷积等;

上图是用计算图示意:

$y=(x+w)∗(w+1)y=(x+w)∗(w+1)$

其中呢,$a=x+w$,$b=w+1$ , $y=a∗b$. (a 和 b 是相似于两头变量的那种感觉。)

Pytorch 在计算的时候,就会把计算过程用下面那样的动态图存储起来。当初咱们计算一下 y 对于 w 的梯度:

$\frac{\partial y}{\partial w} = \frac{\partial y}{\partial a} \frac{\partial a}{\partial w} + \frac{\partial y}{\partial b} \frac{\partial b}{\partial w}$
$=2\times w + x + 1=5$

(下面的计算中,w=1,x=2)

当初咱们用 Pytorch 的代码来实现这个过程:

import torch
w = torch.tensor([1.],requires_grad = True)
x = torch.tensor([2.],requires_grad = True)

a = w+x
b = w+1
y = a*b

y.backward()
print(w.grad)

失去的后果:

2 动态图的叶子节点

这个图中的叶子节点,是 w 和 x,是整个计算图的根基。之所以用叶子节点的概念,是为了 缩小内存,在反向流传完结之后,非叶子节点的梯度会被开释掉,咱们仍然用下面的例子解释:

import torch
w = torch.tensor([1.],requires_grad = True)
x = torch.tensor([2.],requires_grad = True)

a = w+x
b = w+1
y = a*b

y.backward()
print(w.is_leaf,x.is_leaf,a.is_leaf,b.is_leaf,y.is_leaf)
print(w.grad,x.grad,a.grad,b.grad,y.grad)

运行后果是:

能够看到只有 x 和 w 是叶子节点,而后反向流传计算完梯度后(.backward()之后),只有叶子节点的梯度保留下来了。

当然也能够通过 .retain_grad() 来保留非任意节点的梯度值。

import torch
w = torch.tensor([1.],requires_grad = True)
x = torch.tensor([2.],requires_grad = True)

a = w+x
a.retain_grad()
b = w+1
y = a*b

y.backward()
print(w.is_leaf,x.is_leaf,a.is_leaf,b.is_leaf,y.is_leaf)
print(w.grad,x.grad,a.grad,b.grad,y.grad)

运行后果:

3. grad_fn

torch.tensor有一个属性 grad_fn,grad_fn 的作用是记录创立该张量时所用的函数,这个属性反向流传的时候会用到。例如在下面的例子中,y.grad_fn=MulBackward0, 示意 y 是通过乘法失去的。所以求导的时候就是用乘法的求导法令。同样的,a.grad=AddBackward0示意 a 是通过加法失去的,应用加法的求导法令。

import torch
w = torch.tensor([1.],requires_grad = True)
x = torch.tensor([2.],requires_grad = True)

a = w+x
a.retain_grad()
b = w+1
y = a*b

y.backward()
print(y.grad_fn)
print(a.grad_fn)
print(w.grad_fn)

运行后果是:

叶子节点的 .grad_fn 是 None。

4 动态图

两者的区别用一句话概括就是:

  • 动态图:pytorch 应用的,运算与搭建同时进行;灵便,易调节。
  • 动态图:老 tensorflow 应用的,先搭建图,后运算;高效,不灵便。

动态图咱们是须要先定义好运算规定流程的。比方说,咱们先给出

$a = x+w$ , $b=w+1$ , $y=a\times b$

而后把下面的运算流程存储下来,而后把 w =1,x= 2 放到下面运算框架的入口地位进行运算。而动态图是间接对着曾经赋值的 w 和 x 进行运算,而后变运算变构建运算图。

在一个课程 http://cs231n.stanford.edu/sl…,有这样的一个比照例子:

这个代码是 Tensorflow 的,构建运算的时候,先构建运算框架,而后再把具体的数字放入其中。整个过程相似于训练神经网络,咱们要构建好模型的构造,而后再训练的时候再吧数据放到模型外面去。又相似于在游览的时候,咱们当时定要每天的行程路线,而后每天依照路线去口头。

动态图呢,就是间接对数据进行运算,而后动静的构建出运算图。很合乎咱们的运算习惯。

两者的区别在于,动态图先阐明数据要怎么计算,而后再放入数据。假如要放入 50 组数据,运算图因为是当时构建的,所以每一次计算梯度都很快、高效;动态图的运算图是在数据计算的同时构建的,假如要放入 50 组数据,那么就要生成 50 次运算图。这样就没有那么高效。所以称为 动态图

动态图尽管没有那么高效,然而他的长处有以下:

  1. 更容易调试。
  2. 动静计算更实用于自然语言解决。(这个可能是因为自然语言解决的输出往往不定长?)
  3. 动态图更面向对象编程,咱们会感觉更加天然。
退出移动版