01 | PyTorch中的计算图
深度学习运算操作的基本单位是张量Tensor,实际中由于不同深度学习算法的复杂性,可能会导致诸多问题。而为了能够清晰明确地展示、把握求导等一系列运算过程,PyTorch提供了计算图(Computational Graph)机制以进行后向传播自动求导等运算。
计算图是用来描述运算的有向无环图。作为一种图,计算图也有两个主要元素:结点Node与边Edge。其中:
-
结点表示数据,如向量、矩阵、张量等;
-
边表示运算,如加减乘除、卷积等;
为了形象说明计算图的作用,我们用计算图来展示一次后向传播求导的过程。
如我们要求导的目标函数为:
y = ( x + w ) × ( w + 1 ) y = (x + w) \times (w + 1) y=(x+w)×(w+1)
计算图中要求每个边仅代表一次运算,因而需要将目标函数重新拆分为:
a = x + w b = w + 1 y = a × b a = x + w \\ b = w + 1 \\ y = a \times b a=x+wb=w+1y=a×b
然后用计算图中的结点表示数据(结点),用边表示存在运算关系,辅之以运算符号标识,可以得到如下的计算图。
当赋值(x=2,w=1)时,便可以基于计算图顺序计算得到目标函数(y=6),而这正是一次“正向传播”的过程。从图上来看,目标函数y针对w的偏导数,恰恰就是图中结点y到结点w的所有路径之和。
上述计算图可以使得前向传播的过程直观明了,同时另一个作用则是可以辅助后向传播求导。
如对上述目标函数中的自变量w求导,则依据函数求导法则,我们有:
∂ y ∂ w = ∂ y ∂ a ∂ a ∂ x + ∂ y ∂ b ∂ b ∂ w \frac{\partial y}{\partial w}=\frac{\partial y}{\partial a}\frac{\partial a}{\partial x} + \frac{\partial y}{\partial b}\frac{\partial b}{\partial w} ∂w∂y=∂a∂y∂x∂a+∂b∂y∂w∂b
按照上述法则计算偏导数,可以得到各个结点上的偏导数表示,并进而通过后向传播算法计算得到目标函数y在自变量x和w处的偏导数。
有印象的同学一定记得最初讲解torch.Tensor数据结构时,提到其中有一个属性为“is_leaf”来标记其是否为叶子结点。通常叶子节点表示由用户创建的结点,如本例中的w与x,而属性“is_leaf”既可以指示该张量是否是叶子结点。
默认情况下,只有我们创建的结点为叶子结点,其余计算图中的结点均非叶子结点,二者的区别在于,在一次后向传播计算完成后,非叶子结点的梯度值会被释放从而节省内存。
若我们想保留非叶子结点的梯度以便于调试分析,则可以在执行后向传播前采用“a.retain_grad()”命令。
接下来我们在PyCharm中运行测试验证计算图是否正确:
import torch
# 初始化输入结点数值
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
# 构建目标函数计算过程
a = torch.add(w, x)
b = torch.add(w, 1)
y = torch.mul(a, b)
# 保留a的梯度
a.retain_grad()
# 执行后向传播算法
y.backward() print(w.grad)print(a.grad)
# 查看叶子节点属性
print("is_leaf:\n", w.is_leaf, x.is_leaf, a.is_leaf, b.is_leaf, y.is_leaf)
可以看到,只有我们创建的“x”和“w”此时叶子结点,其余则为非叶子结点;但是对于非叶子结点“a”而言,可以使用“a.retain_grad()”方法保存梯度。
02 | PyTorch中的动态图机制
现有深度学习框架除了PyTorch还有Tensorflow,二者具有各自优缺点。其中一个最大的不同就是,PyTorch采用动态图机制,而Tensorflow采用静态图机制。
所谓动态图,通俗来讲就是运算与图搭建同时进行;静态图则相反,一般是先搭建好整体数据流图,然后再输入张量数据进行运算。
二者的区别类似出游方式的选择,动态图就是自由行,全过程是边游览边形成出游轨迹;而静态图则像是跟团游,出游之前已经由旅行社规划了行程,因而游客所做的就是按照行程走完(flow)即可。
动态图具有灵活、易条件的特点;而静态图则因为事先搭建好了图,因此具有执行高效,但不够灵活的特点。
以PyTorch为例,创建张量时,形成最初的叶子结点;编写乘法操作时,同步扩展非叶子结点;随着后续运算过程的输入完成,完整的计算图得以搭建完毕。