ArmNN神经网络技术分析

ArmNN神经网络技术分析

ArmNN 使用介绍

一.   概述

将带领各位如何在 ArmNN 的框架上,使用不同的硬件处理器( CPU 或 NPU 的切换 )。如下图,文章架构图所示 !! 此架构图隶属于 i.MX8M Plus 的方案中,并属于机器学习内的推理引擎(Inference Engine) 的 ArmNN 部分。

 “ArmNN 使用介绍”

ArmNN -文章架构示意图 

二.  ArmNN 介绍

ArmNN 是一套开源的机器学习推理引擎框架,由 ARM 与 Linaro 主导开发的人工智能计划,能够提供用户更简单、轻松、快速的机器学习体验。特别的是 ArmNN 并非有自己的推理引擎,而是可以运行多种深度学习模块框架的 推理引擎(inference engine) 或 委托器(delegates) ,像是 Caffe, TensorFlow, TensorFlow Lite, 以及 ONNX 。 除此之外,亦提供 CPU / GPU/ NPU 等硬件加速资源,并可以搭配 C++ 或 Python 语言进行推理 !! 能够给予 Arm 的硬件更棒的加速体验 !! 

 ArmNN 后端推理框架图 

如下图所示,首先由各家模块 解译(parser) 完成后,将托付给 Graph builder 与 Runtime Optimizer 至各硬设备进行优化,而后续则有三种处理方式 ; 第一种左侧路线,就是纯 CPU 的运算。第二种就是中间路线,利用 ARM Compute Library 与 ARM Neon 核心作多线程优化进行推理。而第三种则是右侧路线,委托给神经网络推理引擎(NNRT),并透过 OVXLIB 与 OpenVX driver 来启动 GPU 或 NPU 进行硬件加速来完成推理!!

ArmNN 后端推理框架图 

下列提供关于 ArmNN 之 Caffe, TensorFlow, TensorFlow Lite, ONNX 等神经网络框架的推理范例,如下列表格所示。

若欲查看更多范例,请查看 i.MX Machine Learning User's Guide.pdf 的 ArmNN 章节。

  原厂提供范例 (Caffe) : 

 

 

 

直接进入开发板的 /usr/bin/armnn-21.02 底下,找到相关执行档(xxx-Armnn),操作下列指令即可使用!!

$ --data-dir=data --model-dir=models --compute=CpuAcc/VsiNpu/CpuRef

--data-dir : 数据路径
--model-dir : 模块路径
--compute : CpuRef 为不启用 CPU 加速 、CpuAcc 为使用 NEON Backend 启用 CPU 加速 、 VsiNpu 为使用 NPU 或是 GPU 加速运算。

若欲查看代码编译方式,请至 i.MX Machine Learning User's Guide.pdf 的 ArmNN 章节。

三.  ArmNN 范例实现

1. Object Classification DEMO (TensorFlow Lite) 

说明 :  此范例使用 Arm NN - TensorFlow Lite神经网络推理框架与 MobileNet 模型进行分类对象。

实现步骤 :

 (1) 于开发板系统中,建立 ArmNN 文件夹

$ cd && mkdir ArmNN
$ cd ~/ArmNN && mkdir models
$ cd ~/ArmNN && mkdir data

 (2) 将测试图片与新的模块传送至开发板系统

$ scp mobilenet_v1_1.0_224_quant.tflite root@xx.xx.xx.xx: ~/ArmNN/models
$ scp Dog.jpg root@xx.xx.xx.xx: ~/ArmNN/data
$ scp Cat.jpg root@xx.xx.xx.xx: ~/ArmNN/data
$ scp shark.jpg root@xx.xx.xx.xx: ~/ArmNN/data

 (3) 范例之运行 CPU 使用方式

$ /usr/bin/armnn-21.08/TfLiteMobilenetQuantized-Armnn --data-dir=data --model-dir=models --compute=CpuAcc​

 (4) 范例之运行 NPU使用方式

$ /usr/bin/armnn-21.08/TfLiteMobilenetQuantized-Armnn --data-dir=data --model-dir=models --compute=VsiNpu​

运行结果 :

如下图所示,分类结果为 第 209 号标签的黄金猎犬(golden retriever) ,准确率为 78.9 %。
在 ArmNN 框架下,使用 CPU-ACC 运算 TF Lite模块则平均花费 48 ms,NPU 运算花费 3 ms。
*** 此范例会同时测试三张影像( Dog / Cat / Shark.jpg )。

 2. Object Classification DEMO (ONNX) 

说明 :  此范例使用 Arm NN - TensorFlow Lite神经网络推理框架与 MobileNet 模型进行分类对象。

实现步骤 :

 (1) 于开发板系统中,建立 ArmNN 文件夹

$ cd && mkdir ArmNN
$ cd ~/ArmNN && mkdir models
$ cd ~/ArmNN && mkdir data

 (2) 将测试图片与新的模块传送至开发板系统

