YOLOX模型部署Android端-NCNN方法

  • 1.YOLOX代码仓库的下载
  • 2.ONNX模型转换
  • 3.NCNN框架模型转换
  • 4 安装Android Studio
  • 5 准备Android项目文件
  • 6 连接手机

将自己任务的YOLOX-nano模型和YOLOX-tiny模型通过NCNN架构的转换方式部署到Android手机端。

1.YOLOX代码仓库的下载

对于自己的任务,需要修改以下几处代码:

  • 1.1数据集的准备(使用的VOC数据格式):在datasets文件夹下新建一个VOCdevkit文件夹->接着在VOCdevkit文件夹下新建VOC2007文件夹->接着在VOC2007文件夹下新建Annotations、ImageSets、JPEGImages三个文件夹,分别存储.xml标签文件、划分数据集为训练集和验证集的文本、和图片数据。
    大概如下图所示:
  • 1.2 根据自己的任务修改几处代码:(1)如果我们使用YOLOX-nano模型,建议在.\exps\example\yolox_voc\文件夹下新建一个yolox_voc_nano.py,该文件与yolox_voc_s.py并列。yolox_voc_nano.py的代码是参考别人的,如下所示:
# encoding: utf-8
import os
import torch
# 需要加上这个
import torch.nn as nn
import torch.distributed as dist
from yolox.data import get_yolox_datadir
from yolox.exp import Exp as MyExp
class Exp(MyExp):def __init__(self):super(Exp, self).__init__()# 修改网络深度和宽度self.depth = 0.33self.width = 0.25self.input_size = (416, 416)self.mosaic_scale = (0.5, 1.5)self.random_size = (10, 20)self.test_size = (416, 416)self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(".")[0]self.enable_mixup = False# 修改类别数self.num_classes = 1# 之前没有加上这个get_model函数,就训练有问题
def get_model(self, sublinear=False):def init_yolo(M):for m in M.modules():if isinstance(m, nn.BatchNorm2d):m.eps = 1e-3m.momentum = 0.03if "model" not in self.__dict__:from yolox.models import YOLOX, YOLOPAFPN, YOLOXHeadin_channels = [256, 512, 1024]# NANO model use depthwise = True, which is main difference.backbone = YOLOPAFPN(self.depth, self.width, in_channels=in_channels, depthwise=True)head = YOLOXHead(self.num_classes, self.width, in_channels=in_channels, depthwise=True)self.model = YOLOX(backbone, head)self.model.apply(init_yolo)self.model.head.initialize_biases(1e-2)return self.modeldef get_data_loader(self, batch_size, is_distributed, no_aug=False, cache_img=False):from yolox.data import (VOCDetection,TrainTransform,YoloBatchSampler,DataLoader,InfiniteSampler,MosaicDetection,worker_init_reset_seed,)from yolox.utils import (wait_for_the_master,get_local_rank,)local_rank = get_local_rank()with wait_for_the_master(local_rank):dataset = VOCDetection(data_dir=os.path.join(get_yolox_datadir(), "VOCdevkit"),# image_sets=[('2007', 'trainval'), ('2012', 'trainval')],# 训练的时候只有VOC2007的数据集,所以需要改这里image_sets=[('2007', 'trainval')],img_size=self.input_size,preproc=TrainTransform(max_labels=50,flip_prob=self.flip_prob,hsv_prob=self.hsv_prob),cache=cache_img,)dataset = MosaicDetection(dataset,mosaic=not no_aug,img_size=self.input_size,preproc=TrainTransform(max_labels=120,flip_prob=self.flip_prob,hsv_prob=self.hsv_prob),degrees=self.degrees,translate=self.translate,mosaic_scale=self.mosaic_scale,mixup_scale=self.mixup_scale,shear=self.shear,enable_mixup=self.enable_mixup,mosaic_prob=self.mosaic_prob,mixup_prob=self.mixup_prob,)self.dataset = datasetif is_distributed:batch_size = batch_size // dist.get_world_size()sampler = InfiniteSampler(len(self.dataset), seed=self.seed if self.seed else 0)batch_sampler = YoloBatchSampler(sampler=sampler,batch_size=batch_size,drop_last=False,mosaic=not no_aug,)dataloader_kwargs = {"num_workers": self.data_num_workers, "pin_memory": True}dataloader_kwargs["batch_sampler"] = batch_sampler# Make sure each process has different random seed, especially for 'fork' methoddataloader_kwargs["worker_init_fn"] = worker_init_reset_seedtrain_loader = DataLoader(self.dataset, **dataloader_kwargs)return train_loaderdef get_eval_loader(self, batch_size, is_distributed, testdev=False, legacy=False):from yolox.data import VOCDetection, ValTransformvaldataset = VOCDetection(data_dir=os.path.join(get_yolox_datadir(), "VOCdevkit"),image_sets=[('2007', 'test')],img_size=self.test_size,preproc=ValTransform(legacy=legacy),)if is_distributed:batch_size = batch_size // dist.get_world_size()sampler = torch.utils.data.distributed.DistributedSampler(valdataset, shuffle=False)else:sampler = torch.utils.data.SequentialSampler(valdataset)dataloader_kwargs = {"num_workers": self.data_num_workers,"pin_memory": True,"sampler": sampler,}dataloader_kwargs["batch_size"] = batch_sizeval_loader = torch.utils.data.DataLoader(valdataset, **dataloader_kwargs)return val_loaderdef get_evaluator(self, batch_size, is_distributed, testdev=False, legacy=False):from yolox.evaluators import VOCEvaluatorval_loader = self.get_eval_loader(batch_size, is_distributed, testdev, legacy)evaluator = VOCEvaluator(dataloader=val_loader,img_size=self.test_size,confthre=self.test_conf,nmsthre=self.nmsthre,num_classes=self.num_classes,)return evaluator

