ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

蝴蝶数据集VOC与YOLO双格式实战:1425张标注转换与YOLO训练指南

蝴蝶数据集VOC与YOLO双格式实战:1425张标注转换与YOLO训练指南 简介本资源为蝴蝶目标检测数据集面向从事计算机视觉、深度学习目标检测的开发者与研究者可用于训练和验证蝴蝶识别模型。数据集包含1425张jpg图片每张均配有对应的VOC格式xml标注与YOLO格式txt标注标注类别统一为butterfly使用labelImg工具完成标注过程遵循准确框选边界、尽量覆盖全部目标、并进行一致性检查的原则。压缩包为rar格式无需解压密码共2000个文件其中xml文件1425个、txt文件575个整体约60.54MB解压后含图片、xml标注和txt标注三个文件夹可直接用对应软件查看标注情况。目前已有235人学习下载适合需要快速获取规范标注数据、开展蝴蝶检测实验或作为教学案例的读者使用。1. 蝴蝶数据集 VOC 与 YOLO 双格式1425 张标注到底怎么用拿到一个蝴蝶数据集标着 VOC 和 YOLO 两种格式、1425 张图第一反应不该是直接丢进模型开跑而是先搞清楚这两套标注到底差在哪、为什么同一批图要存两份。VOC 格式用 XML 描述每个目标的边界框坐标是绝对像素值一个文件对应一张图YOLO 格式用 txt 描述每行一个目标坐标是归一化后的中心点加宽高一个文件同样对应一张图。1425 张这个量级说大不大说小也不小刚好卡在「够训一个能看的检测器但不够挥霍」的位置。做蝴蝶识别的人多半是想做生态监测、科普应用或者细粒度分类的前置检测这批数据能帮你把「蝴蝶在哪」这个问题先解决掉至于「是哪一种蝴蝶」那是后面分类模型的事。这一篇就按我实际处理这类数据集的顺序把格式转换、目录组织、训练配置和踩过的坑一次讲清楚。2. 先搞懂 VOC 和 YOLO 的坐标账为什么不能直接混用2.1 两种格式的坐标体系差异VOC 的 XML 里每个object下有bndbox里面是xmin、ymin、xmax、ymax这四个值是图片上的绝对像素坐标左上角为原点。YOLO 的 txt 里每行是class_id x_center y_center width height后四个都是相对于图片宽高的归一化值范围在 0 到 1 之间。很多人第一次转换时翻车就是因为忘了归一化或者用错了宽高基准。举个例子一张 640×480 的图VOC 里有个框是xmin100, ymin80, xmax300, ymax280转成 YOLO 就是中心点 x (100300)/2/640 0.3125中心点 y (80280)/2/480 0.375宽 (300-100)/640 0.3125高 (280-80)/480 0.4167。算错一步框就飘了。2.2 类别映射与文件命名的一致性VOC 的 XML 里类别是字符串比如namebutterfly/nameYOLO 的 txt 里类别是整数索引从 0 开始。转换时必须维护一张类别到索引的映射表而且这张表在训练和推理时要保持一致。另一个容易忽略的点是文件命名VOC 的 XML 和图片同名不同后缀YOLO 的 txt 也要和图片同名不同后缀。如果图片是img_001.jpg那 XML 应该是img_001.xmltxt 应该是img_001.txt。我见过有人把 txt 命名成img_001.jpg.txt训练时找不到标签白跑一晚上。2.3 一个可直接抄的转换脚本下面这个脚本处理 VOC 到 YOLO 的转换假设你的目录结构是annotations/放 XMLimages/放图片输出到labels/。脚本会读取每张图的实际宽高避免用错基准。import os import xml.etree.ElementTree as ET from PIL import Image # 类别映射按你的实际类别修改 CLASS_MAP {butterfly: 0} def voc_to_yolo(xml_path, img_path, out_txt_path): tree ET.parse(xml_path) root tree.getroot() # 用图片实际尺寸不要用 XML 里可能缺失的 size with Image.open(img_path) as im: w, h im.size lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_MAP: continue cls_id CLASS_MAP[name] bnd obj.find(bndbox) xmin float(bnd.find(xmin).text) ymin float(bnd.find(ymin).text) xmax float(bnd.find(xmax).text) ymax float(bnd.find(ymax).text) # 归一化并限制在 0~1防止越界框 xc max(0.0, min(1.0, (xmin xmax) / 2.0 / w)) yc max(0.0, min(1.0, (ymin ymax) / 2.0 / h)) bw max(0.0, min(1.0, (xmax - xmin) / w)) bh max(0.0, min(1.0, (ymax - ymin) / h)) lines.append(f{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: img_dir images xml_dir annotations out_dir labels os.makedirs(out_dir, exist_okTrue) for fname in os.listdir(xml_dir): if not fname.endswith(.xml): continue stem os.path.splitext(fname)[0] xml_path os.path.join(xml_dir, fname) img_path os.path.join(img_dir, stem .jpg) if not os.path.exists(img_path): print(fmissing image for {stem}, skip) continue out_txt os.path.join(out_dir, stem .txt) voc_to_yolo(xml_path, img_path, out_txt) print(done)逻辑说明脚本先解析 XML拿到每个 object 的类别和绝对坐标再用 PIL 打开对应图片取真实宽高做归一化。参数方面CLASS_MAP必须和你的数据集类别完全一致多一个空格都会导致漏标max(0.0, min(1.0, ...))是保险防止个别标注越界导致训练时 loss 爆炸。跑完后建议抽查几个 txt用可视化脚本画框确认。3. 1425 张蝴蝶图怎么切分与组织目录结构决定训练能不能跑起来3.1 训练集、验证集、测试集的划分比例1425 张不算多划分要谨慎。常见做法是训练集 80%、验证集 10%、测试集 10%也就是大约 1140 / 142 / 143。但如果你的蝴蝶种类多、每类样本少建议用分层抽样保证每个类别在三个集合里都有代表。我一般会先统计每个类别的图片数如果某个类别少于 20 张就把它在训练集里的比例调高验证集里至少留 2 到 3 张否则验证指标会剧烈波动你根本不知道模型是真差还是验证集太小。3.2 目录结构长什么样YOLO 训练时数据集的目录结构直接影响你能不能少改配置。推荐这样组织butterfly_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml图片和标签分开存放但文件名一一对应。data.yaml里写清楚路径和类别名path: ./butterfly_dataset train: images/train val: images/val test: images/test nc: 1 names: [butterfly]如果你的蝴蝶数据集有多个类别nc改成实际数量names按索引顺序列出。注意names的顺序必须和转换脚本里的CLASS_MAP一致否则训练出来的模型会把类别搞反。3.3 划分脚本与随机种子手动拷贝文件容易出错写个脚本按比例划分固定随机种子保证可复现import os import random import shutil random.seed(42) img_dir images_all lbl_dir labels_all out_root butterfly_dataset split_ratio {train: 0.8, val: 0.1, test: 0.1} files [f for f in os.listdir(img_dir) if f.endswith(.jpg)] random.shuffle(files) n len(files) n_train int(n * split_ratio[train]) n_val int(n * split_ratio[val]) splits { train: files[:n_train], val: files[n_train:n_train n_val], test: files[n_train n_val:] } for split, flist in splits.items(): img_out os.path.join(out_root, images, split) lbl_out os.path.join(out_root, labels, split) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for f in flist: stem os.path.splitext(f)[0] shutil.copy(os.path.join(img_dir, f), os.path.join(img_out, f)) lbl_src os.path.join(lbl_dir, stem .txt) if os.path.exists(lbl_src): shutil.copy(lbl_src, os.path.join(lbl_out, stem .txt)) print(split done)参数说明random.seed(42)保证每次划分结果一样方便对比实验split_ratio按你的实际需求调整如果数据量更小可以改成 0.9/0.05/0.05。跑完后检查三个目录的文件数是否和预期一致特别是标签文件有没有漏拷。4. 用 YOLO 训练蝴蝶检测器从环境到第一轮结果的完整命令4.1 环境安装与版本选择YOLO 系列现在主流用 Ultralytics 的包安装命令很简单pip install ultralytics如果你要用 GPU 训练先确认 CUDA 和 PyTorch 版本匹配。我一般会先跑python -c import torch; print(torch.cuda.is_available())返回 True 再继续。蝴蝶数据集 1425 张用 YOLOv8n 或 YOLOv8s 就够n 版最快s 版精度稍好。别一上来就上 x 版数据量撑不住过拟合风险高。4.2 训练命令与关键参数假设你的data.yaml放在butterfly_dataset/下训练命令yolo detect train \ databutterfly_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/butterfly \ nameexp1参数逐个说epochs100是上限patience20表示验证指标 20 轮不提升就早停避免浪费时间imgsz640是输入尺寸蝴蝶目标通常不大640 够用如果小目标多可以试 960但显存要够batch16根据显存调8G 显存跑 640 的 n 版没问题lr00.01是初始学习率默认值数据量小可以降到 0.005。训练过程中看runs/butterfly/exp1/下的results.csv重点看mAP50和mAP50-95是否在涨。4.3 训练完怎么验证和推理训练结束后用验证集跑一次yolo detect val \ modelruns/butterfly/exp1/weights/best.pt \ databutterfly_dataset/data.yaml \ imgsz640推理单张图片yolo detect predict \ modelruns/butterfly/exp1/weights/best.pt \ sourcebutterfly_dataset/images/test \ conf0.25 \ saveTrueconf0.25是置信度阈值蝴蝶背景复杂时可以调到 0.3 减少误检。结果图会保存在runs/detect/predict/下打开看看框得准不准有没有漏掉小蝴蝶。5. 避坑与排查蝴蝶数据集训练中最容易翻车的 5 个点5.1 现象训练 loss 不降mAP 一直是 0原因标签路径不对YOLO 找不到 txt 文件或者 txt 内容为空。解决检查labels/train/下是否有对应图片名的 txt打开一个看里面有没有内容。如果 txt 是空的说明转换脚本里类别映射没匹配上回去检查CLASS_MAP的键和 XML 里的name是否完全一致包括大小写和空格。5.2 现象训练报错「No labels found」原因data.yaml里的路径写错了或者图片和标签的目录结构不符合 YOLO 的预期。解决YOLO 默认会在图片路径的同级目录找labels文件夹或者按data.yaml里的path拼接。我一般直接用绝对路径测试确认没问题再改成相对路径。另外注意train和val后面跟的是目录不是文件。5.3 现象验证集 mAP 很高但测试集一塌糊涂原因划分数据时没有分层验证集和测试集里某些类别样本太少或者训练集和测试集有重复图片。解决用脚本检查三个集合的文件名是否有交集有交集就重新划分。另外统计每个类别的样本数如果某个类别在测试集里只有一两张指标没有参考价值。5.4 现象推理时框的位置明显偏移原因VOC 转 YOLO 时归一化用错了宽高比如用了 XML 里的size而不是图片实际尺寸或者宽高写反了。解决重新跑转换脚本确保用 PIL 读取图片真实尺寸。抽查几个框用 OpenCV 画出来对比原图偏移超过几个像素就要查。5.5 现象训练到一半显存爆了原因batch设太大或者imgsz设太高。解决先把batch降到 8 或 4如果还爆就降imgsz到 416。另外检查有没有其他进程占着显存nvidia-smi看一眼。蝴蝶数据集 1425 张用 n 版模型 640 尺寸8G 显存跑 batch16 是安全的如果你同时开了其他任务降到 8。6. 把 1425 张用到极致小数据集的增强策略与验证技巧1425 张对于检测任务来说属于小数据集想让它发挥出超出量级的性能增强策略和验证方法得讲究。我一般会在 YOLO 的默认增强基础上针对蝴蝶的特点做调整。蝴蝶的形态、颜色、翅膀纹理是判别关键所以颜色抖动可以适当加大但几何变换要克制因为蝴蝶的对称性一旦被破坏模型可能学到错误的特征。在data.yaml同级建一个hyps.yaml覆盖默认增强参数hsv_h: 0.02 hsv_s: 0.7 hsv_v: 0.5 degrees: 10.0 translate: 0.1 scale: 0.3 shear: 2.0 perspective: 0.0 flipud: 0.0 fliplr: 0.5 mosaic: 1.0 mixup: 0.1hsv_s调到 0.7 是让饱和度变化更丰富模拟不同光照下的蝴蝶degrees只给 10 度避免过度旋转导致翅膀方向错乱flipud设为 0因为蝴蝶上下翻转不符合自然姿态mosaic保持 1.0小数据集靠拼接增加场景多样性mixup给 0.1轻微混合防止过拟合。训练时加上hyphyps.yaml即可。验证阶段除了看 mAP我习惯用混淆矩阵和 PR 曲线判断模型到底学到了什么。YOLO 训练完会自动生成confusion_matrix.png和PR_curve.png打开看如果蝴蝶类别和背景的混淆很高说明误检多回去调conf阈值或者增加背景负样本如果召回率上不去说明漏检多检查标注有没有漏框或者把imgsz调大。另一个技巧是拿几张训练集里的图做推理看模型是不是在「背答案」如果训练集上完美、验证集上拉胯那就是过拟合减少epochs或者加大dropoutYOLO 里通过dropout参数控制默认 0.0可以设 0.1。最后说个我自己的习惯每次处理新数据集先拿 100 张跑一个 10 轮的快速实验确认流程通了、指标在动再上全量。1425 张全量跑一次 100 轮n 版在单卡上大概几十分钟但如果你前面格式转错了这几十分钟就是白等。先小后大先通后优这个顺序能帮你省下不少后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表