亚马逊AWS官方博客

使用 NNPACK 库加速 Apache MXNet

Apache MXNet 是供开发人员构建、训练和重复使用深度学习网络的开源库。在这篇博文中,我将向您介绍如何使用 NNPACK 库来加速推理。事实上,当 GPU 推理不可用时,要想从实例中获取更多性能,将 NNPACK 添加到 Apache MXNet 中或许不失为一种简单的方法。和往常一样,“您的情况可能会有所不同”,而且您应该始终运行自己的测试。

在我们开始之前,先来了解一些训练和推理的基础知识吧。

培训

训练是神经网络学习如何正确预测数据集中各个示例的正确标签的步骤。每次一批 (通常包含 32 到 256 个示例),数据集被馈送到网络中,通过反向传播算法调整权重以减少总误差。

浏览完整的数据集被称为 epoch。大型网络可能会接受数百个 epoch 的训练,以达到尽可能最高的准确度。这可能需要几天甚至几周的时间。GPU 具有强大的并行处理能力,即使与最强大的 CPU 相比,训练时间也可以大大缩短。

推理

推理是实际使用经过训练的网络预测新数据示例的步骤。您可以一次预测一个示例,例如像 Amazon Rekognition 一样尝试识别单个图像中的对象,或者在处理来自多个用户的请求时可以一次预测多个示例。

当然,GPU 在推理方面同样十分高效。然而,许多系统由于成本、功耗或外形尺寸限制而无法容纳 GPU。因此,能够快速运行基于 CPU 的推理仍然是一个重要的课题。这正是 NNPACK 库发挥作用的地方,它可以帮助我们在 Apache MXNet 中加速 CPU 推理。

NNPACK 库

NNPACK 是一个可在 GitHub 上使用的开源库。它将如何帮助我们呢?您肯定了解卷积神经网络。这些网络由多个层构建,应用卷积和池来检测输入图像中的特征。

在这篇文章中,我们不涉及实际理论,而是介绍 NNPACK 如何以高度优化的方式实施这些操作 (以及其他一些操作,如矩阵乘法)。如果您对基础理论感兴趣,请参阅这篇 Reddit 帖子的作者提到的研究论文。

NNPACK 可应用于 Linux 和 MacOS X 平台之上。它针对采用 AVX2 指令集的 Intel x86-64 处理器以及采用 NEON 指令集的 ARMv7 处理器和 ARM v8 处理器进行了优化。

在这篇文章中,我使用了运行 Deep Learning AMI 的 c5.9xlarge 实例。以下是我们将要执行的操作:

  • 从源代码构建 NNPACK 库。
  • 使用 NNPACK 从源代码构建 Apache MXNet
  • 使用各种网络运行一些图像分类基准

让我们开始吧。

构建 NNPACK

NNPACK 使用 Ninja 构建工具。但是 Ubuntu 存储库并没有托管最新的版本,所以我们也需要从源代码进行构建。

cd ~
git clone git://github.com/ninja-build/ninja.git && cd ninja
git checkout release
./configure.py --bootstrap
sudo cp ninja /usr/bin

现在,让我们按照以下说明来准备 NNPACK 的构建。

cd ~
sudo -H pip install --upgrade git+https://github.com/Maratyszcza/PeachPy
sudo -H pip install --upgrade git+https://github.com/Maratyszcza/confu
git clone https://github.com/Maratyszcza/NNPACK.git
cd NNPACK
confu setup
python ./configure.py

在实际构建之前,我们需要调整一下配置文件。因为 NNPACK 只是作为一个静态库来构建,而 MXNET 则是作为一个动态库来构建的。也就是说他们将不能正确连接。MXNet 文档建议使用旧版 NNPACK,不过还有另一种方法。

我们需要编辑 build.ninja 文件和“-fPIC”标志,以便将 C 和 C ++ 文件构建为与位置无关的代码,这其实就是我们与 MXNet 共享库连接所需要的全部内容。

cflags = -std=gnu99 -g -pthread -fPIC
cxxflags = -std=gnu++11 -g -pthread -fPIC