当然yolox_voc_nano.py代码你也可以不用新建(只训练nano模型时),只需要在yolox_voc_s.py代码的基础上进行修改(nano和tiny模型都在这上面修改即可,类别数及模型大小)。self.num_classes 类别数、self.depth = 0.33、self.width = 0.25(nano模型:0.33,0.25;tiny模型:0.33,0.375)以及wait_for_the_master函数下的data_dir=路径直接修改为数据集的绝对路径,比如:data_dir=“E:\Android_studio\YOLOX\datasets\VOCdevkit”,而下面的image_sets函数修改为:image_sets=[(‘2007’, ‘trainval’)],。同理,下面的get_eval_loade函数这两处也修改绝对路径和image_sets=[(‘2007’, ‘test’)],。
(2)还需要修改.\yolox\exp\yolox_base.py文件。其中的self.num_classes 类别数、self.depth = 0.33、self.width = 0.25(nano模型:0.33,0.25;tiny模型:0.33,0.375),self.input_size =(416,416)建议为416。其中还可以根据自己的调参习惯进行其余项的修改,最大的epoch数,热重启的学习率,以及多少个epoch进行验证等。
(3)接下来就是.\tools\train.py文件的修改。其中-b为batch size的大小,-f需要修改:default=“exps/example/yolox_voc/yolox_voc_s.py”,-c是加载预训练模型default="weights/yolox_nano.pth"其余的按着自己电脑配置自行设置。
(4)最后就是模型的训练了。

2.ONNX模型转换

默认我们已经训练好了自己的模型,并得到了yolox_nano.pth和yolox_tiny.pth(就是每次得到的best_ckpt.pth进行重命名就可以)。

  • 使用YOLOX官方自带的export_onnx.py进行转换。其中**–output-name需要修改转换模型的保存路径,-f同样需要进行指定文件default="exps/example/yolox_voc/yolox_voc_s.py,-c加载的就是我们训练好的.pt的权值文件。转换提示如下图:(nano和tiny模型需要修改两次,-f指定的yolox_voc_s.py文件需要按着每次转换的模型修改深度和宽度的系数)

3.NCNN框架模型转换

接下来就稍微有些麻烦了~~

  • 3.1 安装protobuf:下载后解压:https://github.com/google/protobuf/archive/v3.4.0.zip ,然后使用

    绿色终端执行命令:
