yolox_nano训练和ncnn安卓部署总结(自己的数据集)(代码片段)

钟良堂的学习笔记 钟良堂的学习笔记     2023-01-23     514

关键词:

yolox_nano模型的参数量极小,并且有着一定的准确度而被使用到手机端的yolox部署:

yolox_nano训练命令:

python tools/train.py -f exps/example/yolox_voc/yolox_voc_nano.py -d 1 -b 8 -c weights/yolox_nano.pth
yolox_nano.pth是官网下载的coco数据集的权重文件来做完这个预训练权重(我发现使用之前训练过的yolox_nano.pth其实也是可以的,这个不是主要问题,重要的是yolox_voc_nano.py这个文件需要好好改,如果改的有问题,就会之后转onnx文件的时候有错误:Missing key(s) & Unexpected key(s) in state_dict…)。

这里需要注意:

-f exps/example/yolox_voc/yolox_voc_nano.py

中的

yolox_voc_nano.py

代码如下:

(在.\\exps\\default\\nano.py和.\\exps/example/yolox_voc/yolox_voc.py基础上修改,也就是把nano.py的init函数和get_model复制粘贴到yolox_voc.py里,修改修改类别数 self.num_classes 还有image_sets,最后把名字变成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.33
        self.width = 0.25
        
        self.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-3
                m.momentum = 0.03
    if "model" not in self.__dict__:
        from yolox.models import YOLOX, YOLOPAFPN, YOLOXHead
        in_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.model

def 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 = dataset

    if 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' method
    dataloader_kwargs["worker_init_fn"] = worker_init_reset_seed

    train_loader = DataLoader(self.dataset, **dataloader_kwargs)

    return train_loader

def get_eval_loader(self, batch_size, is_distributed, testdev=False, legacy=False):
    from yolox.data import VOCDetection, ValTransform

    valdataset = 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_size
    val_loader = torch.utils.data.DataLoader(valdataset, **dataloader_kwargs)

    return val_loader

def get_evaluator(self, batch_size, is_distributed, testdev=False, legacy=False):
    from yolox.evaluators import VOCEvaluator

    val_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_nano了:

yolox_nano训练命令:

python tools/train.py -f exps/example/yolox_voc/yolox_voc_nano.py -d 1 -b 8 -c weights/yolox_nano.pth


这里我没有使用混合精度训练,原因如下博客所示:
https://blog.csdn.net/ELSA001/article/details/120918082?spm=1001.2014.3001.5502

训练结束之后测试一下:

python tools/demo.py image -f exps/example/yolox_voc/yolox_voc_nano.py -c YOLOX_outputs/yolox_voc_nano/best_ckpt.pth --path testfiles/img1.jpg --conf 0.3 --nms 0.65 --tsize 640 --save_result --device cpu

效果如下:

接下来生成onnx文件(YOLOX路径下执行):

python tools/export_onnx.py -n yolox-nano -c weights/yolox_nano.pth --output-name weights/yolox_nano.onnx

yolox_nano.pth文件是训练好的best_ckpt.pth改了名字得来的

效果如下:

(torch_G) E:\\YOLOX>python tools/export_onnx.py -n yolox-nano -c weights/yolox_nano.pth --output-name weights/yolox_nano.onnx
2021-10-28 21:45:50.843 | INFO     | __main__:main:59 - args value: Namespace(batch_size=1, ckpt='weights/yolox_nano.pth', dynamic=False, exp_file=None, experiment_name=None, input='images', name='yolox-nano', no_onnxsim=False, opset=11, opts=[], output='output', output_name='weights/yolox_nano.onnx')
2021-10-28 21:45:51.001 | INFO     | __main__:main:83 - loading checkpoint done.
2021-10-28 21:45:56.211 | INFO     | __main__:main:96 - generated onnx model named weights/yolox_nano.onnx
2021-10-28 21:45:56.773 | INFO     | __main__:main:112 - generated simplified onnx model named weights/yolox_nano.onnx

loading checkpoint done这个过程可能会比较久。

接下来就是导出ncnn文件:

拷贝yolox_nano.onnx文件到E:\\ncnn\\build-vs2019\\tools\\onnx文件下

同时也使用命令行到E:\\ncnn\\build-vs2019\\tools\\onnx目录下:

使用命令生成ncnn相应的param和bin文件:

onnx2ncnn.exe yolox_nano.onnx yolox_nano.param yolox_nano.bin

这里输出了很多Unsupported slice step !也没关系,后面可以改的,主要是因为ncnn不支持Focus模块,会有警告。

修改yolox_nano.param文件:

把 295修改为295 - 9 = 286 (由于我们将删除 10 层并添加 1 层,因此总层数应减去 9)。

然后从 Split 到 Concat 删除 10 行代码,但记住Concat一行最后倒数第二个数字:683。

在输入后添加 YoloV5Focus 层(使用之前的数字 683):

YoloV5Focus      focus                    1 1 images 683

这里需要注意,里面的空格需要一个个慢慢敲的,可以使用Netron软件来看看:

修改之后是这样的:

7767517
286 328
Input            images                   0 1 images
YoloV5Focus      focus                    1 1 images 683
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
....

yolox_nano.param修改之后使用Netron软件来看的效果如下:

这样就算是成功修改了!

使用ncnn_optimize优化ncnn文件:

产生新的param和bin文件:

在E:\\ncnn\\build-vs2019\\tools路径下执行(先拷贝yolox_nano.bin和yolox_nano.param文件到此路径下)

ncnnoptimize.exe yolox_nano.param yolox_nano.bin yolox_nano.param yolox_nano.bin 65536
(torch_G) E:\\ncnn\\build-vs2019\\tools\\onnx>cd ..

(torch_G) E:\\ncnn\\build-vs2019\\tools>ncnnoptimize.exe yolox_nano.param yolox_nano.bin yolox_nano.param yolox_nano.bin 65536
create_custom_layer YoloV5Focus
fuse_convolution_activation Conv_314 Sigmoid_330
fuse_convolution_activation Conv_328 Sigmoid_329
fuse_convolution_activation Conv_347 Sigmoid_363
fuse_convolution_activation Conv_361 Sigmoid_362
fuse_convolution_activation Conv_380 Sigmoid_396
fuse_convolution_activation Conv_394 Sigmoid_395
model has custom layer, shape_inference skipped
model has custom layer, estimate_memory_footprint skipped

这样就算是把ncnn文件优化完成了。

之后在Android studio上面使用build.gradle来自动编译yolox的安卓文件。

编译结束之后,把刚刚优化之后的yolox_nano.param和yolox_nano.bin放在这个assets目录下:

E:\\AndroidStudioProjects\\ncnn-android-yolox\\app\\src\\main\\assets

最后,我们只需要修改cpp目录下的yolox.cpp和yoloxncnn.cpp的class_names数组就行:

点击运行即可检测:

但是这个检测还是有问题的,就是我没办法识别高分辨率的图片和视频,只能识别我喂入神经网络来训练的图片的低分辨率的图片,不过最终还是检测出来了,还是很开心的。

yolov5使用ncnn将模型部署到android端教程部署自己的训练模型到android实现静态图片检测(代码片段)

...project2.3.2.3.安装APP到手机端2.4.demo效果测试2.5.换成自己的训练模型2.5.1.转换自己训练的pt权重为ncnn格式2.5.1.1.导出需要的onnx文件2.5.1.1.1.首先,安装onnx包2.5.1.1.2.使用YOLOv5自带的export.py进行转换2.5.1.1.3.对onnx文件进行压缩2.5.1.2.... 查看详情

56训练paddledetection的tinypose128x96关键点模型部署ncnn框架mnn框架openvino框架

 基本思想:需要移植一个自训练的关键点模型到某开发板上,看到社区已经有了,记录一下流程ncnn/mnn框架流程,然后在移植开发板上,以备自己以后自训练使用实验数据链接:https://pan.baidu.com/s/1Bd8lLtmWLyX64Jzc5743EQ?pwd=yhgh提取码... 查看详情

安卓端使用ncnn部署yolov5(v6.0)(代码片段)

...到你的指尖。ncnn部署yolov5的整体步骤可以分为如下:训练.pt,把.pt模型转为.onnx模型把.onnx模型转换为ncnn模型(.bin和.param)AndroidStudio编译工程成.apk注意整个流程的版本要求很严格,如果对于ncnn不熟的话,... 查看详情

基于flask和网页端部署yolo自训练模型(代码片段)

@Author:Runsen基于flask和网页端部署yolo自训练模型关于yolov5模型的flask的部署,需要通过torch.hub.load加载yolov5自定义的模型,source需要设置localifopt.model=="yolov5":model=torch.hub.load("yolo","custom",path="models/yolov5s.pt",source= 查看详情

基于flask和网页端部署yolo自训练模型(代码片段)

@Author:Runsen基于flask和网页端部署yolo自训练模型关于yolov5模型的flask的部署,需要通过torch.hub.load加载yolov5自定义的模型,source需要设置localifopt.model=="yolov5":model=torch.hub.load("yolo","custom",path="models/yolov5s.pt",source= 查看详情

基于flask和网页端部署yolo自训练模型(代码片段)

@Author:Runsen基于flask和网页端部署yolo自训练模型关于yolov5模型的flask的部署,需要通过torch.hub.load加载yolov5自定义的模型,source需要设置localifopt.model=="yolov5":model=torch.hub.load("yolo","custom",path="models/yolov5s.pt",source= 查看详情

window系统中onnx转化为ncnn详细教程(代码片段)

...成ncnn文件总结前言本文记录了将onnx转化为ncnn框架,方便部署到移动端。前提是你已经安装了vs2016或者其它版本。一、onnx和ncnn是什么?简单描述一下官方介绍,开放神经网络交换(OpenNeuralNetworkExchange)简称ONNX是... 查看详情

androidstudio配置ncnn环境(代码片段)

...经网络前向计算框架。ncnn从设计之初深刻考虑手机端的部署和使用。无第三方依赖,跨平台,手机端cpu的速度快于目前所有已知的开源框架。基于ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开... 查看详情

android配置ncnn环境(代码片段)

...经网络前向计算框架。ncnn从设计之初深刻考虑手机端的部署和使用。无第三方依赖,跨平台,手机端cpu的速度快于目前所有已知的开源框架。基于ncnn,开发者能够将深度学习算法轻松移植到手机端高效执行,开... 查看详情

salesforce开发整理项目部署总结

项目部署顺序全局值集小组自定义字段-对象-设置(SF1紧凑布局要和记录类型在这里要一起部署)邮件模板-静态资源角色工作流-流定义(包含进程生成器)批准过程开发部署<Apex类,页面,触发器,组件>选项卡视图自定义... 查看详情

记录历经三天将自己的yolov5模型部署到android安卓手机(代码片段)

...卓根据视频的流程,基本可以无障碍的将官方的yolov5训练模型部署到自己的安卓手机上。运行结果如下:大体流程在视频中大哥已经讲的很好啦,我在这补充一下我踩到过的坑。1.CMakeLists.txt文件修改如果你是按照视... 查看详情

mobilefacenet

insightface作者训练的mobileFaceNet:  https://github.com/deepinsight/insightface/issues/214ncnn的转换:https://github.com/honghuCode/mobileFacenet-ncnn训练记录:https://github.com/moli232777144/mobilefacen 查看详情

yolov5训练的若干问题总结

这几周玩了一下YOLOV5。选了一个机器猫的示例运行。之前训练完后,都无法识别出来机器猫,后面终于可以了。关键是训练次数和图集一定要多,我是训练了400次,图集是200张。最后终于可以识别出来了。并部署... 查看详情

内存错误和训练部署分离

】内存错误和训练部署分离【英文标题】:Memoryerrorandseparationoftraininganddeploy【发布时间】:2019-09-2722:29:01【问题描述】:我实际上是在尝试将培训和部署部分分开,因为编译程序需要很长时间。有人建议我使用pickle转储和加载... 查看详情

yolov5训练的若干问题总结

这几周玩了一下YOLOV5。选了一个机器猫的示例运行。之前训练完后,都无法识别出来机器猫,后面终于可以了。关键是训练次数和图集一定要多,我是训练了400次,图集是200张。最后终于可以识别出来了。并部署... 查看详情

yolov5训练的若干问题总结

这几周玩了一下YOLOV5。选了一个机器猫的示例运行。之前训练完后,都无法识别出来机器猫,后面终于可以了。关键是训练次数和图集一定要多,我是训练了400次,图集是200张。最后终于可以识别出来了。并部署... 查看详情

社区说|使用tensorflowlite构建和部署自定义对象检测模型

...自定义对象检测模型对象检测简介对象检测模型的获取与训练编写代码在AndroidStudio完成对象检测demo内容回顾20:45-21:00互动问答举办社区GDG北京B站直播访问以下链接或点击阅读原文获取更多资讯https://liv 查看详情

社区说|今晚直播!使用tensorflowlite构建和部署自定义对象检测模型

...自定义对象检测模型对象检测简介对象检测模型的获取与训练编写代码在AndroidStudio完成对象检测demo内容回顾20:45-21:00互动问答举办社区GDG北京B站直播访问以下链接或点击阅读原文获取更多资讯https://liv 查看详情