简介这份资源面向目标检测初学者与需要快速搭建猫狗识别任务的开发者提供一套真实场景下的YOLO猫狗目标检测数据集。图片均经labelimg精细标注标注框质量较高并同步给出voc(xml)、coco(json)与yolo(txt)三种格式标签分别存放于不同文件夹可直接接入YOLO系列模型训练省去格式转换的繁琐步骤。压缩包共2000个文件以1000个xml标注文件和990个txt标签文件为主另含少量html教程、py划分脚本与yaml配置文件整体约23.05MB体积轻便易于下载与迁移。资源还附赠数据集划分脚本可按需生成训练集、验证集与测试集并配套Windows与Linux环境搭建及训练案例教程帮助读者从环境配置到模型训练完整走通流程。目前已有1357人学习下载适合作为课程设计、毕业设计或入门练手的实战数据。1. 从一份猫狗数据集说起1000 张图、三套标签、一个划分脚本到底能省多少事如果你正在入门 YOLO 目标检测大概率卡在同一个地方模型结构看懂了损失函数也背下来了但一打开标注工具就懵了——标完几十张图导出格式选错训练脚本读不进去改完格式又发现训练集和验证集混在一起指标虚高得离谱。这份「YOLO 猫狗目标检测数据集含 1000 张图片 对应 VOC、COCO 和 YOLO 三种格式标签 划分脚本 训练教程」正好打在这个痛点上。它把数据准备阶段最容易翻车的三件事——标注格式转换、数据集划分、训练配置——打包成一条可复现的流水线。猫狗二分类检测虽然简单但它是验证整套流程是否跑通的最佳试验场类别少、目标大、标注歧义低跑不通基本就是流程问题而不是数据问题。适合刚接触 YOLO 数据集的新手也适合想把手头杂乱标注统一成标准格式的熟手。2. 三种标签格式到底差在哪VOC、COCO、YOLO 的坐标逻辑与选型2.1 坐标表示与目录结构的本质区别很多人以为三种格式只是文件后缀不同实际上它们的坐标基准和目录组织完全不一样。VOC 用 XML坐标是绝对像素值左上角和右下角两个点确定一个框COCO 用单个 JSON坐标是[x, y, width, height]的绝对像素且所有图片的标注集中在一个文件里YOLO 用每张图对应的.txt坐标是归一化后的[x_center, y_center, width, height]值域 0 到 1。这个差异直接决定了你在训练时要不要改代码。YOLO 官方训练脚本默认读 YOLO 格式如果你手里只有 VOC 的 XML就必须先转。而 COCO 格式因为标注集中适合做数据集的统计分析比如统计每个类别的框数量分布但不适合直接喂给 YOLO 训练。格式标注文件坐标类型坐标含义类别存储VOC每图一个 XML绝对像素xmin, ymin, xmax, ymaxXML 内 name 字段COCO单个 JSON绝对像素x, y, width, heightJSON 内 categories 数组YOLO每图一个 TXT归一化x_center, y_center, width, heightTXT 行首 class_id选型建议很直接训练用 YOLO 格式做数据分析或跨框架迁移时保留 COCOVOC 作为中间交换格式。这份数据集同时提供三种意味着你可以跳过自己写转换脚本的环节但理解转换逻辑仍然必要因为实际项目中你拿到的往往是单一格式。2.2 从 VOC 转 YOLO 的最小转换脚本假设你拿到的是 VOC 格式的 XML想转成 YOLO 的 TXT核心就是读 XML、取尺寸、算归一化坐标。下面这段脚本可以直接抄import xml.etree.ElementTree as ET import os # 类别映射猫狗数据集只有两类 class_map {cat: 0, dog: 1} def voc_to_yolo(xml_path, output_dir, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() # 用图片实际尺寸做归一化基准不能硬编码 size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] 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) # 归一化并转为中心点加宽高 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 base os.path.splitext(os.path.basename(xml_path))[0] with open(os.path.join(output_dir, base .txt), w) as f: f.write(\n.join(lines))逻辑说明先解析 XML 拿到图片宽高注意这里必须用 XML 里记录的尺寸不能假设所有图片都是 640×640。然后遍历每个 object取类别名映射到数字 id取边界框坐标做归一化。归一化时中心点除以宽高宽高也除以宽高得到 0 到 1 之间的小数。最后写入 TXT每行一个目标空格分隔。参数说明class_map必须和你的data.yaml里的names顺序一致否则训练时类别会错位。img_w和img_h虽然传进来了但实际用的是 XML 里的尺寸这样更安全。输出目录要提前建好脚本不会自动创建。2.3 COCO 格式的读取与类别统计COCO 的 JSON 结构适合做统计分析。比如你想知道猫和狗各有多少个标注框用下面几行就能跑出来import json from collections import Counter with open(annotations/instances.json, r) as f: coco json.load(f) # 建立 category_id 到名字的映射 cat_id_to_name {c[id]: c[name] for c in coco[categories]} counter Counter() for ann in coco[annotations]: counter[cat_id_to_name[ann[category_id]]] 1 print(counter) # 输出类似 Counter({cat: 620, dog: 580})这段代码不涉及训练但能帮你判断数据集是否类别不平衡。如果猫狗数量差距超过 3 比 1训练时就要考虑加类别权重或者做重采样。COCO 的annotations数组里每个元素包含image_id、category_id、bboxbbox是[x, y, width, height]绝对像素。注意 COCO 的id从 1 开始而 YOLO 的 class_id 从 0 开始转换时要减一。3. 划分脚本怎么写才不翻车训练集、验证集、测试集的比例与随机种子3.1 为什么不能直接随机切分文件很多人划分数据集就是random.shuffle然后按比例切但这样有一个隐蔽问题如果同一个场景的图片被切到训练集和验证集验证指标会虚高。猫狗数据集里如果有多张同一只猫在不同角度的照片随机切分会让模型在验证集上「见过」这只猫指标好看但实际泛化能力差。更稳妥的做法是按图片内容分组再切分但这份数据集没有提供分组信息所以退而求其次固定随机种子保证每次划分结果一致至少让实验可复现。下面这个脚本同时处理图片和对应的 YOLO 标签文件import os import random import shutil def split_dataset(img_dir, label_dir, output_dir, ratios(0.7, 0.2, 0.1), seed42): random.seed(seed) # 固定种子保证可复现 images [f for f in os.listdir(img_dir) if f.endswith((.jpg, .png))] random.shuffle(images) n len(images) n_train int(n * ratios[0]) n_val int(n * ratios[1]) splits { train: images[:n_train], val: images[n_train:n_train n_val], test: images[n_train n_val:] } for split, files in splits.items(): img_out os.path.join(output_dir, split, images) lbl_out os.path.join(output_dir, split, labels) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for img_file in files: # 复制图片 shutil.copy(os.path.join(img_dir, img_file), os.path.join(img_out, img_file)) # 复制同名标签后缀换成 txt base os.path.splitext(img_file)[0] label_file base .txt src_label os.path.join(label_dir, label_file) if os.path.exists(src_label): shutil.copy(src_label, os.path.join(lbl_out, label_file)) else: # 没有标签的图片通常是负样本创建空文件 open(os.path.join(lbl_out, label_file), w).close() print(ftrain: {len(splits[train])}, val: {len(splits[val])}, test: {len(splits[test])})逻辑说明先固定随机种子保证每次运行划分结果一样。然后打乱图片列表按 7:2:1 切分。复制时图片和标签必须同名标签文件如果不存在就创建空文件因为 YOLO 训练时负样本也需要对应的空 txt否则会报错找不到标签。参数说明ratios三个数之和必须为 1常见做法是 7:2:1 或 8:1:1。数据量只有 1000 张时测试集 100 张足够评估验证集 200 张用于调参。seed建议固定否则每次划分不同实验无法对比。3.2 划分后的目录结构检查划分完成后目录应该长这样dataset/ ├── train/ │ ├── images/ (700 张) │ └── labels/ (700 个 txt) ├── val/ │ ├── images/ (200 张) │ └── labels/ (200 个 txt) └── test/ ├── images/ (100 张) └── labels/ (100 个 txt)检查两个点图片数量和标签数量是否一致以及每个标签文件的行数是否和图片里的目标数匹配。可以用一行命令快速统计# 统计 train 下所有 txt 的总行数即总标注框数 find dataset/train/labels -name *.txt -exec cat {} | wc -l如果这个数字远小于图片数说明很多图片没有标注可能是漏标或者负样本。猫狗数据集里每张图至少有一只猫或狗所以总框数应该接近 1000 到 1500 之间。3.3 data.yaml 的写法与路径陷阱YOLO 训练需要一个data.yaml告诉它数据在哪、类别是什么。写法如下path: /home/user/dataset # 数据集根目录绝对路径 train: train/images val: val/images test: test/images names: 0: cat 1: dog注意path必须是绝对路径train和val是相对于path的子路径。很多人在这里翻车写了相对路径训练时找不到图片报No such file or directory。另一个坑是names的顺序必须和转换脚本里的class_map一致否则猫被识别成狗。4. 训练教程里的关键参数从 yolov8n.pt 到收敛的完整命令4.1 环境安装与最小训练命令假设你用 PyCharm 或者命令行先装 ultralytics 包pip install ultralytics然后一行命令启动训练yolo detect train datadataset/data.yaml modelyolov8n.pt epochs100 imgsz640 batch16这条命令的含义用yolov8n.pt预训练权重在data.yaml指定的数据集上训练 100 轮输入尺寸 640批次大小 16。yolov8n是最小的模型参数量少适合 1000 张图的小数据集不容易过拟合。参数怎么改如果显存不够把batch降到 8 或 4如果训练损失下降很慢把epochs加到 200如果图片里目标很小把imgsz提到 1280但显存占用会翻倍。猫狗目标通常占图片面积较大640 足够。4.2 训练过程中的指标解读训练开始后控制台会输出每一轮的损失和指标。重点看三个box_loss边界框回归损失应该持续下降如果震荡说明学习率太大。cls_loss分类损失猫狗二分类应该很快降到 0.1 以下。mAP50IoU 阈值 0.5 时的平均精度这是最终指标猫狗数据集上通常能到 0.9 以上。如果mAP50在 0.5 左右就上不去检查标签格式是否正确。常见问题是归一化坐标算错了比如把绝对坐标直接写进 txt导致框全部跑到图片外面。4.3 用训练好的模型做推理训练完成后权重保存在runs/detect/train/weights/best.pt。推理命令yolo detect predict modelruns/detect/train/weights/best.pt sourcetest_images/ saveTruesource可以是单张图片、文件夹或视频。saveTrue会把画了框的结果保存到runs/detect/predict/。如果想看置信度加conf0.5只显示置信度大于 0.5 的框。推理时如果发现框的位置偏移大概率是训练时的imgsz和推理时不一致。YOLO 会自动缩放但缩放比例算错就会偏。保持训练和推理的imgsz一致最稳妥。5. 避坑与排查猫狗数据集训练中最容易翻车的 4 个地方5.1 现象训练报错Label class 2 is not in the dataset原因标签文件里的 class_id 超出了data.yaml里names的范围。猫狗只有 0 和 1如果出现 2说明转换脚本的class_map写错了或者 VOC 的 XML 里有其他类别没过滤掉。解决检查所有 txt 文件里的第一个数字用awk {print $1} *.txt | sort -u看有哪些值。如果有 2回到转换脚本在if cls_name not in class_map: continue那里确保只保留猫狗。5.2 现象训练损失正常下降但 mAP 一直是 0原因标签文件的坐标归一化算错了比如用了绝对坐标除以 255 而不是除以图片宽高。或者图片和标签文件名不匹配YOLO 读不到标签把所有图片当负样本训练。解决随机抽一个 txt 文件看里面的数值是否在 0 到 1 之间。如果大于 1说明归一化错了。再检查图片名和标签名是否只差后缀比如cat_001.jpg对应cat_001.txt。5.3 现象验证集指标比训练集还高原因数据集划分时没有固定随机种子或者验证集图片和训练集图片有重复。1000 张图里如果有同一张图的不同副本随机切分可能把它们分到不同集合。解决用md5sum对所有图片去重确保没有重复文件。划分脚本里固定seed并且每次实验用同一个划分结果。5.4 现象推理时框的位置整体偏移原因训练时用了imgsz640推理时图片被缩放到其他尺寸但 YOLO 的坐标还原逻辑依赖训练时的尺寸。如果推理时手动改了imgsz坐标会偏。解决推理命令里显式指定imgsz640和训练保持一致。如果必须用其他尺寸重新训练时就用那个尺寸。6. 把 1000 张图用到极致数据增强与难例挖掘的两个技巧1000 张图在目标检测里算小数据集直接训练容易过拟合。除了 YOLO 自带的 mosaic、翻转、缩放增强还有两个技巧能明显提升泛化能力。第一个是「复制粘贴增强」。猫狗数据集里如果某些姿态的样本少可以把猫或狗的目标框裁剪出来随机粘贴到其他图片的背景上生成新的训练样本。ultralytics 支持通过copy_paste参数开启但需要分割掩码。没有掩码时可以用矩形框裁剪加高斯模糊边缘减少粘贴痕迹。这个技巧在猫狗这种目标边界清晰的场景下效果很好能把有效样本量翻倍。第二个是「难例挖掘」。训练完第一轮后用best.pt在验证集上推理把置信度低于 0.5 但实际有目标的图片挑出来人工检查标注是否正确。常见问题是猫狗重叠时只标了一只或者夜间照片里目标太暗漏标。把这些难例修正后加入训练集再跑第二轮mAP 通常能涨 2 到 5 个点。我自己的习惯是第一轮训练只跑 50 轮拿到best.pt后先看验证集上的错误案例把漏标和错标修完再跑完整 100 轮。这样比直接跑 200 轮省时间而且最终指标更高。数据集的质量永远比数量重要1000 张标对的图比 5000 张标错的图有用得多。希望帮到你。本文还有配套的精品资源点击获取