docs/demo_guides/android_nnapi.md
Paddle Lite 已支持 Android NNAPI 的预测部署。 其接入原理是加载并分析 Paddle 模型,将 Paddle 算子先转为统一的 NNAdapter 标准算子,再通过 Android NNAPI 进行网络构建,在线生成并执行模型。 需要注意由于不同 SoC 芯片对 Android NNAPI 的支持程度不同,其底层各个计算 IP(CPU、GPU、DSP、NPU 等)对 Android NNAPI 的支持也不同,性能也会有较大区别。 用户可以在运行日志中,搜索关键字『Available devices:』来查看当前 SoC 对 Android NNAPI 的支持情况。
测试环境
编译环境
硬件环境
测试方法
paddle::lite_api::PowerMode CPU_POWER_MODE 设置为 paddle::lite_api::PowerMode::LITE_POWER_HIGH测试结果
| 模型 | |||
|---|---|---|---|
| 骁龙865(ms) | Kirin990-5G(ms) | 紫光展锐T820(ms) | |
| mobilenet_v1_int8_224_per_layer | 10.109 | 47.903 | 7.371 |
| resnet50_int8_224_per_layer | 18.622 | 354.566 | 12.156 |
| ssd_mobilenet_v1_relu_voc_int8_300_per_layer | 23.214 | 68.312 | 17.368 |
| mobilenet_v1_fp32_224 | 12.250 | 3.563 | 20.699 |
| resnet50_fp32_224 | 44.903 | 8.762 | 95.993 |
| ssd_mobilenet_v1_relu_voc_fp32_300 | 23.112 | 8.647 | 36.312 |
您可以查阅 NNAdapter 算子支持列表获得各算子在不同新硬件上的最新支持信息。
下载 Paddle Lite 通用示例程序 PaddleLite-generic-demo.tar.gz ,解压后目录主体结构如下:
- PaddleLite-generic-demo
- image_classification_demo
- assets
- configs
- imagenet_224.txt # config 文件
- synset_words.txt # 1000 分类 label 文件
- datasets
- test # dataset
- inputs
- tabby_cat.jpg # 输入图片
- outputs
- tabby_cat.jpg # 输出图片
- list.txt # 图片清单
- shell
- CMakeLists.txt # 示例程序 CMake 脚本
- build.android.arm64-v8a # arm64-v8a 编译工作目录
- demo # 已编译好的,适用于 amd64-v8a 的示例程序
- build.android.armeabi-v7a # armeabi-v7a 编译工作目录
- demo # 已编译好的,适用于 arm64 的示例程序
...
...
- demo.cc # 示例程序源码
- build.sh # 示例程序编译脚本
- run_with_adb.sh # 示例程序 adb 运行脚本
— run_with_ssh.sh # 示例程序 ssh 运行脚本
- run.sh # 示例程序运行脚本
- libs
- PaddleLite
- android
- armeabi-v7a
- include
- lib
- android_nnapi # NNAdapter 运行时库、Android NNAPI device HAL 库
- libnnadapter.so # NNAdapter 运行时库
- libandroid_nnapi.so # NNAdapter device HAL 库
- libpaddle_full_api_shared.so # 预编译 Paddle Lite full api 库
- libpaddle_light_api_shared.so # 预编译 Paddle Lite light api 库
...
- OpenCV # OpenCV 预编译库
Android shell 端的示例程序
按照以下命令分别运行转换后的 ARM CPU 模型和 Android NNAPI 模型,比较它们的性能和结果;
注意:
1)`run_with_adb.sh` 不能在 Docker 环境执行,否则可能无法找到设备,也不能在设备上运行。
2)`run_with_ssh.sh` 不能在设备上运行,且执行前需要配置目标设备的 IP 地址、SSH 账号和密码。
3)`build.sh` 根据入参生成针对不同操作系统、体系结构的二进制程序,需查阅注释信息配置正确的参数值。
4)`run_with_adb.sh` 入参包括模型名称、操作系统、体系结构、目标设备、设备序列号等,需查阅注释信息配置正确的参数值。
5)`run_with_ssh.sh` 入参包括模型名称、操作系统、体系结构、目标设备、ip地址、用户名、用户密码等,需查阅注释信息配置正确的参数值。
6)下述命令行示例中涉及的设备序列号等均为示例环境,请用户根据自身实际设备环境修改。
在 ARM CPU 上运行 mobilenetv1 全量化模型
$ cd PaddleLite-generic-demo/image_classification_demo/shell
$ ./run_with_adb.sh mobilenet_v1_int8_224_per_layer imagenet_224.txt test android armeabi-v7a cpu d3869b25
Top1 Egyptian cat - 0.502124
Top2 tabby, tabby cat - 0.413927
Top3 tiger cat - 0.071703
Top4 lynx, catamount - 0.008436
Top5 cougar, puma, catamount, mountain lion, painter, panther, Felis concolor - 0.000563
Preprocess time: 4.948000 ms, avg 4.948000 ms, max 4.948000 ms, min 4.948000 ms
Prediction time: 34.962000 ms, avg 34.962000 ms, max 34.962000 ms, min 34.962000 ms
Postprocess time: 4.715000 ms, avg 4.715000 ms, max 4.715000 ms, min 4.715000 ms
基于 Android NNAPI 上运行 mobilenetv1 全量化模型
$ cd PaddleLite-generic-demo/image_classification_demo/shell
$ ./run_with_adb.sh mobilenet_v1_int8_224_per_layer imagenet_224.txt test android armeabi-v7a android_nnapi d3869b25
Top1 Egyptian cat - 0.497230
Top2 tabby, tabby cat - 0.403634
Top3 tiger cat - 0.076047
Top4 lynx, catamount - 0.005850
Top5 great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias - 0.000000
Preprocess time: 5.271000 ms, avg 5.271000 ms, max 5.271000 ms, min 5.271000 ms
Prediction time: 6.877000 ms, avg 6.877000 ms, max 6.877000 ms, min 6.877000 ms
Postprocess time: 5.083000 ms, avg 5.083000 ms, max 5.083000 ms, min 5.083000 ms
如果需要更改测试图片,可将图片拷贝到 PaddleLite-generic-demo/image_classification_demo/assets/datasets/test/inputs 目录下,同时将图片文件名添加到 PaddleLite-generic-demo/image_classification_demo/assets/datasets/test/list.txt 中;
重新编译示例程序:
注意:
1)请根据 `buid.sh` 配置正确的参数值。
2)需在 Docker 环境中编译。
For arm64-v8a
$ ./build.sh android arm64-v8a
For armeabi-v7a
$ ./build.sh android armeabi-v7a
通过 Paddle 训练,或 X2Paddle 转换得到 MobileNetv1 foat32 模型 mobilenet_v1_fp32_224_fluid ;
如果需要使用量化模型,则参考模型量化使用 PaddleSlim 对 float32 模型进行量化(注意:由于 DSP 只支持量化 OP,在启动量化脚本时请注意相关参数的设置),最终得到全量化MobileNetV1 模型 mobilenet_v1_int8_224_per_layer ;
参考模型转化方法,利用 opt 工具转换生成 Android NNAPI 模型,仅需要将 valid_targets 设置为 andriod_nnapi, arm 即可。
注意:
1)PaddleLite-generic-demo 中已经包含了类似 opt 工具优化生成 nb 模型的功能。
$ cd PaddleLite-generic-demo/image_classification_demo/assets/models
$ ./opt --model_dir=mobilenet_v1_int8_224_per_layer \
--optimize_out_type=naive_buffer \
--optimize_out=opt_model \
--valid_targets=android_nnapi,arm
注意:opt 生成的模型只是标记了 Android NNAPI 支持的 Paddle 算子,并没有真正生成 Android NNAPI 模型,只有在执行时才会将标记的 Paddle 算子转成 Android NNAPI 调用实现组网,最终生成并执行模型。
下载 Paddle Lite 源码;
$ git clone https://github.com/PaddlePaddle/Paddle-Lite.git
$ cd Paddle-Lite
$ git checkout <release-version-tag>
编译并生成 PaddleLite+Android NNAPI for armv8 and armv7 的部署库
For armv8
tiny_publish 编译方式
$ ./lite/tools/build_android.sh --android_stl=c++_shared --with_extra=ON --with_cv=ON --with_log=ON --with_exception=ON --with_nnadapter=ON --nnadapter_with_android_nnapi=ON
full_publish 编译方式
$ ./lite/tools/build_android.sh --android_stl=c++_shared --with_extra=ON --with_cv=ON --with_log=ON --with_exception=ON --with_nnadapter=ON --nnadapter_with_android_nnapi=ON full_publish
替换头文件和库
替换 include 目录
$ cp -rf build.lite.android.armv8.gcc/inference_lite_lib.android.armv8.nnadapter/cxx/include/ PaddleLite-generic-demo/libs/PaddleLite/android/arm64-v8a/include/
替换 NNAdapter 运行时库
$ cp -rf build.lite.android.armv8.gcc/inference_lite_lib.android.armv8.nnadapter/cxx/lib/libnnadapter.so PaddleLite-generic-demo/libs/PaddleLite/android/arm64-v8a/lib/android_nnapi/
替换 NNAdapter device HAL 库
$ cp -rf build.lite.android.armv8.gcc/inference_lite_lib.android.armv8.nnadapter/cxx/lib/libandroid_nnapi.so PaddleLite-generic-demo/libs/PaddleLite/android/arm64-v8a/lib/android_nnapi/
替换 libpaddle_light_api_shared.so
$ cp -rf build.lite.android.armv8.gcc/inference_lite_lib.android.armv8.nnadapter/cxx/lib/libpaddle_light_api_shared.so PaddleLite-generic-demo/libs/PaddleLite/android/arm64-v8a/lib/
替换 libpaddle_full_api_shared.so (仅在 full_publish 编译方式下)
$ cp -rf build.lite.android.armv8.gcc/inference_lite_lib.android.armv8.nnadapter/cxx/lib/libpaddle_full_api_shared.so PaddleLite-generic-demo/libs/PaddleLite/android/arm64-v8a/lib/
For armv7
tiny_publis h编译方式
$ ./lite/tools/build_android.sh --arch=armv7 --toolchain=clang --android_stl=c++_shared --with_extra=ON --with_cv=ON --with_log=ON --with_exception=ON --with_nnadapter=ON --nnadapter_with_android_nnapi=ON
full_publish 编译方式
$ ./lite/tools/build_android.sh --arch=armv7 --toolchain=clang --android_stl=c++_shared --with_extra=ON --with_cv=ON --with_log=ON --with_exception=ON --with_nnadapter=ON --nnadapter_with_android_nnapi=ON full_publish
替换头文件和库
替换 include 目录
$ cp -rf build.lite.android.armv7.gcc/inference_lite_lib.android.armv7.nnadapter/cxx/include/ PaddleLite-generic-demo/libs/PaddleLite/android/armeabi-v7a/include/
替换 NNAdapter 运行时库
$ cp -rf build.lite.android.armv7.gcc/inference_lite_lib.android.armv7.nnadapter/cxx/lib/libnnadapter.so PaddleLite-generic-demo/libs/PaddleLite/android/armeabi-v7a/lib/android_nnapi/
替换 NNAdapter device HAL 库
$ cp -rf build.lite.android.armv7.gcc/inference_lite_lib.android.armv7.nnadapter/cxx/lib/libandroid_nnapi.so PaddleLite-generic-demo/libs/PaddleLite/android/armeabi-v7a/lib/android_nnapi/
替换 libpaddle_light_api_shared.so
$ cp -rf build.lite.android.armv7.gcc/inference_lite_lib.android.armv7.nnadapter/cxx/lib/libpaddle_light_api_shared.so PaddleLite-generic-demo/libs/PaddleLite/android/armeabi-v7a/lib/
替换 libpaddle_full_api_shared.so (仅在 full_publish 编译方式下)
$ cp -rf build.lite.android.armv7.gcc/inference_lite_lib.android.armv7.nnadapter/cxx/lib/libpaddle_full_api_shared.so PaddleLite-generic-demo/libs/PaddleLite/android/armeabi-v7a/lib/
替换头文件后需要重新编译示例程序