现在,我们来构建 NNPACK 并运行部分基本测试。

ninja
ninja smoketest

我们完成了 NNPACK 构建。您应该可以在 ~/NNPACK/lib 中看到这个库。

使用 NNPACK 构建 Apache MXNet

首先,我们安装 dependency 以及最新的 MXNet 源代码 (撰写本文时为 0.11.0-rc3)。详细的构建说明请参阅 MXNet 网站

cd ~
sudo apt-get install -y libopenblas-dev liblapack-dev libopencv-dev
git clone --recursive https://github.com/apache/incubator-mxnet.git
cd incubator-mxnet/
git checkout 1.0.0

现在,我们需要配置 MXNet 构建。您应该编辑 make/config.mk 文件并设置以下变量,以便在构建中包含 NNPACK 以及之前安装的 dependency。只需复制文件末尾的所有内容。

NNPACK = /home/ubuntu/NNPACK
# the additional link flags you want to add
ADD_LDFLAGS = -L$(NNPACK)/lib/ -lnnpack -lpthreadpool
# the additional compile flags you want to add
ADD_CFLAGS = -I$(NNPACK)/include/ -I$(NNPACK)/deps/pthreadpool/include/

USE_NNPACK=1
USE_BLAS=openblas
USE_OPENCV=1

现在,我们准备构建 MXNet。我们的实例有 36 个 vCPU,让我们来好好利用它们吧。

make -j72

大约四分钟后,构建完成。让我们来安装全新的 MXNet 库及其 Python binding。

sudo apt-get install -y python-dev python-setuptools python-numpy python-pip
cd python
sudo -H pip install --upgrade pip
sudo -H pip install -e .

我们可以在 Python 中导入 MXNet,从而快速检查是否有合适的版本。

Python 2.7.12 (default, Nov 20 2017, 18:23:56)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import mxnet
>>> mxnet.__version__
'1.0.0'

一切准备完毕。可以运行部分基准了。

基准测试

用几张图像进行基准测试并不能让我们就 NNPACK 是否发挥效用得出可靠的判断。不过幸好 MXNet 源代码包含一个基准测试脚本,可以通过以下模型以各种批处理大小提供随机生成的图像:AlexNet、VGG16、Inception-BN、Inception v3、ResNet-50 和 ResNet-152。当然,这里的重点不是执行预测,而只是测算推理时间。

在我们开始之前,需要在脚本中修复一行代码。我们的实例没有安装 GPU (这是关键问题),而且脚本无法正确检测到这一事实。以下是需要在 ~/incubator-mxnet/example/image-classification/benchmark_score.py 中做出的修改。执行到这里时,让我们来添加其他批处理大小。

#devs = [mx.gpu(0)] if len(get_gpus()) > 0 else []
devs = []
devs.append(mx.cpu())
batch_sizes = [1, 2, 4, 8, 16, 32, 64, 128, 256]

可以运行部分基准了。我们对 NNPACK 使用八个线程,这是最大的推荐值。

cd ~/incubator-mxnet/example/image-classification/
export MXNET_CPU_NNPACK_NTHREADS=8
python benchmark_score.py

作为参考,我也在运行 vanilla MXNet 1.0 的相同实例上运行了相同的脚本。以下图表显示了每秒图像数量与批处理大小的关系。您肯定可以猜测得到,每秒的图像数量越多越好。

您可以看到,NNPACK 为 AlexNet、VGG 和 Inception-BN 的加速非常明显,尤其是单个图像推理 (速度提高了 4 倍之多)。

注意:由于本文讨论范围以外的原因,Inception v3 和 ResNet 没有加速,所以我没有提供这些网络的图表。


结论

希望您能够喜欢这篇文章,也期待您的反馈。如需了解有关深度学习和 Apache MXNet 内容的更多信息,请在 MediumTwitter 上关注我。


作者简介

Julien 一直致力于在欧洲、中东和非洲大力传播人工智能和机器学习。他倾尽全力帮助开发人员和企业实现自己的想法。闲暇之余,他反复地徜徉在 JRR Tolkien 的作品之中。