0


基于yolov5的Android版本目标检测app开发(部署安卓手机)

基于yolov5的Android版本目标检测app开发(部署安卓手机)

0、项目开发需求
(1)开发app部署到安卓手机
(2)支持VOC数据集上所有的目标检测
1、开发环境搭建
windows10+pytorch+pyCharm+Anaconda
python 3.8
torch 1.9.0+cu111
torchvision 0.10.0+cu111
显卡:NVIDIA GeForce RTX 3070

2、数据集准备
(1)下载VOC数据集(链接)
(2)将VOC数据集的格式调整为yolov5的(链接)
yolov5是通过读取.yaml文件进行数据集加载的,.yaml文件内容如下所示
在这里插入图片描述其中原VOC数据集与yolov5数据集文件夹结构对比如图所示:
在这里插入图片描述
在需要训练模型的.yaml里修改类别个数:

在这里插入图片描述

3、模型训练

(1)需要修改初始参数

  1. """
  2. weights: 权重文件/需要提前下载,后面模型训练在此基础上进行,修改为自己的路径
  3. cfg: 模型配置文件 包括nc、depth_multiple、width_multiple、anchors、backbone、head等,修改为自己的路径
  4. data: 数据集配置文件 包括path、train、val、test、nc、names、download等,修改为自己的路径
  5. hyp: 初始超参文件,修改为自己的路径
  6. epochs: 训练轮次
  7. batch-size: 训练批次大小(根据自己硬件选择建议(6-32))
  8. img-size: 输入网络的图片分辨率大小
  9. resume: 断点续训, 从上次打断的训练结果处接着训练 默认False
  10. nosave: 不保存模型 默认False(保存) True: only test final epoch
  11. notest: 是否只测试最后一轮 默认False True: 只测试最后一轮 False: 每轮训练完都测试mAP
  12. workers: dataloader中的最大work数(线程个数),根据自己硬件选择
  13. device: 训练的设备
  14. single-cls: 数据集是否只有一个类别 默认False
  15. rect: 训练集是否采用矩形训练 默认False
  16. noautoanchor: 不自动调整anchor 默认False(自动调整anchor)
  17. evolve: 是否进行超参进化 默认False
  18. multi-scale: 是否使用多尺度训练 默认False
  19. label-smoothing: 标签平滑增强 默认0.0不增强 要增强一般就设为0.1
  20. adam: 是否使用adam优化器 默认False(使用SGD)
  21. sync-bn: 是否使用跨卡同步bn操作,再DDP中使用 默认False
  22. linear-lr: 是否使用linear lr 线性学习率 默认False 使用cosine lr
  23. cache-image: 是否提前缓存图片到内存cache,以加速训练 默认False
  24. image-weights: 是否使用图片采用策略(selection img to training by class weights) 默认False 不使用
  25. bucket: 谷歌云盘bucket 一般用不到
  26. project: 训练结果保存的根目录 默认是runs/train
  27. name: 训练结果保存的目录 默认是exp 最终: runs/train/exp
  28. exist-ok: 如果文件存在就ok不存在就新建或increment name 默认False(默认文件都是不存在的)
  29. quad: dataloader取数据时, 是否使用collate_fn4代替collate_fn 默认False
  30. save_period: Log model after every "save_period" epoch 默认-1 不需要log model 信息
  31. artifact_alias: which version of dataset artifact to be stripped 默认lastest 貌似没用到这个参数?
  32. local_rank: rank为进程编号 -1且gpu=1时不进行分布式 -1且多块gpu使用DataParallel模式math
  33. entity: wandb entity 默认None
  34. upload_dataset: 是否上传dataset到wandb tabel(将数据集作为交互式 dsviz表 在浏览器中查看、查询、筛选和分析数据集) 默认False
  35. bbox_interval: 设置界框图像记录间隔 Set bounding-box image logging interval for W&B 默认-1 opt.epochs // 10
  36. """
  37. parser = argparse.ArgumentParser()# --------------------------------------------------- 常用参数 ---------------------------------------------
  38. parser.add_argument('--weights',type=str, default='weights/yolov5s.pt',help='initial weights path')
  39. parser.add_argument('--cfg',type=str, default='models/yolov5s.yaml',help='model.yaml path')
  40. parser.add_argument('--data',type=str, default='data/VOC.yaml',help='dataset.yaml path')
  41. parser.add_argument('--hyp',type=str, default='data/hyps/hyp.finetune.yaml',help='hyperparameters path')
  42. parser.add_argument('--epochs',type=int, default=200)
  43. parser.add_argument('--batch-size',type=int, default=8,help='total batch size for all GPUs')
  44. parser.add_argument('--img-size', nargs='+',type=int, default=[640,640],help='[train, test] image sizes')
  45. parser.add_argument('--resume', nargs='?', const=True, default=False,help='resume most recent training')
  46. parser.add_argument('--nosave', action='store_true',help='True only save final checkpoint')
  47. parser.add_argument('--notest', action='store_true',help='True only test final epoch')
  48. parser.add_argument('--workers',type=int, default=1,help='maximum number of dataloader workers')
  49. parser.add_argument('--device', default='cuda:0',help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
  50. parser.add_argument('--single-cls', action='store_true',help='train multi-class data as single-class')# --------------------------------------------------- 数据增强参数 ---------------------------------------------
  51. parser.add_argument('--rect', action='store_true',help='rectangular training')
  52. parser.add_argument('--noautoanchor', action='store_true',help='disable autoanchor check')
  53. parser.add_argument('--evolve', default=False, action='store_true',help='evolve hyperparameters')
  54. parser.add_argument('--multi-scale', default=True, action='store_true',help='vary img-size +/- 50%%')
  55. parser.add_argument('--label-smoothing',type=float, default=0.0,help='Label smoothing epsilon')
  56. parser.add_argument('--adam', action='store_true',help='use torch.optim.Adam() optimizer')
  57. parser.add_argument('--sync-bn', action='store_true',help='use SyncBatchNorm, only available in DDP mode')
  58. parser.add_argument('--linear-lr', default=False, action='store_true',help='linear LR')
  59. parser.add_argument('--cache-images', action='store_true',help='cache images for faster training')
  60. parser.add_argument('--image-weights', default=True, action='store_true',help='use weighted image selection for training')# --------------------------------------------------- 其他参数 ---------------------------------------------
  61. parser.add_argument('--bucket',type=str, default='',help='gsutil bucket')
  62. parser.add_argument('--project', default='runs/train',help='save to project/name')
  63. parser.add_argument('--name', default='exp',help='save to project/name')
  64. parser.add_argument('--exist-ok', action='store_true',help='existing project/name ok, do not increment')
  65. parser.add_argument('--quad', action='store_true',help='quad dataloader')
  66. parser.add_argument('--save_period',type=int, default=-1,help='Log model after every "save_period" epoch')
  67. parser.add_argument('--artifact_alias',type=str, default="latest",help='version of dataset artifact to be used')
  68. parser.add_argument('--local_rank',type=int, default=-1,help='DDP parameter, wins do not modify')# --------------------------------------------------- 三个W&B(wandb)参数 ---------------------------------------------
  69. parser.add_argument('--entity', default=None,help='W&B entity')
  70. parser.add_argument('--upload_dataset', action='store_true',help='Upload dataset as W&B artifact table')
  71. parser.add_argument('--bbox_interval',type=int, default=-1,help='Set bounding-box image logging interval for W&B')# parser.parse_known_args()# 作用就是当仅获取到基本设置时,如果运行命令中传入了之后才会获取到的其他配置,不会报错;而是将多出来的部分保存起来,留到后面使用
  72. opt = parser.parse_known_args()[0]if known else parser.parse_args()return opt

修改完以上参数就可以开始训练了。
(2)训练数据记录
1)训练参数
batch size:8
works:1
epoch:200

