
最近在折腾宠物识别项目手头这套猫狗检测数据集是我反复清洗和标注出来的一共4300张图片已经整理成 YOLO 格式直接丢给 YOLOv8 训练就能跑。和网上那些做分类任务的数据集不一样这批数据每张图都有目标框标注能用于真实场景的检测任务比如识别画面里的猫猫狗狗的位置而不是仅仅告诉你是猫还是狗。如果你正准备做宠物检测、自动喂食、宠物门禁这类功能或者刚接触 YOLO 想找个干净的数据集练手这篇内容应该能帮你少走不少弯路。我会从数据集的构成开始讲然后说清楚 YOLO 标签文件到底怎么写再把用 YOLOv8 训练的完整过程和参数选择逐项拆开最后重点聊聊我实际训练中踩过的几个坑以及部署时怎么提速。全程不堆术语但每一步都能直接复现。1. 数据集概览4300张图到底够用在哪里1.1 核心构成与参数说明这套数据集总共包含 4300 张图片目标类别是猫cat和狗dog我按约 1:1 的比例做了均衡猫图 2160 张左右狗图 2140 张左右避免模型过于偏向某一类。每张图不一定只有一个目标有些场景里同时出现多只猫或多只狗也有一猫一狗同框的画面平均每张图约 1.5 个标注框总计标注目标数约 6500 个。图片尺寸不是整齐划一的主要来自不同分辨率的设备覆盖了 640×480、1280×720、1920×1080 等常见分辨率也有些手机竖屏的照片。训练时 YOLO 会统一做 letterbox 缩放所以混分辨率问题不大但这也意味着原图长宽比比较多样正好能模拟真实业务的图片输入。场景多样性方面我刻意保证了几类覆盖室内场景客厅、卧室、厨房光线有强光和暗光。室外场景小区、公园、街道背景有草地、水泥地面、栏杆。特殊姿态睡觉、奔跑、跳跃、侧躺、背对镜头。遮挡情况部分身体被沙发、桌子、主人腿部遮挡或者猫狗互相遮挡。小目标远处的人物带着宠物宠物在画面中占比很小。训练集和验证集的划分我用了常见的 8:2也就是 3440 张做训练860 张做验证划分的时候确保同一只动物的多张不同照片不会被全塞进同一个集合。你拿到数据集后也不妨沿用这个划分如果后续自己采集了新图片还能按同样比例补进去继续迭代。1.2 这套数据能解决什么问题猫狗检测是最典型的目标检测入门场景但它的实用价值比想象中大得多。拿我自己的项目来说最初做的是智能宠物喂食器需要检测到猫靠近食盆就拍照记录狗过来就自动锁盖这种需求本质上就是一个实时检测任务。如果你也想做相关产品这套数据能支撑这些方向宠物相册自动分类检测出画面中的猫狗再配合分类模型区分品种。宠物门禁当猫接近时自动开门狗接近时保持关闭逻辑就是检测框的类别判断。流浪动物监控在固定摄像头画面中统计一定时间段内出现的猫狗数量。宠物走失寻回结合检索模型在用户上传的照片中快速找出宠物所在位置。短视频自动剪辑根据时间轴上的检测结果把包含宠物的片段剪切出来。以上场景的共同点是可以共用一个检测模型的输出也就是类别、置信度和框坐标。只要这个基础检测模型够稳上层业务怎么玩都行。1.3 和 COCO、Cats vs Dogs 等公开数据集的区别很多人会问“COCO 里本来就有猫和狗直接用 COCO 预训练不就行了吗”确实可以但 COCO 中猫狗的标注数量远少于这套专用数据集而且很多图像的分辨率偏低小猫小狗在画面中往往就占几十个像素专门用来迁移学习还可以直接评估效果并不理想。另一个常被拿来对比的是 Cats vs Dogs 分类数据集它只有整图分类标签没有目标框。你拿它训练 YOLO 会非常别扭因为没有定位信息模型学不到“目标在哪儿”。这套猫狗检测数据集就不一样每张图的 txt 标定文件里都有框的归一化坐标天然对接 YOLO 训练流程省掉你重新标注的功夫。当然专用数据集数量级毕竟只有 4300不可能覆盖所有品种、所有光照、所有拍摄角度。这点我有清醒认识所以后面我会专门讲怎么用迁移学习、数据增强和难例挖掘来弥补数据量的不足。2. 数据格式解读从一张图到一个 txt 文件2.1 YOLO 标签格式和坐标归一化的原理YOLO 系列模型要求的标签文件是 txt 格式每行代表一个目标格式是class_id x_center y_center width height值得强调的是这里不存顶点坐标而是存中心点坐标和框的宽高并且全部除以了图片宽高归一化到 0 到 1 之间。这样做的好处是模型训练时不管输入图片被缩放成多大框的相对位置都不会变不会因为某些图片是 1024 宽、另一些是 640 宽而导致标签失效。我举个例子一张 1024×768 的图片目标框左上角坐标为 (200, 150)右下角坐标为 (600, 400)那么宽600 - 200 400高400 - 150 250中心点 X200 400 / 2 400归一化后为 400 / 1024 0.390625中心点 Y150 250 / 2 275归一化后为 275 / 768 0.358072宽400 / 1024 0.390625高250 / 768 0.325521所以这一行就是0 0.390625 0.358072 0.390625 0.325521如果同一张图里有多个目标就多写几行不用管顺序。我在标注时把 cat 设为类别 0dog 设为类别 1如果和你自己的需求刚好相反记得统一修改 data.yaml 里的类别名和顺序。2.2 数据集目录结构与 data.yaml 文件刚拿到手的数据集目录长这样pet_det/ ├── images/ │ ├── train/ │ │ ├── cat_001.jpg │ │ ├── cat_002.jpg │ │ └── dog_001.jpg │ └── val/ │ ├── cat_030.jpg │ └── dog_018.jpg ├── labels/ │ ├── train/ │ │ ├── cat_001.txt │ │ ├── cat_002.txt │ │ └── dog_001.txt │ └── val/ │ ├── cat_030.txt │ └── dog_018.txt └── data.yamlimages 和 labels 下必须有同名文件比如images/train/cat_001.jpg对应labels/train/cat_001.txt文件名前缀一致扩展名不同。很多新手刚跑 YOLO 训练时提示找不到标签多半就是文件名没对齐或者 image 和 label 目录名拼错了。data.yaml 的内容如下path: /path/to/pet_det train: images/train val: images/val names: 0: cat 1: dog需要注意path字段可以写成相对路径也可以写绝对路径我建议在 Linux 服务器上直接写绝对路径能省掉很多奇奇怪怪路径拼接问题。还有一点YOLOv8 之后names是一个 dict键值对不能反了否则训练时类别名和标签 id 会对不上。2.3 标签质量检查动手写个可视化小脚本我强烈建议在训练前先肉眼检查一遍标注框别急着开训练。我曾经因为一个标注文件的坐标写错导致模型训练出来猫狗框全都偏到左下角排查半天才发现是某个脚本批量处理时把 normalize 除错了。最简单的检查方法是写个 Python 脚本用 OpenCV 把 txt 里的框画回原图看看。直接用这段按需改路径import cv2 img_path pet_det/images/val/cat_030.jpg label_path pet_det/labels/val/cat_030.txt img cv2.imread(img_path) h, w img.shape[:2] with open(label_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: continue class_id, x_c, y_c, bw, bh map(float, parts) 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) label cat if int(class_id) 0 else dog cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) cv2.imwrite(checked.jpg, img)把输出图打开看看重点关注三类问题框是否明显大于目标包含了大量墙壁、地板。框是否只框住了半只猫或者漏掉了主要身体区域。类别 id 是否标反比如猫被写成 dog。如果发现问题数量多不要硬筛直接重新标注或重采样效果更好。少量脏数据其实可以通过后面讲的训练策略容忍但大面积错标一定会拖低 mAP。3. 从零训练 YOLOv8 猫狗检测模型的实操流程3.1 环境准备与模型选型训练机器上只需要装一个 ultralytics 库它会自动把依赖带起来。直接用 pip 安装就行pip install ultralytics如果你的机器没有 GPU也能在 CPU 上跑但 4300 张图训练 100 个 epoch 会非常煎熬我建议至少用云端的普通 GPU 实例比如 16GB 显存起步。显存不够就把 batch size 调小千万别一上来就爆显存。关于模型选型YOLOv8 有 n / s / m / l / x 档位我的建议是模型参数量速度倾向适用场景yolov8n约 320 万极快嵌入式设备、移动端原型yolov8s约 1100 万快常规 CPU 推理、边缘盒子yolov8m约 2500 万中等服务器 GPU 推理追求精度yolov8l约 4300 万较慢高精度需求算力充足yolov8x约 6800 万慢学术实验精度优先训练前我建议直接用官方预训练权重也就是 COCO 上训练好的权重。因为 COCO 里包含猫狗类别模型已经具备一定的猫狗特征抽象能力在此基础上微调 4300 张图片要比从零训练收敛快得多最终精度也会更好。我自己选的是 yolov8s 起步精度和速度都能兼顾后面再根据实测情况决定是否换更大模型。3.2 训练参数怎么设背后的理由是什么命令直接写yolo detect train datapet_det/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 patience20 device0挑几个关键参数说说我的依据epochs1004300 张图不算大100 个 epoch 足够跑出收敛趋势。如果你发现验证集的 mAP 还在明显上升就继续加 epochs不用被这个初始值锁死。imgsz640YOLO 的默认输入分辨率适配绝大多数目标检测需求。如果后面想提升小目标召回率可以把imgsz提到 768 或 1024但训练时长和显存占用都会增加要先确认机器扛得住。batch16这个要结合显存调整。24GB 显存跑 yolov8s 的 640 分辨率batch32 也没问题16GB 就设 16。batch 太大不会显著提高效果反而可能让训练后期不稳定适中就行。patience20早停轮数。连续 20 个 epoch 验证集指标不提升就提前停止省时间。device0指定第一张 GPU。只有 CPU 就改成devicecpu。不需要手动调学习率ultralytics 默认会自动选择参考学习率配合 AdamW 优化器在多数场景下都表现稳定。训练时如果 loss 在前期降得很慢可以先确认下是否用了预训练权重再检查数据标注是否有问题。3.3 训练日志怎么看以及保存下来的文件训练过程中终端会实时打印每个 epoch 的损失和指标主要看这几个box_loss定位损失如果这个值居高不下大概率是标注框不准或者目标尺度分布过于极端。cls_loss分类损失猫狗类别很容易区分这个值正常应该降得很快。mAP50IoU 阈值 50% 下的平均精度这是立竿见影的硬指标4300 张数据跑到 0.95 左右并不难。mAP50-95更严格的多阈值指标会比 mAP50 低不少更能反映框的贴合度。训练结束后项目里会生成runs/detect/train目录里面包含每个 epoch 的曲线图、混淆矩阵、验证集预测结果样例。最有用的是weights/best.pt和weights/last.ptbest.pt是验证集指标最好的权重部署时直接用这个。验证预测图我每次都会翻一遍重点看模型把猫狗框得准不准、有没有把背景中的人腿当成猫、有没有把熊猫玩具检测成狗。这些图上看起来很小的问题恰恰能暴露训练集里的分布缺陷。4. 训练中的实际问题那些教程不会告诉你的失败经验4.1 类别不平衡与“虚高精度”的陷阱虽然我刻意让猫狗数量接近 1:1但如果你在自己采集数据时没有控制比例比如猫图 4000 张、狗图只有 300 张模型很容易偷懒把所有模糊目标都归为猫因为猫类样本多总损失比较低。我第一版数据集就吃过这个亏。当时总体 mAP50 到 0.94 看起来很好但单独看狗的 recall 只有 0.62原因是狗样本少且多是小目标模型直接选择“躺平”。解决办法有几个我推荐组合使用统计每类标注框数量如果悬殊训练时对少数类做采样增加。对少数类做目标级复制增强比如把狗目标粘贴到空白背景中生成额外样本。在 loss 里调整类别权重但 YOLOv8 原生没有直接开放这个开关所以多数情况还是靠数据层解决。判断是否偏科不要只看 overall mAP。训练完第一件事就是看混淆矩阵里的逐类 recall把猫和狗分开统计别被漂亮的总分骗了。4.2 猫狗姿态差异大标签框怎么标才稳猫和狗的身体形状差异很大狗常站着身体是长方形猫喜欢蜷成一团身体接近圆球。加上耳朵、尾巴、伸长的爪子标注标准不统一会让模型很困惑。我最初整理数据时把尾巴尖和耳朵尖也包进去发现模型后期预测的框普遍偏大IoU 下降。后来统一标准框的主体是头身连接的核心躯干。耳朵不算在框内除非耳朵很大且紧贴头部。尾巴不算在框内尾巴尖远离身体时很容易引入大量背景。如果猫狗互相咬住、抱在一起分开标注两个框不要合并标注。这个标准看起来很简单但标注员如果不统一框的边界抖动非常严重。你在用任何数据集之前最好抽 50 个框做一次统计看看框的宽高比分布如果一个猫框宽高比 0.3一个猫框宽高比 1.2训练时 anchor 匹配就会乱。4.3 小目标漏检远处一只猫就是考卷的大题宠物检测的难点其实不在大脸特写而在“远处有一只猫蹲在墙角”。小目标在 640 分辨率下可能只有 20×30 像素特征非常弱很容易漏检。我测试过同样的模型把输入分辨率从 640 提到 768小目标召回率提升了 5 个点左右代价是推理时间增加约 20%。另外YOLOv8 的 mosaic 增强默认是开的它能模拟出大量大小目标混合的场景对小目标训练有一定的正面作用但如果发现小目标仍然漏可以试着把mosaic换成close_mosaic最后 10 个 epoch 关掉让模型适应真实分布。还有一个容易被忽略的点如果你部署时使用了原始图流但训练时总是 letterbox 到 640那么当输入源是 1920×1080 且猫很小时检测效果会非常差。这种情况建议部署端直接裁剪感兴趣区域做二次检测比盲目拉高全局输入分辨率更高效。4.4 从混淆矩阵反向定位模型缺陷训练结束后的confusion_matrix.png是一个 2x2 加上 background 的小矩阵但信息量很大。猫狗二分类的矩阵里第一行第一类是真正率第二行第二列是召回率最右下角是 background 误检率。我一般按这个顺序排查如果猫被错分成狗的比例高说明两类训练样本在视觉上太接近需要增加猫样本中“长得像狗的猫”的图像比如无毛猫、全身黑色的猫。如果背景误检占比高说明负样本不够丰富模型分不清地毯花纹、玩偶和宠物。解决方案是收集一批完全没有任何宠物的街区、客厅照片标注为空 txt 文件混入训练集让模型专门学“空背景”。如果框偏而且 IoU 低对照验证集预测图看是偏左还是偏右通常和标签噪声有关可以重新清洗标签。不要只看 mAP50不同业务对误检的容忍度不一样。门禁场景宁可漏检一次也不要误触发 10 次开门那么你的调优方向应该是压低 background 误检率哪怕牺牲一点召回率也在所不惜。5. 让模型真正能用推理部署与效果持续优化5.1 导出 ONNX 并用 CPU 或 Jetson 加速训练完成后第一件事是导出部署格式。YOLOv8 官方支持 ONNX、TensorRT、OpenVINO 等导出。我常用的是 ONNX因为兼容性最好yolo export modelruns/detect/train/weights/best.pt formatonnx dynamicTruedynamicTrue允许 batch size 和输入尺寸变化方便在服务端处理不同分辨率。导出后用onnxruntime测试一下推理速度import onnxruntime as ort import numpy as np sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name # 假设输入是 1x3x640x640 dummy np.random.randn(1, 3, 640, 640).astype(np.float32) out sess.run(None, {input_name: dummy})如果你的部署目标是树干电脑、Jetson Nano 之类建议再导出 TensorRT 引擎。TensorRT 能把推理时间压到 CPU 的十分之一甚至更低但导出的引擎是特定硬件和版本的换设备要重新导出这点务必注意。5.2 数据增强与难例挖掘把 4300 张的价值放大数据量有限最有效的补救手段是增强和难例挖掘。ultralytics 内置的增强包括翻转、旋转、缩放、亮度变化、mosaic 等默认配置已经不错但有几个开关可以再调hsv_h、hsv_s、hsv_v控制色调、饱和度和亮度变化。如果你的使用环境主要是室内暖光可以适当提高hsv_h让模型对灯光的鲁棒性更好。degrees小幅旋转适合宠物乱跑时图像角度多变的情况但不要超过 15 度否则变形太严重。translate平移增强能模拟宠物在画面中位置不断变化的情况。难例挖掘是另一个方向。当第一版模型训练好以后把真实摄像头拍摄的数据送入模型挑出那些置信度不高但实际有猫狗的片段重新标注并加入训练集。这样做三轮以后模型对自家场景的适应能力会明显提升通常比盲目增加 1000 张网上图片更管用。5.3 进阶扩展从检测框到实例分割和品种识别如果后续需求从“猫/狗在哪”升级到“把猫从背景里精细抠出来”建议直接切到 YOLOv8-seg。它同样支持训练猫狗分割数据集只是在标注时需要多边形的分割掩码而不是矩形框。矩形框能快速过滤画面但边缘不够精细分割模型在宠物美妆、短视频抠图这类场景中效果要明显好一档。另外如果你想做品种识别可以在检测框基础上再接一个分类模型把框内区域裁剪下来后送进分类器。这样做的好处是检测和分类解耦某个品种识别不准时只更新分类模型不需要重新训练检测模型迭代成本低很多。我之前还试过用检测出来的框做 track 跟踪统计猫在某个区域内的活动时长配合定时喂食器做“猫走了再开盖”的逻辑。YOLOv8 输出框之后接一个简单的 IoU 匹配就能实现短时跟踪这种组合玩法是通用的也可以迁移到其他检测场景。一点个人的体会整个项目做下来我最深的感受是猫狗检测本身并不难难的是把 4300 张图像的分布打磨到和真实场景一致。标注质量、类别均衡、小目标覆盖这三者任何一边出问题训练时都会加倍还给你。如果你准备用这套数据集起步我建议不要一上来就追求大模型。先用 yolov8s 跑通链路再针对自己的摄像头画面做难例迭代效果会比直接堆模型容量好得多。训练时手里常备一张混淆矩阵图和几张验证预测图比盯着一堆 loss 数字有用。最后分享一个小技巧把训练过程里的 best.pt 多保存几个副本因为验证集指标有时候早停后还会反弹。留下一套历史权重真到了现场效果不理想时回退一版再调参比重新训练省心不少。