
猫狗检测数据集这件事我断断续续搞了快一个月中间踩的坑比训练模型本身还多。网上公开的宠物图片一大堆但真正能直接喂给YOLO训练的宠物识别数据集反而少见——要么数量不够要么标注格式五花八门还得自己写脚本转格式、清脏数据光整理就得花两三天。这次整理了一套4300张的YOLO猫狗检测数据集涵盖猫、狗两个类别图片和标注全部按YOLO标准目录结构排好data.yaml配置也写好了解压就能直接训练。这篇文章就把数据集的结构、标注细节、采集清洗思路以及我用YOLOv8训练这套数据的完整过程和踩过的坑都摊开讲一遍给正在做宠物检测或者刚上手目标检测的朋友一个参考。1. 数据集全貌与项目定位1.1 为什么需要一套干净的宠物检测数据集做宠物识别的人应该都有体会真正卡住你的往往不是模型选型而是数据集。几个主流公开数据集各有各的问题PASCAL VOC虽然有cat和dog这两类但每类图片也就几百张姿态和场景都比较单一训练出来的模型泛化能力有限。COCO标注质量高但包含80个类别文件结构复杂解压和格式转换就要折腾半天而且直接拿完整COCO训练宠物检测器负样本干扰太多对小白不友好。网络爬图很多人会自己写爬虫去搜cat、dog但爬回来的图脏数据比例高有广告图、卡通图、文字水印图还有大量重复图标注前光清洗就要消耗大量时间。所以我这套数据集的设计目标很明确让使用者跳过数据准备阶段直接进入训练环节。4300张图片虽然不算海量但对于猫狗这种类别差异明显、形态相对固定的目标来说配合数据增强和预训练权重完全能训练出一个可用性很高的检测模型。我自己实测下来在验证集上mAP50能到0.97左右放到实际场景里识别效果也稳定。作为宠物识别方向的起步数据集或者YOLO实战练手项目这个体量是很舒服的。1.2 数据集目录结构与YOLO标注格式核心整个数据集解压后大概5GB左右目录结构是这样的cat_dog_dataset/ ├── images/ │ ├── train/ # 3400张 │ ├── val/ # 600张 │ └── test/ # 300张 ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── README.md图片和标签一一对应文件名完全一致只是后缀不同。图片是JPG格式分辨率从640x480到1920x1080不等训练时YOLO会自动统一缩放。label是标准的YOLO txt格式每个目标一行格式为class_id x_center y_center width height所有坐标值都归一化到0~1之间。举个例子一张640x480的图片里某只猫的边界框左上角在(100, 80)右下角在(500, 400)那么对应的一行标注就是0 0.468750 0.500000 0.625000 0.666667计算过程是x_center (100500)/2/640 0.46875y_center (80400)/2/480 0.5width (500-100)/640 0.625height (400-80)/480 0.6667。这个格式初学者经常搞错坐标忘记归一化、写反宽高是高频问题后面我会专门说怎么检查规避。data.yaml的内容是这样的path: /path/to/cat_dog_dataset train: images/train val: images/val test: images/test nc: 2 names: [cat, dog]注意path这个字段YOLOv8会以它作为基准路径去拼接train、val的相对路径。我建议直接写绝对路径省得在不同机器上切换时由于路径不对导致报错。2. 图像采集与标注规范2.1 数据来源与多样性把控数据集的核心竞争力不在于数量而在于多样性。如果图片都是在摄影棚里拍的背景干净、光照均匀、宠物正对镜头那模型学到的就是背景特征而不是猫狗特征。所以我在采集时有意识地从几个维度拉大数据分布场景维度室内客厅、阳台、小区楼下、宠物医院、猫咖、户外草地、树林、海边沙滩等。光照维度白天强光、阴天、傍晚逆光、夜晚室内灯光。其中逆光和低光照样本大约占15%这部分是提升模型鲁棒性的关键。尺度维度特写大目标、全身中目标、远景小目标三档。小目标大约占总体框数的15%左右后续验证发现这是最容易漏检的部分。姿态维度正面、侧面、背面、奔跑、跳跃、睡觉、舔毛、进食等。多姿态的样本能有效避免模型对特定姿态过拟合。遮挡情况大约18%的图片存在不同程度的部分遮挡比如猫躲在沙发后面只露出头、狗被主人挡住半边身体或者宠物身后有栏杆形成线条干扰。图片来源主要是整理了公开图库中可商用的宠物图片补充了一部分自己拍摄的生活照图片层面已经做过一轮去重处理同一个场景连拍的照片只保留一张质量最好的避免train集和val集出现同源图片泄漏。这一点很重要如果同一只猫在不同图片里被拆到训练集和验证集会导致模型表现虚高实际部署时打回原形。2.2 标注清洗流程与质量校验标注阶段我用LabelImg做了一遍初始标注保存为Pascal VOC格式的XML文件然后再统一转成YOLO txt。清洗过滤的标准有三条剔除模糊图片对焦不准、运动模糊导致轮廓边界不清晰的直接删掉。模型学不到特征不说还会干扰损失函数。剔除目标过小的图片如果猫狗在图中只占不到20x20像素就算标了框模型也很难学会因此这类样本我不保留。剔除标注有争议的样本比如宠物和背景颜色接近、边界难以判断的标注员之间可能有分歧这类数据看起来很丰富实际会造成标签噪声反而拖累收敛。一条很重要的质检经验标签转换脚本写完不能直接信必须可视化抽查。我写了下面这个Python脚本把标签画到图片上快速目检import cv2 import os img_dir images/val label_dir labels/val for img_name in os.listdir(img_dir): if not img_name.endswith(.jpg): continue img_path os.path.join(img_dir, img_name) label_path os.path.join(label_dir, img_name.replace(.jpg, .txt)) img cv2.imread(img_path) h, w img.shape[:2] with open(label_path, r) as f: for line in f.readlines(): parts line.strip().split() cls_id int(parts[0]) x_c, y_c, bw, bh map(float, parts[1:]) x1 int((x_c - bw / 2) * w) y1 int((y_c - bh / 2) * h) x2 int((x_c bw / 2) * w) y2 int((y_c bh / 2) * h) color (0, 255, 0) if cls_id 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.imshow(check, img) key cv2.waitKey(0) if key 27: # ESC退出 break cv2.destroyAllWindows()跑一遍脚本重点检查三类问题框是否完全包住目标、坐标是否在图片范围内、类别是否标错。这种可视化抽查建议在每次新增样本后都做一次看起来多花几分钟实际上帮你省掉后面因为脏标签导致模型训练不收敛的几小时排查时间。2.3 类别平衡与训练集划分整个数据集共4300张图片类别分布情况如下纯猫图片约1800张纯狗图片约1900张猫狗同框的混合图片约600张。目标框总量约7800个其中猫框接近3800个狗框约4000个。猫和狗的比例几乎没有偏差训练时不需要做类别加权这是个比较舒服的状态。划分训练集、验证集、测试集时我遵循了三条原则按图片划分而非按目标框划分保证同一张图片不会被拆到不同集合里。采用分层抽样先把数据按室内猫、户外猫、室内狗、户外狗等细分组分层再从每组里按比例抽取这样能保证验证集和测试集里的场景分布和训练集基本一致。比例控制采用3400/600/300约8:1.4:0.7。验证集稍微多一点没关系因为最终还要用独立的测试集做终极评估。另外特别提醒一下如果后续你自己继续扩充数据一定要检查新图片在已有数据里有没有重复。可以用文件哈希或者简单的感知哈希算法重复样本进入不同集合是数据泄漏最常见的来源。3. YOLOv8训练实操流程3.1 环境准备与数据放置训练环节直接选择了YOLOv8理由有三一是官方支持做得最好文档齐全不需要自己拼装训练脚本二是检测头和解耦分类结构对中小型数据集的收敛效率高三是后续部署生态完善转ONNX、TensorRT都有现成工具链。安装很简单pip install ultralytics国内网络环境下如果下载慢可以换成国内PyPI镜像源进行安装。装好后验证一下版本确保是v8系列yolo version然后把数据集解压到一个固定路径比如/home/user/datasets/cat_dog并修改data.yaml里的path字段为绝对路径。这里有一个实测中很容易踩的坑如果你把数据集放在网盘同步目录、或者项目工程目录里中途挪动了位置data.yaml里的相对路径会失效报错信息还特别隐晦经常只提示no labels found。所以建议大家先把数据集放到位再改yaml。3.2 训练参数的选择与理由模型方面我建议起步用yolov8n.pt或者yolov8s.pt的预训练权重。4300张的数据量确实不算大从头训练很容易欠拟合而加载COCO预训练权重做迁移学习模型在早期就能继承到通用的边缘、纹理和物体语义特征训练收敛速度明显加快。我的关键训练参数如下参数设置值选择理由imgsz640YOLOv8默认尺寸对中小目标效果均衡显存占用适中batch168GB显存显卡如RTX 3060/4060刚好跑得动epochs100配合早停机制实际用了约60轮就收敛了optimizerAdamW中小数据集上比SGD收敛更快学习率波动小lr00.001迁移学习场景下不宜过大避免破坏预训练特征patience20连续20轮验证集指标不提升就自动停止augment默认开启Mosaic等增强操作对小数据集的泛化能力提升明显关于显存估算可以按这个经验值来YOLOv8n在640分辨率下batch16大约占用6GB显存换成YOLOv8s大概8GB。如果你的显卡只有6GB显存就把batch降到8或者imgsz降到512两者影响的数据量不同。降低imgsz主要牺牲小目标检测能力降低batch则影响梯度稳定性优先降低batch更安全。3.3 训练执行与日志解读命令行执行训练yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0当然也可以用Python API方式结合代码方式管理训练流程方便后续自动调参from ultralytics import YOLO model YOLO(yolov8n.pt) model.train( datadata.yaml, epochs100, imgsz640, batch16, optimizerAdamW, lr00.001, patience20, device0, )训练过程中的日志很有信息量。我实际训练时观察到几个阶段性的变化第1~5轮loss快速下降从初始的2.0降到0.8左右。这是因为预训练权重已经具备了很好的特征提取能力只需要微调检测头。第6~30轮loss下降变缓曲线呈平滑下滑。此时mAP50从0.2逐渐爬升到0.85以上主要在学习类别专属的细粒度特征。第31~60轮loss基本平稳mAP稳定在0.95以上。如果训练集和验证集loss的gap持续扩大就是典型的过拟合信号这时早停机制会在patience轮数后自动终止训练。训练结束后结果保存在runs/detect/train/目录下。记住一点选最终的模型权重时用best.pt而不是last.pt。best.pt是验证集上mAP最高的那个检查点last.pt只是训练流程结束时的状态后者很可能已经过拟合了。4. 模型评估与效果分析4.1 验证结果关键指标解读训练完成后在独立测试集上跑一次官方评估yolo detect val modelruns/detect/train/weights/best.pt datadata.yaml splittest我拿best.pt在测试集上的结果如下类别图像数目标数精确率P召回率RmAP50mAP50-95all3005620.9560.9210.9740.883cat3002960.9410.9080.9670.857dog3002660.9710.9340.9810.909这里有几个关键指标要帮新手理清。mAP50是指在IoU阈值为0.5时以不同置信度阈值画出PR曲线曲线下的面积。通俗讲就是预测框和真实框重叠超过50%就算检测成功这个指标对检测位置要求比较宽松。mAP50-95则是在0.5到0.95之间每隔0.05取一个阈值求平均对框的定位精度要求苛刻得多。两个指标差距越大说明框的位置精度还有优化空间。可以看到狗的检测效果整体好于猫。这个现象在实际场景中也常见可能是因为狗的体型更大、轮廓更清晰、运动模式更多样而猫的体型相对小出现躲藏和姿态蜷缩的情况更频繁导致边界框变化范围大。如果你的场景里猫的检测精度偏低不用太惊讶这是数据分布本身决定的。4.2 典型bad case与针对性优化我把自己验证集上预测失败的case都抽出来整理出了一个分类表建议大家也做同样的事真正能发现问题的是这些fail case失败类型占比典型场景优化方向小目标漏检38%远景中猫狗占比过小提高imgsz到960补充小目标样本增强Mosaic遮挡漏检27%猫在沙发角落只露头、狗在草丛中针对性增加遮挡样本降低NMS阈值运动模糊18%奔跑中的狗目标模糊引入运动模糊增强缩短曝光时间类图像相似背景干扰17%橘猫在偏黄的落叶中、白狗在雪地增加背景变化适当调高置信度阈值针对小目标漏检最直接有效的办法是把imgsz从640提到960。我自己试过一轮mAP50-95提升了约2.3个百分点代价是训练时间几乎翻倍推理速度变慢。所以是否提升分辨率取决于你的部署场景对速度的容忍度。另一个性价比很高的优化是调整NMS参数。YOLOv8默认的IoU阈值是0.7如果在密集遮挡场景下经常漏检可以试着把conf_thres置信度阈值调低到0.2甚至0.15把nms_iou调低到0.5让两个高重叠的预测框不至于被合并得只剩一个。粗调下来mAP50确实有提升但误检数量也会增加需要根据业务场景权衡。5. 常见问题与避坑实录5.1 数据与标注方向的坑训练过程中我发现很多训练问题追根溯源其实是数据层面的问题。这里整理几个高频踩坑点每一个都是我实际碰到过的标签文件和图片文件名不一致。比如图片是IMG_001.JPG标签写成img_001.txtWindows系统下不区分大小写Linux下直接找不到标签导致大量图片被当成负样本。检查时用脚本对比两个目录的文件名是最靠谱的方法。坐标越界。用标注框裁剪图片再接回来时坐标很容易出现负数或超过1.0的情况。YOLO训练虽然不会直接报错但会严重影响损失函数。处理办法很简单标注转换脚本里加一个范围校验发现越界就打印文件名。空标签文件。有些图片确实没有目标这个没问题但如果标注脚本对无目标图片的处理逻辑写错了可能生成一个0字节的txt导致训练中断。YOLO训练时出现No labels found in train set这类报错先排查空标签。类别ID顺序不一致。同一个数据集在不同阶段新增类别时如果没有固定好类别顺序训练时的类别映射就会错乱。解决方法是把数据集根目录的data.yaml作为唯一真源所有脚本都从yaml解析类别顺序不要硬编码。5.2 训练过程中的坑训练时的几个典型问题也一并说一下。显存不足OOM最常见的就是batch太大或者imgsz太高。如果显卡是8GB显存你强行跑yolov8s的batch32肯定直接报CUDA out of memory。优先把batch降到8试一次还不够就换yolov8n。注意不能只改batch不改显存预算要在训练前用nvidia-smi看一眼显存占用情况。loss突然变成NaN通常原因是学习率太大导致梯度爆炸或者数据里出现了异常标注比如坐标写了负值。先用torch.cuda.amp.autocast()判断是否混合精度问题但多数情况下把lr0下调一个数量级就能解决。验证集mAP曲线震荡如果训练loss平稳但验证集指标忽高忽低多半是验证集划分不够均匀或者是数据增强随机性太大导致的。我习惯每5轮固定一组增强种子做验证能缓解一部分不稳定。当然首先要检查验证集有没有包含极端困难样本。训练/验证loss gap过大比如train_loss一直在降val_loss却开始回升这是典型的过拟合信号。小数据集最容易出现解决办法是提前触发早停、减弱Mosaic增强比例或者增加Dropout系数。这里再分享一个我长期保留的习惯每轮训练开始前都写一个5分钟的脚本把标注可视化抽查一遍刚开始会觉得麻烦但做多了就发现它的价值远超你的付出。数据管好训练就成功了一半。结尾这次整理数据集加训练的过程我自己感触最深的一点是在目标检测项目里数据集质量的权重远高于模型结构的权重。同样是4300张图如果你只是从网上下载一堆照片随便标标框和精心设计多样性分布、严格清洗标签之后训练出来的模型效果差距会是天壤之别。很多人纠结于要不要换YOLOv10、要不要改进注意力机制其实先把数据管好再谈模型改进也不迟。最后再分享一个小技巧这套数据集后续还可以往多个方向扩展。比如增加一个宠物品种的细分子类或者加入夜晚红外相机的图像做鲁棒性测试甚至把标注格式转成COCO后拿去做实例分割任务。如果你想拿它作为起步数据集我个人建议先跑通整个训练-评估-部署链路把流程跑顺了再回头扩充数据范围成长速度会快很多。希望这篇记录对你有帮助也欢迎在实际训练中遇到问题来交流。