YOLO猫狗数据集训练避坑指南:VOC/COCO/YOLO标签格式转换与实战 简介这份YOLO猫狗目标检测数据集面向计算机视觉入门与进阶开发者适用于目标检测模型训练、算法验证及课程实验等场景。数据均为真实场景采集的高质量图片场景丰富经labelimg精细标注标注框质量可靠并同步提供vocxml、cocojson与yolotxt三种格式标签分目录存放可直接接入YOLO系列模型训练。压缩包共约2000个文件以1986个xml标注文件为主另含少量html教程、txt说明与py脚本整体约115.12MB。资源附带环境搭建、训练案例教程及数据集划分脚本可按需自行划分训练集、验证集与测试集省去从零整理数据的繁琐流程。目前已有535人学习下载适合希望快速获得规范标注数据、缩短数据准备周期并专注模型调优的读者参考使用。1. 拿到一份 YOLO 猫狗数据集先别急着 train三种标签格式到底怎么选很多人拿到「YOLO猫狗目标检测数据集(含5000张图片)对应voc、coco和yolo三种格式标签划分脚本训练教程.rar」这类压缩包第一反应是解压、改data.yaml、直接yolo train。我见过太多人卡在这一步训练跑起来了mAP 却低得离谱回头查半天才发现标签格式和模型配置对不上。猫狗检测本身不难难的是同一批图片被三种格式各写了一遍你得先搞清楚它们各自在说什么再决定用哪一套喂给 YOLO。这份数据集的价值不在「5000 张」这个数字而在于它把 VOC、COCO、YOLO 三种标注同时给了出来。VOC 是 XML 逐图描述COCO 是单个 JSON 汇总YOLO 是每图一个 txt 的归一化坐标。三种格式描述的是同一件事但字段含义、坐标基准、类别编号规则完全不同。新手最容易翻车的地方就是把 COCO 的[x, y, w, h]当成 YOLO 的归一化值直接塞进去或者把 VOC 的 1-based 类别 id 当成 0-based 用。这篇文章面向三类人刚入门目标检测、想拿猫狗数据跑通第一个模型的手里有类似多格式数据集、需要做格式转换和划分的以及准备把猫狗检测迁移到其他类别、想复用这套流程的。我会按「格式原理 → 转换与划分 → 训练配置 → 避坑 → 进阶验证」的顺序讲每一步都给可抄的命令和参数最后落到怎么判断这份数据集值不值得投入。2. 三种标签格式的字段对照与转换脚本2.1 VOC、COCO、YOLO 的坐标基准差异先把三种格式的核心字段摆在一起看不然后面转换全是玄学。维度VOC (XML)COCO (JSON)YOLO (txt)存储方式每图一个 xml全部图一个 json每图一个 txt坐标字段xmin,ymin,xmax,ymaxbbox: x,y,w,hclass cx cy w h坐标基准绝对像素左上右下绝对像素左上宽高归一化 0~1中心宽高类别编号名称字符串category_id 从 1 开始从 0 开始图片尺寸存在 size 节点存在 images 数组不存需外部读取关键差异有三个。第一VOC 和 COCO 用绝对像素YOLO 用归一化值转换时必须除以图片宽高。第二VOC 是左上右下两点COCO 是左上角加宽高YOLO 是中心点加宽高三者几何含义不同。第三类别编号起点不同COCO 的category_id通常从 1 开始YOLO 必须从 0 开始差一位就是全部错位。提示转换前先用PIL或cv2读一遍图片真实尺寸不要相信 XML 里写的size有些数据集在裁剪后没更新这个字段会导致归一化全错。2.2 用 Python 把 VOC 转成 YOLO 格式下面这段脚本把 VOC 的 xml 批量转成 YOLO 的 txt同时生成classes.txt。假设目录结构是annotations/放 xmlimages/放同名图片。import os import xml.etree.ElementTree as ET from PIL import Image # 类别顺序决定 YOLO 的 class id必须和后续 data.yaml 一致 CLASSES [cat, dog] CLASS_TO_ID {c: i for i, c in enumerate(CLASSES)} 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 里的 size 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): cls_name obj.find(name).text.strip() if cls_name not in CLASS_TO_ID: continue # 跳过未定义类别避免 id 错位 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) # 转成中心点 宽高再归一化 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 裁剪越界值防止归一化后超出 0~1 cx, cy min(max(cx, 0), 1), min(max(cy, 0), 1) bw, bh min(max(bw, 0), 1), min(max(bh, 0), 1) lines.append(f{CLASS_TO_ID[cls_name]} {cx:.6f} {cy:.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)) voc_to_yolo(annotations, images, labels)逻辑说明CLASSES的顺序就是最终 YOLO 的类别编号cat是 0dog是 1这个顺序必须和训练时的data.yaml完全一致否则模型学到的「0」可能是狗。坐标转换先算中心点和宽高再除以图片真实宽高做归一化。越界裁剪是必须的VOC 标注里经常有框超出图片边界的情况不裁剪会导致 YOLO 训练时 loss 异常。参数说明xml_dir、img_dir、out_dir按实际路径改。CLASSES如果数据集里还有别的类别按字母序或自定义顺序补全但一旦定了就不要中途改。:.6f保留六位小数YOLO 官方推荐精度太少会丢坐标。2.3 COCO 转 YOLO 与划分脚本的配合COCO 转 YOLO 稍微绕一点因为 COCO 的 json 里图片和标注是分开的两个数组需要先用image_id做关联。import json import os from PIL import Image CLASSES [cat, dog] # COCO 的 category_id 从 1 开始这里建立映射到 0-based CAT_ID_TO_YOLO {1: 0, 2: 1} def coco_to_yolo(json_path, img_dir, out_dir): os.makedirs(out_dir, exist_okTrue) data json.load(open(json_path)) # 建立 image_id - 文件信息 的索引 img_info {img[id]: img for img in data[images]} # 按 image_id 聚合标注 anns {} for ann in data[annotations]: anns.setdefault(ann[image_id], []).append(ann) for img_id, info in img_info.items(): w, h info[width], info[height] lines [] for ann in anns.get(img_id, []): if ann[category_id] not in CAT_ID_TO_YOLO: continue x, y, bw, bh ann[bbox] # COCO 是左上角 宽高 cx (x bw / 2) / w cy (y bh / 2) / h nw, nh bw / w, bh / h cls CAT_ID_TO_YOLO[ann[category_id]] lines.append(f{cls} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) out_name os.path.splitext(info[file_name])[0] .txt with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(lines)) coco_to_yolo(annotations/instances.json, images, labels)逻辑说明COCO 的bbox是[x, y, width, height]x、y 是左上角绝对坐标所以中心点是x w/2。CAT_ID_TO_YOLO这个映射表是必须的因为 COCO 的category_id不保证连续也不保证从 1 开始直接减 1 是常见错误。聚合标注用字典按image_id分组避免每张图都遍历整个 annotations 数组。参数说明json_path指向 COCO 的 instances 文件img_dir是图片目录。如果数据集里 COCO 的category_id不是 1、2先打印data[categories]看清楚再改映射表。划分脚本一般做三件事按比例切分 train/val/test、把图片和标签同步移动到对应目录、生成data.yaml。常见做法是 8:1:1 或 7:2:1猫狗这种两类任务 8:1:1 足够。划分时要注意图片和标签必须同名同批移动否则会出现「有图无标签」的静默错误训练时这些图会被当成负样本拉低召回。3. 用这份数据集跑通 YOLO 训练的最小配置3.1 data.yaml 的四个必填字段与路径陷阱YOLO 训练只认一个data.yaml字段不多但每个都能让你翻车。# data.yaml path: /home/user/catdog # 数据集根目录绝对路径最稳 train: images/train # 相对 path 的训练图片目录 val: images/val # 相对 path 的验证图片目录 nc: 2 # 类别数猫和狗 names: [cat, dog] # 顺序必须和转换时的 CLASSES 一致四个字段里path用绝对路径train和val用相对路径这是 YOLO 官方推荐的写法混用相对和绝对最容易出「找不到图片」的报错。nc和names的长度必须相等names的顺序就是类别 id 的顺序和前面转换脚本里的CLASSES一一对应。标签目录不用写进 yamlYOLO 默认去图片路径里把images替换成labels找同名 txt所以目录结构必须是images/train对labels/train。注意如果你的标签目录不叫labels或者图片和标签不在同级YOLO 会静默跳过找不到的标签训练照跑但学不到东西。跑之前先用ls labels/train | wc -l和ls images/train | wc -l对一下数量。3.2 从预训练权重开始训练的命令与参数猫狗检测数据量 5000 张不算大从 COCO 预训练权重微调是最稳的路线别从零训。yolo detect train \ modelyolov8n.pt \ datadata.yaml \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/catdog \ nameexp1逻辑说明modelyolov8n.pt用 nano 版本5000 张图两类目标nano 足够且训练快显存占用低。epochs100配合patience2020 轮验证指标不升就早停避免过拟合。imgsz640是 YOLO 默认输入尺寸猫狗目标通常占图比例较大640 够用如果图片里猫狗很小再考虑 1280。batch16是 8G 显存的安全值显存大可加到 32。参数说明lr00.01是初始学习率微调任务常用 0.01从零训才用 0.01 以上。project和name决定输出目录方便多次实验对比。如果训练时 loss 一开始就 nan先查标签里有没有归一化值超过 1 或为负再查nc和实际类别数是否一致。3.3 训练过程中的三个观察指标训练日志里重点看三个box_loss、cls_loss、mAP50。box_loss下降说明框的位置在收敛cls_loss下降说明类别判断在变好mAP50是最终效果的直接体现。猫狗两类任务5000 张图正常情况 mAP50 能到 0.9 以上。如果box_loss一直不降八成是标签坐标有问题如果cls_loss震荡检查类别是否严重不均衡比如猫 4500 张狗 500 张。验证阶段用yolo detect val modelruns/catdog/exp1/weights/best.pt datadata.yaml看每类的 precision 和 recall。如果某一类 recall 特别低去验证集里翻几张漏检的图大概率是这类目标在训练集里样本太少或标注质量差。4. 多格式数据集转换与训练的避坑清单4.1 类别编号错位导致全盘学错现象训练 loss 正常下降mAP 也有数值但推理时猫狗标签完全反了或者置信度普遍偏低。原因VOC 的类别是字符串COCO 的category_id从 1 开始YOLO 要求从 0 开始。转换时如果直接拿 COCO 的 id 减 1而category_id恰好是 1、2 就没事但有些数据集是 1、3 或 0、1减 1 就错位。更隐蔽的是 VOC 转 YOLO 时CLASSES顺序和data.yaml的names不一致。解决转换前先打印所有出现过的类别名和 id建立显式映射表不要用算术运算推。转换后抽三张图用yolo detect predict跑一下人工核对标签和框是否对应。4.2 图片和标签不同步导致静默丢样本现象训练能跑但 mAP 比预期低一截验证集上某些图明显有目标却检测不到。原因划分脚本只移动了图片没移动标签或者图片和标签文件名大小写不一致Linux 下区分大小写。YOLO 找不到标签时不会报错直接当负样本处理。解决划分后做一次数量核对images/train和labels/train的文件数必须相等文件名去掉扩展名后必须一一对应。写个脚本做集合差集把有图无标签、有标签无图的都列出来。4.3 归一化坐标越界引发 loss 异常现象训练刚开始 loss 就是 nan 或者异常大几十轮都不收敛。原因VOC 或 COCO 的标注框超出图片边界转换时没裁剪归一化后出现大于 1 或小于 0 的值。YOLO 对越界坐标的梯度计算会爆炸。解决转换脚本里加min(max(v, 0), 1)裁剪同时统计裁剪了多少个框如果比例超过 5%说明原始标注质量有问题考虑直接丢弃这些框或整图。4.4 验证集混入训练集造成指标虚高现象验证 mAP 高得离谱接近 1.0但实际推理新图片效果差。原因划分脚本用随机切分时没固定随机种子或者按图片切分时同一张图的多个标注被分到不同集合。更常见的是数据集本身有重复图片一张在 train 一张在 val。解决划分时固定random.seed(42)按图片文件名做切分而不是按标注。划分后用图片哈希去重把 train 和 val 之间重复的图删掉。4.5 直接改 data.yaml 的 names 顺序现象换了类别名顺序后重新训练模型完全学不会。原因names的顺序决定了类别 id改了顺序等于把之前所有标签的 id 含义都改了但标签文件里的数字没变模型学到的映射全乱。解决names一旦确定就不要改。如果确实要调整类别重新跑一遍转换脚本让标签文件和names同步更新。5. 怎么验证这份数据集值不值得投入以及一个提效技巧判断一份猫狗数据集能不能用别只看图片数量按下面三步走。第一步抽 20 张图用yolo detect predict跑预训练模型看猫狗能不能被检出来能检出来说明图片质量过关。第二步统计每类标注框的数量和尺寸分布如果某一类框数少于总数的 10%训练时要做过采样或加权。第三步用yolo detect val在划分好的验证集上跑一遍看 mAP50 和每类 recallrecall 低于 0.7 的类别重点查标注。一个提效技巧把三种格式的转换和划分写成一个prepare.py用命令行参数控制输入格式这样换数据集时只改路径不改逻辑。import argparse def main(): parser argparse.ArgumentParser() parser.add_argument(--format, choices[voc, coco, yolo], requiredTrue) parser.add_argument(--src, requiredTrue, help标注源目录或 json 路径) parser.add_argument(--img, requiredTrue, help图片目录) parser.add_argument(--out, defaultlabels, help输出标签目录) args parser.parse_args() if args.format voc: voc_to_yolo(args.src, args.img, args.out) elif args.format coco: coco_to_yolo(args.src, args.img, args.out) else: print(已是 YOLO 格式直接检查目录结构) if __name__ __main__: main()逻辑说明用argparse把格式选择做成参数VOC 和 COCO 走各自的转换函数YOLO 格式只做检查。这样一份脚本能复用到其他数据集不用每次重写。参数说明--format三选一--src对 VOC 是 xml 目录、对 COCO 是 json 文件路径--img是图片目录--out默认labels。我自己踩过最深的坑是第一次做格式转换时没核对类别顺序训练了两天才发现猫狗标签反了白白浪费算力。后来养成的习惯是转换完先抽三张图可视化确认框和类别都对再开始训练。这个习惯帮我省下的时间远比多写几行检查代码多。希望帮到你。本文还有配套的精品资源点击获取