$ scp mobilenetv2-1.0.onnx root@xx.xx.xx.xx: ~/ArmNN/models
$ scp Dog.jpg root@xx.xx.xx.xx: ~/ArmNN/data
$ scp Cat.jpg root@xx.xx.xx.xx: ~/ArmNN/data
$ scp shark.jpg root@xx.xx.xx.xx: ~/ArmNN/data

 (3) 范例之运行 CPU 使用方式

$ /usr/bin/armnn-21.08/OnnxMobileNet-Armnn --data-dir=data --model-dir=models --compute=CpuAcc

 (4) 范例之运行 NPU使用方式

$ /usr/bin/armnn-21.08/OnnxMobileNet-Armnn --data-dir=data --model-dir=models --compute=VsiNpu

运行结果 :

如下图所示,分类结果为 第 209 号标签的黄金猎犬(golden retriever) ,准确率为 15.54 %。
在 ArmNN 框架下,使用 CPU-ACC 运算 TF Lite模块则平均花费 272 ms,NPU 运算花费 545 ms。
目前 ONNX 的推理引擎与 AI 芯片的底层描述尚未完善故效能较差。
*** 此范例会同时测试三张影像( Dog / Cat / Shark.jpg )。

四.  结语

上述已经介绍了 ArmNN 的使用方式,藉此可以选择 TensorFlow 或是 ONNX 的神经网络框架进行推理。并可任意使用至 CPU / GPU / NPU 等加速运算芯片。在量化后的 MobileNet 最快可达到每帧 3ms 的推理速度 !!

ArmNN如何编译

ArmNN是Arm机构开源的基于Arm嵌入式设备的inference框架,在Arm Cortex-A CPUs、Arm Mali GPUs、Arm Machine Learning processor都可以达到很高的加速效果。不过可惜的是,由于缺乏文档及教程,该框架在国内推广的程度不高,目前Github上star仅有359个。相对于其他竞品inference框架如NCNN、Tengine、Mace、MNN等等,ArmNN的知名度显得很小。不过笔者在项目的多次使用中,发现ArmNN是一个被低估的框架(在Arm设备上的性能几乎都优于目前的前传框架),不亏是Arm家精心调教的SDK,对自家核心的性能调教到了极致。

ArmNN基于Arm的另外一个开源计算引擎ComputeLibrary做后端的核心计算,前端支持多种离线训练框架,如TensorFlow、TFLITE、CAFFE以及ONNX。从功能上来说,几乎实现了与市面上所有离线训练框架无缝对接。而且ArmNN在FP32、FP16及INT8上的加速非常可观,笔者在RK3399上做300x300的Mobilenet-SSD(depth\_multiplier=1.0),效率可达90ms/帧,其余的框架大多在160ms左右徘徊。

笔者后续会在本专栏开源基于ArmNN的Mobilenet-SSD的部署流程及项目代码。接下来,将先跟大家讨论如何编译ArmNN。由于目标平台是RK3399-Android-8.1,将基于android-Arm64-v8a进行编译。下面开始:

 

 下载NDK

笔者使用的版本为NDK-r17c,由于ArmNN使用了一些C++14的新特性,所以老一些的NDK版本在编译的时候会出很多莫名其妙的错误。出于稳妥考虑,建议大家用r17c以上的版本,准备完毕以后,需要配置NDK路径:

export NDK=~/armnn-devenv/toolchains/android-ndk-r17c

接下来制作自己的toolchain编译工具链,

$NDK/build/tools/make_standalone_toolchain.py \  

       --arch arm64 \    

       --api 26 \    

       --stl=libc++\ 

       --install-dir=$HOME/armnn-devenv/toolchains/aarch64-android-r17b

 export PATH=$HOME/armnn-devenv/toolchains/aarch64-android-r17b/bin:$PATH

如果想持久化以上环境变量到系统中,可以写进.bashrc文件中(或macOS的.bash\_profile文件)。

 编译Boot

先下载对应版本的Boost库,

mkdir ~/armnn-devenv/boost 

cd ~/armnn-devenv/boost

wget https://dl.bintray.com/boostorg/release/1.64.0/source/boost_1_64_0.tar.bz2tar xvf boost_1_64_0.tar.bz2

进行编译,

echo "using gcc : arm : aarch64-linux-android-clang++ ;" > $HOME/armnn-devenv/boost/user-config.jam 

cd ~/armnn-devenv/boost/boost_1_64_0

 ./bootstrap.sh --prefix=$HOME/armnn-devenv/boost/install

./b2 install --user-config=$HOME/armnn-devenv/boost/user-config.jam \  

toolset=gcc-arm link=static cxxflags=-fPIC --with-filesystem \  --with-test --with-log --with-program_options -j16

 编译ComputeLibrary

先下载对应版本的ComputeLibrary,

cd ~/armnn-devenv

git clone https://github.com/ARM-software/ComputeLibrary.git

安装scons后(sudo apt-get install scons),进行编译

cd ComputeLibrary

