【目标检测】YOLOv5跑通VOC2007数据集
前言
如果经常阅读我博客的读者,想必对YOLOv5并不陌生。在Pytorch:YOLO-v5目标检测(上)一文中,我使用了coco128数据集,非常轻松的跑通了。然而在使用VOC2007数据集时,却遇到重重阻碍。主要问题在数据标签转化这个阶段,VOC数据集标注形式是xml,需要将其转换为txt。很多博文并未把文件的放置位置交代清楚,导致走了不少弯路,本篇博文就记录如何不走弯路地跑通VOC数据集。
VOC数据集
我是用的VOC数据集是VOC2007,它的文件格式长这样:
注:官网上下载的话训练验集和测试集是分成两个压缩包VOCtrainval_06-Nov-2007.tar
和VOCtest_06-Nov-2007.tar
,此处我将其进行合并,如需下载我合并后的数据集,可跳转到文末进行下载。
- Annotations
该文件包含数据标注的xml文件 - ImageSets
该文件包含数据集的划分 - JPEGImages
该文件包含图像数据集
拿到数据集,第一件需要干的事是把JPEGImages
文件夹名称改成images
,具体原因后面解释,改完之后如图所示:
数据集处理
从GitHub上,下载Yolov5代码
项目地址:
https://github.com/ultralytics/yolov5
下载完之后,在文件中新建一个文件,我起名为voc_label.py
,起名,位置均随意,这个文件主要干两件事:
- 1、将ImageSets中的训练集、测试集、验证集提出来,拼凑成可以直接访问的绝对路径,如图所示
- 2、把xml格式的标注转换成txt格式,如图所示:
图中红色方框圈住的是要提取出的数据,对于每一个目标,txt格式的数据有5个,分别为(class, x , y , w, h),即类别、中心点(x,y),宽高(w,h)。这里的转换公式在代码中有写道,不作细述。注意class必须是以0开始的序号,否则训练时会出现类别溢出的报错。
voc_label.py
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import joinsets = ['train', 'test', 'val']Imgpath = 'D:/Desktop/Work/VOC2007/images'
xmlfilepath = 'D:/Desktop/Work/VOC2007/Annotations/'
ImageSets_path = 'D:/Desktop/Work/VOC2007/ImageSets/Segmentation/'
Label_path = 'D:/Desktop/Work/VOC2007/'
classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]def convert(size, box):dw = 1. / size[0]dh = 1. / size[1]x = (box[0] + box[1]) / 2.0y = (box[2] + box[3]) / 2.0w = box[1] - box[0]h = box[3] - box[2]x = x * dww = w * dwy = y * dhh = h * dhreturn (x, y, w, h)def convert_annotation(image_id):in_file = open(xmlfilepath + '%s.xml' % (image_id))out_file = open(Label_path + 'labels/%s.txt' % (image_id), 'w')tree = ET.parse(in_file)root = tree.getroot()size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)for obj in root.iter('object'):difficult = obj.find('difficult').textcls = obj.find('name').textif cls not in classes or int(difficult) == 1:continuecls_id = classes.index(cls)xmlbox = obj.find('bndbox')b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))bb = convert((w, h), b)out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')for image_set in sets:if not os.path.exists(Label_path + 'labels/'):os.makedirs(Label_path + 'labels/')image_ids = open(ImageSets_path + '%s.txt' % (image_set)).read().strip().split()list_file = open(Label_path + '%s.txt' % (image_set), 'w')for image_id in image_ids:list_file.write(Imgpath + '/%s.jpg\n' % (image_id))convert_annotation(image_id)list_file.close()
使用时,替换路径和类别classes即可。
运行之后,会在数据集文件夹下生成四个文件,labels中的txt文件和images中的图片名称一一对应。
训练准备
YOLOv5是通过yaml格式的配置文件来找到对应的训练测试数据,因此在训练前需要对该文件进行简单配置。
尽管YOLOv5已有自带的voc.yaml配置文件,但为了之后训练自己的数据,我这里还是新建一个mydata.yaml来将VOC数据进行导入。
train: D:/Desktop/Work/VOC2007/train.txt
val: D:/Desktop/Work/VOC2007/val.txt
test: D:/Desktop/Work/VOC2007/test.txt# number of classes
nc: 20# class names
names: [ 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor' ]
文件内容很简单,需要指定三个数据集的路径,类别个数和类别名称。
开始训练
打开train.py文件
主要需要调整三个参数
我使用yolov5s作为预训练模型,如下图所示进行修改。
运行之后,程序会自动从官网下载yolov5s.pt模型文件,放在根目录下面。
如果前面的操作和我一样,到此时应该能顺利跑通训练程序。
程序默认的epochs为300,为了尽快看到效果,可以改小些,训练完后,会在runs -> train -> exp 中看到训练和验证的文件。
如果再次运行,会发现生成了一个新的文件夹exp2…这是由于yolov5默认将每次运行结果单独放一个文件夹存储。
具体代码可参见train.py的518行
opt.save_dir = increment_path(Path(opt.project) / opt.name, exist_ok=opt.exist_ok | opt.evolve) # increment run
这里的increment_path
函数就是每次累加exp序号,如果需要将结果保存到指定路径,可以直接将路径替换到等号右边。
当然,Yolov5也提供了一种便捷的方式放置不断生成exp文件。
在超参数设定中,有个参数为exist-ok
,其默认为False,将其设置为True,则程序再次运行会在最近的exp生成文件。
另外,还有各种不同的参数,参数含义补充如下,可供研究参考。
parser = argparse.ArgumentParser()parser.add_argument('--weights', type=str, default='yolov5s.pt', help='initial weights path')parser.add_argument('--cfg', type=str, default='models/yolov5s.yaml', help='model.yaml path 模型配置和网络结构的yaml文件路径')parser.add_argument('--data', type=str, default='data/mydata.yaml', help='data.yaml path 数据集配置的yaml文件路径,包括数据集的路径,类名等关键信息')parser.add_argument('--hyp', type=str, default='data/hyp.scratch.yaml', help='超参数配置的yaml文件路径')parser.add_argument('--epochs', type=int, default=2)parser.add_argument('--batch-size', type=int, default=16, help='total batch size for all GPUs')parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='[train, test] image sizes 输入图像的分辨率大小')parser.add_argument('--rect', action='store_true', help='rectangular training 是否采用矩形图像训练,默认是False')parser.add_argument('--resume', nargs='?', const=True, default=False, help='resume most recent training 从给定的path/last.pt恢复训练,如果为空,则从最近保存的path/last.pt恢复训练')parser.add_argument('--nosave', action='store_true', help='only save final checkpoint 保存模型,只保存最后的检查点,默认为False')parser.add_argument('--notest', action='store_true', help='only test final epoch 训练中不进行test,只测试最后一个轮次,默认为False')parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check 不自动调整anchor,默认为False')parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters 是否进行超参数进化,默认为False')parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')parser.add_argument('--cache-images', action='store_true', help='cache images for faster training 是否提前缓存图片到内存,以加快训练速度,默认为False')parser.add_argument('--image-weights', action='store_true', help='use weighted image selection for training')parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%% 是否进行多尺度训练,默认为False')parser.add_argument('--single-cls', action='store_true', help='train multi-class data as single-class 将所有数据按照一个类别进行训')parser.add_argument('--adam', action='store_true', help='use torch.optim.Adam() optimizer 是否使用 torch.optim.Adam() 优化器,默认是False')parser.add_argument('--sync-bn', action='store_true', help='use SyncBatchNorm, only available in DDP mode 是否使用跨卡同步BN')parser.add_argument('--local_rank', type=int, default=-1, help='DDP parameter, do not modify')parser.add_argument('--workers', type=int, default=0, help='maximum number of dataloader workers')parser.add_argument('--project', default='runs/train', help='save to project/name')parser.add_argument('--entity', default=None, help='W&B entity')parser.add_argument('--name', default='exp', help='save to project/name')parser.add_argument('--exist-ok', default=False, action='store_true', help='existing project/name ok, do not increment')parser.add_argument('--quad', action='store_true', help='quad dataloader')parser.add_argument('--linear-lr', action='store_true', help='linear LR')parser.add_argument('--label-smoothing', type=float, default=0.0, help='Label smoothing epsilon')parser.add_argument('--upload_dataset', action='store_true', help='Upload dataset as W&B artifact table')parser.add_argument('--bbox_interval', type=int, default=-1, help='Set bounding-box image logging interval for W&B')parser.add_argument('--save_period', type=int, default=-1, help='Log model after every "save_period" epoch')parser.add_argument('--artifact_alias', type=str, default="latest", help='version of dataset artifact to be used')opt = parser.parse_args()
开始测试
上面的过程只运用到了模型的训练和验证,打开test.py,可使用测试集对模型进行测试。
需要修改的参数和训练程序差不多,值得注意的是,yolov5在每次训练之后会输出两个模型文件,一个是best.pt
,即验证集上表现最好(mAP最高)的模型,另一个是last.pt
,即最后一轮训练的模型。通常来说,输入best.pt
进行测试即可。
测试运行之后,会在runs中生成一个test文件,其中可进行训练结果和标注结果的对比。
开始检测
训练/测试只停留在数据集范围内,下面要对一些数据集之外的数据进行检测,打开detect.py文件
修改source
为检测图片的文件夹,运行之后,在run->detect中输出检测结果。
更多拓展
如果你的目的只是跑通VOC数据集,那现在估计已经成功了(可以给本文点个赞来分享你成功的快乐 )。
如果你想更深入地研究Yolov5模型,可继续进行阅读。
超参数注释
在训练时,引入了--hyp
这个属性,在data/hyp.scratch.yaml
这个文件中,包含了训练所有的参数设置。
下面是各参数含义的解释。
# Hyperparameters for COCO training from scratch
# python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300
# See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials# 优化器相关
lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3) 初始学习率
lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf) 余弦退火超参数
momentum: 0.937 # SGD momentum/Adam beta1 学习率动量
weight_decay: 0.0005 # optimizer weight decay 5e-4 权重衰减系数# 预热学习相关
warmup_epochs: 3.0 # warmup epochs (fractions ok) 预热学习epoch
warmup_momentum: 0.8 # warmup initial momentum 预热学习率动量
warmup_bias_lr: 0.1 # warmup initial bias lr 预热学习率# 不同损失函数权重,以及其他损失函数相关内容
box: 0.05 # box loss gain giou损失的系数
cls: 0.5 # cls loss gain 分类损失的系数
cls_pw: 1.0 # cls BCELoss positive_weight 分类BCELoss中正样本的权重
obj: 1.0 # obj loss gain (scale with pixels) 有无物体损失的系数
obj_pw: 1.0 # obj BCELoss positive_weight 有无物体BCELoss中正样本的权重
iou_t: 0.20 # IoU training threshold 标签与anchors的iou阈值iou training threshold# anchor锚框
anchor_t: 4.0 # anchor-multiple threshold 标签的长h宽w/anchor的长h_a宽w_a阈值, 即h/h_a, w/w_a都要在(1/4.0, 4.0)之间
# anchors: 3 # anchors per output layer (0 to ignore)# 数据增强相关 - 色彩转换
fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
hsv_h: 0.015 # image HSV-Hue augmentation (fraction) 色调
hsv_s: 0.7 # image HSV-Saturation augmentation (fraction) 饱和度
hsv_v: 0.4 # image HSV-Value augmentation (fraction) 明度
# 数据增强相关:旋转、平移、扭曲等
degrees: 0.0 # image rotation (+/- deg) 旋转角度
translate: 0.1 # image translation (+/- fraction) 水平和垂直平移
scale: 0.5 # image scale (+/- gain) 缩放
shear: 0.0 # image shear (+/- deg) 剪切
perspective: 0.0 # image perspective (+/- fraction), range 0-0.001 透视变换参数
# 数据增强相关 - 翻转
flipud: 0.0 # image flip up-down (probability) 上下翻转概率
fliplr: 0.5 # image flip left-right (probability) 左右翻转概率
# 数据增强相关 - mosaic/mixup
mosaic: 1.0 # image mosaic (probability) 进行mosaic的概率(一幅图像融合四幅图像)
mixup: 0.0 # image mixup (probability) 进行mixup的概率(对两个样本-标签数据对按比例相加后生成新的样本-标签数据)
我所使用的是YOLOv5-5.0版本,只有这一个超参数文件。而在官网最新的版本中,已经添加了多个文件。
每个文件属性依旧是上面这些,只是数值不同。至于如何进行调参会让效果更好,有必要进行更多的实验尝试。
更改文件名的逻辑
现在来解决之前遗留的问题,为什么要把图片文件夹名改成images
在源码dataset.py
的341行,定义了img2label_paths这个路径函数,这里面固定了images和labels的名称。
如果未改文件夹名,会产生这个报错。
AssertionError: train: No labels in D:\Desktop\Work\XDUAV-dataset2\train.cache. Can not train without labels.
数据集/源码
本文使用的VOC2007数据集下载地址:
https://pan.baidu.com/s/1Be9Ya5__2J9LKJhV5RkhaA?pwd=8888
本文编辑之后的Yolov5文件:
https://pan.baidu.com/s/1GHAbUdU-Rf0dNc-FYgonCA?pwd=8888
后记
经读者指出,这样操作存在一点小问题,即数据集并没有被充分利用,修改后版本见我的这篇博文【目标检测】YOLOv5跑通VOC2007数据集(修复版)
【目标检测】YOLOv5跑通VOC2007数据集相关推荐
- 【点云3D目标检测】跑通CIA-SSD过程中的一些报错集锦
前言 本文主要是介绍了在跑通CIA-SSD系列算法过程中遇到的一些bug,下面是对CIASSD算法的一个简单的介绍. CIA-SSD其基本思想是校准单步目标检测中分类和定位两个任务,提出Confide ...
- 《深度学习与目标检测 YOLOv5》
<深度学习与目标检测 YOLOv5> flyfish 基础 深度学习基础 - 向量 深度学习基础 - 累加符号和连乘符号 深度学习基础 - 最大似然估计 深度学习基础 - 朴素贝叶斯 深度 ...
- 目标检测 YOLOv5 - 卷积层和BN层的融合
目标检测 YOLOv5 - 卷积层和BN层的融合 即Conv2d和 BatchNorm2d融合 flyfish 为了减少模型推理时间,YOLOv5源码中attempt_load已经包括两层的合并,主要 ...
- 目标检测 YOLOv5 anchor设置
目标检测 YOLOv5 anchor设置 1 anchor的存储位置 1.1 yaml配置文件中例如 models/yolov5s.yaml # anchors anchors:- [10,13, 1 ...
- 目标检测 YOLOv5 自定义网络结构
目标检测 YOLOv5 自定义网络结构(YOLOv5-ShuffleNetV2) flyfish 版本:YOLOv5:v5 具体已经借鉴的自定义网络结构包括 YOLOv5-MobileNetV3 Mo ...
- 简单快速建立pytorch环境YOLOv5目标检测 模型跑起来(超简单)
简单快速建立pytorch环境+实现YOLOv5目标检测 模型跑起来(超简单) 一.下载yolov5模型代码: yolo代码 提取码:2022 下载后解压 二.简单快速创建pytorch环境: 1.条 ...
- 基于mmdetection 旋转目标检测(OBB detection)+DOTA数据集自定义数据集+配docker
这两周得益于组里的任务需求,肝了一个遥感类的飞机旋转框目标检测,在给定的4096*4096的大尺度分辨率图片上去识别检测飞机. 经过模型检测后输出结果图如下图所示: 可以看到最终的结果还是不错的,通过 ...
- 目标检测 YOLOv5 - 如何提高模型的指标,提高精确率,召回率,mAP等
目标检测 YOLOv5 - 如何提高模型的指标,提高精确率,召回率,mAP等 flyfish 文中包括了YOLOv5作者分享的提高模型指标小技巧和吴恩达(Andrew Ng)在做缺陷检测项目( ste ...
- 目标检测 YOLOv5网络v6 0版本总结
目标检测 YOLOv5网络v6.0版本总结 YOLOv5对比YOLOv4 输入端:在模型训练阶段,提出了Mosaic数据增强.自适应锚框计算.自适应图片缩放等: Backbone网络:融合其它检测算法 ...
- [数据集][VOC][目标检测]河道垃圾水面漂浮物数据集目标检测可用yolo训练-1304张介绍
数据集格式:Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件,仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数):1304 标注数量(xml文件个数):130 ...
最新文章
- nvidia-jetson系列硬件平台上安装Qt
- 基于神经网络的溶解度预测和回归分析
- GridView格式化数据失效
- JavaScript对象系统说明图
- POI的入门:创建单元格设置数据
- SAP UI5 应用开发教程之二十一 - SAP UI5 的自定义格式器(Custom Formatter)
- android viewpager 滑动方法,Android中Viewpager禁止滑动的实现
- 将Teams app升级到net6
- Github项目|几行代码即可实现人脸检测、目标检测的开源计算机视觉库
- 关于#if NET1的一点小得
- Java connot reduce_hadoop错误:org.apache.hadoop.mapreduce.lib.input.FileSplit cannot be cast t...
- 学计算机买笔记本还是平板,学生买平板还是笔记本电脑好
- 如何修改IDM下载器的临时文件夹位置
- Linux paste合并文件,使用多个字符作为间隔符
- 计算机二级考试怎么练题库,计算机二级考试单选题训练题库
- rangeOfString 与containsString
- 对接银行的方法与流程
- CentOS7如何设置开机自启动程序、开机自启动脚本?
- LintCode Find the Duplicate Number
- MySQL数据字典生成工具