日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Paddle-Lite 安卓端部署

發(fā)布時(shí)間:2023/12/20 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Paddle-Lite 安卓端部署 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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)整加框部分代碼的麻煩。

// Post-processstart = new Date();long outputShape[] = outputTensor.shape();long outputSize = 1;for (long s : outputShape) {outputSize *= s;}outputImage = inputImage;outputResult = new String();Canvas canvas = new Canvas(outputImage);Paint rectPaint = new Paint();rectPaint.setStyle(Paint.Style.STROKE);rectPaint.setStrokeWidth(1);Paint txtPaint = new Paint();txtPaint.setTextSize(12);txtPaint.setAntiAlias(true);int txtXOffset = 4;int txtYOffset = (int) (Math.ceil(-txtPaint.getFontMetrics().ascent));int imgWidth = outputImage.getWidth();int imgHeight = outputImage.getHeight();int objectIdx = 0;final int[] objectColor = {0xFFFF00CC, 0xFFFF0000, 0xFFFFFF33, 0xFF0000FF, 0xFF00FF00,0xFF000000, 0xFF339933};for (int i = 0; i < outputSize; i += 6) {float score = outputTensor.getFloatData()[i + 1];if (score < scoreThreshold) {continue;}int categoryIdx = (int) outputTensor.getFloatData()[i];String categoryName = "Unknown";if (wordLabels.size() > 0 && categoryIdx >= 0 && categoryIdx < wordLabels.size()) {categoryName = wordLabels.get(categoryIdx);}float rawLeft = outputTensor.getFloatData()[i + 2]/320;float rawTop = outputTensor.getFloatData()[i + 3]/320;float rawRight = outputTensor.getFloatData()[i + 4]/320;float rawBottom = outputTensor.getFloatData()[i + 5]/320;float clampedLeft = Math.max(Math.min(rawLeft, 1.f), 0.f);float clampedTop = Math.max(Math.min(rawTop, 1.f), 0.f);float clampedRight = Math.max(Math.min(rawRight, 1.f), 0.f);float clampedBottom = Math.max(Math.min(rawBottom, 1.f), 0.f);float imgLeft = clampedLeft * imgWidth;float imgTop = clampedTop * imgWidth;float imgRight = clampedRight * imgHeight;float imgBottom = clampedBottom * imgHeight;int color = objectColor[objectIdx % objectColor.length];rectPaint.setColor(color);txtPaint.setColor(color);canvas.drawRect(imgLeft, imgTop, imgRight, imgBottom, rectPaint);canvas.drawText(objectIdx + "." + categoryName + ":" + String.format("%.3f", score),imgLeft + txtXOffset, imgTop + txtYOffset, txtPaint);outputResult += objectIdx + "." + categoryName + " - " + String.format("%.3f", score) +" [" + String.format("%.3f", rawLeft) + "," + String.format("%.3f", rawTop) + "," + String.format("%.3f", rawRight) + "," + String.format("%.3f", rawBottom) + "]\n";objectIdx++;}end = new Date();postprocessTime = (float) (end.getTime() - start.getTime());return true;

至此,Andriod端的部署就完成了。試著運(yùn)行一下吧!

關(guān)于Andriod端部署:
直接替換模型不修改代碼的話是跑不通的,主要是因?yàn)閷儆跊]有預(yù)處理成模型的能接收的數(shù)據(jù)。
這里表現(xiàn)在:

原本SSD模型的輸入為:im [1,3,300,300] 而yolo的模型輸入要求為:input0: im [1,3,320,320]input1: im_sz[,320,320]

在替換模型之后記得要修改模型的與處理部分,以及模型輸出的處理部分。

如果對(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日本a网| 久色 | 亚洲无毛视频 | 天天想你免费观看完整版高清电影 | 天堂中文在线看 | 欧美在线一二 | 国产亚洲精品久久久 | 中文字幕精品视频在线观看 | 日韩av无码一区二区三区 | 丰满人妻老熟妇伦人精品 | 天天天天天操 | 先锋资源在线视频 | 一级性生活黄色片 | 欧美亚洲图片小说 | 一级片久久 | 日本熟妇浓毛 | 九色综合网 | 国产丝袜在线 | 亚洲第一页av | 亚洲色婷婷一区二区三区 | 日韩精品资源 | 欧美亚洲一区 | 99激情视频 | 久久久久久av无码免费看大片 | 热久久精品免费视频 | 色偷偷成人 | 伊人精品视频在线观看 | 丝袜毛片| 9久久精品| 正在播放经典国语对白 | 国产夜夜嗨 | 物业福利视频 | 国产在线视视频有精品 | 国产偷国产偷av亚洲清高 | 国产美女视频网站 | 色婷婷激情av | 欧美精品一卡二卡 | 国产福利在线看 | 影音先锋在线视频 | 日韩一级在线 | 亚洲av第一成肉网 | 亚洲一区二区在线电影 | 黑丝久久 | 五月在线视频 | 欧美视频一区二区 | 乱淫av| 最新国产视频 | 日韩三级a | 黑鬼巨鞭白妞冒白浆 | 欧美中文字幕在线播放 | 欧美视频色 | 去毛片 | 日韩免费精品视频 | 爱福利视频网 | jzjzjzjzj亚洲成熟少妇 | 欧美日韩在线视频一区二区 | 看全色黄大色黄大片女一次牛 | 国产在线一区二区三区 | 国产午夜精品久久久久久久 | 自拍1页| 国产主播一区二区 | 朱竹清到爽高潮痉挛 | 精品人妻一区二区三区久久嗨 | 亚洲av综合色区无码另类小说 | 蜜桃视频黄色 | 免费在线中文字幕 | 久久久极品 | 手机在线观看av | 97超碰福利 | 久久久久国产一区二区三区潘金莲 | 波多野结衣在线观看一区 | 日本xxxx裸体xxxx| 久久亚洲精品小早川怜子 | 在线观看亚洲成人 | 白白色视频在线 | 中国一级黄色大片 | 欧美乱大交| 国产无精乱码一区二区三区 | 亚洲黄色a级片 | 亚洲gay视频| 国产成人免费在线视频 | 国产老熟女伦老熟妇露脸 | 成人国产在线观看 | 国产中文字幕网 | 蜜桃tv一区二区三区 | 成人动漫中文字幕 | 好屌妞视频这里只有精品 | 自拍偷拍另类 | 中文字幕在线看 | 免费成人91| 国精产品一区一区三区免费视频 | 中文字幕人妻丝袜乱一区三区 | 日韩专区视频 | xxx久久久| 四虎影视库 | 国产精品久久久久久妇女 | 免费三级在线 | 丁香婷婷九月 | 免费色视频 |