ARTICLE DETAIL

资讯详情

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

YOLO宠物识别实战:4300张猫狗检测数据集训练与部署全流程

YOLO宠物识别实战:4300张猫狗检测数据集训练与部署全流程 前阵子我在捣鼓一个宠物智能设备需求看起来就一句话识别画面里到底有没有猫或狗。可真等下手做才发现这一句话背后全是坑。为此我干脆自己攒了一套猫狗检测数据集总共有4300张图用YOLO训练宠物识别模型从标注格式到部署全流程走了一遍。这篇就毫无保留地把整套方案拆开讲包括数据集怎么凑、标签怎么标、模型怎么选、训练参数怎么调、上线后遇到哪些问题。想入门YOLO目标检测、或是正打算做宠物识别相关项目的朋友可以参考这套流程省得像我一样踩一圈。1. 为什么我决定自己整理一套猫狗检测数据集1.1 一个看似简单的需求背后全是细节宠物识别不是“给一张图判断猫还是狗”这么简单。真实场景里猫缩在沙发角落被抱枕挡了一半黑狗在夜晚逆光下只剩一团轮廓两只宠物凑在一起打闹这些情况会同时出现。如果只是拿分类模型做识别根本拿不到“宠物到底在画面哪个位置”。所以我直接锁定了目标检测方案模型要输出bounding box加类别这样才能进一步驱动设备动作比如猫靠近自动锁住喂食器、狗闯入禁区触发告警。这个需求对模型有两个硬要求。一是实时性单帧推理速度要在可接受范围内否则设备体验会很差二是误检率宠物监控类应用如果一天到晚瞎报用户很快就会把功能关掉。综合下来YOLO系列是性价比最高的选择速度快、生态成熟、训练部署链路完整。而YOLO要训练好第一步永远是数据这也成了我决定自己整理数据集的直接原因。1.2 公开数据集救不了你的实际场景动手之前我也在开源数据集里翻过一轮。很多公开的猫狗检测数据集看缩略图似乎很美但真拿来做项目就会发现问题。最常见的是类别不平衡。有些数据集里狗的图片数量明显多于猫直接训练会导致猫的召回率偏低。而在实际产品里猫和狗的重要程度是一样的漏检哪边都会出问题。第二是背景太干净很多图来自图库宠物在正中间背景是白墙或纯色草地摄像头设备看到的却是沙发缝、窗帘逆光、地毯花纹这种复杂环境模型很容易不知所措。第三是标注格式不统一有的是VOC格式XML有的是COCO格式JSON有些txt文件里坐标根本没归一化。就算费劲转成YOLO格式也经常发现框偏大、框偏小、类别标错需要大量返工。所以我干脆决定自己整理一套。公开数据集适合做通用预训练但不适合直接拿去做场景交付。只有自己控制采集、清洗、标注、切分的每个环节才能知道模型表现好到底是因为什么。2. 数据集设计与标注方案2.1 4300张图是怎么攒出来的最终留下的可训练图片是4300张猫和狗基本对半猫约2150张、狗约2150张。里面掺了大概5%~8%的多宠物图片也就是同一画面里既有猫又有狗这部分样本对多目标检测能力提升非常关键没有它们模型很容易在两只宠物同框时只检出其中一个。图片来源我做了混合。一部分是自己拿手机拍的大概300张专门拍家里的猫在不同光线、不同角落下的状态一部门是从合法的图集类素材里筛选还有很大一部分是从视频里抽帧得到的。视频抽帧有个明显好处同一只宠物在连续帧里有不同的姿态、不同的遮挡程度、不同的身体朝向相当于给数据集加入了丰富的时序变化。但抽帧一定要做去重不然训练集和验证集里出现同一段画面的连续帧验证指标会虚高看着mAP很漂亮部署后立刻露馅。清洗阶段我卡得比较狠。分辨率低于300×300的图片直接删掉模糊到肉眼都难分辨的删掉有严重水印或贴纸遮挡宠物主体的删掉。卡通、插画、3D渲染图也一律排除除非你的项目本身就做卡通宠物识别。这样清洗的目的是让模型贴近真实摄像头输入而不是训练集精美得像写真集部署后每天对着客厅的乱糟糟环境发懵。2.2 YOLO标签格式与归一化坐标计算YOLO的标签格式是每张图对应一个txt文件每行代表一个目标class_id x_center y_center width height这五个数字里x_center、y_center是目标框中心点的坐标width和height是框的宽高。注意这四个值全部是归一化到0~1之间的小数不是像素值。这一点对刚入门的朋友特别容易踩坑。如果标签存成绝对像素图片一旦被缩放框的位置就全对不上了。归一化坐标天然能够适配任意输入尺寸因为训练时模型总会把图缩放到固定大小。拿一个具体例子来算。假设一张图宽度1600px、高度1200px里面有一只猫框的左上角坐标是(400,300)右下角坐标是(900,800)。那么框宽w900-400500像素框高h800-300500像素中心点x(400900)/2650像素中心点y(300800)/2550像素。归一化之后x_center 650 / 1600 0.40625y_center 550 / 1200 0.45833w 500 / 1600 0.3125h 500 / 1200 0.41667如果猫的class_id约定为0那这个txt文件里就是一行0 0.40625 0.45833 0.3125 0.41667。我标注的时候先用LabelImg做初标再做格式转换。也有朋友改用X-AnyLabeling这类支持半自动分割的标注工具效率确实高一些但转换出来的坐标格式一定要再核对尤其要检查归一化逻辑是不是和YOLO一致。2.3 标注质量检查与类别平衡标注完成后要通篇过两遍这个环节千万别省。我自己检查时最看重三类问题。第一是类别混淆。黑猫和黑狗在暗光环境下真的很容易标错冬天深色毛发的宠物拍出来就是一团黑影人眼都容易看走眼标注时稍不留神就会把猫标成狗。这种错误比框偏了几个像素严重得多因为模型会收到互相矛盾的梯度信号。第二是框的松紧程度。框太紧会截掉耳朵、尾巴模型会学得束手束脚框太松会把旁边的茶几角、抱枕边包进去等于让模型把背景当目标一起学。我的经验是目标框包住可见的完整躯干就好被挡住的部分不用强行外扩毕竟你要的是“这只宠物在哪个区域”不是“这只宠物的轮廓有几斤几两”。第三是漏标。有些图片目标若隐若现实在看不清就删掉千万不要留着却不标框。漏标的目标在训练时会被网络当作背景模型学到的反而成了“这个区域没有宠物”这是最坑的错误信号。类别平衡方面我统计的是框数量而不是图片数量因为一张图可能同时有好几只猫或狗。最终猫框约3400个狗框约3300个基本做到1:1。如果某一类框偏多我会优先补充另一类的困难样本而不是用损失函数的采样权重硬凑因为前者能让模型真正见到更多样化的目标。3. YOLO系列模型选型与训练环境搭建3.1 为什么选YOLO而不是其他检测方案刚入门的朋友常纠结YOLO和Faster R-CNN这类两阶段检测器怎么选。我的判断标准很直接先看部署设备再看精度要求。两阶段检测器先挖候选区域再做分类和回归在小目标检测、密集场景上确实有精度优势但推理速度往往跟不上。假设你的设备是普通x86 CPU或者Jetson这类边缘硬件Faster R-CNN做单帧推理很难达到理想帧率。YOLO把检测当成单次回归问题网络一次性输出所有框、类别和置信度虽然在极度复杂的场景下精度上限可能不如两阶段但猫狗识别这种类别少、目标尺度偏向中等大小的任务YOLO的精度已经完全够用。还有生态因素。Ultralytics官方把训练、验证、导出、部署集成得很完善一个命令就能从零开始训练再一个命令导出ONNX或TensorRT。如果后续要做实例分割YOLOv8-seg和更新版本的分割模型也支持直接训练不需要另起炉灶换框架。对做实际产品的人来说这套链路确实好上手。3.2 选YOLOv8s还是YOLOv8n我最终用的是YOLOv8s没有选更小的n也没有选更大的m原因要结合数据集规模和部署目标来说。YOLOv8n参数量约3.2M适合手机端和极低功耗场景但参数量小如果训练数据质量或数量不够精度上限会比较紧张。YOLOv8s参数量约11.2M精度比n高一截在CPU上用ONNX推理640×640输入大约100~200ms/帧在GPU或NPU上可以轻松实时。这是我在精度和速度之间找平衡选择。YOLOv8m约26M参数精度更高但推理开销更大适合算力充足的设备。4300张的数据量对n来说不算特别富裕用s更稳。如果将来要上电池供电的低功耗设备我会先训练一个精度很好的s模型再把它蒸馏到n上而不是直接拿n裸训。机器学习的通用经验是当模型容量不够时先让大模型学到好特征再蒸馏给小模型效果往往好过小模型自己死磕。3.3 环境安装与硬件选择训练环境我用的版本组合是Python 3.10、PyTorch 2.1以上、CUDA 11.8或12.1加上Ultralytics 8.x。安装就一条命令pip install ultralytics装好后先确认GPU能用import torch print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))我手里是一张RTX 3060 12GB显卡。训练YOLOv8s、batch16、imgsz640完全没压力。如果你的显存是8GB那就把batch降到8同时要确保AMP自动混合精度开着。Ultralytics默认就开启AMP能用半精度训练显存占用减少很多训练速度也会提升。手头没有NVIDIA GPU也没关系小数据集用CPU跑也能出结果只是训练时间会拉长到几小时甚至十几小时适合只做实验验证。4. 完整训练流程与核心参数调优4.1 数据集划分与data.yaml配置我按train:val:test8:1:1来划分也就是3440张训练、430张验证、430张测试。验证集用来做早停和调参测试集只在最终评估时看一眼避免模型“背答案”。这里有一个关键细节划分不能直接全量随机打乱然后切一刀。因为我的数据里有大量来自视频抽帧的图片同源连续帧之间高度相似如果随机切分训练集和验证集里会出现大量同源图验证得分虚高。我的做法是把图片按来源分桶再从每个桶里按比例抽保证同一个视频序列的帧尽可能只落在一个集合里。data.yaml的写法如下path: /data/pet_detection train: images/train val: images/val test: images/test names: 0: cat 1: dognames的顺序必须和标注txt里的class_id完全一致。我标注时约定了cat0、dog1那训练和推理阶段也要保持这个顺序否则部署时就是把“猫的框”贴上“狗的名字”。4.2 训练启动与逐参数解读实际训练命令yolo detect train \ datadata.yaml \ modelyolov8s.pt \ epochs150 \ batch16 \ imgsz640 \ patience30 \ device0参数选择背后的逻辑epochs1504300张图片不算多配合数据增强150轮足够收敛。如果数据量只有几百张最好加载预训练权重并加强增强盲目加大epoch只会更快过拟合。batch16在12GB显存下跑得很稳比这更大能提升一点训练稳定性但显存会接近瓶颈。imgsz640与官方预训练权重最匹配的输入尺寸。训练和部署都应保持一致不要训练用1280、部署用640那样会引入分辨率不一致的性能损失。patience30连续30轮验证集mAP不提升就早停。这个参数能节省大量无效等待时间。训练启动后我会同时打开tensorboard看实时曲线Ultralytics会在runs/detect目录下输出日志也可以直接加--project和--name参数管理实验。训练结束后weights文件夹里会出现best.pt和last.ptbest.pt是验证集上表现最好的权重之后所有评估和部署都默认用它。4.3 训练过程观察与损失曲线怎么看训练日志里主要关注三类lossbox_loss定位损失、cls_loss分类损失、dfl_loss分布焦点损失。YOLOv8的回归分支用的是CIoU损失DFL则对边界框四条边的分布做建模让框更贴合目标边缘。正常状态是三类loss都缓缓下降大约第50到第80轮后进入平台期。如果cls_loss一直在降而验证集指标反而反弹说明模型开始过拟合这时候不要急着加数据增强先检查训练集里是不是有大量重复帧在给模型“灌答案”。我这套数据训到第95轮左右触发早停。best.pt在验证集上的指标大约是mAP0.5在0.938上下mAP0.5:0.95在0.851附近。两个类别这种任务量能有这个数字已经不错。如果你的目标检测场景更复杂比如大量小目标mAP还会明显下降这是正常现象不是模型故障。4.4 评估指标不只盯着mAP很多人只看mAP但宠物识别这种场景我更建议把precision和recall分开看。如果是宠物门禁漏报猫等于功能失效recall优先级更高宁可偶尔误报也不能漏。如果是宠物监控告警用户对误报零容忍频繁误触发会直接卸载功能那precision优先级更高。两者都要兼顾就看F1分数。YOLO训练完会在验证目录里生成混淆矩阵和PR曲线。生产环境里我把置信度阈值conf_thres设成0.4NMS的iou阈值设成0.45这样一个配置能让precision和recall相对均衡。如果你要追高召回把conf降到0.25要追高精确就把conf升到0.5以上。这个阈值调整不需要重新训练改推理参数就行。5. 高频问题排查与实战避坑5.1 Loss不下降或震荡如何排查我训练第一版数据时遇到过失控状况loss到第60轮左右突然向上抬头当时第一反应是学习率太大结果检查半天才发现是有几个标注文件的class_id写成了2但names里根本没有这个类模型等于在学一个不存在的标签。我把排查顺序整理成了固定套路碰到loss异常先按这个顺序走效率高很多先看loss曲线从头到尾的趋势。如果从不下降或震荡剧烈先怀疑标注文件随机抽查image和txt的对应关系。可视化训练集中的图片把标注框画出来确认框确实落在目标上而不是飘在背景里。检查数据集切分确认没有同源图片跨集合。以上都正常才轮到学习率、数据增强、imgsz这些超参数。做深度学习项目数据问题永远排在超参数前面。数据不乱模型通常不会疯。5.2 漏检、误检集中的位置怎么处理漏检最典型的场景是目标太小。宠物在画面远处只有几十个像素高YOLOv8s容易直接把它当背景扫过去。处理思路是提高训练分辨率到768补充这类小目标在数据集里的占比。如果部署密度允许也可以在推理时用更大的imgsz代价是延迟变高。严重遮挡和极端姿态也是一个漏检重灾区。猫团成一团只露半张脸或背对镜头只给你一个屁股这些情况人眼都容易看走眼。这类样本没法靠hsv颜色抖动、平移旋转这些通用增强变出来必须靠现实采集专门补充。误检经常集中在固定区域。如果摄像头长期固定画面里某个玩偶、盆栽长得像猫就会频繁误报。最简单的方案是给固定机位拍一段空场景视频做负样本微调让模型学会“这个角落是背景不是目标”。做监控类产品时这条经验几乎每次都能派上用场。5.3 训练结果和部署结果不一致的原因训练时一切正常导出ONNX到目标设备后同一张图检测结果对不上这个坑几乎每个人都会遇到。常见原因有以下四个。第一是预处理通道顺序。训练时模型输入是RGB但OpenCV读图默认是BGR如果推理前不做cv2.cvtColor(img, cv2.COLOR_BGR2RGB)模型看到的颜色就全乱了。第二是归一化方式不同。YOLO通常用像素值除以255归一化到0~1有些导出模型已经在内部做了归一化有些则要求输入原始0~255图像必须看模型的实际输入约定。第三是letterbox填充。训练时输入统一到640×640但原始图片宽高比各不相同需要做灰色填充的letterbox保证目标比例不被拉伸。如果直接把原图resize到640×640框的位置和大小都会偏。第四是NMS参数不一致。训练时NMS的iou阈值如果和部署时不同重复框的过滤结果也会不同。我遇到过一个案例部署时把iou_thres从0.45改到了0.6结果原本两个重叠框应该合并成一个的模型却输出了两个框视觉上就像一次误检。这几个点列成一个小表就是下面这样的快速排查卡现象优先怀疑项检查方法检测框整体偏移letterbox或resize逻辑不一致打印预处理后的图像尺寸和坐标映射检测框偏大偏小重叠多NMS阈值与训练时不一致对比部署端iou_thres和训练配置颜色异常、类别混乱RGB/BGR通道顺序搞反转成RGB后肉眼对比图像颜色置信度普遍偏低归一化方式不一致确认模型输入是否要求除以2556. 部署落地与后续扩展经验6.1 导出ONNX并在CPU上跑起来YOLOv8导出ONNX只需要一条命令yolo export modelbest.pt formatonnx opset12 simplifyTrue导出后可以用onnxruntime进行推理这样目标机器上就不需要再装PyTorch了。核心工作其实只有一个把训练时的预处理链路完整搬到推理端。推荐写一个最小可用的脚本先验明正确性再扩展到多线程场景。import cv2 import numpy as np import onnxruntime as ort session ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) image cv2.imread(test.jpg) image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # 这里继续完成letterbox调整尺寸然后归一化到0~1 # 最后转成CHW格式增加batch维度送入session.run推理输出一般是(1, 84, 8400)这样的维度8400对应不同尺度下的候选框数量84里包含4个边界框坐标、1个目标置信度、2个类别得分再加上其他辅助参数。如果不手写后处理直接用Ultralytics的predict接口也能跑但那还需要PyTorch环境所以需要ONNX还是建议自己把后处理写一遍。在普通CPU服务器上YOLOv8s ONNX跑640×640推理单帧延迟大概在120到180毫秒之间做实时跟踪会吃力但做摄像头抽帧检测或事件触发完全够用。如果要在GPU或NPU上做多路实时视频检测配合TensorRT优化之后单帧可以降到几毫秒就能撑起多路并行分析不过那是另一个话题了。6.2 实际项目中哪些坑是模型解决不了的训练集再完善也不代表上线后万事大吉。我在真实项目里遇到过几个数据集很难根治的情况。隔着纱窗或玻璃时猫在纱窗后面摄像头捕捉到的是网格纹理和反光叠加在一起的杂乱图像模型检测时会飘这是成像问题不是模型问题只能靠硬件或图像预处理改善。强逆光导致宠物只剩一个剪影毛发的纹理信息几乎全丢了模型只能勉强给个框根本不稳。这种情况需要调整摄像头曝光策略或者换一台宽动态范围更好的摄像头纯靠喂数据效果有限。还有一个经典陷阱摄像头对着客厅电视机正好在播放猫狗视频模型就会误以为家里来宠物了。这个问题的合理解法是做运动检测或者对固定机位设定活动区域电视画面属于“不合理的活动区域”直接屏蔽。做这类系统数据和模型只占一半另一半是设备侧的规则工程越早想明白越省事。6.3 如果继续做我会在数据集上补什么当前这4300张数据已经能处理通用的猫狗检测问题但如果要把这套数据集升级成更完整的宠物识别方案我会补三块内容。第一是品种级细分类。现在只分猫狗两类下一步可以加品种标签做成树状结构比如先判断是猫还是狗再细分到常见品种。这样需要收集更多样本不然布偶猫、橘猫、德牧、柯基这些常见品种的数据很难覆盖全。第二是姿态与关键点。检测框只能表达宠物在哪个位置表达不了它正在趴着、站着还是跑动。加上关键点检测或姿态估计之后就能做行为分析比如判断猫是否在磨爪子、狗是否在转圈叼东西。第三是实例分割。把检测框升级成分割掩码可以更好地区分宠物和背景混杂的边缘遮挡情况下的计数也会更准。现在YOLO系列已经有分割模型可以直接训练数据标注工具Mirror上是复用这套检测标注做二次精修代价是标注成本会明显上升。说实话后面这几项我还在摸索推进中。也希望正在做宠物识别的朋友能从这篇内容里少踩几个坑把精力和时间花在真正值得打磨的需求上。
返回列表