Apache Mxnet 简明教程

Apache MXNet - Python Packages

在本章中,我们将了解 Apache MXNet 中可用的 Python 包。

Important MXNet Python packages

MXNet 具有以下重要的 Python 包,我们将会逐个讨论 −

  1. Autograd (Automatic Differentiation)

  2. NDArray

  3. KVStore

  4. Gluon

  5. Visualization

首先我们从 Apache MXNet 的 Autograd Python 包开始。

Autograd

Autograd 表示 automatic differentiation 用于将梯度从损失指标反向传播到每个参数。它在反向传播时使用动态规划方法来有效计算梯度。它也被称为反向模式自动微分化。这种技术在很多参数影响单个损失指标的「扇入」情况下非常有效。

What are gradients?

梯度是神经网络训练过程中的基础。它们基本上告诉我们如何改变网络参数以提高其性能。

众所周知,神经网络 (NN) 由加法、乘积、卷积等运算符组成。这些运算符在计算中会使用参数,例如卷积核中的权重。我们必须为这些参数找到最佳值,而梯度则向我们展示了方法并引导我们找到解决方案。

graph of gradients

我们关注的是改变参数对网络性能的影响,梯度会告诉我们,在某个变量依赖于某个变量时,当我们改变该变量时,该变量会增加或减少多少。性能通常使用我们尝试最小化的损失指标来定义。例如,对于回归,我们可能尝试最小化我们的预测与精确值之间的 L2 损失,而对于分类,我们可能最小化 cross-entropy loss

一旦我们按照损失计算了每个参数的梯度,就可以使用优化器,例如随机梯度下降。

How to calculate gradients?

我们有以下选项来计算梯度 −

  1. Symbolic Differentiation − 第一个选项是符号微分化,它为每个梯度计算公式。这种方法的缺点是,随着网络的加深和运算符变得更加复杂,它将迅速导致难以置信的冗长公式。

  2. Finite Differencing − 另一个选项是使用有限差分法,它对每个参数尝试微小差值,并观察损失指标如何响应。这种方法的缺点是,它在计算上会很昂贵,并且可能具有较差的数值精度。

  3. Automatic differentiation − 解决上述方法缺点的方案是使用自动微分化将梯度从损失指标反向传播到每个参数。传播允许我们使用动态规划方法来有效计算梯度。这种方法也被称为反向模式自动微分化。

Automatic Differentiation (autograd)

在这里,我们将详细了解 autograd 的工作原理。它基本上在以下两个阶段进行工作 −

Stage 1 − 该阶段称为训练的 ‘Forward Pass’ 。顾名思义,在此阶段它创建了网络用于预测和计算损失指标所使用运算符的记录。

Stage 2 − 该阶段称为训练的 ‘Backward Pass’ 。顾名思义,在此阶段它通过该记录向后进行工作。向后进行时,它会评估每个运算符的偏导数,一直到网络参数。

automatic differentiation

Advantages of autograd

以下是使用自动微分化 (autograd) 的优势 −

  1. Flexible − 灵活是我们使用 autograd 时的一大好处,它给予我们在定义我们的网络时更大的灵活度。我们可以在每次迭代中更改运算。这些被称为动态图,在需要静态图的框架中实现它们要复杂得多。即使在这种情况 autograd 仍能够正确反向传播梯度。

  2. Automatic − autograd 是自动的,即反向传播过程的复杂性由它为您处理。我们只需要指定我们有兴趣计算哪些梯度。

  3. Efficient − Autogard 非常有效地计算梯度。

  4. Can use native Python control flow operators − 我们可以使用原生 Python 控制流运算符,例如 if 条件和 while 循环。autograd 仍然可以有效且正确地反向传播梯度。

Using autograd in MXNet Gluon

这里,借助示例,我们将了解如何在 MXNet Gluon 中使用 autograd

Implementation Example

在以下示例中,我们将实现一个有两个层回归模型。实现后,我们将使用自动梯度计算损失函数关于各个权重参数的梯度 −

首先,如下导入自动梯度和其他必需的包 −

from mxnet import autograd
import mxnet as mx
from mxnet.gluon.nn import HybridSequential, Dense
from mxnet.gluon.loss import L2Loss

现在,我们需要如下定义网络 −

N_net = HybridSequential()
N_net.add(Dense(units=3))
N_net.add(Dense(units=1))
N_net.initialize()

现在我们需要如下定义损失 −

loss_function = L2Loss()

接下来,我们需要如下创建虚拟数据 −

x = mx.nd.array([[0.5, 0.9]])
y = mx.nd.array([[1.5]])

现在,我们已准备好进行首次前向网络遍历。我们希望自动梯度记录计算图,以便我们可以计算梯度。为此,我们需要在 autograd.record 上下文的范围内运行网络代码,如下所示 −

with autograd.record():
   y_hat = N_net(x)
   loss = loss_function(y_hat, y)

现在,我们准备进行反向遍历,首先对目标量调用反向方法。在我们示例中,目标量是损失,因为我们正尝试计算损失关于参数的梯度 −

loss.backward()

现在,对于网络的每个参数,我们都有梯度,优化器将使用这些梯度来更新参数值,以提升性能。让我们检查第一层的梯度,如下所示 −

N_net[0].weight.grad()

Output

输出如下 −

[[-0.00470527 -0.00846948]
[-0.03640365 -0.06552657]
[ 0.00800354 0.01440637]]
<NDArray 3x2 @cpu(0)>

Complete implementation example

完整实现示例如下:

from mxnet import autograd
import mxnet as mx
from mxnet.gluon.nn import HybridSequential, Dense
from mxnet.gluon.loss import L2Loss
N_net = HybridSequential()
N_net.add(Dense(units=3))
N_net.add(Dense(units=1))
N_net.initialize()
loss_function = L2Loss()
x = mx.nd.array([[0.5, 0.9]])
y = mx.nd.array([[1.5]])
with autograd.record():
y_hat = N_net(x)
loss = loss_function(y_hat, y)
loss.backward()
N_net[0].weight.grad()