cd <protobuf-root-dir>
mkdir build-vs2017
cd build-vs2017
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -
DCMAKE_INSTALL_PREFIX=%cd%/install -Dprotobuf_BUILD_TESTS=OFF -
Dprotobuf_MSVC_STATIC_RUNTIME=OFF ../cmake
nmake
nmake install

编译后执行,验证是否安装。

protoc.exe --version
  • 3.2 编译NCNN,从该地址下载:https://github.com/Tencent/ncnn/releases。同样打开刚才的(VS2017X64)的命令终端(进入到ncnn根目录下),执行以下语句:
cd <ncnn-root-dir>
mkdir -p build-vs2017
cd build-vs2017
cmake -G"NMake Makefiles" -DCMAKE_BUILD_TYPE=Release -
DCMAKE_INSTALL_PREFIX=%cd%/install -DProtobuf_INCLUDE_DIR=D:/protobuf3.4.0/build-vs2019/install/include -DProtobuf_LIBRARIES=D:/protobuf-3.4.0/buildvs2019/install/lib/libprotobuf.lib -DProtobuf_PROTOC_EXECUTABLE=D:/protobuf3.4.0/build-vs2019/install/bin/protoc.exe -DNCNN_VULKAN=OFF ..
nmake
nmake install

编译后.\ncnn\build-vs2019\tools\onnx下有onnx2ncnn.exe
注:这里其实还可以使用另一种官方的库,实在是忘记参考哪个博客下载的,该文件下包含转换的exe程序,而且不需要下载编译,可直接用该文件夹.\X64\bin\下的onnx2ncnn.exe,ncnnoptimize.exe:网盘地址:链接:https://pan.baidu.com/s/1aKNmAvApLsnKtBl0BXA22Q
提取码:8ewm

  • 3.3 生成NCNN文件。拷贝yolox_nano.onnx和yolox_tiny.onnx文件到onnx2ncnn.exe,ncnnoptimize.exe文件下,生成ncnn相应的param和bin文件。(命令如下)
onnx2ncnn.exe yolox_nano.onnx yolox_nano.param yolox_nano.bin
onnx2ncnn.exe yolox_tiny.onnx yolox_tiny.param yolox_tiny.bin

因为ncnn不支持Focus模块,会有警告:(没关系,不用管)

Unsupported slice step !
Unsupported slice step !
Unsupported slice step !
  • 3.4 因为ncnn不支持Focus模块,所以需要对yolox_nano.param、yolox_tiny.param进行修改。
    (1)yolo_nano.param模型修改前:
7767517
295 328
Input           images                   0 1 images
Split           splitncnn_input0         1 4 images images_splitncnn_0
images_splitncnn_1 images_splitncnn_2 images_splitncnn_3
Crop             Slice_4                 1 1 images_splitncnn_3 647 -23309=1,0
-23310=1,2147483647 -23311=1,1
Crop             Slice_9                 1 1 647 652 -23309=1,0
-23310=1,2147483647 -23311=1,2
Crop             Slice_14                 1 1 images_splitncnn_2 657 -23309=1,0
-23310=1,2147483647 -23311=1,1
Crop             Slice_19                 1 1 657 662 -23309=1,1
-23310=1,2147483647 -23311=1,2
Crop             Slice_24                 1 1 images_splitncnn_1 667 -23309=1,1
-23310=1,2147483647 -23311=1,1
Crop             Slice_29                 1 1 667 672 -23309=1,0
-23310=1,2147483647 -23311=1,2
Crop             Slice_34                 1 1 images_splitncnn_0 677 -23309=1,1
-23310=1,2147483647 -23311=1,1
Crop             Slice_39                 1 1 677 682 -23309=1,1
-23310=1,2147483647 -23311=1,2
Concat           Concat_40               4 1 652 672 662 682 683 0=0
Convolution     Conv_41                 1 1 683 1177 0=16 1=3 11=3 2=1 12=1
3=1 13=1 4=1 14=1 15=1 16=1 5=1 6=1728
Swish           Mul_43                   1 1 1177 687
ConvolutionDepthWise Conv_44                 1 1 687 1180 0=16 1=3 11=3 2=1
12=1 3=2 13=2 4=1 14=1 15=1 16=1 5=1 6=144 7=16
Swish           Mul_46                   1 1 1180 691
Convolution     Conv_47                 1 1 691 1183 0=32 1=1 11=1 2=1 12=1
3=1 13=1 4=0 14=0 15=0 16=0 5=1 6=512
Swish           Mul_49                   1 1 1183 695

