YOLO:NNPACK评估 - zhonglong/TPV GitHub Wiki

NNPACK导入

NNPACK用于神经网络加速,基于多核并行计算和SIMD(单指令多数据流)。以优化Darknet为例,darknet-nnpack运行在树莓派3上,按README.md的介绍,先在树莓派下载源代码验证,再考虑移植到Android平台。

Darknet with NNPACK
https://github.com/digitalbrain79/darknet-nnpack
NNPACK for Darknet
https://github.com/digitalbrain79/NNPACK-darknet

依赖库包括:pthreadpool,FXdiv,FP16和psimd,下载到NNPACK-darknet的deps目录下。除pthreadpool外,其余三个库只使用头文件。

pthread-based thread pool for C/C++
https://github.com/Maratyszcza/pthreadpool
C99/C++ header-only library for division via fixed-point multiplication by inverse
https://github.com/Maratyszcza/FXdiv
Conversion to/from half-precision floating point formats
https://github.com/Maratyszcza/FP16
Portable 128-bit SIMD intrinsics
https://github.com/Maratyszcza/psimd

nnpack和pthreadpool

根据darknet-nnpack/Makefile可知,编译带NNPACK的Darknet依赖nnpack和pthreadpool两个库,这两个库都是通过编译NNPACK-darknet源码(含deps)得到的。

ifeq ($(NNPACK), 1)
COMMON+= -DNNPACK
CFLAGS+= -DNNPACK
LDFLAGS+= -lnnpack -lpthreadpool
endif

最初的设想是采用树莓派上编译好的库,但树莓派上编译生成的是.a文件(静态库),无法直接用于Android。

根据NNPACK-darknet的描述,和NNPACK-darknet/jni/Android.mk可知,NNPACK-darknet支持Android交叉编译。

Cross-compilation for Android
- Download and setup Android NDK
- Add ndk-build to PATH variable
- Navigate to NNPACK directory and setup dependencies (confu setup)
- Build NNPACK with ndk-build build system.

因为本机没有配置ndk-build,所以还是决定以源码方式导入。

DarknetDemoInAndroid导入NNPACK

  1. 将darknet-nnpack的include和src目录同步到DarknetDemoInAndroid/app/src/main/cpp/darknet下;

  2. 根据NNPACK-darknet/jni/Android.mk,将NNPACK-darknet,pthreadpool,FXdiv,FP16和psimd五个工程的源代码拷贝到DarknetDemoInAndroid/app/src/main/cpp/nnpack下;

  3. 根据根据NNPACK-darknet/jni/Android.mk,修改DarknetDemoInAndroid/app/CMakeLists.txt,将NNPACK源代码加入编译;

  4. 修改build.gradle和CMakeLists.txt,启用NNPACK和clang编译器,并禁用OpenMP;

导入NNPACK后,性能有明显提升,在X588识别时间从4秒左右减少到1秒左右,在锤子M1L识别时间从1.2秒以内减少到0.6秒以内。

NNPACK技术分析

NNPACK主要采用两种方式来提升性能: 一是多线程,采用pthread线程库; 二是算法优化,卷积层(convolutional_layer)正向传播(forward)改用nnp_convolution_inference函数; 其余如NEON指令向量化,在darknet-nnpack并未直接使用。

因NNPACK也是BLAS加速库,不再使用Darknet的gemm函数,无法与功能相同的OpenBLAS同时使用。

NDK Crash定位

NDK Crash有两种定位方式:addr2line和ndk-stack,Android Studio下采用ndk-trace会比较简单。 先将NDK目录加入环境变量,再切换到工程目录,以TpvYolo为例,输入:

adb logcat | ndk-stack -sym TpvYolo\app\build\intermediates\cmake\release\obj\arm64-v8a\libdarknetlib.so

请参考:

Android studio下使用ndk-stack定位crash
https://blog.csdn.net/a568478312/article/details/78182422
⚠️ **GitHub.com Fallback** ⚠️