Paddle-Lite 安卓端部署
Paddle-Lite 安卓端部署
最近因?yàn)橐咔樵蛘诩依?#xff0c;就搜集了些照片用PaddleDetection訓(xùn)練了一個(gè)口罩分類的模型,摸索了一下Paddle-Lite的Andriod部署,恰好Paddle-Lite最近也有比較大的迭代更新,這篇博客記錄了我的摸索過程和一點(diǎn)點(diǎn)心得。
我不太熟悉Andriod開發(fā),此demo僅僅在Paddle-Lite-DemoPaddle-Lite-Demo的基礎(chǔ)上替換模型,修改了少量代碼,以跑通訓(xùn)練和部署流程為目的。
如果此文能幫到大家,請(qǐng)給個(gè)小星星吧 Github
廢話不多說(shuō),先給大家展示一下效果:
因?yàn)楸救伺老x能力有限,也就搜集了600多張圖片,數(shù)據(jù)集太小,最后的mAP大概在90左右。
正文開始:
1.PaddlePaddle開發(fā)環(huán)境:
如果自己沒有支持CUDA的GPU設(shè)備的話可以選擇百度官方的AI-Studio。
自己有設(shè)備的話可以參照PaddleDection安裝說(shuō)明配置開發(fā)環(huán)境。
注:請(qǐng)注意匹配PaddlePaddle版本(1.7)和PaddleDetection分支(0.2)。
2.模型訓(xùn)練:
具體訓(xùn)練流程請(qǐng)參考PaddleDetection官方教程。
我采用的模型是yolov3_mobilenet_v1。如果你還沒開始訓(xùn)練的話,請(qǐng)你選擇yolo系列的模型,因?yàn)椴煌P偷妮斎胼敵鲇兴煌?/p>
3.模型導(dǎo)出:
假設(shè)你模型已經(jīng)訓(xùn)練完畢并且保存在了
/_path_/_to_/_dir_/PaddleDetection/output/yolov3_mobilenet_v1_mask請(qǐng)?jiān)赑addleDection目錄下執(zhí)行以下代碼:
python tools/export_model.py -c configs/yolov3_mobilenet_v1_mask.yml \--output_dir=./inference_model \-o weights=output/yolov3_mobilenet_v1_mask/model_final預(yù)測(cè)模型會(huì)導(dǎo)出到inference_model/yolov3_mobilenet_v1_mask目錄下,模型名和參數(shù)名分別為__model__和__params__。
具體導(dǎo)出方法請(qǐng)參考:這里。
4.模型轉(zhuǎn)換:
工具準(zhǔn)備
模型轉(zhuǎn)換需要用到Paddle-Lite提供的模型轉(zhuǎn)換工具:opt
這里我們使用Paddle-Lite官方發(fā)布的版本,Paddle-Lite Github倉(cāng)庫(kù)的release界面,選擇release版本下載對(duì)應(yīng)的轉(zhuǎn)化工具。
也可以參考文檔自行編譯。
轉(zhuǎn)換模型
我們將opt工具拷貝到PaddleDetection目錄下,執(zhí)行以下命令:
./opt --model_file=yolov3_mobilenet_v1_mask/__model__ \--param_file=/yolov3_mobilenet_v1_mask/__params__ \--optimize_out=mask \--optimize_out_type=naive_buffe(3) 更詳盡的轉(zhuǎn)化命令總結(jié):
./opt \--model_dir=<model_param_dir> \--model_file=<model_path> \--param_file=<param_path> \--optimize_out_type=(protobuf|naive_buffer) \--optimize_out=<output_optimize_model_dir> \--valid_targets=(arm|opencl|x86|npu|xpu) \--prefer_int8_kernel=(true|false) \--record_tailoring_info =(true|false) 選項(xiàng) 說(shuō)明 --model_dir 待優(yōu)化的PaddlePaddle模型(非combined形式)的路徑 --model_file 待優(yōu)化的PaddlePaddle模型(combined形式)的網(wǎng)絡(luò)結(jié)構(gòu)文件路徑。 --param_file 待優(yōu)化的PaddlePaddle模型(combined形式)的權(quán)重文件路徑。 --optimize_out_type 輸出模型類型,目前支持兩種類型:protobuf和naive_buffer,其中naive_buffer是一種更輕量級(jí)的序列化/反序列化實(shí)現(xiàn)。若您需要在mobile端執(zhí)行模型預(yù)測(cè),請(qǐng)將此選項(xiàng)設(shè)置為naive_buffer。默認(rèn)為protobuf。 --optimize_out 優(yōu)化模型的輸出路徑。 --valid_targets 指定模型可執(zhí)行的backend,默認(rèn)為arm。目前可支持x86、arm、opencl、npu、xpu,可以同時(shí)指定多個(gè)backend(以空格分隔),Model Optimize Tool將會(huì)自動(dòng)選擇最佳方式。如果需要支持華為NPU(Kirin 810/990 Soc搭載的達(dá)芬奇架構(gòu)NPU),應(yīng)當(dāng)設(shè)置為npu, arm。 --prefer_int8_kernel 若待優(yōu)化模型為int8量化模型(如量化訓(xùn)練得到的量化模型),則設(shè)置該選項(xiàng)為true以使用int8內(nèi)核函數(shù)進(jìn)行推理加速,默認(rèn)為false。 --record_tailoring_info 當(dāng)使用 根據(jù)模型裁剪庫(kù)文件 功能時(shí),則設(shè)置該選項(xiàng)為true,以記錄優(yōu)化后模型含有的kernel和OP信息,默認(rèn)為false。** 如果待優(yōu)化的fluid模型是非combined形式,請(qǐng)?jiān)O(shè)置–model_dir,忽略–model_file和–param_file。
如果待優(yōu)化的fluid模型是combined形式,請(qǐng)?jiān)O(shè)置–model_file和–param_file,忽略–model_dir。
優(yōu)化后的模型為以.nb名稱結(jié)尾的單個(gè)文件。**
到這里我們已經(jīng)得到了mask.nb這個(gè)模型文件。
5. 準(zhǔn)備Paddle-Lite-Demo
參考Github的readme準(zhǔn)備demo。
在官方 release 預(yù)編譯庫(kù)下載編譯庫(kù)并替換demo中的庫(kù),或者手動(dòng)編譯。
Android更新預(yù)測(cè)庫(kù)
替換jar文件:將生成的build.lite.android.xxx.gcc/inference_lite_lib.android.xxx/java/jar/PaddlePredictor.jar替換demo中的Paddle-Lite-Demo/PaddleLite-android-demo/image_classification_demo/app/libs/PaddlePredictor.jar
替換arm64-v8a jni庫(kù)文件:將生成build.lite.android.armv8.gcc/inference_lite_lib.android.armv8/java/so/libpaddle_lite_jni.so庫(kù)替換demo中的Paddle-Lite-Demo/PaddleLite-android-demo/image_classification_demo/app/src/main/jniLibs/arm64-v8a/libpaddle_lite_jni.so
替換armeabi-v7a jni庫(kù)文件:將生成的build.lite.android.armv7.gcc/inference_lite_lib.android.armv7/java/so/libpaddle_lite_jni.so庫(kù)替換demo中的Paddle-Lite-Demo/PaddleLite-android-demo/image_classification_demo/app/src/main/jniLibs/armeabi-v7a/libpaddle_lite_jni.so.
注意,一定要換的最新的預(yù)測(cè)庫(kù)
編譯運(yùn)行object_detection_demo,確保能運(yùn)行。
6.替換原demo中的模型
原demo運(yùn)行成功,接下來(lái)該換上我們自己的模型了。
1. 將模型拷貝到 Paddle-Lite-Demo/PaddleLite-android-demo/object_detection_demo/app/src/main/assets/models/mask 目錄下并改名為model.nb。
2. 將訓(xùn)練模型時(shí)的mask_label_list文件拷貝到 Paddle-Lite-Demo/PaddleLite-android-demo/object_detection_demo/app/src/main/assets/labels/mask_label_list 。
3. 修改 Paddle-Lite-Demo/PaddleLite-android-demo/object_detection_demo/app/src/main/res/values/strings.xml 文件。
<string name="MODEL_PATH_DEFAULT">models/mask</string> <string name="LABEL_PATH_DEFAULT">labels/mask_label_list</string><string name="INPUT_SHAPE_DEFAULT">1,3,320,320</string> <string name="INPUT_MEAN_DEFAULT">0.485,0.456,0.406</string> <string name="INPUT_STD_DEFAULT">0.229,0.224,0.225</string>4.修改代碼:
將:
protected long[] inputShape = new long[]{1, 3, 300, 300}; protected float[] inputMean = new float[]{0.5f, 0.5f, 0.5f}; protected float[] inputStd = new float[]{0.5f, 0.5f, 0.5f};修改為:
protected long[] inputShape = new long[]{1, 3, 320, 320}; protected float[] inputMean = new float[]{0.485f, 0.456f, 0.406f}; protected float[] inputStd = new float[]{0.229f, 0.224f, 0.225f};** 其中320為模型中圖片輸入的大小,如果你的模型為608,請(qǐng)改成608。*
修改模型輸入部分為:
// Set input shapeTensor inputTensor0 = getInput(0);inputTensor0.resize(inputShape);Tensor inputTensor1 = getInput(1);inputTensor1.resize(new long[] {1,2});// Pre-process image, and feed input tensor with pre-processed dataDate start = new Date();int channels = (int) inputShape[1];int width = (int) inputShape[3];int height = (int) inputShape[2];float[] inputData = new float[channels * width * height];if (channels == 3) {int[] channelIdx = null;if (inputColorFormat.equalsIgnoreCase("RGB")) {channelIdx = new int[]{0, 1, 2};} else if (inputColorFormat.equalsIgnoreCase("BGR")) {channelIdx = new int[]{2, 1, 0};} else {Log.i(TAG, "Unknown color format " + inputColorFormat + ", only RGB and BGR color format is " +"supported!");return false;}int[] channelStride = new int[]{width * height, width * height * 2};for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {int color = inputImage.getPixel(x, y);float[] rgb = new float[]{(float) red(color) / 255.0f, (float) green(color) / 255.0f,(float) blue(color) / 255.0f};inputData[y * width + x] = (rgb[channelIdx[0]] - inputMean[0]) / inputStd[0];inputData[y * width + x + channelStride[0]] = (rgb[channelIdx[1]] - inputMean[1]) / inputStd[1];inputData[y * width + x + channelStride[1]] = (rgb[channelIdx[2]] - inputMean[2]) / inputStd[2];}}} else if (channels == 1) {for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {int color = inputImage.getPixel(x, y);float gray = (float) (red(color) + green(color) + blue(color)) / 3.0f / 255.0f;inputData[y * width + x] = (gray - inputMean[0]) / inputStd[0];}}} else {Log.i(TAG, "Unsupported channel size " + Integer.toString(channels) + ", only channel 1 and 3 is " +"supported!");return false;}inputTensor0.setData(inputData);inputTensor1.setData(new int[] {320,320});Date end = new Date();preprocessTime = (float) (end.getTime() - start.getTime());修改模型的輸出的處理部分:
yolo 的模型輸出為坐標(biāo)值,ssd為坐標(biāo)點(diǎn)的相對(duì)值,這里統(tǒng)一/320 就轉(zhuǎn)換成了相對(duì)值,省去了調(diào)整加框部分代碼的麻煩。
至此,Andriod端的部署就完成了。試著運(yùn)行一下吧!
附
關(guān)于Andriod端部署:
直接替換模型不修改代碼的話是跑不通的,主要是因?yàn)閷儆跊]有預(yù)處理成模型的能接收的數(shù)據(jù)。
這里表現(xiàn)在:
在替換模型之后記得要修改模型的與處理部分,以及模型輸出的處理部分。
如果對(duì)模型的部署還有問題,歡迎大家來(lái)paddle-lite官方群(696965088)和小伙伴們一起探討。
apk下載鏈接:https://pan.baidu.com/s/1uWTRb0EvV6gQJF8x8D2pPQ 密碼:utl2
模型文件下載鏈接:https://pan.baidu.com/s/1Qn3j8tBfHG5JOZ-Ye7oU-Q 密碼:cuir
完整代碼鏈接:https://github.com/ralph0813/Paddle_Lite_Object_Detection_Demo
如果對(duì)模型的部署還有問題,歡迎大家來(lái)paddle-lite官方群(696965088)和小伙伴們一起探討。
apk下載鏈接:https://pan.baidu.com/s/1uWTRb0EvV6gQJF8x8D2pPQ 密碼:utl2
模型文件下載鏈接:https://pan.baidu.com/s/1Qn3j8tBfHG5JOZ-Ye7oU-Q 密碼:cuir
完整代碼鏈接:https://github.com/ralph0813/Paddle_Lite_Object_Detection_Demo
注:僅供測(cè)試使用,非百度官方發(fā)布模型
總結(jié)
以上是生活随笔為你收集整理的Paddle-Lite 安卓端部署的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sql包含怎么写_实习生简历怎么写?都包
- 下一篇: 一个正方形截取四分之一后如何四等分