ARTICLE DETAIL

资讯详情

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

蜈蚣数据集VOC+YOLO双格式:237张单类别训练与优化指南

蜈蚣数据集VOC+YOLO双格式:237张单类别训练与优化指南 简介本资源为蜈蚣目标检测数据集面向从事深度学习目标检测训练的学生、算法工程师及科研人员可用于验证YOLO或Faster R-CNN等模型在单类别小样本场景下的表现。压缩包共713个文件包含237张jpg原图、237个VOC格式xml标注文件、237个yolo格式txt标注文件另有少量说明文件整体约68.14MB目录结构清晰方便直接接入主流检测框架。所有图片均由labelImg工具人工画框标注类别为Centipede共255个标注框标注准确合理省去自行采集与标注的时间成本。目前已有96人学习下载适合快速搭建训练与验证流程、测试数据增强策略或作为课程实验素材使用。需注意该数据集不对训练所得模型或权重文件的精度作任何保证仅提供标注数据本身。1. 蜈蚣数据集 VOCYOLO 双格式237 张 1 类别到底能训出什么手上只有 237 张图、1 个类别很多人第一反应是「这点数据能干嘛」。我去年接过一个中药材仓储的虫害监测小需求客户只给了一批蜈蚣样本图要求识别出画面里有没有蜈蚣用来触发后续的喷药流程。当时拿到的就是这种 VOC 标注、单类别、两百多张的小包。结论先放这单类别 237 张只要标注干净、增广到位训一个能用的检测器完全够甚至比堆几千张脏数据更省事。这个数据集的价值不在「大」而在「干净且双格式」——VOC 的 XML 保留了原始标注信息YOLO 的 txt 省去了转换步骤两条路都能走。适合谁适合刚入门 YOLO 想跑通全流程的人、做垂直小场景虫害、零件、特定动物的工程师以及需要快速验证一个检测想法值不值得投入的团队。下面我把从拿到这个 zip 到训出可用权重、再到排查翻车点的完整路径讲清楚。2. 先搞懂 VOC 与 YOLO 两种格式差在哪别在转换上白费功夫2.1 两种格式的坐标逻辑根本不是一回事VOC 格式每张图对应一个 XML 文件标注信息写在object节点里核心是bndbox下的xmin、ymin、xmax、ymax这四个值是绝对像素坐标原点在图片左上角。一个 XML 里可以有多个object每个 object 带自己的name类别名。蜈蚣数据集是单类别所以每个 XML 里通常只有一个 objectname 大概率是wugong或centipede这类具体以你解压后看到的为准。YOLO 格式每张图对应一个 txt 文件每行代表一个目标格式是class_id x_center y_center width height。后四个值全是归一化到 0~1 的相对值分别表示中心点横纵坐标和框的宽高都要除以图片的原始宽高。class_id 从 0 开始编号单类别就只有 0。这两种格式的差异决定了转换时最容易出错的地方VOC 的 xmax/ymax 是框的右下角坐标而 YOLO 要的是中心点和宽高中间要做一次几何换算。很多人直接拿 xmax 当 width 用训出来的框会整体偏移这是血泪经验里最常见的一条。2.2 双格式包到手后先做一次完整性核对拿到蜈蚣数据集VOC格式yolo格式237张1类别.zip别急着解压就开训。先核对三件事图片数量、标注数量、两者是否一一对应。常见做法是解压后分两个目录一个VOC含JPEGImages和Annotations一个YOLO含images和labels。# 统计图片和标注数量确认是否都是 237 find VOC/JPEGImages -type f \( -name *.jpg -o -name *.png \) | wc -l find VOC/Annotations -type f -name *.xml | wc -l find YOLO/images -type f \( -name *.jpg -o -name *.png \) | wc -l find YOLO/labels -type f -name *.txt | wc -l逻辑说明四个数字应该完全一致都是 237。如果 XML 数量少于图片说明有图漏标如果 YOLO 的 txt 数量对不上说明转换时丢了文件。参数上没什么可调的就是数数。这一步花两分钟能省掉后面训练时「为什么 loss 不降」的半天排查。提示文件名不含扩展名必须在图片和标注之间严格对应。VOC 里是001.jpg配001.xmlYOLO 里是001.jpg配001.txt。大小写敏感001.JPG和001.jpg在 Linux 下会被当成两个文件。2.3 用脚本把 VOC 转成 YOLO 并做坐标校验虽然包里已经给了 YOLO 格式但你要学会自己转因为实际项目里拿到的往往只有 VOC。下面这个脚本把 VOC 的 XML 转成 YOLO 的 txt同时打印每张图的框数量方便你发现异常。import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_dir, img_dir, out_dir, class_map): 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) w, h Image.open(img_path).size lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: continue bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 关键换算先算中心点再算宽高最后归一化 xc (xmin xmax) / 2.0 / w yc (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 越界裁剪防止标注时手抖画出图外 xc min(max(xc, 0), 1) yc min(max(yc, 0), 1) bw min(max(bw, 0), 1) bh min(max(bh, 0), 1) lines.append(f{class_map[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) out_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(lines)) print(f{xml_file}: {len(lines)} boxes) voc_to_yolo(VOC/Annotations, VOC/JPEGImages, YOLO/labels, class_map{wugong: 0})逻辑说明class_map把类别名映射到 id单类别就是{wugong: 0}如果你的 XML 里 name 是别的拼写改这里。归一化用图片真实宽高所以必须先打开图片拿尺寸不能硬编码。越界裁剪是后悔药标注时框超出图片边界的情况很常见不裁的话 YOLO 训练会报坐标异常。参数上:.6f保留六位小数足够YOLO 官方推荐至少六位。跑完看输出每张图的框数量应该是 1 或少数几张有多个蜈蚣。如果某张图打印出 0 boxes说明那个 XML 里没有有效 object要么是负样本要么是漏标需要人工确认。3. 237 张单类别怎么切分与增广小数据集的训练集构建3.1 切分比例别照搬 8:1:1常规做法是训练集:验证集:测试集 8:1:1但 237 张按这个切验证集只有 23 张测试集 23 张评估结果的抖动会非常大一次运气好 mAP 冲到 0.9下次就掉到 0.7你根本不知道模型真实水平。我一般对小数据集用 7:2:1 甚至 6:2:2让验证集至少有 40 张以上评估才稳。import os import random import shutil random.seed(42) # 固定种子保证每次切分一致方便复现 imgs sorted(os.listdir(YOLO/images)) random.shuffle(imgs) n len(imgs) train_end int(n * 0.7) val_end int(n * 0.9) splits { train: imgs[:train_end], val: imgs[train_end:val_end], test: imgs[val_end:] } for split, files in splits.items(): os.makedirs(fdataset/images/{split}, exist_okTrue) os.makedirs(fdataset/labels/{split}, exist_okTrue) for f in files: shutil.copy(fYOLO/images/{f}, fdataset/images/{split}/{f}) txt os.path.splitext(f)[0] .txt shutil.copy(fYOLO/labels/{txt}, fdataset/labels/{split}/{txt}) print(split, len(files))逻辑说明random.seed(42)是必须的否则每次切分不同你没法判断指标变化是模型改进了还是数据换了。切分后目录结构要符合 YOLO 训练要求images/train配labels/train路径层级一致。参数上 0.7/0.2/0.1 是我对小数据集的默认值你可以根据验证集指标稳定性微调。3.2 增广参数怎么设才不把蜈蚣增成别的虫237 张要撑起训练增广是核心。但增广不是越多越好蜈蚣是细长多足的目标某些增广会破坏它的形态特征。常见做法是在 YOLO 的配置里开这几项hsv_h0.015色调微调、hsv_s0.7饱和度、hsv_v0.4明度、degrees10小角度旋转、translate0.1平移、scale0.5缩放、flipud0.0上下翻转关掉、fliplr0.5左右翻转开。为什么上下翻转要关蜈蚣在自然场景里腹面朝上的概率极低上下翻转会造出不符合物理规律的样本模型学到的是噪声。左右翻转没问题蜈蚣左右对称。旋转角度别超过 15 度大角度旋转会让细长的身体被裁切框和内容对不上。# data.yaml path: ./dataset train: images/train val: images/val test: images/test nc: 1 names: [wugong]逻辑说明nc: 1是单类别names里的顺序对应 class_id必须和转换脚本里的 class_map 一致。path用相对路径方便整个目录搬移。这个 yaml 是 YOLOv5/v8 通用的数据配置格式改路径就能复用。注意增广只在训练时生效验证和测试不能开增广否则评估指标虚高。YOLO 框架默认就是这么处理的但你自己写 dataloader 时要留意。4. 用 YOLOv8 在本地跑通训练命令、参数与显存控制4.1 环境装完先跑官方模型验证链路别一上来就训自己的数据先用官方预训练权重跑一张图确认环境没问题。这一步能排除掉 80% 的「训练报错其实是环境问题」。pip install ultralytics yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg逻辑说明yolov8n.pt是最小的 nano 模型下载快、显存占用低。source指向一张测试图跑通后会生成runs/detect/predict/目录里面有画了框的结果图。如果这一步就报错先解决 CUDA、torch 版本匹配问题别往下走。参数上 nano 模型约 3.2M 参数6G 显存足够训练。4.2 正式训练的命令与关键参数yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs200 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience50 \ device0 \ projectruns/wugong \ nameexp1逻辑说明epochs200对小数据集够用配合patience50早停验证集 50 轮不提升就停省时间。imgsz640是 YOLO 默认输入尺寸蜈蚣如果在大图里占比很小可以提到 960 或 1280但显存翻倍。batch16是 8G 显存的稳妥值显存不够就降到 8 或 4。lr00.01初始学习率lrf0.01最终学习率是初始的百分之一余弦退火。device0指定第一块 GPUCPU 训练把这里改成cpu但 237 张 CPU 也能忍。训练过程中重点看三个指标box_loss应该持续下降mAP50应该上升cls_loss单类别下会很快趋近于 0。如果box_loss震荡不降先查标注坐标有没有越界或为负。4.3 显存不够时的三个降级手段237 张图本身不大但imgsz和batch是显存杀手。按优先级降先把batch从 16 降到 8再降imgsz从 640 到 512最后换更小的模型nano 已经最小了只能减层不推荐。还有一个技巧是开ampTrue自动混合精度YOLOv8 默认开启能省约 30% 显存别关掉。# 显存紧张时的保守配置 yolo detect train datadata.yaml modelyolov8n.pt epochs200 imgsz512 batch8 ampTrue device0逻辑说明imgsz512会让小目标召回下降蜈蚣如果本身在图中就小慎用。ampTrue在部分老显卡如 GTX 10 系上可能不稳定报 NaN 就关掉。参数没有万能值以nvidia-smi看到的显存占用不超过 90% 为准。5. 训练不收敛、框偏移、漏检小数据集高频翻车排查5.1 现象loss 从第一轮就不降一直卡在高位原因九成是标注格式问题。要么 txt 里的坐标没归一化还是像素值要么 class_id 写成了 1 而nc1只认 0要么图片和标注文件名对不上导致读不到标注。解决随便打开一个 txt看数值是不是都在 0~1 之间再看第一列是不是 0。用 2.3 的脚本重新转一遍脚本里的越界裁剪和归一化能修掉大部分问题。5.2 现象训练 loss 正常降但验证时框整体偏移原因VOC 转 YOLO 时把xmax当成了 width或者归一化时用错了图片尺寸比如用了缩放过的小图尺寸去除原图坐标。解决抽一张图用标注工具打开把 txt 里的框画回去肉眼比对是否和原框重合。不重合就回查转换脚本里w和h的来源必须是原图尺寸。5.3 现象mAP 虚高到 0.95 以上但实际推理漏检严重原因验证集和训练集有重叠或者验证时开了增广。237 张切分时如果没固定种子可能同一张图既在训练又在验证。解决检查dataset/images/train和val里有没有同名文件有就是切分脚本写错了。另外确认验证配置里没有开augmentTrue。5.4 现象蜈蚣细长身体被截断只检出头部或尾部原因锚框anchor尺寸和蜈蚣的长宽比不匹配。YOLOv8 是无锚框的但默认的回归范围对极端长宽比目标仍不友好。解决提高imgsz让细长目标占更多像素或在数据里增加蜈蚣完整身体的样本比例。如果用的是带锚框的 YOLOv5需要重新聚类 anchor。5.5 现象训练到一半 loss 突然变 NaN原因学习率过高或某张图的标注框宽高为 0xmin 等于 xmax。解决把lr0从 0.01 降到 0.001并在转换脚本里加一行过滤if bw 0 or bh 0: continue。宽高为 0 的框会让除法产生 inf进而污染整个 batch 的梯度。6. 从 237 张到可用模型验证技巧与继续加数据的判断线训完之后别只看 mAP 数字要拿测试集做一次盲测。我一般会把runs/wugong/exp1/weights/best.pt拿出来对dataset/images/test跑一遍推理把结果图和原图并排看。重点看三类漏检的图里蜈蚣是不是被遮挡或只露出一部分误检的图里是不是有类似蜈蚣的细长物体比如绳子、草茎框的松紧程度太松说明回归没学好太紧可能切掉身体。yolo detect predict modelruns/wugong/exp1/weights/best.pt sourcedataset/images/test saveTrue conf0.25逻辑说明conf0.25是置信度阈值低于这个值的框不显示。排查漏检时把它降到 0.1看低置信框里有没有真目标排查误检时提到 0.5看高置信框是不是都正确。这个参数在部署时才是最终决策点训练阶段用它来诊断。那 237 张到底够不够我的判断线是如果测试集 mAP50 能稳定在 0.85 以上且漏检集中在遮挡和极小目标那这个量级够用可以进入部署验证。如果 mAP50 在 0.6 附近晃且错误类型分散说明数据多样性不足需要补数据。补的时候别盲目加量优先补模型当前分错的场景换个背景、换个光照、换个蜈蚣姿态每类补 20~30 张比随机再抓 200 张有用。最后一个习惯每次训完把data.yaml、训练命令、best.pt和测试集评估结果存一个文件夹命名带日期。小数据集的模型迭代快没有这个后悔药两周后你根本想不起来哪个权重对应哪次改动。这套流程我用了很多次237 张单类别从来不是瓶颈瓶颈永远在标注一致性和验证的诚实度上。希望帮到你。本文还有配套的精品资源点击获取
返回列表