PaddleLite使用OpenCL预测部署

Lite支持在Android系统上运行基于OpenCL的程序,目前支持Ubuntu环境下armv8、armv7的交叉编译。

编译

编译环境

  1. Docker 容器环境;
  2. Linux(推荐 Ubuntu 16.04)环境。

详见 源码编译指南-环境准备 章节。

编译选项

参数介绍
—arm_os代表目标操作系统目前仅支持且默认为android
—arm_abi代表体系结构类型,支持armv8和armv7默认为armv8即arm64-v8a;armv7即armeabi-v7a
—arm_lang代表编译目标文件所使用的编译器默认为gcc,支持 gcc和clang两种

编译Paddle-Lite OpenCL库范例

注:以android-armv8-opencl的目标、Docker容器的编译开发环境为例,CMake3.10,android-ndk-r17c位于/opt/目录下。

  1. # 假设当前位于处于Lite源码根目录下
  2. # 导入NDK_ROOT变量,注意检查您的安装目录若与本示例不同
  3. export NDK_ROOT=/opt/android-ndk-r17c
  4. # 删除上一次CMake自动生成的.h文件
  5. rm ./lite/api/paddle_use_kernels.h
  6. rm ./lite/api/paddle_use_ops.h
  7. # 根据指定编译参数编译
  8. ./lite/tools/ci_build.sh \
  9. --arm_os=android \
  10. --arm_abi=armv8 \
  11. --arm_lang=gcc \
  12. build_test_arm_opencl