把 295修改为295 - 9 = 286 (由于我们将删除 10 层并添加 1 层,因此总层数应减去 9)。然后从 Split 到 Concat 删除 10 行代码,但记住Concat一行最后倒数第二个数字:683。在输入后添加 YoloV5Focus 层(使用之前的数字 683):

YoloV5Focus     focus                   1 1 images 683

yolox_nano.param文件修改后:(注:YoloV5Focus一定不要写错大小写,app闪退就是因为大小写)

286 328
Input           images                   0 1 images
YoloV5Focus     focus                   1 1 images 683

(2)yolo_tiny.param模型修改前:

7767517
235 268
Input           images                   0 1 images
Split           splitncnn_input0         1 4 images images_splitncnn_0
images_splitncnn_1 images_splitncnn_2 images_splitncnn_3
Crop             Slice_4                 1 1 images_splitncnn_3 467 -23309=1,0
-23310=1,2147483647 -23311=1,1
Crop             Slice_9                 1 1 467 472 -23309=1,0
-23310=1,2147483647 -23311=1,2
Crop             Slice_14                 1 1 images_splitncnn_2 477 -23309=1,0
-23310=1,2147483647 -23311=1,1
Crop             Slice_19                 1 1 477 482 -23309=1,1
-23310=1,2147483647 -23311=1,2
Crop             Slice_24                 1 1 images_splitncnn_1 487 -23309=1,1
-23310=1,2147483647 -23311=1,1
Crop             Slice_29                 1 1 487 492 -23309=1,0
-23310=1,2147483647 -23311=1,2
Crop             Slice_34                 1 1 images_splitncnn_0 497 -23309=1,1
-23310=1,2147483647 -23311=1,1
Crop             Slice_39                 1 1 497 502 -23309=1,1
-23310=1,2147483647 -23311=1,2
Concat           Concat_40               4 1 472 492 482 502 503 0=0
Convolution     Conv_41                 1 1 503 877 0=24 1=3 11=3 2=1 12=1 3=1
13=1 4=1 14=1 15=1 16=1 5=1 6=2592
Swish           Mul_43                   1 1 877 507
Convolution     Conv_44                 1 1 507 880 0=48 1=3 11=3 2=1 12=1 3=2
13=2 4=1 14=1 15=1 16=1 5=1 6=10368
Swish           Mul_46                   1 1 880 511
Split           splitncnn_0             1 2 511 511_splitncnn_0
511_splitncnn_1
Convolution     Conv_47                 1 1 511_splitncnn_1 883 0=24 1=1 11=1
2=1 12=1 3=1 13=1 4=0 14=0 15=0 16=0 5=1 6=1152

把 235修改为235 - 9 = 226 (由于我们将删除 10 层并添加 1 层,因此总层数应减去 9);然后从 Split 到 Concat 删除 10 行代码,记住Concat一行最后倒数第二个数字:503。在输入后添加 YoloV5Focus 层(使用之前的数字 503)。修改后为:

7767517
226 268
Input           images                   0 1 images
YoloV5Focus     focus                   1 1 images 503

(3)对算子量化。使用ncnnoptimize.exe进行模型的量化。基于刚刚修改的.param和.bin文件,在终端输入:

ncnnoptimize.exe yolox_nano.param yolox_nano.bin yolox_nano.param yolox_nano.bin 65536

yolox_nano.param文件中开头的286改280,328改310(自动改的)

ncnnoptimize.exe yolox_tiny.param yolox_tiny.bin yolox_tiny.param yolox_tiny.bin 65536

yolox_tiny.param文件中开头的226改220,268改250(自动改的)
其中.param为模型的结构文件,.bin为模型的参数文件。