scons arch=arm64-v8a neon=1 opencl=1 embed_kernels=1 extra_cxx_flags="-fPIC" \

  benchmark_tests=0 validation_tests=0 os=android -j16

● 编译谷歌的ProtoBuf

首先仍是下载对应的源码,并切换至对应版本,

mkdir ~/armnn-devenv/google

 cd ~/armnn-devenv/google 

 git clone https://github.com/google/protobuf.git 

 cd protobuf

 git checkout -b v3.5.2 v3.5.2

 

 

需要注意的是,这里需要编译对应PC(笔者为x86)和目标平台(Arm64-v8a)的两个版本。编译过程中依赖cUrl、autoconf、llibtool等,可以通过如下命令安装 sudo apt-get install curl autoconf libtool build-essential g++。下面先编译x86版本的,

 

./autogen.sh 

 mkdir x86_build 

 cd x86_build

 ../configure --prefix=$HOME/armnn-devenv/google/x86_pb_install 

 make install -j16 

 cd ..

随后安装Arm64-v8a版本的,

mkdir arm64_build

 cd arm64_build

 CC=aarch64-linux-android-clang \

   CXX=aarch64-linux-android-clang++ \

   CFLAGS="-fPIE -fPIC" LDFLAGS="-pie -llog" \ 

    ../configure --host=aarch64-linux-android \

   --prefix=$HOME/armnn-devenv/google/arm64_pb_install \

    --with-protoc=$HOME/armnn-devenv/google/x86_pb_install/bin/protoc

make install -j16

 cd ..

● 编译ArmNN

这里采用的frontend为tensorflow,所以需要先下载对应的tensorflow源码,

cd ~/armnn-devenv/google/

git clone https://github.com/tensorflow/tensorflow.git

随后下载ArmNN源码,

cd ~/armnn-devenv/ 

git clone https://github.com/ARM-software/armnn.git

在PC中生成解析tensorflow的protobuf定义(使用x86平台中编译好的protoc),
cd ~/armnn-devenv/google/tensorflow 

 ~/armnn-devenv/armnn/scripts/generate_tensorflow_protobuf.sh \

  $HOME/armnn-devenv/google/tf_pb $HOME/armnn-devenv/google/x86_pb_install

随后编译ArmNN,
mkdir ~/armnn-devenv/armnn/build

cd ~/armnn-devenv/armnn/build 

CXX=aarch64-linux-android-clang++                                                                         \

CC=aarch64-linux-android-clang                                                                                \

CXX_FLAGS="-fPIE -fPIC"                                                                                            \

cmake ..                                                                                                                     \

  -DCMAKE_SYSTEM_NAME=Android                                                                          \

  -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a                                                             \

 -DCMAKE_ANDROID_STANDALONE_TOOLCHAIN=$HOME/armnn-devenv/toolchains/aarch64-android-r17c/ \ -DCMAKE_EXE_LINKER_FLAGS="-pie -llog"                           \

   -DARMCOMPUTE_ROOT=$HOME/armnn-devenv/ComputeLibrary/                          \

   -DARMCOMPUTE_BUILD_DIR=$HOME/armnn-devenv/ComputeLibrary/build           \

   -DBOOST_ROOT=$HOME/armnn-devenv/boost_1_64_0/install/                               \

   -DARMCOMPUTENEON=1 -DARMCOMPUTECL=1                                                    \

   -DTF_GENERATED_SOURCES=$HOME/armnn-devenv/google/tf_pb/                       \     -DBUILD_TF_PARSER=1                                                                                            \

   -DPROTOBUF_ROOT=$HOME/armnn-devenv/google/arm64_pb_install/                   \

   -DBUILD_TESTS=1                                                                                                   \

   -DTHIRD_PARTY_INCLUDE_DIRS=$HOME/armnn-devenv/armnn/third-party/stb      \

  -DCMAKE_BUILD_TYPE=Release -DBUILD_ARMNN_QUANTIZER=1 -DBUILD_ARMNN_SERIALIZER=1 

make -j16

编译完以后,可以将库和测试用例推到目标平台中进行测试,
adb push libarmnnTfParser.so /data/local/tmp/

adb push libarmnn.so /data/local/tmp/ 

adb push UnitTests /data/local/tmp/ 

adb push $NDK/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so /data/local/tmp/ 

adb push $HOME/armnn-devenv/google/arm64_pb_install/lib/libprotobuf.so /data/local/tmp/libprotobuf.so.15.0.1 

adb shell 'ln -s libprotobuf.so.15.0.1 /data/local/tmp/libprotobuf.so.15' 

adb shell 'ln -s libprotobuf.so.15.0.1 /data/local/tmp/libprotobuf.so'

执行测试用例,
adb shell 'LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/UnitTests'

 

参考文献链接

https://www.wpgdadatong.com/blog/detail/45902

https://mp.weixin.qq.com/s/gPMfN6chEO37aOPRoKUsNg

posted @ 2023-07-23 05:04  吴建明wujianming  阅读(414)  评论(0编辑  收藏  举报