|
1 | 1 | # Android平台 |
| 2 | + |
| 3 | +PaddleX的安卓端部署由PaddleLite实现,部署的流程如下,首先将训练好的模型导出为inference model,然后对模型进行优化,最后使用PaddleLite的预测库进行部署,PaddleLite的详细介绍和使用可参考:[PaddleLite文档](https://paddle-lite.readthedocs.io/zh/latest/) |
| 4 | + |
| 5 | +> PaddleX --> Inference Model --> PaddleLite Opt --> PaddleLite Inference |
| 6 | +
|
| 7 | +文章简介: |
| 8 | +- step1: 介绍如何将PaddleX导出为inference model |
| 9 | +- step2: 使用PaddleLite的OPT模块对模型进行优化 |
| 10 | +- step3: 介绍了基于MobileNetv2的安卓demo,以及PaddleX Android SDK |
| 11 | + |
| 12 | +## step 1. 将PaddleX模型导出为inference模型 |
| 13 | + |
| 14 | +参考[导出inference模型](../export_model.html)将模型导出为inference格式模型。 |
| 15 | +**注意:由于PaddleX代码的持续更新,版本低于1.0.0的模型暂时无法直接用于预测部署,参考[模型版本升级](../upgrade_version.md)对模型版本进行升级。** |
| 16 | + |
| 17 | +## step 2. 将inference模型优化为PaddleLite模型 |
| 18 | + |
| 19 | +目前提供了两种方法将Paddle模型优化为PaddleLite模型: |
| 20 | + |
| 21 | +- 1.python脚本优化模型,简单上手,目前支持最新的PaddleLite 2.6.1版本 |
| 22 | +- 2.bin文件优化模型(linux),支持develop版本(Commit Id:11cbd50e),适用于部署`DeepLab模型`的用户。 |
| 23 | + |
| 24 | +### 2.1 使用python脚本优化模型 |
| 25 | + |
| 26 | +```bash |
| 27 | +pip install paddlelite |
| 28 | +python /PaddleX/deploy/lite/export_lite.py --model_dir /path/to/inference_model --save_file /path/to/lite_model_name --place place/to/run |
| 29 | +``` |
| 30 | + |
| 31 | +| 参数 | 说明 | |
| 32 | +| ---- | ---- | |
| 33 | +| --model_dir | 预测模型所在路径,包含"\_\_model\_\_", "\_\_params\_\_", "model.yml"文件 | |
| 34 | +| --save_file | 模型输出的名称,假设为/path/to/lite_model_name, 则输出为路径为/path/to/lite_model_name.nb | |
| 35 | +| --place | 运行的平台,可选:arm\|opencl\|x86\|npu\|xpu\|rknpu\|apu,安卓部署请选择`arm`| |
| 36 | + |
| 37 | +### 2.3 使用bin文件优化模型(linux) |
| 38 | + |
| 39 | +首先下载并解压: [模型优化工具opt](https://bj.bcebos.com/paddlex/deploy/lite/model_optimize_tool_11cbd50e.tar.gz) |
| 40 | + |
| 41 | +``` bash |
| 42 | +./opt --model_file=<model_path> \ |
| 43 | + --param_file=<param_path> \ |
| 44 | + --valid_targets=arm \ |
| 45 | + --optimize_out_type=naive_buffer \ |
| 46 | + --optimize_out=model_output_name |
| 47 | +``` |
| 48 | +详细的使用方法和参数含义请参考: [使用opt转化模型](https://paddle-lite.readthedocs.io/zh/latest/user_guides/opt/opt_bin.html) |
| 49 | + |
| 50 | +## step 3. 移动端(Android)预测 |
| 51 | + |
| 52 | +### 3.1 要求 |
| 53 | + |
| 54 | +- Android Studio 3.4 |
| 55 | +- Android手机或开发板 |
| 56 | + |
| 57 | +### 3.2 分类Demo |
| 58 | + |
| 59 | +#### 3.2.1 导入工程 |
| 60 | + |
| 61 | +- 打开Android Studio,在"Welcome to Android Studio"窗口点击"Open an existing Android Studio project",在弹出的路径选择窗口中进入`/PaddleX/deploy/lite/android/demo`目录,然后点击右下角的"Open"按钮,导入工程; |
| 62 | +- 通过USB连接Android手机或开发板; |
| 63 | +- 载入工程后,点击菜单栏的Run->Run 'App'按钮,在弹出的"Select Deployment Target"窗口选择已经连接的Android设备,然后点击"OK"按钮; |
| 64 | + |
| 65 | +#### 3.2.2 自定义模型 |
| 66 | + |
| 67 | +首先根据step1~step2描述,准备好Lite模型(.nb文件)和yml配置文件(注意:导出Lite模型时需指定--place=arm),然后在Android Studio的project视图中: |
| 68 | + |
| 69 | +- 将paddlex.nb文件拷贝到`/src/main/assets/model/`目录下。 |
| 70 | +- 将model.yml文件拷贝到`/src/main/assets/config/`目录下。 |
| 71 | +- 根据需要,修改文件`/src/main/res/values/strings.xml`中的`MODEL_PATH_DEFAULT`和`YAML_PATH_DEFAULT`指定的路径。 |
| 72 | + |
| 73 | +### 3.3 PaddleX Android SDK介绍 |
| 74 | + |
| 75 | +PaddleX Android SDK是PaddleX基于Paddle-Lite开发的安卓端AI推理工具,以PaddleX导出的Yaml配置文件为接口,针对不同的模型实现图片的预处理,后处理,并进行可视化,开发者可集成到业务中。 |
| 76 | +该SDK自底向上主要包括:Paddle-Lite推理引擎层,Paddle-Lite接口层以及PaddleX业务层。 |
| 77 | + |
| 78 | +- Paddle-Lite推理引擎层,是在Android上编译好的二进制包,只涉及到Kernel 的执行,且可以单独部署,以支持极致的轻量级部署。 |
| 79 | +- Paddle-Lite接口层,以Java接口封装了底层c++推理库。 |
| 80 | +- PaddleX业务层,封装了PaddleX导出模型的预处理,推理和后处理,以及可视化,支持PaddleX导出的检测、分割、分类模型。 |
| 81 | + |
| 82 | + |
| 83 | + |
| 84 | +#### 3.3.1 SDK安装 |
| 85 | + |
| 86 | +首先下载并解压[PaddleX Android SDK](https://bj.bcebos.com/paddlex/deploy/lite/paddlex_lite_11cbd50e.tar.gz),得到paddlex.aar文件,将拷贝到android工程目录app/libs/下面,然后为app的build.gradle添加依赖: |
| 87 | + |
| 88 | +``` |
| 89 | +dependencies { |
| 90 | + implementation fileTree(include: ['*.jar','*aar'], dir: 'libs') |
| 91 | +} |
| 92 | +
|
| 93 | +``` |
| 94 | + |
| 95 | +#### 3.3.2 SDK使用用例 |
| 96 | +``` |
| 97 | +import com.baidu.paddlex.Predictor; |
| 98 | +import com.baidu.paddlex.config.ConfigParser; |
| 99 | +import com.baidu.paddlex.postprocess.DetResult; |
| 100 | +import com.baidu.paddlex.postprocess.SegResult; |
| 101 | +import com.baidu.paddlex.postprocess.ClsResult; |
| 102 | +import com.baidu.paddlex.visual.Visualize; |
| 103 | +
|
| 104 | +// Predictor |
| 105 | +Predictor predictor = new Predictor(); |
| 106 | +// model config |
| 107 | +ConfigParser configParser = new ConfigParser(); |
| 108 | +// Visualize |
| 109 | +Visualize visualize = new Visualize(); |
| 110 | +// image to predict |
| 111 | +Mat predictMat; |
| 112 | +
|
| 113 | +// initialize |
| 114 | +configParser.init(context, model_path, yaml_path, cpu_thread_num, cpu_power_mode); |
| 115 | +visualize.init(configParser.getNumClasses()); |
| 116 | +predictor.init(context, configParser) |
| 117 | +
|
| 118 | +// run model |
| 119 | +if (predictImage != null && predictor.isLoaded()) { |
| 120 | + predictor.setInputMat(predictMat); |
| 121 | + runModel(); |
| 122 | +} |
| 123 | +
|
| 124 | +// get result & visualize |
| 125 | +if (configParser.getModelType().equalsIgnoreCase("segmenter")) { |
| 126 | + SegResult segResult = predictor.getSegResult(); |
| 127 | + Mat visualizeMat = visualize.draw(segResult, predictMat, predictor.getImageBlob()); |
| 128 | +} else if (configParser.getModelType().equalsIgnoreCase("detector")) { |
| 129 | + DetResult detResult = predictor.getDetResult(); |
| 130 | + Mat visualizeMat = visualize.draw(detResult, predictMat); |
| 131 | +} else if (configParser.getModelType().equalsIgnoreCase("classifier")) { |
| 132 | + ClsResult clsResult = predictor.getClsResult(); |
| 133 | +} |
| 134 | +``` |
| 135 | +#### 3.3.3 Result成员变量 |
| 136 | + |
| 137 | +**注意**:Result所有的成员变量以java bean的方式获取。 |
| 138 | + |
| 139 | +```java |
| 140 | +com.baidu.paddlex.postprocess.ClsResult |
| 141 | +``` |
| 142 | + |
| 143 | +##### Fields |
| 144 | +> * **type** (String|static): 值为"cls"。 |
| 145 | +> * **categoryId** (int): 类别ID。 |
| 146 | +> * **category** (String): 类别名称。 |
| 147 | +> * **score** (float): 预测置信度。 |
| 148 | +
|
| 149 | +```java |
| 150 | +com.baidu.paddlex.postprocess.DetResult |
| 151 | +``` |
| 152 | +##### Nested classes |
| 153 | +> * **DetResult.Box** 模型预测的box结果。 |
| 154 | +
|
| 155 | +##### Fields |
| 156 | +> * **type** (String|static): 值为"det"。 |
| 157 | +> * **boxes** (List<DetResult.Box>): 模型预测的box结果。 |
| 158 | +
|
| 159 | +```java |
| 160 | +com.baidu.paddlex.postprocess.DetResult.Box |
| 161 | +``` |
| 162 | +##### Fields |
| 163 | +> * **categoryId** (int): 类别ID。 |
| 164 | +> * **category** (String): 类别名称。 |
| 165 | +> * **score** (float): 预测置信度。 |
| 166 | +> * **coordinate** (float[4]): 预测框值:{xmin, ymin, xmax, ymax}。 |
| 167 | +
|
| 168 | +```java |
| 169 | +com.baidu.paddlex.postprocess.SegResult |
| 170 | +``` |
| 171 | +##### Nested classes |
| 172 | +> * **SegResult.Mask**: 模型预测的mask结果。 |
| 173 | +
|
| 174 | +##### Fields |
| 175 | +> * **type** (String|static): 值为"Seg"。 |
| 176 | +> * **mask** (SegResult.Mask): 模型预测的mask结果。 |
| 177 | +
|
| 178 | +```java |
| 179 | +com.baidu.paddlex.postprocess.SegResult.Mask |
| 180 | +``` |
| 181 | +##### Fields |
| 182 | +> * **scoreData** (float[]): 模型预测在各个类别的置信度,长度为numClass$\times\$H$\times\$W |
| 183 | +> * **scoreShape** (long[4]): scoreData的shape信息,[1,numClass,H,W] |
| 184 | +> * **labelData** (long[]): 模型预测置信度最高的label,长度为`H$\times\$W$\times\$1 |
| 185 | +> * **labelShape** (long[4]): labelData的shape信息,[1,H,W,1] |
| 186 | +
|
| 187 | +#### 3.3.4 SDK二次开发 |
| 188 | + |
| 189 | +- 打开Android Studio新建项目(或加载已有项目)。点击菜单File->New->Import Module,导入工程`/PaddleX/deploy/lite/android/sdk`, Project视图会新增名为sdk的module |
| 190 | +- 在app的build.grade里面添加依赖: |
| 191 | + ``` |
| 192 | + dependencies { |
| 193 | + implementation project(':sdk') |
| 194 | + } |
| 195 | + ``` |
| 196 | + |
| 197 | +- 源代码位于sdk/main/java/下,修改源码进行二次开发后,点击菜单栏的Build->Run 'sdk'按钮可编译生成aar,文件位于sdk/build/outputs/aar/路径下。 |
0 commit comments