拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

YOLO猫狗检测数据集详解:从标注清洗到YOLOv8训练实战

YOLO猫狗检测数据集详解:从标注清洗到YOLOv8训练实战

猫狗检测数据集这件事,我断断续续搞了快一个月,中间踩的坑比训练模型本身还多。网上公开的宠物图片一大堆,但真正能直接喂给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 = (100+500)/2/640 = 0.46875,y_center = (80+400)/2/480 = 0.5,width = (500-100)/640 = 0.625,height = (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。清洗过滤的标准有三条:

  1. 剔除模糊图片:对焦不准、运动模糊导致轮廓边界不清晰的,直接删掉。模型学不到特征不说,还会干扰损失函数。
  2. 剔除目标过小的图片:如果猫狗在图中只占不到20x20像素,就算标了框,模型也很难学会,因此这类样本我不保留。
  3. 剔除标注有争议的样本:比如宠物和背景颜色接近、边界难以判断的,标注员之间可能有分歧,这类数据看起来很丰富,实际会造成标签噪声,反而拖累收敛。

一条很重要的质检经验:标签转换脚本写完不能直接信,必须可视化抽查。我写了下面这个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分辨率下,batch=16大约占用6GB显存;换成YOLOv8s大概8GB。如果你的显卡只有6GB显存,就把batch降到8,或者imgsz降到512,两者影响的数据量不同。降低imgsz主要牺牲小目标检测能力,降低batch则影响梯度稳定性,优先降低batch更安全。

3.3 训练执行与日志解读

命令行执行训练:

yolo detect train data=data.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 device=0

当然也可以用Python API方式,结合代码方式管理训练流程,方便后续自动调参:

from ultralytics import YOLO model = YOLO('yolov8n.pt') model.train( data='data.yaml', epochs=100, imgsz=640, batch=16, optimizer='AdamW', lr0=0.001, patience=20, device=0, )

训练过程中的日志很有信息量。我实际训练时,观察到几个阶段性的变化:

  • 第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 model=runs/detect/train/weights/best.pt data=data.yaml split=test

我拿best.pt在测试集上的结果如下:

类别图像数目标数精确率P召回率RmAP50mAP50-95
all3005620.9560.9210.9740.883
cat3002960.9410.9080.9670.857
dog3002660.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 数据与标注方向的坑

训练过程中我发现,很多训练问题追根溯源,其实是数据层面的问题。这里整理几个高频踩坑点,每一个都是我实际碰到过的:

  1. 标签文件和图片文件名不一致。比如图片是IMG_001.JPG,标签写成img_001.txt,Windows系统下不区分大小写,Linux下直接找不到标签,导致大量图片被当成负样本。检查时用脚本对比两个目录的文件名是最靠谱的方法。

  2. 坐标越界。用标注框裁剪图片再接回来时,坐标很容易出现负数或超过1.0的情况。YOLO训练虽然不会直接报错,但会严重影响损失函数。处理办法很简单:标注转换脚本里加一个范围校验,发现越界就打印文件名。

  3. 空标签文件。有些图片确实没有目标,这个没问题,但如果标注脚本对无目标图片的处理逻辑写错了,可能生成一个0字节的txt导致训练中断。YOLO训练时出现"No labels found in train set"这类报错,先排查空标签。

  4. 类别ID顺序不一致。同一个数据集在不同阶段新增类别时,如果没有固定好类别顺序,训练时的类别映射就会错乱。解决方法是把数据集根目录的data.yaml作为唯一真源,所有脚本都从yaml解析类别顺序,不要硬编码。

5.2 训练过程中的坑

训练时的几个典型问题也一并说一下。

显存不足(OOM):最常见的就是batch太大或者imgsz太高。如果显卡是8GB显存,你强行跑yolov8s的batch=32,肯定直接报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后拿去做实例分割任务。如果你想拿它作为起步数据集,我个人建议先跑通整个训练-评估-部署链路,把流程跑顺了,再回头扩充数据范围,成长速度会快很多。希望这篇记录对你有帮助,也欢迎在实际训练中遇到问题来交流。

返回列表