尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于YOLO的猫情绪检测:从数据集构建到模型部署实战

基于YOLO的猫情绪检测:从数据集构建到模型部署实战 最近我整理了一份猫情绪检测数据集一共3200张图全部转成了YOLO格式的txt标注。这份数据不是网上随手爬下来的图片堆而是按真实可训练的标准重新过了一遍每张图都有人工核过的边界框框里的猫被标成对应情绪状态。它的用途很直接——拿去做目标检测模型让程序在一张画面里同时回答“猫在哪”和“猫现在是什么状态”这两个问题。如果你在做宠物智能硬件比如自动猫门、宠物摄像头或者手头有一个YOLO项目想找个有标注的真实数据集练手跑通全流程又或者搞动物行为学需要自动化的行为标注工具这份数据都可以直接用。我自己用它训练了一个YOLOv8模型从数据整理到训练后验证整个流程大约花了两天时间定位精度和状态分类准确率都到了可用的水平。这篇文章不是数据集说明书而是记录我踩坑的过程数据怎么筛、情绪标签怎么定、训练参数怎么设、遇到BN崩溃怎么救以及模型怎么落地部署。下面直接按流程来聊。1. 项目整体设计思路与方案选型1.1 为什么从猫情绪检测切入先聊聊为什么选猫情绪而不是猫品种、猫姿势这类方向。原因很实际猫的情绪识别在宠物行业里有明确需求。现在的智能宠物设备大多只做“物体检测加运动检测”能识别猫来了、猫在动但识别不了猫的状态。而猫的情绪状态直接关联行为焦虑的猫容易抓挠家具攻击状态的猫可能伤人放松的猫适合互动。如果设备能识别这些状态就可以做出自动避让、安抚提醒、异常报警等功能。同时猫情绪检测是一个典型的“细粒度目标检测”问题。猫不像人表情上没有明显的“笑”和“哭”它的情绪更多表现在耳朵角度、瞳孔大小、尾巴姿态和身体紧绷程度上。这些线索分布在整个身体上所以用一个包含全猫的边界框去表达状态更合理这也是选目标检测而不是图像分类的原因之一。这个方向还带有一个现实挑战情绪判定的主观性很强。同一张图不同人可能给出不一样的情绪标签。所以做数据集的时候最难的其实不是画框而是把“主观判断”统一成一批人都能遵守的规则。后面我单独讲标注规范。1.2 为什么选YOLO而不是分类模型或关键点检测有人可能会问既然要判断情绪状态为什么不用分类模型比如对整张图直接输出“开心/焦虑/攻击”原因在于实际场景里画面往往不止一只猫或者猫只占画面的一部分。分类模型会对整张图做全局判断一旦背景里出现两只猫、或者猫的位置很偏分类结果几乎没有参考价值。那为什么不用关键点检测关键点方案确实能更精细地捕捉耳朵位置、瞳孔状态但标注成本非常高。单猫的耳朵、眼睛、尾巴尖、四肢关节这些关键点一张图可能要标十几个点如果按3200张图来算工作量会翻好几倍。而且关键点模型对光照、遮挡非常敏感一旦猫侧身或躲在沙发后面关键点预测会大量丢失。我实测下来YOLO方案还有一个额外优势它天然支持多猫场景。家庭养猫不止一只摄像头画面里同时出现两只猫、甚至三只猫的情况很常见。YOLO的检测头会输出多个候选框每个框独立分配一个情绪类别这就够了。从工程角度看YOLO的生态也最成熟v5、v8甚至更新版本的导出、量化、部署链路齐全省去了自己搭模型工具的麻烦。1.3 3200张数据集够不够用说实话3200张图放在今天的深度学习标准下不算大。常见的目标检测数据集比如COCO有超过12万张图像遥感领域常用的HRSC2016也有数千张图像。那3200张够用吗我的判断是对于“单目标、多状态”的任务基本够起步但要想效果好要配合预训练权重和合理的数据增强不能裸训。从训练角度看YOLOv8这类模型通常先用ImageNet或COCO预训练权重初始化模型已经具备丰富的通用视觉特征。猫的轮廓、纹理、背景分割这些低级特征不需要从零学模型只需要在已有特征上“微调”猫情绪状态的判别逻辑。3200张足够让模型在常见场景里收敛但极端角度、弱光、剧烈运动这些情况还需要扩充。如果觉得数据不够我推荐两个最低成本的扩充方向一是用视频抽帧一段10分钟的监控视频按每秒2帧抽能得到约1200帧画面再按相邻帧相似度去掉重复帧二是找公开数据集做预训练迁移比如先在相似的行为检测数据集上训练出特征提取头再迁移到猫情绪上。这两个方法都不需要额外标注见效很快。2. 数据采集与标注把情绪“翻译”成边界框2.1 数据来源、采集与初筛数据来源上我用了三种方式组合自己拍的猫视频抽帧、朋友提供的养猫监控片段、以及从开放图库筛选的宠物图片。不建议直接去搜索引擎批量爬图虽然快但版权和重复内容问题会让人头疼。自行拍摄的素材在光线、场景上可能单一所以一定要混合三到四种不同来源让模型见到更多样的环境。采集时要注意画质统一。模型训练最怕什么图片格式混乱、分辨率差距过大。我处理时把所有图片统一压到最长边不超过1280像素同时检查是否有严重模糊和运动拖影。猫的动作很快很多抽帧画面是糊的这类图需要做清晰度筛选。一个简单经验是模糊到人眼都看不懂猫的姿态时就不要放进数据集它只会给模型灌输噪声。还要处理重复帧。视频抽帧最容易出连续几十帧几乎相同的画面模型反复看到相近样本会倾向于把样本特征背下来而不是学到泛化规则。我去重的方式是用相邻帧的感知哈希对比设定阈值后把重复的全删了。最终保留的3200张图里真正有信息量的样本才算数。2.2 情绪类别定义与标注规范这份数据集里我把猫的情绪状态分成了四类relaxed放松、alert警惕、anxious紧张、aggressive攻击/防御。一开始我也想过加“happy”“sad”这类情绪但后来全部砍掉了因为猫的“高兴”和“专心看窗外”在视觉上几乎没有可标注的区分点。情绪检测模型能学到的是猫的“可观察行为状态”而不是内在情感。这个认知一定要提前建立。为了让不同标注员保持一致我定了一套可量化的标准类别英文标签典型行为信号放松relaxed耳朵自然前伸或略侧瞳孔正常或偏小身体舒展可能卧着、缓慢眨眼警惕alert耳朵竖直朝向前方瞳孔扩大身体静止但肌肉紧绷眼睛紧盯某个方向紧张anxious耳朵压平或朝两侧尾巴夹紧或快速摆动身体低伏频繁舔鼻攻击/防御aggressive炸毛、弓背、耳朵完全后压瞳孔极缩或极放大伴随呲牙或嘶吼姿势这些行为信号全部集合到一起后让标注员围绕“整体姿势”做判断。边界框的规则也相当重要框必须完整包住猫主体允许包含尾巴尖不要只框头因为情绪判断依赖全身姿态。如果猫被遮挡超过三分之一比如只露个头、身体完全在沙发后面宁可删掉也不要勉强标“放松”那会导致模型学到一个没有上下文的错误绑定。2.3 标注工具选型与质量校验我测试了LabelImg、Label Studio、X-AnyLabeling三个工具。LabelImg最轻量适合单人快速画框Label Studio适合多人协作能设审核流X-AnyLabeling内置了SAM可以用提示词先做自动分割再转成外接框效率最高。如果你只有一两百张图LabelImg足够如果要常态化维护数据建议直接用Label Studio做团队协作把标注和审核拆成两个角色。标注完成后一定要做质量校验这一步不能省。我做了三层校验第一层检查标签格式。打开txt文件确认每一行是“class x_center y_center width height”且坐标在0到1之间第二层检查类别分布。统计四类样本数量如果“relaxed”有1800张、“aggressive”只有150张就需要补充攻击姿态的数据否则模型会倾向把所有猫都预测成放松第三层是可视化审核。把标注框画回原图上随机抽200张人眼看一遍框是否贴合、类别是否合适。这一步能在进训练之前拦截掉大量低级错误。从VOC或COCO格式转YOLO格式时有一个常见坑是坐标中心化计算。VOC是左上角和右下角坐标转成YOLO的xywh时必须除以图片宽高得到相对坐标并且center_x要和宽的单位一致。我自己写过一次转换脚本因为忘了归一化导致模型训练时loss直接变成nan后面会专门讲这个问题。3. 用YOLOv8训练猫情绪检测模型3.1 数据集目录与yaml配置训练前先把数据整理成YOLO标准目录结构。我习惯这样组织datasets/cat_emotion/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/每个txt文件和对应图片保持同名目录也一一对应。划分时用8:1:1的比例并且按类别数量做分层抽样保证每一类在所有集合中的占比基本一致。之前有人直接把数据放到一个文件夹里随机切结果测试集里“aggressive”一张都没有mAP看起来很高但模型一遇到攻击状态的猫就漏检。数据配置文件写起来很简单就是一个yamlpath: /path/to/datasets/cat_emotion train: images/train val: images/val test: images/test names: 0: relaxed 1: alert 2: anxious 3: aggressive需要注意两点一是path要用绝对路径或保证在项目目录下运行时相对路径正确二是names里的顺序必须和标注txt里的类别编号一致。我见过不少翻车案例txt里标记是“2 anxious”yaml里却把2写成了aggressive模型训练出来精度惨不忍睹排查半天才发现是配置文件错位。3.2 训练参数设置与背后逻辑我用的版本是YOLOv8起步模型是yolov8n.pt预训练权重。训练命令大概是yolo detect train \ datacat_emotion.yaml \ modelyolov8n.pt \ imgsz640 \ batch16 \ epochs200 \ lr00.01 \ optimizerAdamW \ patience30 \ projectruns/cat_emotion逐个说下参数理由。imgsz设640是YOLOv8的默认值对猫这种中等尺寸目标很合适。如果画面里的猫特别小比如摄像头装在3米高处往下拍建议把imgsz提高到960甚至1280但显存占用会明显上升。batch16是在8GB显存下的稳妥值如果显存更大可以开到32或64更大的batch一般能带来更平滑的梯度更新。epochs200配合patience30意思是连续30轮验证集mAP不提升就早停避免无效训练浪费时间。优化器用AdamW而不是SGD对小数据集收敛更稳定。数据增强方面我保留了YOLO默认的mosaic、flip和hsv增强关闭了mixup。原因是mixup会把两只猫叠在一起生成很奇怪的混合图对情绪检测这种细粒度任务不太友好。如果训练过程中发现个别类别严重欠拟合我会单独调整增强策略比如对样本数量少的类别做更保守的翻转和裁剪避免把关键行为特征破坏掉。3.3 训练流程与结果监控训练过程中要盯三个指标训练loss、验证集mAP0.5、mAP0.5:0.95。mAP0.5是IoU阈值0.5下的平均精度主要反映“框得准不准”、类别判得对不对mAP0.5:0.95是在0.5到0.95多个阈值下的平均要求更严也更贴近真实部署。我跑完200轮后mAP0.5在0.87左右mAP0.5:0.95在0.63左右。这个成绩对3200张的细粒度数据集来说是可以用的。测试集上专门看混淆矩阵发现最容易混淆的是alert和anxious因为两种状态下猫的耳朵都可能有不同程度的竖直或后压仅在尾巴和身体姿态上有微妙差异。这个现象和标注阶段遇到的判断难点是一致的。如果验证集的loss不断下降但mAP一直不涨一般不是参数问题而是标签噪声太大相同的视觉特征被贴了不同的标签模型无法形成稳定决策边界。此时最有效的动作是回到标注阶段把混淆集中的图像抽出来重新投票确认标签而不是盲目调参数。4. 训练中的坑从标签噪声到模型崩溃的排查4.1 标签噪声和类别混淆还是头疼先说标签噪声的影响。我一开始让两个人分别标注没有做统一核对结果训练到第50轮时发现“anxious”的召回率只有0.3。抽图回看发现被标成anxious的样本中有将近三分之一按规范应该算alert。这类噪声会让模型学到的是“反正这两个类差不多”最后只能瞎猜。解决办法就是规范化审核流程。我重新把两类图像并排对比整理出一份带示例图的标注手册标清楚耳朵角度在什么区间算“竖直”瞳孔扩大到什么程度算“扩大”。之后重新过了一遍数据把拿不准的样本全部删掉不凑数。数据量从3200张掉到2850张但第二轮训练mAP涨了接近5个点。少而精的原则在这类任务里非常适用。还需要说一下类别不平衡。如果四类样本数量差距过大模型会偏向高频类别。我的建议有两条一是收集时定向补拍低频状态比如故意逗猫触发攻击姿态二是训练时用类别加权损失。YOLO在类别损失上支持设置权重把低频类的权重调高一些即可但注意别调太高否则会过拟合到少数样本的特征上。4.2 BN崩溃与loss异常处理训练时最容易遇到的崩溃是BN层统计量失稳表现是loss在某轮后变成nan或者验证mAP直接归零。我遇到过两次一次是因为标注坐标出现负数另一次是学习率设太大。排查顺序我一般是这样先检查标签文件里有没有坐标越界或负值最直接的方法是写脚本遍历所有txt看一眼坐标是否在0到1区间再检查yaml的names配置和txt类别编号是否对应最后看学习率。yolov8n这种小模型初始学习率0.01很正常但如果你反复中断续训warmup逻辑会干扰先前的优化状态我建议重新从头训而不是续训。如果你加了自定义增强也需要排查数据管线。我第二次BN崩溃就是自己在预处理里加了随机裁剪但裁剪后没有重新归一化到640x640导致模型输入尺寸混乱BN的统计量被带偏。YOLO的输入尺寸必须保持统一想用多尺度训练就让框架内部的scale参数去做不要在外面破坏尺寸一致性。4.3 小目标、运动模糊与识别率下降猫在快速转头、跳跃时画面里的目标会出现运动模糊边界框会变得不稳定。还有环境光照不足时图像噪声增大模型会把噪声当成纹理信息。针对这两个问题我做了三件事把输入分辨率从640提升到960小目标召回率提升明显数据增强里把“模糊”“噪声”单独做成增强项模拟运动模糊和传感器噪声模型对低质量帧的抗性增强推理时加帧间平滑对同一个目标在连续帧上的类别做投票或EMA单帧误报被抑制。另外有很多做目标检测的朋友会讨论用NWD替换IoU损失来改进小目标检测。NWD即Normalized Wasserstein Distance是把边界框建模成二维高斯分布来计算距离的损失对微小框的偏移不像IoU那样敏感。如果你的监控画面里猫在很远的位置框只有十几个像素用NWD替换CIoU损失确实能提升召回。我们这批数据以中等目标为主所以没有大规模引入但如果你的场景是“全景摄像头拍十几只猫”值得一试。5. 从验证集到落地导出与场景扩展5.1 模型导出与TensorRT加速训练完成后需要部署到实际场景。YOLOv8导出命令很简单yolo export modelweights/best.pt formatonnx导出的ONNX可以直接用ONNX Runtime推理但要达到视频流级别的速度我会再转成TensorRT引擎在Jetson等设备上做FP16量化。一个踩过的坑是TensorRT和YOLO的解码层版本必须匹配。Ultralytics在导出时提供simplify选项能去掉一些冗余算子但不要为了省事把一些必要的解码层删了否则检测结果的坐标会完全偏移。在8GB显存的Jetson Orin上我实测用TensorRT FP16跑640分辨率的YOLOv8n单路推理大概在15到25毫秒一帧支持7到8路1080p25帧的视频流检测。这个水平已经足够覆盖家庭监控场景。如果还想压帧率可以降成432p输入或者把batch动态化来分摊固定开销但要注意小目标在低分辨率下丢失会比较严重。5.2 落地场景与后续升级路径这个模型最典型的落地是宠物摄像头。场景可以这样设定画面里检测到猫处于aggressive状态设备自动推送“猫咪正在攻击”提醒连续长时间anxious则提醒主人“家里的猫状态不好注意加环境安抚”。自动猫门也可以做一个联动策略只有relaxed状态才放行攻击状态时关闭出口减少多猫家庭的冲突。如果想继续提升我建议往三个方向扩展。第一是加入时序维度用连续帧序列做状态判断因为单帧里“伸懒腰”和“攻击前兆”可能相似但动作变化趋势不同可以用YOLO检测加特征序列输入轻量时序模型来解决。第二是加个体识别把猫的身份和状态一起输出这样才能长期追踪某只猫的焦虑频次、进食前后的状态变化。第三是结合行为学知识体系把检测到的状态对齐到标准行为编码输出可报告的结构化结果这对宠物医生和行为咨询师非常有价值。从数据整理到模型部署这一整套流程我已经完整跑通了。你可能会发现我花在调整模型参数上的时间其实不多大部分精力都花在了数据标注规范和标签质量上。同样的3200张YOLO格式数据标签整不整齐直接决定了模型水平的上下限。最后再分享一点个人体会情绪检测模型的输出不要当成猫的“内心真实感受”来解读。我们标注的其实是猫的可观察行为状态模型学到的也是这个。把类别名定为“警觉行为”“防御行为”而不是“害怕”“生气”会让后续使用这套模型的人更清楚它的边界也更难被误用。这个细节从数据标注到产品文档都应该保持一致。
返回列表