编译产物位于build.lite.android.armv8.gcc.opencl下的inference_lite_lib.android.armv8.opencl文件夹内,这里仅罗列关键产物:

  • cxx:该目录是编译目标的C++的头文件和库文件;
  • demo:该目录包含了两个demo,用来调用使用libpaddle_api_full_bundled.alibpaddle_api_light_bundled.a,分别对应mobile_fullmobile_light文件夹。编译对应的demo仅需在mobile_fullmobile_light
    • mobile_full:使用cxx config,可直接加载fluid模型,若使用OpenCL需要在mobilenetv1_full_api.cc代码里开启DEMO_USE_OPENCL的宏,详细见代码注释;
    • mobile_light:使用mobile config,只能加载model_optimize_tool优化过的模型;
  • opencl:该目录存放opencl实现的相关kernel。
  1. .
  2. |-- cxx
  3. | |-- include
  4. | | |-- paddle_api.h
  5. | | |-- paddle_image_preprocess.h
  6. | | |-- paddle_lite_factory_helper.h
  7. | | |-- paddle_place.h
  8. | | |-- paddle_use_kernels.h
  9. | | |-- paddle_use_ops.h
  10. | | `-- paddle_use_passes.h
  11. | `-- lib
  12. | |-- libpaddle_api_full_bundled.a
  13. | |-- libpaddle_api_light_bundled.a
  14. | |-- libpaddle_full_api_shared.so
  15. | `-- libpaddle_light_api_shared.so
  16. |-- demo
  17. | `-- cxx
  18. | |-- Makefile.def
  19. | |-- README.md
  20. | |-- include
  21. | | |-- paddle_api.h
  22. | | |-- paddle_lite_factory_helper.h
  23. | | |-- paddle_place.h
  24. | | |-- paddle_use_kernels.h
  25. | | |-- paddle_use_ops.h
  26. | | `-- paddle_use_passes.h
  27. | |-- mobile_full
  28. | | |-- Makefile
  29. | | `-- mobilenetv1_full_api.cc
  30. | `-- mobile_light
  31. | |-- Makefile
  32. | `-- mobilenetv1_light_api.cc
  33. `-- opencl
  34. `-- cl_kernel
  35. |-- buffer
  36. | |-- depthwise_conv2d_kernel.cl
  37. | |-- elementwise_add_kernel.cl
  38. | |-- fc_kernel.cl
  39. | |-- im2col_kernel.cl
  40. | |-- layout_kernel.cl
  41. | |-- mat_mul_kernel.cl
  42. | |-- pool_kernel.cl
  43. | `-- relu_kernel.cl
  44. |-- cl_common.h
  45. `-- image
  46. |-- channel_add_kernel.cl
  47. |-- elementwise_add_kernel.cl
  48. |-- pool_kernel.cl
  49. `-- relu_kernel.cl

调用libpaddle_api_full_bundled.alibpaddle_api_light_bundled.a见下一部分运行示例。

运行示例

下面以android、ARMv8、gcc的环境为例,介绍3个示例,分别如何在手机上执行基于OpenCL的ARM GPU推理过程。

注意: 以下命令均在Lite源码根目录下运行。在3个示例前,下面这段命令都先要执行用来准备环境:

  1. # 在/data/local/tmp目录下创建OpenCL文件目录
  2. adb shell mkdir -p /data/local/tmp/opencl
  3. adb shell mkdir -p /data/local/tmp/opencl/cl_kernel/buffer
  4. adb shell mkdir -p /data/local/tmp/opencl/cl_kernel/image
  5. # 将OpenCL的kernels文件推送到/data/local/tmp/opencl目录下
  6. adb push lite/backends/opencl/cl_kernel/cl_common.h /data/local/tmp/opencl/cl_kernel/
  7. adb push lite/backends/opencl/cl_kernel/buffer/* /data/local/tmp/opencl/cl_kernel/buffer/
  8. adb push lite/backends/opencl/cl_kernel/image/* /data/local/tmp/opencl/cl_kernel/image/

运行示例1: 编译产物demo示例

  1. ######################################################################
  2. # 编译mobile_full的demo #
  3. ######################################################################
  4. # 步骤: #
  5. # 0.确保编译Paddle-Lite时编译了OpenCL; #
  6. # 1.编辑`mobilenetv1_full_api.cc`代码, 开启`DEMO_USE_OPENCL`的宏; #
  7. # 2.在产物目录`demo/cxx/mobile_full`下编译`mobile_full`的demo; #
  8. # 3.上传demo, 模型, opencl kernel文件到手机; #
  9. # 4.运行demo得到预期结果. #
  10. ######################################################################
  11. adb shell mkdir /data/local/tmp/opencl/mobilenet_v1
  12. chmod +x ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_full/mobilenetv1_full_api
  13. adb push ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_full/mobilenetv1_full_api /data/local/tmp/opencl/
  14. adb push ./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1
  15. # use mobile_full run mobilenet_v1
  16. # `GLOG_v` is log level
  17. adb shell "export GLOG_v=0; \
  18. /data/local/tmp/opencl/mobilenetv1_full_api \
  19. --model_dir=/data/local/tmp/opencl/mobilenet_v1 \
  20. --optimized_model_dir=/data/local/tmp/opencl/full_api_opt_model"
  21. ######################################################################
  22. # 编译mobile_light的demo #
  23. ######################################################################
  24. # 步骤: #
  25. # 0.确保编译Paddle-Lite时编译了OpenCL; #
  26. # 1.编译model_optimize_tool并对模型优化, `targets`参数为`opencl`; #
  27. # 2.在产物目录`demo/cxx/mobile_light`下编译`mobile_light`的demo; #
  28. # 3.上传demo, 模型, opencl kernel文件到手机; #
  29. # 4.运行demo得到预期结果. #
  30. ######################################################################
  31. # use model_optimize_tool to optimize model
  32. ./build.model_optimize_tool/lite/api/model_optimize_tool \
  33. --model_dir=./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/ \
  34. --optimize_out_type=naive_buffer \
  35. --optimize_out=./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/ \
  36. --valid_targets=opencl
  37. adb shell mkdir /data/local/tmp/opencl/mobilenet_v1
  38. chmod +x ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_light/mobilenetv1_light_api
  39. adb push ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_light/mobilenetv1_light_api /data/local/tmp/opencl/
  40. adb push ./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1
  41. # use mobile_light run mobilenet_v1
  42. adb shell "export GLOG_v=5; \
  43. /data/local/tmp/opencl/mobilenetv1_light_api \
  44. --model_dir=/data/local/tmp/opencl/"

运行示例2: test_mobilenetv1单元测试

  • 运行文件准备
  1. # 将mobilenet_v1的模型文件推送到/data/local/tmp/opencl目录下
  2. adb shell mkdir -p /data/local/tmp/opencl/mobilenet_v1
  3. adb push build.lite.android.armv8.gcc.opencl/third_party/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1/
  4. # 将OpenCL单元测试程序test_mobilenetv1,推送到/data/local/tmp/opencl目录下
  5. adb push build.lite.android.armv8.gcc.opencl/lite/api/test_mobilenetv1 /data/local/tmp/opencl
  • 执行OpenCL推理过程

使用如下命令运行OpenCL程序。其中:

  • --cl_path指定了OpenCL的kernels文件即cl_kernel所在目录;
  • --modle_dir指定了模型文件所在目录。
  1. adb shell chmod +x /data/local/tmp/opencl/test_mobilenetv1
  2. adb shell /data/local/tmp/opencl/test_mobilenetv1 \
  3. --cl_path=/data/local/tmp/opencl \
  4. --model_dir=/data/local/tmp/opencl/mobilenet_v1 \
  5. --warmup=1 \
  6. --repeats=1

注意: 因为权重参数均会在Op Kernel第一次运行时进行加载,所以第一次的执行时间会略长。一般将warmup的值设为1,repeats值设为多次。

运行示例3: test_layout_opencl单元测试

  • 运行文件准备
  1. # 将OpenCL单元测试程序test_layout_opencl,推送到/data/local/tmp/opencl目录下
  2. adb push build.lite.android.armv8.gcc.opencl/lite/kernels/opencl/test_layout_opencl /data/local/tmp/opencl/

OpenCL推理过程**

  1. adb shell chmod +x /data/local/tmp/opencl/test_layout_opencl
  2. adb shell /data/local/tmp/opencl/test_layout_opencl

如何在Code中使用

见运行示例1的demo代码:

  1. ./lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc;
  2. ./lite/demo/cxx/mobile_full/mobilenetv1_full_api.cc.

注:这里给出的链接会跳转到线上最新develop分支的代码,很可能与您本地的代码存在差异,建议参考自己本地位于lite/demo/cxx/目录的代码,查看如何使用。

NOTE: 对OpenCL的支持还在持续开发中。