参与:吴攀、蒋思源、李亚洲 深度学习的力量为其在真实世界的应用创造出了巨大的机会。但深度学习的训练往往需要巨大的计算能力,有时候我们却没法(或没钱)去使用强大的服务器或 NVIDIA 的 Jetson 那样的嵌入式加速平台。假如你需要使用一块树莓派开发板为你家的小院子开发一个目标跟踪器呢?换句话说,如果你需要在没有加速器的 ARM CPU 上运行一个 CNN,你该怎么做?德国 BuddyGuard GmbH 的机器学习工程师 Dmytro Prylipko 近日在 LinkedIn 上发表了一篇文章,分享了他在弱硬件上运行深度神经网络的经验方法。
机器学习社区已经在加速神经网络推理上进行了很长一段时间的研究了,也已经出现了大量可能有效的解决方案。在这篇文章中,atv,我将尝试回答一个简单的问题:什么软件库/工具包/框架可以帮助改善我们训练好的模型的推理时间?出于文章篇幅的考虑,这篇文章我不会考虑修改网络架构(尽管这确实是一个好方法,比如 SqeezeNet),而是仅仅探讨那些已经可以在 ARM 设备上投入生产并且提供了 C/C++ 接口(因为我们很少在嵌入式设备上使用 Lua 或 Python)的工具包和软件库。所以在这里我仅仅实验了 Caffe、TensorFlow 和 MXNet。 我们可以做什么 要加速你的计算,我们有两个主要的大方向:1)修改模型;2)加速框架。当然,也可能是将这两者结合起来(而且确实是不错的想法)。前一种方法往往需要使用更低的权重精度(也被称为量化(quantization))和/或权重剪枝(weights pruning)。剪枝背后的思想是深度学习模型中的重要参数化冗余,而低精度方法(为浮点数使用了定点或动态定点表示)则利用了这样一个事实——即推理过程并不需要高精度:因为运算的线性本质和非线性的动态范围压缩(dynamic range compression),量化误差(quantization errors)往往倾向于亚线性地(sub-linearly)传播,而不会引起数值不稳定性(Vanhoucke, V., Senior, A., & Mao, M. (2011). Improving the speed of neural networks on CPUs)。此外,我们甚至可以使用低精度乘法来训练模型。结合 SIMD 指令(比如 SSE3),参数量化可以实现非常有效的计算加速。但是目前我们还很难找到同时使用了这两者的解决方案。比如 Ristretto 可以执行自动量化,但它却并没有利用其来降低计算成本。TensorFlow 也可以执行量化,但其推理时间实际上却增加了 5 到 20 倍,因为其向图(graph)中还引入了辅助量化/去量化节点(auxiliary quantize/dequantize nodes)。所以,如果空间上的考虑很重要,那么实际上我们可以将量化仅仅看作是一种压缩网络权重的方法。至少对于当前的状态而言,我们可以这样考虑。 另一方面,我们也有用于框架的加速执行时间(execution time)的方法,atv直播,而不会影响到模型参数。这些方法基本上都是试图优化矩阵之间的乘法(GEMM)的通用计算技巧,并因此会同时影响卷积层(其计算通常是 im2col + GEMM)和全连接层。除此之外是 NNPACK:一个用于深度学习框架的加速包。这个加速包还曾得到过 Yann LeCun 的推荐!就我所知,NNPACK 使用了 FFT 来将时间域中的卷积运算替换成了频域中的乘法计算。 另一个方法是将网络定义和权重翻译成针对目标进行优化过的代码,而不是将它们运行在同样一个框架内。这种方法的典型案例是 TensorRT。还有 CaffePresso 可以将 Caffe prototxt 翻译成针对各种不同后端的更低级的规格。但是,TensorRT 的运行需要 CUDA,而且只能在 NVIDIA GPU 上使用,而 CaffePresso 也需要某种硬件加速器(DSP、FPGA 或 NoC),所以这两种都不适合用于我的测试硬件——树莓派。 相关链接: Ristretto:?page_id=621 NNPACK: TensorRT: CaffePresso: 调测配置 当谨慎地评估现存的解决办法后,我发现下列方法能够加速当前流行的可用模型的推理: 如果你的构架使用了 OpenBLAS,你可以尝试其为深度学习进行过优化的分支: NNPACK 能和其他一些框架(包括 Torch、Caffe 和 MXNet)联合使用: 当在树莓派上使用 TensorFlow 时,你可以使用 NEON 指令集提供一些 optimization flags:#raspberry-pi 通过这些,我能列出以下调测配置: 带有 OpenBLAS 主分支(master branch)的 Caffe 作为后端(caffe-openblas) 带有 OpenBLAS 的深度学习优化分支(caffe-openblas-dl)的 Caffe 使用 OPTFLAGS="-Os" (tf-vanilla) 编译的 TensorFlow 使用 OPTFLAGS="-Os -mfpu=neon-vfpv4 -funsafe-math-optimizations -ftree-vectorize" (tf-neon-vfpv4) 编译的 TensorFlow 带有用于线性代数计算的 OpenBLAS (mxnet-openblas) 的 Vanilla MXNet 带有 OpenBLAS 的深度学习优化分支 (mxnet-openblas-dl) 的 MXNet (责任编辑:本港台直播) |