自动梯度计算看似很神奇,但它其实并不是魔术。
它背后的原理很值得深入了解,这些知识将帮助我们构建更大规模的网络。
看看下面这个非常简单的网络。它甚至不算一个神经网络,而只是一系列计算。
在上图中,我们看到输入x被用于计算y,y再被用于计算输出z。
假设y和z的计算过程如下:
如果我们希望知道输出
z
z
z如何随
x
x
x变化,我们需要知道梯度
d
y
/
d
x
dy/dx
dy/dx。下面我们来逐步计算。
第一行是微积分的链式法则(chain rule),对我们非常重要。
我们刚刚算出,
z
z
z随
x
x
x的变化可表示为
4
x
4x
4x。如果
x
=
3.5
x = 3.5
x=3.5,则
d
z
/
d
x
=
4
×
3.5
=
14
dz/dx = 4 × 3.5 = 14
dz/dx=4×3.5=14。
当 y y y以 x x x的形式定义,而 z z z以 y y y的形式定义时,PyTorch便将这些张量连成一幅图,以展示这些张量是如何连接的。这幅图叫计算图(computation graph)。
在我们的例子中,计算图看起来可能是下面这样的:
我们可以看到
y
y
y是如何从
x
x
x计算得到的,
z
z
z是如何从
y
y
y计算得到的。此外,PyTorch还增加了几个反向箭头,表示
y
y
y如何随着
x
x
x变化,
z
z
z如何随着
y
y
y变化。这些就是梯度,在训练过程中用来更新神经网络。微积分的过程由PyTorch完成,无须我们自己动手计算。
为了计算出
z
z
z如何随着
x
x
x变化,我们合并从
z
z
z经由
y
y
y回到
x
x
x的路径中的所有梯度。这便是微积分的链式法则。
PyTorch先构建一个只有正向连接的计算图。我们需要通过backward()函数,使PyTorch计算出反向的梯度。
梯度dz/dx在张量x中被存储为x.grad。
值得注意的是,张量
x
x
x内部的梯度值与z的变化有关。这是因为我们要求PyTorch使用z.backward ()从
z
z
z反向计算。因此,
x
.
g
r
a
d
x.grad
x.grad是
d
z
/
d
x
dz/dx
dz/dx,而不是
d
y
/
d
x
dy/dx
dy/dx。
大多数有效的神经网络包含多个节点,每个节点有多个连进该节点的链接,以及从该节点出发的链接。让我们来看一个简单的例子,例子中的节点有多个进入的链接。
可见,输入
a
a
a和
b
b
b同时对
x
x
x和
y
y
y有影响,而输出
z
z
z是由
x
x
x和
y
y
y计算出来的。
这些节点之间的关系如下。
我们按同样的方法计算梯度。
接着,把这些信息添加到计算图中。
现在,我们可以轻易地通过z到a的路径计算出梯度dz/da。实际上,从z到a有两条路径,一条通过x,另一条通过y,我们只需要把两条路径的表达式相加即可。这么做是合理的,因为从a到z的两条路径都影响了z的值,这也与我们用微积分的链式法则计算出的dz/da的结果一致。
d
z
/
d
a
=
d
z
/
d
x
+
d
x
/
d
a
+
d
z
/
d
y
+
d
y
/
d
a
dz/da = dz/dx+dx/da +dz/dy+dy/da
dz/da=dz/dx+dx/da+dz/dy+dy/da
第一条路径经过
x
x
x,表示为
2
×
2
2 × 2
2×2;第二条路径经过
y
y
y,表示为
3
×
10
a
3×10a
3×10a。所以,
z
z
z随
a
a
a变化的速率是
4
+
30
a
4 + 30a
4+30a。
如果
a
a
a是2,则
d
z
/
d
a
dz/da
dz/da是4 + 30 × 2 = 64。
我们来检验一下用PyTorch是否也能得出这个值。首先,我们定义PyTorch构建计算图所需要的关系。
接着,我们触发梯度计算并查询张量
a
a
a里面的值。
有效的神经网络通常比这个小型网络规模大得多。但是PyTorch构建计算图的方式以及沿着路径向后计算梯度的过程是一样的。
- Colab服务允许我们在谷歌的服务器上运行Python代码。Colab使用Python笔记本,我们只需要一个Web浏览器即可使用。
- PyTorch是一个领先的Python机器学习架构。它与numpy类似,允许我们使用数字数组。同时,它也提供了丰富的工具集和函数,使机器学习更容易上手。
- 在PyTorch中,数据的基本单位是张量(tensor)。张量可以是多维数组、简单的二维矩阵、一维列表,也可以是单值。
- PyTorch的主要特性是能够自动计算函数的梯度(gradient)。梯度的计算是训练神经网络的关键。为此,PyTorch需要构建一张计算图(computationgraph),图中包含多个张量以及它们之间的关系。在代码中,该过程在我们以一个张量定义另一个张量时自动完成。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)