4 安装Android Studio

网址:https://developer.android.google.cn/studio/
安装时会提示安装SDK
注意:Android SDK安装路径中不要有空格
注意配置:
File->Settings->Appearance & Behavior ->System Settings->Android SDK
SDK Platforms选中面向手机的Android版本
SDK Tools选中NDK, CMake
(值得注意的是:校园网会出现加载不出来SDK Tools的选项,所以要使用手机热点)

5 准备Android项目文件

  • 5.1 首先下载Android开发文件:https://github.com/nihui/ncnn-android-nanodet(里面已经有参考和步骤,我下载好的:链接:https://pan.baidu.com/s/14S05OMCx-O2BAvMx5cnJdA 提取码:5epp)
  • 5.2 放置ncnn的安卓文件:https://github.com/Tencent/ncnn/releases
    下载ncnn-YYYYMMDD-android-vulkan.zip
    课程中使用ncnn-20210720-android-vulkan.zip
    解压ncnn-YYYYMMDD-android-vulkan.zip后放置到app/src/main/jni 并修改 app/src/main/jni/CMakeLists.txt中的ncnn_DIR
  • 5.3 放置opencv的安卓文件:https://github.com/nihui/opencv-mobile
    下载opencv-mobile-XYZ-android.zip
    课程中使用opencv-mobile-4.5.3-android.zip
    解压opencv-mobile-XYZ-android.zip后放置到app/src/main/jni并修改 app/src/main/jni/CMakeLists.txt中的 OpenCV_DIR
  • 5.4 修改CMakeLists.txt文件
project(ncnnyolox)
cmake_minimum_required(VERSION 3.10)
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/opencv-mobile-4.5.3-android/sdk/native/jni)
find_package(OpenCV REQUIRED core imgproc)
set(ncnn_DIR ${CMAKE_SOURCE_DIR}/ncnn-20210720-androidvulkan/${ANDROID_ABI}/lib/cmake/ncnn)
find_package(ncnn REQUIRED)
add_library(ncnnyolox SHARED yoloxncnn.cpp yolox.cpp ndkcamera.cpp)
target_link_libraries(ncnnyolox ncnn ${OpenCV_LIBS} camera2ndk mediandk)
  • 5.5 自己数据集训练模型的部署
    asset文件下,替换自己训练及转化的模型
    修改yolox.cpp和yoloxncnn.cpp文件中的class_names(自己按着自己的任务修改)

6 连接手机

  • 6.1 手机打开开发者模型,并打开开发者模式下的USB调试功能。
  • 6.2 此时手机界面弹出提示窗口,选择允许,Android Studio就会连接到手机了。
  • 6.3 点击右上方app左侧的绿色小锤子(不知道叫啥)再加载一次需要的环境,然后点击右侧的绿色三角开始键,apk就部署到手机上了。
    下面是我最新的部署结果:
    部署前:

    自己的模型部署后:

    有疑问的小伙伴可以联系我一起解决~~

