opencl.md 9.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
# Lite基于OpenCL的ARM GPU预测

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/`目录下。

```bash
# 假设当前位于处于Lite源码根目录下

# 导入NDK_ROOT变量,注意检查您的安装目录若与本示例不同
export NDK_ROOT=/opt/android-ndk-r17c

# 删除上一次CMake自动生成的.h文件
rm ./lite/api/paddle_use_kernels.h
rm ./lite/api/paddle_use_ops.h

# 根据指定编译参数编译
./lite/tools/ci_build.sh \
  --arm_os=android \
  --arm_abi=armv8 \
  --arm_lang=gcc \
  build_test_arm_opencl
```

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

- `cxx`:该目录是编译目标的C++的头文件和库文件;
- `demo`:该目录包含了两个demo,用来调用使用`libpaddle_api_full_bundled.a``libpaddle_api_light_bundled.a`,分别对应`mobile_full``mobile_light`文件夹。编译对应的demo仅需在`mobile_full``mobile_light`
  - `mobile_full`:使用cxx config,可直接加载fluid模型,若使用OpenCL需要在`mobilenetv1_full_api.cc`代码里开启`DEMO_USE_OPENCL`的宏,详细见代码注释;
  - `mobile_light`:使用mobile config,只能加载`model_optimize_tool`优化过的模型;
- `opencl`:该目录存放opencl实现的相关kernel。

```bash
.
|-- cxx
|   |-- include
|   |   |-- paddle_api.h
|   |   |-- paddle_image_preprocess.h
|   |   |-- paddle_lite_factory_helper.h
|   |   |-- paddle_place.h
|   |   |-- paddle_use_kernels.h
|   |   |-- paddle_use_ops.h
|   |   `-- paddle_use_passes.h
|   `-- lib
|       |-- libpaddle_api_full_bundled.a
|       |-- libpaddle_api_light_bundled.a
|       |-- libpaddle_full_api_shared.so
|       `-- libpaddle_light_api_shared.so
|-- demo
|   `-- cxx
|       |-- Makefile.def
|       |-- README.md
|       |-- include
|       |   |-- paddle_api.h
|       |   |-- paddle_lite_factory_helper.h
|       |   |-- paddle_place.h
|       |   |-- paddle_use_kernels.h
|       |   |-- paddle_use_ops.h
|       |   `-- paddle_use_passes.h
|       |-- mobile_full
|       |   |-- Makefile
|       |   `-- mobilenetv1_full_api.cc
|       `-- mobile_light
|           |-- Makefile
|           `-- mobilenetv1_light_api.cc
`-- opencl
    `-- cl_kernel
        |-- buffer
        |   |-- depthwise_conv2d_kernel.cl
        |   |-- elementwise_add_kernel.cl
        |   |-- fc_kernel.cl
        |   |-- im2col_kernel.cl
        |   |-- layout_kernel.cl
        |   |-- mat_mul_kernel.cl
        |   |-- pool_kernel.cl
        |   `-- relu_kernel.cl
        |-- cl_common.h
        `-- image
            |-- channel_add_kernel.cl
            |-- elementwise_add_kernel.cl
            |-- pool_kernel.cl
            `-- relu_kernel.cl
```

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



## 运行示例

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


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

```bash
# 在/data/local/tmp目录下创建OpenCL文件目录
adb shell mkdir -p /data/local/tmp/opencl
adb shell mkdir -p /data/local/tmp/opencl/cl_kernel/buffer
adb shell mkdir -p /data/local/tmp/opencl/cl_kernel/image

# 将OpenCL的kernels文件推送到/data/local/tmp/opencl目录下
adb push lite/backends/opencl/cl_kernel/cl_common.h /data/local/tmp/opencl/cl_kernel/
adb push lite/backends/opencl/cl_kernel/buffer/* /data/local/tmp/opencl/cl_kernel/buffer/
adb push lite/backends/opencl/cl_kernel/image/* /data/local/tmp/opencl/cl_kernel/image/
```

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