关于batch size和works有个疑问,第一次训练的时候batch size可以设置到12和works 为2 后面就不可以了,不知道为啥!!!!

2)训练耗时:接近23个小时。。。。。
在这里插入图片描述
3)CPU以及GPU占用率
在这里插入图片描述4)result

在这里插入图片描述5)模型验证:

  1. """
  2. opt参数解析
  3. weights: 模型的权重地址 默认 weights/best.pt
  4. source: 测试数据文件(图片或视频)的保存路径 默认data/images
  5. imgsz: 网络输入图片的大小 默认640
  6. conf-thres: object置信度阈值 默认0.25
  7. iou-thres: 做nms的iou阈值 默认0.45
  8. max-det: 每张图片最大的目标个数 默认1000
  9. device: 设置代码执行的设备 cuda device, i.e. 0 or 0,1,2,3 or cpu
  10. view-img: 是否展示预测之后的图片或视频 默认False
  11. save-txt: 是否将预测的框坐标以txt文件格式保存 默认True 会在runs/detect/expn/labels下生成每张图片预测的txt文件
  12. save-conf: 是否保存预测每个目标的置信度到预测tx文件中 默认True
  13. save-crop: 是否需要将预测到的目标从原图中扣出来 剪切好 并保存 会在runs/detect/expn下生成crops文件,将剪切的图片保存在里面 默认False
  14. nosave: 是否不要保存预测后的图片 默认False 就是默认要保存预测后的图片
  15. classes: 在nms中是否是只保留某些特定的类 默认是None 就是所有类只要满足条件都可以保留
  16. agnostic-nms: 进行nms是否也除去不同类别之间的框 默认False
  17. augment: 预测是否也要采用数据增强 TTA
  18. update: 是否将optimizer从ckpt中删除 更新模型 默认False
  19. project: 当前测试结果放在哪个主文件夹下 默认runs/detect
  20. name: 当前测试结果放在run/detect下的文件名 默认是exp
  21. exist-ok: 是否存在当前文件 默认False 一般是 no exist-ok 连用 所以一般都要重新创建文件夹
  22. line-thickness: 画框的框框的线宽 默认是 3
  23. hide-labels: 画出的框框是否需要隐藏label信息 默认False
  24. hide-conf: 画出的框框是否需要隐藏conf信息 默认False
  25. half: 是否使用半精度 Float16 推理 可以缩短推理时间 但是默认是False
  26. """
  27. parser = argparse.ArgumentParser()
  28. parser.add_argument('--weights', nargs='+',type=str, default='runs/train/exp19/weights/best.pt',help='model.pt path(s)')
  29. parser.add_argument('--source',type=str, default='data/images/112.mp4',help='file/dir/URL/glob, 0 for webcam')
  30. parser.add_argument('--imgsz','--img','--img-size',type=int, default=640,help='inference size (pixels)')
  31. parser.add_argument('--conf-thres',type=float, default=0.25,help='confidence threshold')
  32. parser.add_argument('--iou-thres',type=float, default=0.45,help='NMS IoU threshold')
  33. parser.add_argument('--max-det',type=int, default=1000,help='maximum detections per image')
  34. parser.add_argument('--device', default='',help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
  35. parser.add_argument('--view-img', action='store_true',help='show results')
  36. parser.add_argument('--save-txt', action='store_true',help='save results to *.txt')
  37. parser.add_argument('--save-conf', action='store_true',help='save confidences in --save-txt labels')
  38. parser.add_argument('--save-crop', action='store_true',help='save cropped prediction boxes')
  39. parser.add_argument('--nosave', action='store_true',help='do not save images/videos')
  40. parser.add_argument('--classes', nargs='+',type=int,help='filter by class: --class 0, or --class 0 2 3')
  41. parser.add_argument('--agnostic-nms', action='store_true',help='class-agnostic NMS')
  42. parser.add_argument('--augment', action='store_true',help='augmented inference')
  43. parser.add_argument('--update', action='store_true',help='update all models')
  44. parser.add_argument('--project', default='runs/detect',help='save results to project/name')
  45. parser.add_argument('--name', default='exp',help='save results to project/name')
  46. parser.add_argument('--exist-ok', action='store_true',help='existing project/name ok, do not increment')
  47. parser.add_argument('--line-thickness', default=3,type=int,help='bounding box thickness (pixels)')
  48. parser.add_argument('--hide-labels', default=False, action='store_true',help='hide labels')
  49. parser.add_argument('--hide-conf', default=False, action='store_true',help='hide confidences')
  50. parser.add_argument('--half', action='store_true',help='use FP16 half-precision inference')
  51. parser.add_argument('--prune-model', default=False, action='store_true',help='model prune')
  52. parser.add_argument('--fuse', default=False, action='store_true',help='fuse conv and bn')
  53. opt = parser.parse_args()

输入一张图,输入一段视屏:
修改图片路径或者视屏路径即可。代码里面的 cv2.waitKey(1) 需要修改,图片为 cv2.waitKey(0) ,视屏为 cv2.waitKey(1)

  1. # 是否需要显示我们预测后的结果 img0(此时已将pred结果可视化到了img0中)if view_img:
  2. cv2.imshow(str(p), im0)
  3. cv2.waitKey(1)# 1 millisecond

在这里插入图片描述

输入电脑摄像头:
修改detect.py配置
在这里插入图片描述

在这里插入图片描述

4、模型转换
1).将.pt 转换为onnx
在模型pt转化为onnx的时候需要先进行修改models中的cocommon.py,修改Focus 去除slice数组操作,如果不改后续onnx2ncnn转换的时候会报错。

  1. #原代码中训练用的defforward(self, x):return self.conv(torch.cat([x[...,::2,::2], x[...,1::2,::2], x[...,::2,1::2], x[...,1::2,1::2]],1))
  1. #模型转换用的代码defforward(self, x):#修改Focus去除slice数组操作,如果不改后续onnx2ncnn转换的时候会报错return self.conv(torch.cat([x, x,x,x],1))

