蜈蚣数据集VOC与YOLO双格式:237张单类别标注训练全流程
简介本资源为蜈蚣目标检测数据集面向从事计算机视觉、深度学习目标检测的开发者与研究者尤其适合需要单一类别小样本数据验证模型或进行迁移学习实验的场景。压缩包共713个文件包含237张jpg图片、237个VOC格式xml标注文件、237个yolo格式txt标注文件及少量说明文件整体约68.14MB可同时满足Pascal VOC与YOLO两种主流训练框架的数据读取需求。标注采用labelImg工具完成仅设Centipede一个类别共标注255个矩形框标注准确合理可直接用于训练与评估。目前已有96人学习下载适合快速搭建蜈蚣检测基线、测试数据增强策略或作为课程实验与毕业设计的素材。数据集仅提供标注文件不对模型精度作保证使用者需自行划分训练集与验证集并调整超参数。1. 蜈蚣数据集 VOC 与 YOLO 双格式237 张单类别标注到底能训出什么手上只有 237 张蜈蚣图片标注还分 VOC 和 YOLO 两套格式很多人第一反应是“这点数据能干嘛”。我最初也这么想直到把它当成一个小样本单类别检测的基准集来用才发现它的价值不在数量而在干净。单类别意味着没有类别竞争237 张意味着你可以在十分钟内跑完一轮训练VOC 和 YOLO 双格式意味着你不用写转换脚本就能直接喂给不同框架。它适合三类人想验证 YOLO 训练流程是否跑通的新手、需要快速做消融实验的算法工程师、以及要给别人演示“从标注到推理”全链路的布道者。这个数据集不解决精度天花板问题但它解决“我到底有没有把流程走对”的问题。下面我从格式差异讲到训练参数再到避坑和验证把这条最短路径拆开。2. VOC 与 YOLO 格式的差异为什么同一批图要存两份标注2.1 XML 与 TXT 的坐标逻辑完全不同VOC 格式每张图对应一个 XML 文件里面用bndbox记录xmin, ymin, xmax, ymax这是绝对像素坐标原点在左上角。YOLO 格式每张图对应一个 TXT 文件每行是class_id x_center y_center width height全部是归一化到 0~1 的相对值原点同样在左上角但宽高是相对于整图尺寸的比例。很多人第一次转换时翻车就是因为把 VOC 的绝对坐标直接除以图片宽度却忘了xmax和xmin的差值才是宽度而不是xmax本身。我一般会先确认图片尺寸是否一致。如果 237 张图尺寸参差不齐VOC 转 YOLO 时必须逐张读取实际宽高不能用一个固定值去归一化。下面这段脚本是我常用的转换逻辑处理单类别时class_id恒为 0。import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_dir, img_dir, out_dir): os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() # 图片文件名来自 XML 的 filename 节点 img_name root.find(filename).text img_path os.path.join(img_dir, img_name) with Image.open(img_path) as im: w, h im.size lines [] for obj in root.findall(object): # 单类别class_id 固定为 0 cls_id 0 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) # 归一化中心点和宽高 x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) txt_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) voc_to_yolo(annotations_xml, images, labels_yolo)逻辑说明先解析 XML 拿到绝对坐标再用PIL读取对应图片的真实宽高最后做归一化。参数上x_center和y_center保留六位小数足够YOLO 官方解析时对精度不敏感。注意filename节点必须和实际图片文件名一致否则会报FileNotFoundError。如果 XML 里没有filename可以用 XML 文件名去匹配图片但前提是命名规则统一。2.2 目录结构决定你能不能直接开训YOLO 系列对目录结构有硬性要求images/train、images/val、labels/train、labels/val四个文件夹必须平级且图片和标签文件名一一对应。VOC 格式则通常把 JPEG 和 XML 混在一起或者分JPEGImages和Annotations两个文件夹。我见过太多人把 VOC 的 XML 直接丢进 YOLO 的labels文件夹结果训练时 loss 一直是nan因为解析器读到的不是归一化坐标。常见做法是先用脚本按 8:2 划分训练集和验证集再分别复制图片和标签。下面这个划分脚本会生成train.txt和val.txt同时把文件复制到对应目录。# 假设图片在 images/标签在 labels_yolo/ mkdir -p dataset/images/train dataset/images/val mkdir -p dataset/labels/train dataset/labels/val # 随机打乱后按 8:2 划分 ls images/ | shuf all_files.txt total$(wc -l all_files.txt) train_count$(( total * 80 / 100 )) head -n $train_count all_files.txt | while read f; do cp images/$f dataset/images/train/ base${f%.*} cp labels_yolo/$base.txt dataset/labels/train/ done tail -n $((train_count 1)) all_files.txt | while read f; do cp images/$f dataset/images/val/ base${f%.*} cp labels_yolo/$base.txt dataset/labels/val/ done参数说明shuf做随机打乱避免按文件名排序导致分布偏差。train_count取 80%237 张图大约 189 张训练、48 张验证。如果图片扩展名不统一base${f%.*}能去掉最后一个点之后的内容但要求图片和标签的主文件名完全一致。执行完检查一下dataset/labels/train里的 TXT 数量是否和dataset/images/train里的图片数量相等不等就说明有孤儿文件。2.3 单类别数据集的 YAML 配置怎么写YOLOv5 和 YOLOv8 都用 YAML 描述数据集路径和类别。单类别时nc: 1names: [centipede]。路径建议写绝对路径避免训练时工作目录变化导致找不到文件。# centipede.yaml path: /home/user/dataset train: images/train val: images/val nc: 1 names: [centipede]注意path下面直接跟train和val的相对路径不要写成images/train/带尾部斜杠某些版本会解析失败。如果训练时报No labels found先检查labels/train是否和images/train平级再检查 TXT 文件里是否有空行或全零坐标。3. 用 YOLOv8 在 237 张图上跑通训练参数怎么设才不浪费算力3.1 环境配置与最小命令YOLOv8 对环境要求不算苛刻Python 3.8 以上、PyTorch 1.8 以上即可。我一般用 conda 建一个干净环境避免和系统里的其他包冲突。conda create -n centipede python3.10 -y conda activate centipede pip install ultralytics装完后直接跑训练命令。237 张图用yolov8n.pt预训练权重就够了没必要上yolov8x小数据集上大模型反而容易过拟合。yolo detect train \ datacentipede.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectcentipede_runs \ nameexp1参数说明epochs100对 237 张图偏多但配合patience20会在验证集指标不再提升时提前停止。imgsz640是 YOLOv8 的默认输入尺寸如果原图小于 640会做填充如果远大于 640建议先缩放到 640 再标注否则小目标会被过度压缩。batch16在 8GB 显存上能跑如果显存不够降到 8 或 4。lr00.01是初始学习率小数据集上可以降到 0.001 防止震荡。3.2 训练日志里必须盯住的三个指标第一个是box_loss如果它在前 10 个 epoch 内不下降说明标签格式有问题优先检查 TXT 里的坐标是否在 0~1 之间。第二个是mAP50单类别数据集上这个值通常能到 0.8 以上如果低于 0.5要么是验证集太小要么是标注框漏标严重。第三个是cls_loss单类别时它应该很快降到接近 0如果一直很高检查 YAML 里的nc是否写成了 2 或更大。我习惯在训练命令里加plotsTrue跑完后会生成confusion_matrix.png和results.png。混淆矩阵能直接看出漏检和误检的比例比盯着 loss 曲线直观得多。237 张图跑 100 个 epoch 在单卡 3060 上大约 15 分钟如果超过半小时检查是不是imgsz设成了 1280 或者batch太小导致频繁读盘。3.3 推理时置信度门限怎么调训练完先用yolo detect predict跑几张验证集图片看默认conf0.25下的效果。蜈蚣这种细长目标如果背景复杂默认门限可能会漏检。我一般会写一个循环把conf从 0.1 到 0.5 各跑一遍统计检出框数量。from ultralytics import YOLO model YOLO(centipede_runs/exp1/weights/best.pt) for conf in [0.1, 0.2, 0.3, 0.4, 0.5]: results model.predict(dataset/images/val, confconf, saveFalse) total_boxes sum(len(r.boxes) for r in results) print(fconf{conf}, boxes{total_boxes})逻辑说明conf越低检出框越多但误检也会增加。单类别数据集上我通常选在检出框数量趋于平稳的那个值比如从 0.1 到 0.2 数量翻倍但从 0.3 到 0.4 只增加几个那 0.3 就是比较稳的门限。注意saveFalse避免生成大量图片占用磁盘确认门限后再开saveTrue输出可视化结果。4. 避坑与排查237 张单类别数据集最容易翻车的五个地方4.1 现象训练 loss 从第一轮就是 nan原因YOLO 格式的 TXT 里坐标没有归一化或者出现了负数。VOC 转 YOLO 时如果xmax小于xmin算出来的宽度是负值。 解决用脚本遍历所有 TXT检查每行后四个数是否都在 0~1 之间且width和height大于 0。发现异常就回到 XML 里核对标注框是否画反了。4.2 现象验证集 mAP 一直是 0原因val路径下的图片和标签没有对应上或者 YAML 里的names和 TXT 里的class_id不匹配。单类别时class_id必须是 0如果标成了 1而nc1解析器会直接忽略。 解决随机抽一个验证集 TXT看第一列是不是 0。再看centipede.yaml里的val路径是否指向了包含图片和标签的父目录而不是直接指向images/val。4.3 现象训练到一半显存爆了原因batch设得太大或者imgsz设成了 1280 但图片本身很小填充后反而增加了计算量。 解决先把batch降到 4 跑一轮确认能跑通再逐步往上加。237 张图用batch8和batch16的最终精度差异通常不到 1%没必要为了大 batch 牺牲稳定性。4.4 现象推理时框住了整张图原因TXT 里出现了0 0.5 0.5 1.0 1.0这样的全图框通常是标注时误操作或者转换脚本把没有目标的图片也生成了默认框。 解决统计每个 TXT 的宽度和高度如果接近 1.0直接删掉这一行。单类别数据集里全图框会让模型学会“偷懒”把整张图判为正样本。4.5 现象换了 YOLOv5 后同样的数据跑不动原因YOLOv5 的 YAML 里nc和names的写法与 YOLOv8 略有不同且 YOLOv5 要求train和val写成 TXT 列表文件路径而不是目录。 解决YOLOv5 需要先生成train.txt和val.txt每行是图片的绝对路径。然后在 YAML 里写train: train.txtval: val.txt。不要直接把 YOLOv8 的 YAML 拿过来用。5. 用 237 张图验证模型是否真的学到了蜈蚣三个进阶技巧第一个技巧是留出法交叉验证。237 张图做 5 折交叉验证每折训练 189 张、验证 48 张跑完 5 次后看 mAP 的均值和方差。如果方差超过 0.1说明数据分布不均匀某些折里的蜈蚣姿态或背景差异太大。我一般会固定随机种子把 5 折的results.png叠在一起看曲线重合度越高模型越稳。第二个技巧是用 VOC 格式的 XML 做独立验证。YOLO 训练用的是归一化坐标但 VOC 的 XML 保留了绝对像素坐标。你可以写一个脚本把模型预测的归一化框还原成绝对坐标再和 XML 里的bndbox做 IoU 对比。这样能排除归一化过程中引入的精度损失尤其适合检查小目标。def yolo_to_voc(x_center, y_center, bw, bh, img_w, img_h): xmin int((x_center - bw / 2) * img_w) ymin int((y_center - bh / 2) * img_h) xmax int((x_center bw / 2) * img_w) ymax int((y_center bh / 2) * img_h) return max(0, xmin), max(0, ymin), min(img_w, xmax), min(img_h, ymax)参数说明img_w和img_h必须和训练时imgsz缩放后的尺寸一致如果训练时做了 letterbox 填充还原时还要减去填充偏移。这个函数返回的坐标可以直接和 VOC XML 里的值算 IoUIoU 低于 0.5 的框就是模型没学好的部分。第三个技巧是冻结主干只训检测头。237 张图从头训容易过拟合我一般会先冻结 YOLOv8 的主干网络只训练最后的检测头 20 个 epoch再解冻全部微调 30 个 epoch。这样 mAP 通常比直接训 100 个 epoch 高 3~5 个百分点。命令里加freeze10表示冻结前 10 层具体层数可以用model.model打印出来看。最后一个习惯每次跑完实验把centipede.yaml、训练命令和results.png一起存到一个带日期的文件夹里。237 张图跑一轮很快但如果不记录参数两周后你根本想不起来哪个exp对应哪个学习率。我吃过这个亏现在哪怕只改一个conf也会新建一个文件夹。希望帮到你。本文还有配套的精品资源点击获取