ArmNN是一个性能十分强劲的inference框架,本文主要分享下对ArmNN的编译。
首发:https://zhuanlan.zhihu.com/p/71369040
作者:张新栋
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文件)。
- 编译Boost
先下载对应版本的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.bz2
tar 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'
- 最后
至此,我们完成了ArmNN的编译。ArmNN是一个性能十分强劲的inference框架,我们在后续的专栏中,会持续给大家更新ArmNN的使用方法及教程,欢迎大家留言讨论、关注专栏。谢谢大家!
专注嵌入式端的AI算法实现,欢迎关注作者微信公众号和知乎嵌入式AI算法实现专栏。
更多嵌入式AI相关的技术文章请关注极术嵌入式AI专栏。