```bash
######################################################################
# 编译mobile_full的demo                                              #
######################################################################
# 步骤:                                                              #
#   0.确保编译Paddle-Lite时编译了OpenCL;                             #
#   1.编辑`mobilenetv1_full_api.cc`代码, 开启`DEMO_USE_OPENCL`的宏;  #
#   2.在产物目录`demo/cxx/mobile_full`下编译`mobile_full`的demo;     #
#   3.上传demo, 模型, opencl kernel文件到手机;                       #
#   4.运行demo得到预期结果.                                          #
######################################################################
adb shell mkdir /data/local/tmp/opencl/mobilenet_v1
chmod +x ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_full/mobilenetv1_full_api
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/
adb push ./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1

# use mobile_full run mobilenet_v1
# `GLOG_v` is log level
adb shell "export GLOG_v=0; \
    /data/local/tmp/opencl/mobilenetv1_full_api \
    --model_dir=/data/local/tmp/opencl/mobilenet_v1 \
    --optimized_model_dir=/data/local/tmp/opencl/full_api_opt_model"



######################################################################
# 编译mobile_light的demo                                             #
######################################################################
# 步骤:                                                              #
#   0.确保编译Paddle-Lite时编译了OpenCL;                             #
#   1.编译model_optimize_tool并对模型优化, `targets`参数为`opencl`;  #
#   2.在产物目录`demo/cxx/mobile_light`下编译`mobile_light`的demo;   #
#   3.上传demo, 模型, opencl kernel文件到手机;                       #
#   4.运行demo得到预期结果.                                          #
######################################################################

# use model_optimize_tool to optimize model
./build.model_optimize_tool/lite/api/model_optimize_tool \
  --model_dir=./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/ \
  --optimize_out_type=naive_buffer \
  --optimize_out=./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/ \
  --valid_targets=opencl

adb shell mkdir /data/local/tmp/opencl/mobilenet_v1
chmod +x ./build.lite.android.armv8.gcc.opencl/inference_lite_lib.android.armv8.opencl/demo/cxx/mobile_light/mobilenetv1_light_api
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/
adb push ./build.lite.android.armv8.gcc.opencl/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1

# use mobile_light run mobilenet_v1
adb shell "export GLOG_v=5; \
  /data/local/tmp/opencl/mobilenetv1_light_api \
  --model_dir=/data/local/tmp/opencl/"
```

### 运行示例2: test_mobilenetv1单元测试

- **运行文件准备**

```bash
# 将mobilenet_v1的模型文件推送到/data/local/tmp/opencl目录下
adb shell mkdir -p /data/local/tmp/opencl/mobilenet_v1
adb push build.lite.android.armv8.gcc.opencl/third_party/install/mobilenet_v1/* /data/local/tmp/opencl/mobilenet_v1/

# 将OpenCL单元测试程序test_mobilenetv1,推送到/data/local/tmp/opencl目录下
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`指定了模型文件所在目录。

```bash
adb shell chmod +x /data/local/tmp/opencl/test_mobilenetv1

adb shell /data/local/tmp/opencl/test_mobilenetv1 \
  --cl_path=/data/local/tmp/opencl \
  --model_dir=/data/local/tmp/opencl/mobilenet_v1 \
  --warmup=1 \
  --repeats=1
```

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

### 运行示例3: test_layout_opencl单元测试

- **运行文件准备**

```bash
# 将OpenCL单元测试程序test_layout_opencl,推送到/data/local/tmp/opencl目录下
adb push build.lite.android.armv8.gcc.opencl/lite/kernels/opencl/test_layout_opencl /data/local/tmp/opencl/
```


OpenCL推理过程**

```bash
adb shell chmod +x /data/local/tmp/opencl/test_layout_opencl
adb shell /data/local/tmp/opencl/test_layout_opencl
```


# 如何在Code中使用

见运行示例1的demo代码:

1. [./lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/demo/cxx/mobile_light/mobilenetv1_light_api.cc);
2. [./lite/demo/cxx/mobile_full/mobilenetv1_full_api.cc](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/lite/demo/cxx/mobile_full/mobilenetv1_full_api.cc).

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

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