YOLOX模型部署Android端-NCNN方法相关推荐

  1. 【视频课】快速掌握6大模型部署框架(Pytorch+NCNN+MNN+Tengine+TensorRT+微信小程序)!...

    前言 欢迎大家关注有三AI的视频课程系列,我们的视频课程系列共分为5层境界,内容和学习路线图如下: 第1层:掌握学习算法必要的预备知识,包括Python编程,深度学习基础,数据使用,框架使用. 第2层 ...

  2. 收藏 | YOLOX模型部署、优化及训练全过程

    点上方计算机视觉联盟获取更多干货 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者丨叶润源 来源丨https://www.yuque.com/yerunyuan/ar9831/tsm0id ...

  3. 机器学习模型部署的三种方法

    "企业机器学习需要从数据工程和数据平台的角度看待大局[...],"贾斯汀·诺曼(Justin Norman)在今年巴塞罗那的DataWorks峰会上关于机器学习模型的部署的演讲中说 ...

  4. 树莓派4B部署YOLOv5目标检测模型部署(包含加速方法以及模型训练方法总结)

    树莓派4B部署YOLOv5目标检测模型部署 1.工作内容简介: (1)训练鱼类目标识别模型.首先建立水下鱼类目标数据集,由于目前国内暂时并没有可用红鳍东方鲀标注数据集,本文利用Labelimage软件 ...

  5. 深度学习模型部署的几种方法

    由于模型训练完之后需要上线部署,这个过程中需要将模型集成到当前的软件架构中,因此要根据软件架构考虑模型的实际部署方法.目前来看主流的部署方法有以下几种方案: 1.python服务接口 在python服 ...

  6. Yolo模型部署的两种方法

    目录 1 需求描述 第1种:封装darknet框架 第2种:weights模型转pb模型 2 weights模型转pb模型方法 3 重要备注 (1)关于预处理: (2)关于模型输入输出的数据结构和节点 ...

  7. 【视频课】快速掌握5大模型部署框架(NCNN+MNN+Tengine+TensorRT+微信小程序)

    前言 欢迎大家关注有三AI的视频课程系列,我们的视频课程系列共分为5层境界,内容和学习路线图如下: 第1层:掌握学习算法必要的预备知识,包括Python编程,深度学习基础,数据使用,框架使用. 第2层 ...

  8. 直击行业痛点!端侧模型部署的成熟解决方案有了!

    深度学习经过多年发展,AI已经深入人心,事实上,在图像.文本领域,AI在多个产业已经落地了诸多应用,我们熟知的自动驾驶.语音助手,背后就大量运用了AI技术. 当下,飞桨PaddlePaddle.Ten ...

  9. TensorFlow与PyTorch模型部署性能比较

    TensorFlow与PyTorch模型部署性能比较 前言 2022了,选 PyTorch 还是 TensorFlow?之前有一种说法:TensorFlow 适合业界,PyTorch 适合学界.这种说 ...

最新文章

  1. 利用LVS+Keepalived 实现高性能高可用负载均衡服务器
  2. C#零基础入门04:打老鼠初级之枚举、重构、事件处理器
  3. docker ubuntu镜像_docker使用教程
  4. 阿里巴巴如何改善开发人员在 K8s 上的体验?
  5. 前端js变量踩坑,部分手机浏览器不支持let、const
  6. linux gnome启动命令,如何在Gnome Shell上自动启动程序
  7. 内网击穿之 HTTP 穿透:网站没上线?如何让全世界的人都可以访问你本地的网站?
  8. canvas笔记-使用canvas画圆及点阵的使用
  9. Silverlight 5 Beta新特性[3]多窗口支持
  10. 简单的JSP分页显示
  11. python读音-Python怎么读
  12. 使用element插件中Descriptions遇到的坑
  13. 【易错点 学习笔记】Solidity语法constant/view/pure
  14. python 取数组最后一个_在numpy数组中查找最后一个值
  15. [人工智能-深度学习-38]:卷积神经网络CNN - 常见分类网络- ResNet网络架构分析与详解
  16. 【论文阅读】Improving Document-level Relation Extraction via Contextualizing Mention Representations and W
  17. matlab object是什么意思,求大神指导一下代码大概是什么意思。。
  18. Mac OSX中设置路由
  19. python爬虫学习笔记(三)——淘宝商品比价实战(爬取成功)
  20. 我的投资案例(2)-阿丁特的股东,好狗狗的业务

热门文章

  1. linux tomcat优化
  2. 《一个优秀淘宝运营每天必做6件事》爆款猫教你来运营!
  3. 华为怎么分屏操作技巧_糖豆人终极淘汰赛扒拉怎么操作 扒拉抓人技巧介绍
  4. python爬虫代码实例源码_python爬虫代码示例分享
  5. 花呗接入央行征信系统后还可以用花呗付款吗?
  6. golang 静态代码检测工具golangci-lint使用
  7. Oracle Primavera P6乱码问题
  8. 会展管理SaaS如何利用帮助中心来提升服务水平?
  9. 1、利用蓝牙定位及姿态识别实现一个智能篮球场套件(一)——用重写CC2541透传模块做成智能手环
  10. 如何更换荧石云的手机号码