修改export.py参数

  1. img-size: 输入模型的图片size=(height, width) 默认=[640,640] 可以减小一下尺寸免得手机卡爆了
  2. batch-size: batch大小 默认=1
  3. device: 模型运行设备 cuda device, i.e.0or0,1,2,3or cpu 默认=cpu
  4. include: 要将pt文件转为什么格式 可以为单个原始也可以为list 默认=['torchscript','onnx','coreml']
  5. half: 是否使用半精度FP16export转换 默认=False
  6. inplace: 是否set YOLOv5 Detect() inplace=True 默认=False
  7. train: 是否开启model.train() mode 默认=True coreml转换必须为True
  8. optimize: TorchScript转化参数 是否进行移动端优化 默认=False
  9. dynamic: ONNX转换参数 dynamic_axes ONNX转换是否要进行批处理变量 默认=False
  10. simplify: ONNX转换参数 是否简化onnx模型 默认=False
  11. opset-version: ONNX转换参数 设置版本 默认=10"""
  12. parser = argparse.ArgumentParser()
  13. parser.add_argument('--weights',type=str, default='../runs/train/exp19/weights/best.pt',help='weights path')
  14. parser.add_argument('--img-size', nargs='+',type=int, default=[416,416],help='image (height, width)')
  15. parser.add_argument('--batch-size',type=int, default=1,help='batch size')
  16. parser.add_argument('--device', default='cpu',help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
  17. parser.add_argument('--include', nargs='+', default=['torchscript','onnx','coreml'],help='include formats')
  18. parser.add_argument('--half', action='store_true',help='FP16 half-precision export')
  19. parser.add_argument('--inplace', action='store_true',help='set YOLOv5 Detect() inplace=True')
  20. parser.add_argument('--train', default="True", action='store_true',help='model.train() mode')
  21. parser.add_argument('--optimize', action='store_true',help='TorchScript: optimize for mobile')
  22. parser.add_argument('--dynamic', action='store_true',help='ONNX: dynamic axes')
  23. parser.add_argument('--simplify', action='store_true',help='ONNX: simplify model')
  24. parser.add_argument('--opset-version',type=int, default=10,help='ONNX: opset version')
  25. opt = parser.parse_args()return opt

模型简化可以用以下命令:
python -m onnxsim yolov5s.onnx yolov5ssim.onnx,自己把“yolov5s.onnx”修改成自己的名字就好了,如果没有安装onnxsim,先安装pip install onnx-simplifier再运行上面的简化指令python -m onnxsim yolov5s.onnx yolov5ssim.onnx
或者在export.py中设置参数,则转换为onnx 以后模型已经被简化了。
在这里插入图片描述

2).将onnx转换为ncnn
a.简单粗暴的:https://convertmodel.com/
直接选择输入输出模型就可以使用,简单粗暴,方便快捷。
在这里插入图片描述
b.使用cmake 进行编译,过程较复杂难道较大,切容易出错,后面进行补充。

c、在ncnn(https://github.com/Tencent/ncnn/releases)库下载对应的Windows和VS版本的文件,比如说我这里安装的VS2019,我下载的文件就是:https://github.com/Tencent/ncnn/releases/download/20220216/ncnn-20220216-windows-vs2019.zip
版本问题的话没有太多要求,下好后解压,在X64/bin文件下有对应的exe文件,把模型文件拷贝到当前目录,在文件夹里面按住shift点右键打开Powershell窗口,输入***./onnx2ncnn yolov5s.onnx yolov5s.param yolov5s.bin当前目录就会出现 yolov5s.param yolov5s.bin两个文件.
然后接着重复打开Powershell,
./ncnnoptimize yolov5s.param yolov5s.bin yolov5s_out.param yolov5s_out.bin 65536*** 压缩文件大小。
在这里插入图片描述

4、修改转换后的模型.param文件

打开上一步生成的 .param文件,直接拉到最后,将图中的3个数字改为-1,这一步是为了防止Android移植后,检测结果正确显示用,如果不改的话,会出现n多个框,密密麻麻的覆盖你的原本图片。
修改前:
在这里插入图片描述修改后:
在这里插入图片描述log.csdnimg.cn/c23f82279b344211b023cbd8e313db30.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6aqR552A5ouW5ouJ5py65Y675peF6KGM,size_18,color_FFFFFF,t_70,g_se,x_16)

自此模型准备完毕下一步在app开发里面加载。
5、Androidapp开发
官网提供了现成的模块:ncnn-android-yolov5 https://github.com/nihui/ncnn-android-yolov5

1)下载ncnn-20220216-android-vulkan(链接:https://github.com/Tencent/ncnn/releases
在这里插入图片描述2)修改代码
找到3个Permute查看对应的Output的name,修改完成后,继续修改class_names,换成自己的标签,最后连上设备就可以识别图像了。

在这里插入图片描述

6、运行检测

在这里插入图片描述


本文转载自: https://blog.csdn.net/weixin_31588979/article/details/123770162
版权归原作者 骑着拖拉机去旅行 所有, 如有侵权,请联系我们删除。

“基于yolov5的Android版本目标检测app开发(部署安卓手机)”的评论:

还没有评论