ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于YOLOv8的猫情绪检测数据集制作与训练实战解析

基于YOLOv8的猫情绪检测数据集制作与训练实战解析 做猫情绪检测这件事一开始在我朋友圈里被当成玩笑直到有个朋友家的猫因为应激被误诊成肠胃炎多花了两千块检查费。我这才意识到如果能有一个可靠的行为检测工具提前发现猫的焦虑、恐惧或者攻击倾向对养猫的人来说意味着什么。于是就有了这套3200张的猫情绪检测数据集以及基于YOLO训练宠物行为检测模型的完整方案。这套数据集专门为目标检测而准备不是简单的图像分类而是把每只猫在画面中的位置用框标出来同时打上情绪行为标签。配合YOLO你可以训练出一个既能“找到猫”、又能“判断状态”的模型直接跑在监控摄像头、宠物喂食器或者手机App上。本文面向的是准备自己制作数据集、想用YOLOv8训练宠物行为模型的朋友我会把从标注到训练的完整路径拆开讲包括我踩过的坑和实测有效的参数。1. 先搞明白猫情绪检测到底检测什么1.1 情绪是抽象概念检测落地靠的是行为特征很多人一听到“情绪检测”就觉得玄学猫又不是人怎么知道它开心还是生气实际上这里说的情绪不是内在感受而是通过猫的行为表现去推断状态。猫的情绪会外化成一系列可观察的肢体信号耳朵角度、瞳孔大小、尾巴姿态、身体高度、是否发出哈声、是否弓背炸毛。这些信号组合起来基本可以对应到几种典型状态。我把这套数据集的类别设计成了四个放松、警惕、紧张/恐惧、攻击准备。放松状态常见于猫咪眯眼、侧躺、尾巴自然垂下或慢速摆动警惕状态表现为耳朵竖起、眼睛圆睁、身体静止、瞳孔放大紧张/恐惧则伴随飞机耳、压低身体、尾巴夹紧、甚至原地缩成一团攻击准备最明显的就是弓背炸毛、张嘴哈气、前爪紧绷。每个类别背后都是一组行为特征的组合数据集只管把这些视觉特征标注出来。正因为情绪判断需要落到具体的、可标注的视觉信号上这套数据集才能在训练中收敛。如果直接打标签“开心”、“难过”人类的标注一致性都很差模型更学不到稳定特征。所以做这类数据集第一步不是急着开会讨论分类而是把抽象概念翻译成可操作的标注规则。1.2 为什么任务必须用目标检测而不是图像分类早期我也想过用图像分类模型处理给每张图打一个整体标签比如“这张图里的猫是紧张状态”。但实际场景很快打脸镜头里猫经常只占很小一块区域背景里有沙发、花瓶、另一只猫分类模型会把大量注意力放在无关像素上。更麻烦的是照片里可能同时有两只猫一只在睡觉一只在警惕地盯着你整图分类压根没法表达这种多目标状态。YOLO这种目标检测模型在这个场景下是天然合适的。它同时回归出每个目标的边界框和类别概率天然能够解决“多只猫各自处于什么状态”的问题。而且YOLO家族发展到现在尤其是YOLOv8之后的版本对小目标、遮挡场景的容忍度已经比早期版本高出不少。配合你自己整理的猫情绪数据集训练出来的模型既能定位猫在画面里的位置也能给出它的行为状态。有人会问为什么不直接上实例分割分割模型理论上更精细能把猫的轮廓逐像素抠出来但标注成本是检测框的好几倍。对于情绪检测这种任务边界框已经足够表达“猫在哪里、状态如何”精确到像素轮廓带来的收益远小于标注成本。这也是我选YOLO而不是分割模型的核心原因在工业落地场景里投入产出比比算法炫技重要得多。1.3 3200张数据量是否够用规模估算与策略很多人看到3200这个数字第一反应是“这么少能训出东西吗”说实话如果做的是通用物体检测3200张确实不够看但做特定宠物情绪识别情况完全不同。这套数据的核心不是数量而是每个类别下都有足够多样且标注一致的正样本。四个类别平均每个类别800张左右这个量级配合数据增强和预训练权重完全能训出一个可用的模型。当然单纯追求数量没意义。我曾经见过有人爬了几万张宠物图片下载下来也没清洗直接标注结果训练出来的模型把拖把都识别成猫。数据质量永远是第一位的。3200张数据要覆盖不同品种、不同年龄、不同光照和拍摄角度、不同遮挡程度保证类别分布尽量均匀。如果四个类别里“放松”占了两千张“攻击准备”只有三百张那模型大概率会把攻击状态漏掉。关于是否能再加大量数据我的建议是先跑到瓶颈再说。3200张数据老老实实标注好配合离线增强训练一轮看验证集的表现。如果mAP50已经稳定在预期值附近就不需要盲目扩数据如果某个类别的召回率明显偏低针对那个类别补充样本比整体堆图片高效得多。2. 数据集制作全流程采集、清洗、标注一个都不能省2.1 图片从哪来版权、场景与实际拍摄数据集起步的第一件事永远是图片来源。我这次用了三个渠道混合自己用手机和摄像头拍的家庭场景猫照片几位养猫朋友授权提供的素材以及部分可商用授权的开源图片网站图片。这样做的好处是场景多样性足够既有室内暖光下的静态猫也有户外半遮挡的流浪猫还有不同品种的差异。如果你打算复刻这套过程我的建议是优先使用自己拍摄的素材因为版权最干净标注时也更清楚每张图的拍摄环境。从网络渠道取图时一定要确认授权协议不要直接爬宠物博主或者猫舍的照片既涉及版权风险也可能违反平台协议。可用来源包括Pixabay、Unsplash这类明确标注免费商用的图库一些开源宠物数据集也可以作为补充。采集过程中要刻意记录拍摄条件和猫的状态来源。比如这张图是在它吃饭前拍的还是一靠近它就炸毛时拍的这些信息不一定进标注文件但能帮你判断标注是否合理。我踩过的坑是拿到一批网络图片后只看了猫的外貌没有核对行为状态结果发现有些“攻击准备”的图片其实是几张哈欠连拍纯属误导。2.2 标注规范框选什么、怎么定义边界标注规范是整个数据集质量的生命线。我统一用“整只猫主体”作为检测框目标而不是只框猫脸或者只框身体局部。因为情绪行为大量体现在尾巴、耳朵、背部弧度上如果只框脸尾巴弓起这种典型攻击信号就完全没法学习。对于侧卧的猫就框它的整个身体轮廓不留过多环境背景对于被遮挡的猫框出可见部分的全部主体即可。每一张图的标签类别按前面定义的四类行为状态来打。这里有一条关键规则如果图片中猫的情绪状态不明确宁可放弃这张图也不要硬标注。比如一只猫背着身只能看到后脑勺你根本看不到耳朵和尾巴那它到底是放松还是警惕连人都判断不了模型自然也学不会。数据集中存在大量“不可判断”的样本只会把训练目标搞乱。标注工具我用过LabelImg和X-AnyLabeling后者对YOLO格式的支持更顺手可以自动用预标注模型辅助标记再手动修正类别和框。如果你手上只有几十张图用LabelImg手画也完全够用如果数量大强烈建议先用一个现成YOLO模型做预标注再人工核对能省下两倍时间。但无论用哪种工具标注完成后必须有二次审核环节最好是两个人独立标注同一批图统计一致率一致率低于90%就当标注规范有问题要重新调整规则。2.3 数据清洗与质量过滤垃圾进垃圾出训练结果的上限取决于数据质量这句话在猫情绪数据集上体现得尤其明显。我把原始素材里不合格的图片分成了几类模糊图片、过曝或欠曝到看不清猫肢体细节的图片、重复或近似重复的图片、以及情绪状态无法由人判断的图片。这些全部在标注前就剔除而不是等训练结束发现某类识别很差再回去排查。图片去重这步很多人会忽略。连拍模式下同一个动作会出现多张几乎一样的照片如果不清洗直接进数据集模型会把这组重复样本当成大量训练依据导致对特定姿态过拟合。我用哈希比对和感知哈希两轮去重把余弦相似度高于阈值的图片只保留一张效果很明显。还有一个我后来才意识到的大坑素材来源中有些图片自带水印或截图边框这些干扰信息会被模型学进特征里去。测试阶段用一张干净的验证图我惊讶地发现模型在检测“攻击准备”时似乎对图片左下角的水印区域异常敏感。排查后才知道部分网络来源的图片水印位置相近模型学到了水印和攻击标签的伪相关性。清洗阶段必须把这些带水印的图全部清掉或者统一裁剪掉水印区域。2.4 数据增强和数据划分训练集/验证集/测试集数据增强是在有限样本下提升泛化能力的重要手段。我用增强配置包括水平翻转、随机裁剪、亮度饱和度调整、轻微旋转和噪声注入。对于猫情绪检测水平翻转非常有效因为猫的左右姿态天然对称上下翻转则不推荐猫不会倒着出现在镜头里强行翻转只会制造不真实样本。增强要控制幅度不能把耳朵姿态扭曲到无法辨认。有一次我把旋转角度设到30度模型在训练集上拟合得很好但验证集上猫的正常卧躺姿态却频繁漏检。原因就是训练样本里出现了大量夸张角度的旋转猫模型学到了这种不正常的视角分布。我最后还是把旋转角度压到10度以内才恢复正常。数据集划分上我用训练集占80%验证集和测试集各占10%。关键原则是保证同一只猫的同类图片尽量只出现在一个集合里避免验证集和训练集出现几乎相同的连拍图导致验证指标虚高。划分完成后一定要按类别统计一下每个子集的样本分布确认四个情绪类别在验证集和测试集里都有足够数量否则测试mAP就是看运气。3. YOLOv8训练猫情绪模型全流程3.1 环境准备和预训练模型下载我推荐直接用Ultralytics的YOLOv8/PyTorch工具链因为它的API简洁数据处理、训练、评估、导出一体化非常适合自定义数据集。环境安装很简单创建一个Python 3.8以上的虚拟环境然后pip安装ultralytics包即可。GPU训练建议至少6GB显存如果没有显卡用CPU也能跑但训练时间会成倍增加建议先用小模型版本试水。预训练模型下载是一个重要环节。YOLO预训练模型可以从官方仓库下载常用的是yolov8n.pt和yolov8s.pt。为什么不从零训练因为COCO等大模型预训练权重已经学会了大量通用的物体边缘、纹理、颜色特征你只需要在它基础上微调最后的检测部分就可以用很少的数据把小目标识别做起来。我实测下来用yolov8n作为起点3200张数据训练100轮效果已经能满足大部分的室内监控场景如果追求更高精度再升级到yolov8m或yolov8l。训练前先跑一次最简单的预测加载预训练模型随便传一张带有猫的图片看看原始权重能把画面中的猫检测成什么。这一步不是必须但很能帮你建立对模型能力的直觉——COCO里本身有猫这个类别所以预训练模型在未见数据上也能大致框出猫只是情绪类别是空白。3.2 数据集整理成YOLO格式文件目录和txt标注YOLO格式要求图片和标签分开存放标签文件与图片文件同名但扩展名为txt每一行是一行标注内容类别ID、归一化后的中心点x坐标、中心点y坐标、框宽度、框高度。归一化就是除以图片的宽高所有值都在0到1之间模型处理起来更方便。目录结构可以参考这样dataset/ images/ train/ val/ test/ labels/ train/ val/ test/ data.yamldata.yaml文件是训练配置的核心里面声明了训练集和验证集的路径、类别数量、以及每个类别的名称。比如猫情绪数据集可以写成train: dataset/images/train val: dataset/images/val test: dataset/images/test nc: 4 names: [relaxed, alert, fearful, aggressive]我自己写了一个小脚本把LabelImg或X-AnyLabeling导出的标注格式转换成YOLO的txt格式同时完成图片路径的随机划分。脚本里有个很实用的细节转换前会校验每个txt文件里是否存在越界坐标或者空标注文件越界坐标哪怕只是大了0.01都会让训练过程出现奇怪的loss跳动我会在转换时直接把越界值裁剪到0到1之间。3.3 训练超参数设置从入门到有效第一次训练我建议先用保守参数跑通流程再逐步调整。我常用的一段训练命令是yolo detect train datadataset/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 lr00.01 patience20 device0这里解释几个关键超参数。imgsz设为640是因为这个尺寸兼顾了检测精度和显存占用猫在画面里虽然不一定大但640分辨率足以保留耳朵、尾巴等特征。batch根据显存来定如果显存不够报CUDA out of memory就把batch调小一半。epochs设100配合patience20的早停机制当连续20轮验证集mAP没有提升时自动停止可以避免无谓的算力消耗。YOLO损失函数这块值得稍微展开说。它的总损失由三部分组成分类损失判断类别对不对、边框回归损失判断框的位置准不准、置信度损失判断框里是不是真的有目标。训练日志里看到的train/box_loss、train/cls_loss、train/dfl_loss就是这几部分。如果分类损失一直不掉大概率是数据集标注类别有问题如果边框损失降不下去则可能标注框偏大偏小不统一需要回头检查标注规范。还有一个容易忽略的细节YOLOv8在处理自定义数据集时会根据数据集中所有标注框的尺寸统计自动重新计算Anchor锚框大小。这个功能默认开着按理说不需手动干预但如果你发现训练前期loss震动得非常剧烈可以看一眼自动Anchor的结果是否合理尤其是当数据集中同时存在“整只猫的全身框”和“裁剪后的半身框”时Anchor分布可能被拉偏最稳妥的做法是统一标注规范后再训练。3.4 训练过程监控与结果评估训练开始后我们要关注验证集上的表现而不是训练集loss。每轮结束时Ultralytics会输出类似“all 98 0.732 0.411”这样的指标分别是类别数、mAP50和mAP50-95。mAP50指的是当预测框和真实框的IoU阈值大于0.5时计算的平均精度这个指标对一般落地场景已经足够直观mAP50-95更严格把IoU从0.5到0.95每隔0.05算一次再平均更能反映模型定位的精细程度。训练完成后用下面命令在测试集上评估yolo detect val modelruns/detect/train/weights/best.pt datadataset/data.yaml重点看混淆矩阵。YOLO生成的混淆矩阵图里对角线值越高越好说明每个类都正确识别如果“紧张/恐惧”这一类的预测大量落在“警惕”上说明这两个类在视觉特征上太接近需要回看标注是否有交叉。我自己测试时发现紧抓的第一版模型容易把“攻击准备”误判成“紧张/恐惧”因为两者都可能有炸毛、弓背但攻击准备往往伴随张嘴哈气和前爪下压。后来我调整了数据增加这类细节明显的攻击图并把标注说明里强调“是否有攻击动作细节”混淆矩阵立刻就好看了很多。除了混淆矩阵还要看每个类别的召回率。召回率低表示漏检严重比如“放松”类召回率很高但“警惕”类召回率只有0.6说明模型对警惕状态的敏感度不足。优化手段通常是在增强时增加警惕类样本的翻转、亮度扰动或者干脆补充真实数据。不要只看总体mAP类别维度的表现才是数据集是否均衡的最好反馈。4. 训练猫情绪模型常见问题与避坑实录4.1 类别不平衡和数据不干净四个情绪类别在实际生活里出现的频率差异很大。放松状态最常见警惕次之攻击状态可遇不可求。这导致很多自行收集的数据集天然不平衡模型会把所有猫都预测成放松因为这样做整体准确率也不低。解决这个问题没有银弹我的做法是少数类别额外做“样本复制加权”比如攻击准备样本少就在每轮训练时把这个类的图片重复复制一份到训练集或者上调该类在损失函数中的权重。对于数据不干净的问题排查方法是看训练日志里验证集loss是否存在早期不降反升或者混淆矩阵里出现奇怪的跨类混淆。我有一次发现模型把窗帘后的猫影识别成攻击状态检查后发现这些训练图中有一批带阴影、背景复杂的图标注时把阴影边缘也框了进去。后来我把这批图重新裁剪并修正了标签框模型才消停。4.2 小目标漏检和遮挡猫情绪检测真正难在小目标场景。家用摄像头一般挂在墙上拍到的猫可能只占画面的十分之一面积这种情况下模型经常漏检。我的解决方案首先是提高输入分辨率从imgsz640提高到768甚至960小目标召回率会有明显提升代价是显存占用和推理速度下降。其次是使用更大的模型从yolov8s升级到yolov8m但这两个手段都治标不治本最有效的是为数据集中增加更多小目标样本并确保标注时对远处的小猫也认真框选而不是因为图小就草率标注。遮挡也是猫行为检测的常态场景。猫经常躲在沙发底下、纸箱里露个头或者尾巴出来。这种时候如果因为看不到完整身体而放弃标注模型就永远学不会在遮挡下识别猫。我的标注规则是只要能看到判断情绪的关键部位比如耳朵、脸部、尾巴就允许标注如果只能看到一个模糊背影则放弃。这样既能保持数据有效性又不对模型提出超出人类判断能力的要求。4.3 过拟合、loss振荡与训练崩溃3200张数据规模不算大训练时容易出现过拟合。典型表现是训练loss持续下降验证loss从某轮开始反弹。我踩过的一个明显过拟合案例是把所有增强关闭后训练训练集mAP接近0.95验证集mAP只有0.6。开增强后验证集会提升一大截。此外引入随机失活和更积极的早停机制也能有效防止模型在训练集上“背诵”数据。关于训练中bn崩溃这是YOLO训练里出现概率不高但一旦出现就很头疼的问题。表现为某一轮loss突然跳到一个极大值之后再也回不来实质是BatchNorm层在统计量更新时遇到异常样本导致数值不稳定。常见原因是batch size太小或者数据里混入了极端异常的标注框。如果是batch太小可以调大batch或使用梯度累积如果是数据问题去清洗异常标注比改网络更有效。我还遇到过训练过程中loss反复震荡但验证集mAP一直不涨的情况。这时候首先看学习率训练后期学习率过高会导致震荡检查训练日志里lr曲线如果接近尾声还保持高位建议换上余弦退火或直接调低初始学习率。一个快速有效的方法是重跑一轮只改lr0和lrf往往比盲目加数据更能解决问题。4.4 部署时显存与速度优化训练完的猫情绪模型如果只放在本地验证还不够真正有价值的是部署到边缘端比如摄像头或手机应用。我通常导出的流程是先用best.pt做验证确认效果后导出为ONNX格式再用TensorRT在GPU上做推理加速。Ultralytics自带的导出命令非常方便yolo export modelruns/detect/train/weights/best.pt formatonnx dynamicFalse imgsz640导出完成后用onnxruntime跑一遍测试确认推理输出和PyTorch几乎一致。如果资源更紧张还能采用半精度和INT8量化。INT8量化能大幅压缩模型体积但量化本身需要小心我用默认设置量化过一次结果猫的“警惕”类被大量误报成“攻击准备”明显是量化误差放大了类别边界。后来我改用混合量化策略对分类层保持浮点精度才把指标恢复回来。部署时另一个常用优化是降低输入尺寸。如果你的摄像头画面里猫占比较稳定可以从imgsz640降到480或者416检测速度会提升很多代价只是小目标稍微漏检。实测在室内客厅场景用yolov8s加上TensorRT和输入尺寸416单GPU能跑到几百帧以上移动端的CPU也能有接近实时的速度。关键是部署前先统计自己在实际场景里的目标大小分布再决定输入尺寸而不是盲目追求最大分辨率。5. 从检测到行为理解这套数据还能怎么扩展5.1 连续帧行为识别与状态跟踪单帧检测只是起点。猫的情绪往往是动态变化的与其看一帧不如连续观察几十帧一只猫可能从放松慢慢进入警惕再突然变成攻击准备。用YOLO检测出的每帧结果可以输入给一个时序模型比如简单的帧差统计或LSTM去识别行为趋势。我在实际项目里用的思路是先对每帧做检测输出目标的类别和置信度然后为每个猫目标维护一个短暂的历史状态队列。如果队列里“惊恐”连续出现5帧以上才上报异常事件如果只是单帧闪一下就过滤掉。这样可以明显减少误报因为实际使用中焦距变化、猫回头一瞬间的角度改变都可能造成单帧误判。5.2 多模态猫情绪判断视觉信号再好也有盲区。猫在紧张时会发出哈声或低吼这些声音是视觉检测看不到的猫的情绪也受环境因素影响比如有陌生人进门、洗澡前后。于是很自然的扩展方向是融合麦克风阵列采集的声音特征和环境传感器信号做成真正的多模态情绪判断系统。做法上不需要一开始就把所有特征塞进神经网络。我的建议是先保留视觉检测结果作为主干状态声音检测作为辅助触发器当视觉模型判定“放松”同时检测到急促高频叫声时触发“警惕”状态升级当视觉模型检测到攻击准备动作且麦克风捕捉到哈声时直接判定高冲突风险。这种规则式的多模态融合好调试、可解释比强行端到端训练省很多数据。5.3 迁移到其他宠物应用猫情绪数据集的价值还不止于猫。同样的行为特征在其他宠物上也部分成立狗的攻击准备有僵直身体和呲牙兔子的恐惧有压低耳朵和蜷缩仓鼠受惊的僵住姿势也很典型。迁移到其他宠物时不需要重新做几千张数据而是复用这个模型的底层特征只用几百张新宠物的标注数据做微调。具体操作就是把data.yaml里的nc改成新宠物的行为类别数然后加载已经训练好的猫情绪权重作为起点用新的数据集继续训练几十轮。这个过程我实际跑过一次用600张狗的图片做微调训练不到一两个小时就能得到一个可用的犬类行为检测模型准确率比从头训练高出一大截。这说明一个认真标注的领域数据集本身就是一个可复用的基础资产不只是用一次就扔。回看整个项目最深的体会是技术上限往往不是模型决定的而是数据质量决定的。3200张数据听起来不多但如果你认真把标注一致性做到位、把脏数据清干净、把类别分布调平衡训练效果超过几万张随手爬来的数据。我后来在宠物智能摄像头项目的测试中用这套权重检测猫的异常行为在普通客厅场景下能跑出接近实时的推理速度误报率比预期低很多。最后再分享一个小技巧每次跑完一轮训练别急着删数据集把训练日志、权重、混淆矩阵一起存下来这样后续优化才有对照基线。如果你也在做类似的数据集和检测项目欢迎按这套流程走一遍少踩很多坑。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进