尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

蝴蝶数据集实测:1425张VOC与YOLO双格式标注能否直接开训

蝴蝶数据集实测:1425张VOC与YOLO双格式标注能否直接开训 简介本资源为蝴蝶目标检测数据集面向从事计算机视觉、深度学习目标检测的开发者与学习者可用于模型训练、算法验证及课程实验。数据集共1425张jpg图片每张均配有对应的VOC格式xml标注与YOLO格式txt标注标注类别统一为butterfly使用labelImg完成遵循准确框选边界、尽量覆盖全部目标、标注后一致性检查等规范可直接用于检测任务。压缩包为rar格式无需解压密码内含图片、xml、txt三个文件夹解压后即可用对应软件查看标注情况。资源包共2000个文件其中xml文件1425个、txt文件575个整体约60.54MB图片大小在1-500KB之间。目前已有235人学习下载适合需要快速获取规范标注数据、搭建蝴蝶检测基线或进行格式转换练习的读者参考使用。1. 蝴蝶数据集实测1425 张 VOC 与 YOLO 双格式标注到底能不能直接开训上周有个做农业虫情监测的朋友甩给我一个压缩包说是在棚里拍蝴蝶顺带标了一批数据问我能不能直接拿去训检测模型。我解压一看1425 张 jpg配了 1425 个 xml 和 1425 个 txt类别只有一个 butterfly标注工具是 labelImg。这种「单类别、双格式、千张级」的数据集在目标检测里属于典型的入门到进阶过渡料——说它小够跑通全流程说它大又不足以撑起一个工业级模型。它真正解决的是「我不想从零标数据但我想验证一套 YOLO 训练链路是否跑得通」这个诉求。适合谁刚学 YOLO 想找现成数据练手的人、需要快速搭一个蝴蝶识别 demo 的开发者、以及想对比 VOC 与 YOLO 两种格式转换差异的从业者。下面我按实际拆包、转换、训练、排错的顺序把这份数据集的用法和边界讲透。2. 拆包先看结构VOC 与 YOLO 双格式到底怎么对应拿到压缩包别急着往训练脚本里塞先把目录结构摸清楚。这份数据集解压后是三个文件夹一个放 jpg 原图一个放 xml一个放 txt。很多人第一次用双格式数据集会懵——到底该用哪套其实两套是同一批标注的两种表达xml 是 VOC 的 XML 结构txt 是 YOLO 的归一化坐标。你得先确认它们是否一一对应否则后面训练出现「图片找不到标签」的玄学问题排查起来很费劲。2.1 VOC 的 XML 结构与 YOLO 的 TXT 结构差异VOC 格式的 xml 里关键节点是filename、size、object下的name和bndbox。bndbox 存的是绝对像素坐标xmin, ymin, xmax, ymax。而 YOLO 的 txt 每行是class_id x_center y_center width height全部归一化到 0~1。这份数据集类别只有 butterfly所以 class_id 恒为 0。理解这个差异你才能判断转换脚本有没有写错。我一般会先抽三张图用脚本把 xml 和 txt 的框还原到图上肉眼比对是否重合。这一步花五分钟能省掉后面几小时的 loss 不下降排查。import xml.etree.ElementTree as ET import os def parse_voc_xml(xml_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) boxes [] for obj in root.iter(object): name obj.find(name).text bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) boxes.append((name, xmin, ymin, xmax, ymax)) return w, h, boxes # 抽一张看看 w, h, boxes parse_voc_xml(Annotations/butterfly_702.xml) print(f尺寸: {w}x{h}, 目标数: {len(boxes)}) for b in boxes: print(b)这段代码把 xml 里的宽高和目标框读出来。参数上注意size节点有的数据集会缺失缺失时得用 PIL 读图补上。逻辑说明先拿图像尺寸再遍历所有 object输出类别和绝对坐标。如果你发现某个 xml 的 bndbox 超出图像范围那这张标注就有问题训练时会被 YOLO 的 dataloader 过滤掉导致实际参与训练的图片少于 1425。2.2 校验图片与标注的一一对应关系双格式数据集最常见的坑是「图片有xml 没有」或者「txt 有图片没有」。我写了个校验脚本一次性列出所有不匹配项。import os img_dir JPEGImages xml_dir Annotations txt_dir labels imgs set(os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(.jpg)) xmls set(os.path.splitext(f)[0] for f in os.listdir(xml_dir) if f.endswith(.xml)) txts set(os.path.splitext(f)[0] for f in os.listdir(txt_dir) if f.endswith(.txt)) print(图片无xml:, imgs - xmls) print(xml无图片:, xmls - imgs) print(图片无txt:, imgs - txts) print(txt无图片:, txts - imgs)跑完如果四个集合都为空说明 1425 张完全对齐。如果有差异优先以图片为准把多余的标注删掉或补标。这份数据集正文里列了十个文件名比如 butterfly_702、butterfly_853说明命名是 butterfly_编号 的规则校验时用 splitext 去后缀比对最稳。提示校验脚本跑完记得看一眼图片总数是不是 1425有些压缩包在传输过程中会丢文件尤其是分卷压缩的情况。3. 从 VOC 转 YOLO转换脚本与四个边界坑虽然数据集已经带了 txt但很多人拿到 VOC 格式后想自己转一遍或者想把 txt 转回 xml 做可视化。这一章把双向转换讲清楚顺便把转换过程中最容易翻车的四个边界问题列出来。YOLO 训练时读的是 txt所以如果你拿到的只有 xml必须转如果两套都有建议还是自己转一遍确保坐标归一化没算错。3.1 归一化坐标的计算与类别映射VOC 转 YOLO 的核心公式x_center (xmin xmax) / 2 / wy_center (ymin ymax) / 2 / hwidth (xmax - xmin) / wheight (ymax - ymin) / h。类别名到 id 的映射要固定这份数据集只有 butterfly映射成 0 即可。如果以后扩展多类别映射表要写进classes.txt顺序不能乱。import xml.etree.ElementTree as ET import os from PIL import Image classes [butterfly] class_to_id {c: i for i, c in enumerate(classes)} def voc_to_yolo(xml_path, img_path, out_txt_path): tree ET.parse(xml_path) root tree.getroot() # 优先用 PIL 读尺寸避免 xml 里 size 缺失或错误 with Image.open(img_path) as im: w, h im.size lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_to_id: continue bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 裁剪到图像边界内 xmin max(0, min(xmin, w)) xmax max(0, min(xmax, w)) ymin max(0, min(ymin, h)) ymax max(0, min(ymax, h)) if xmax xmin or ymax ymin: continue xc (xmin xmax) / 2 / w yc (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{class_to_id[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) with open(out_txt_path, w) as f: f.write(\n.join(lines))逻辑说明先读图拿真实宽高再遍历 object做边界裁剪最后归一化写入。参数上:.6f保留六位小数YOLO 官方推荐至少六位少了会导致小目标框偏移。类别映射用字典扩展时只改 classes 列表。3.2 四个边界坑越界、空标注、小数点、类别错位第一个坑是越界框。有些标注员手抖xmax 写成 1920 但图宽只有 1920归一化后 x_center 可能大于 1YOLO 直接报错。上面代码里做了min(xmax, w)裁剪但裁剪后如果 xmax xmin 就跳过避免产生无效框。第二个坑是空标注。一张图里没有 butterflyxml 里没有 object 节点转出来的 txt 是空文件。YOLO 训练时空 txt 是合法的表示背景图但如果你用某些第三方脚本空文件会被当成损坏标签。我一般保留空 txt并在训练配置里确认allow_empty相关参数。第三个坑是小数点精度。有的转换脚本用round(x, 2)两位小数在 640 分辨率下误差能到几个像素小目标直接训崩。必须保留六位。第四个坑是类别错位。如果你有多个类别classes 列表顺序和 txt 里的 id 必须一致。我见过有人把butterfly写成0但 classes.txt 第一行是cat结果模型学出来全是猫。这份数据集单类别暂时不会遇到但扩展时一定要检查。注意转换完成后随机抽 10 张图用labelImg打开 txt 格式的 labels 目录肉眼确认框的位置和 xml 一致。这一步是后悔药别省。4. 避坑排查训练前必须过的五道检查数据集本身质量不错但「能打开」和「能训出东西」是两回事。这一章列五个我实际踩过的坑每个按现象、原因、解决写。你照着过一遍能避开八成训练初期的报错。4.1 现象训练启动报「No labels found」原因YOLO 默认在images同级找labels目录或者路径配置里train指向的 txt 列表路径不对。这份数据集解压后三个文件夹是平级的如果你直接把JPEGImages当 images 用YOLO 会去JPEGImages同级找labels找不到就报这个。解决要么把目录改成images/train和labels/train的标准结构要么在 data.yaml 里显式写train: /path/to/train.txttrain.txt 里每行是图片绝对路径。我一般用后者改起来快。4.2 现象loss 一直不降mAP 卡在 0.01原因txt 里的坐标没归一化或者归一化时除了错误的宽高。比如用 xml 里的 size 宽高但 size 写的是 500x500实际图是 1920x1080坐标全错。解决用 PIL 重新读图拿真实尺寸重跑转换脚本。验证方法随便挑一个 txt把坐标乘回图像宽高画框看是否贴合蝴蝶。4.3 现象训练中途报「ZeroDivisionError」或「invalid bbox」原因存在宽或高为 0 的框通常是 xmin xmax 或 ymin ymax。标注时点了两下同一个位置就会这样。解决在转换脚本里加判断if xmax xmin or ymax ymin: continue。同时统计被跳过的框数量如果超过总数 1%说明标注质量有问题得回头修。4.4 现象验证集 mAP 正常但推理时框全偏原因训练时用了 letterbox 填充推理时没做同样的预处理或者 txt 坐标对应的是原图但推理输入被 resize 后没还原。解决确认训练和推理的预处理一致。YOLO 官方推理脚本会自动处理如果你自己写推理记得把输出框按比例映射回原图尺寸。4.5 现象图片总数 1425但训练日志显示只有 1200 张参与原因部分图片损坏或格式不是标准 jpgPIL 打不开dataloader 直接跳过。另外空 txt 在某些版本里也会被跳过。解决用 PIL 批量验证图片完整性损坏的重新导出。空 txt 确认是否要保留如果保留检查 YOLO 版本的skip_empty参数。from PIL import Image import os bad [] for f in os.listdir(JPEGImages): if not f.endswith(.jpg): continue try: with Image.open(os.path.join(JPEGImages, f)) as im: im.verify() except Exception as e: bad.append((f, str(e))) print(损坏图片:, bad)这段校验脚本跑一遍把打不开的图片列出来。参数上im.verify()只检查文件头不解码全图速度快。如果坏图多建议重新解压压缩包可能是下载不完整。5. 进阶用法用这份数据集验证 YOLO 改进点与导出部署数据集的价值不止于跑通 baseline。1425 张单类别蝴蝶图刚好适合做小规模消融实验——你想试一个新的损失函数、换一个 neck 结构、或者验证 TensorRT 导出后的速度用它比用 COCO 快得多。这一章讲两个具体技巧一是怎么用它快速对比不同 YOLO 版本的收敛差异二是导出 ONNX 后怎么确认输出节点没接错。5.1 用 1425 张做小规模消融的配置建议我一般把数据按 8:1:1 切分训练集 1140 张验证集 142 张测试集 143 张。batch size 设 16输入 640跑 100 epoch。这个规模下单卡 1080Ti 大概两小时能跑完一轮。如果你想对比两个改进点固定随机种子只改模型结构其他超参不动。注意这份数据集类别少mAP 容易过拟合看 loss 曲线比看最终 mAP 更可靠。# 切分脚本示例 python split.py --img_dir JPEGImages --txt_dir labels --out_dir dataset --ratio 8:1:1切分时确保同一张图不会同时出现在训练和验证集。我见过有人按 txt 行切分结果同一张图的不同框被分到两边验证集 mAP 虚高。5.2 导出 ONNX 与 TensorRT 的验证方法训练完导出 ONNX用onnxruntime跑一张图对比 PyTorch 输出。如果数值差异大于 1e-3检查导出时的 opset 和动态轴设置。这份数据集输入固定 640x640导出时把 dynamic 关掉TensorRT 推理更快。import onnxruntime as ort import numpy as np sess ort.InferenceSession(butterfly.onnx) inp np.random.randn(1, 3, 640, 640).astype(np.float32) out sess.run(None, {images: inp}) print(输出节点数:, len(out)) for o in out: print(o.shape)逻辑说明构造一个随机输入跑 ONNX 会话看输出 shape 是否符合预期。YOLO 一般输出[1, 25200, 85]或类似结构具体看版本。如果输出节点名不对用sess.get_outputs()查。参数上注意输入名要和导出时一致常见是images。提示TensorRT 部署时预处理和后处理必须和训练一致。蝴蝶数据集图片大小 1-500KB分辨率不一推理前统一 resize 到 640保持长宽比填充灰边。从那以后我每次拿到新数据集都强制走一遍「校验对应关系 → 抽图可视化 → 转换后复查 → 训练前查坏图」这四步再也没出现过训到一半发现标签错位的翻车。希望帮到你。本文还有配套的精品资源点击获取
返回列表