ARTICLE DETAIL

资讯详情

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

基于YOLOv8的猫情绪识别:从数据集构建到边缘端部署实践

基于YOLOv8的猫情绪识别:从数据集构建到边缘端部署实践 养过猫的应该都体会过那种无力感它突然炸毛你不知道是外面过路的野猫刺激了它还是家里什么地方让它不安它连续几天躲床底你也察觉不到它其实已经焦虑了很长时间。情绪是猫咪健康和安全的晴雨表但猫的语言又是出了名的难懂。这个项目最开始的动机就是这个痛点我把收集整理的3200张猫行为图片做成了一份标注好情绪的YOLO目标检测数据集再基于YOLOv8训练出一个能从画面里直接输出情绪状态的检测模型。整套项目覆盖了数据集设计、清洗增强、训练调优、问题排查和边缘端部署的完整闭环。不论你是想做智能宠物摄像头、兽医辅助行为评估还是单纯想用YOLO数据集练练手这份数据和这套流程都值得参考。1. 数据集设计逻辑情绪类别怎么定标注怎么控1.1 为什么是3200张为什么只做4类情绪先回答一个被问得最多的问题3200张够用吗以及为什么情绪类别不是5类、6类而是只有4类。深度学习的数据量需求永远取决于任务难度。猫情绪检测本质是目标检测任务客体形态变化很大——不同品种、不同角度、不同光照——但好在这份数据集聚焦的是情绪状态不需要精细到眼睛、眉毛这种亚细粒度特征。3200张这个体量配合数据增强和预训练权重完全可以把YOLO的小体量模型训练到可用的工程水平。类别设计上我最终选定4类relaxed放松、tensed紧张/警惕、aggressive攻击/防御、fearful恐惧/焦虑。这里有个现实问题猫的情绪词典远比4类丰富还有好奇、困倦、发情等等但类别数量一多标注一致性和类间区分度都会快速下降。比如“好奇”和“紧张”瞳孔放大、耳朵前倾的症状几乎重叠强行分开只会让标注员之间互相打架模型也很难学到区分。4类是在“信息量”和“可标注性”之间折中后的方案。样本量也按这个逻辑分配。3200张并非简单平均切碎我按大约1:1.1:0.9:1的分布收集relaxed略多一点aggressive略少一点因为攻击姿态在公开素材里确实更难找。总的原则是每个类别不低于700张这样即使某些图在后续清洗中报废也不至于破坏类别平衡。1.2 标注质量控制格式、边界与一致性YOLO数据集的核心就是txt标注文件。格式不复杂每行一个目标五个值分别是类别编号、中心点x坐标、中心点y坐标、宽、高全部归一化到0到1之间。比如这一行2 0.6132 0.4561 0.3205 0.3847表示一个类别为2的aggressive目标框中心点位于图片宽度的61.3%、高度的45.6%处框宽占整图32%框高占38.5%。标注工具我用的X-AnyLabeling它自带一批现成检测模型可以先自动把猫的位置框出来我再手动调整边界和情绪标签。有预标注辅助的情况下一张单猫图大约30到60秒搞定比纯手工的2到3分钟快得多。3200张图一个人利用晚间和周末整两周内能完成第一版。但工具只是辅助真正的难点在于“什么样的边界算一个框”。有些猫侧卧着身体蜷成一个团有些猫竖着尾巴站立——框该不该把尾巴包进去我的处理原则是主体框必须包含头部、躯干和大部分前肢如果尾巴展开明显就包含蜷在体侧就无所谓。框不要超出猫身体轮廓太多但也不要为了框得紧把猫耳朵裁掉因为耳朵状态是情绪分类的关键特征。这些看似“抠细节”的决策最终都会直接影响mAP。情绪标签的一致性比边界更难控。我要求自己在标注前先固定一套特征判据relaxed以眯眼、身体舒展、尾巴自然盘绕为主tensed以耳朵直立或后压、瞳孔放大、身体紧绷、尾巴缓慢摆动为主aggressive必须有炸毛、弓背、飞机耳、哈气或挥爪其中至少一个特征fearful以身体低伏、夹尾、躲藏动作为主。没有明显特征的图宁可标成tensed或relaxed也不硬贴aggressive。硬贴只会让模型学到错误关联后期看混淆矩阵会非常迷惑。2. 数据清洗与增强3200张怎么变成上万张的效果2.1 清洗流程删哪些图、留哪些图按什么标准数据集拿到手以后第一件事不是写代码而是删图。3200张原始图里通常混着一批低质量样本——运动模糊的、裁切失败的、连续两帧几乎一样的甚至偶尔有几张图里根本没有猫。这些图喂给模型轻则浪费迭代次数重则让训练震荡。我的清洗流程分三步。第一步写脚本统计所有图片的尺寸和平均亮度把分辨率低于640x640、亮度极端异常的图先抽出来人工复查。第二步做模糊检测用拉普拉斯算子算图内方差低于阈值的单独归档。第三步查重复帧连续采集的图片只要结构相似度超过0.95就只保留一张。3200张走完这三步通常剩2900到3000张再补拍或补充素材把有效样本回填到3200。有一点要提醒不要为了让数字好看就强行保留坏图。这里说的3200张是最终“有效样本”的数量中间清洗掉的我单独放在discard目录不参与训练也不删以后做数据对比时还有回看价值。2.2 增强策略别把猫P得不像猫增强是这套项目能压榨数据集潜力的关键。YOLO官方训练流程默认开Mosaic——把4张图随机拼成一张提升小目标检测和上下文多样性。但在情绪任务上我踩过坑Mosaic生成的拼接图如果太夸张比如把两只猫的头拼到一只猫身上情绪标注就失真了。所以我的做法是保留Mosaic但控制在2到4张拼接范围且每张拼图里的目标框都保留完整语义。除了Mosaic我用的是下面这套增强组合增强方式参数设置使用理由水平翻转概率0.5情绪语义左右对称成本几乎为零旋转±10度模拟镜头轻微角度变化不产生非自然形态尺度缩放0.8-1.2倍模拟镜头远近适度即可HSV扰动色调±20饱和度±30亮度±30提升光照和毛色差异下的鲁棒性Mosaic0.5概率合成多样上下文对多目标场景友好增强处理采用在线方式——每轮训练随机组合而不是预先一次性生成静态图。这样做既省硬盘还能让模型每轮见到不完全相同的样本。算下来3200张原始图一个epoch实际参与训练的等效样本量在9000到10000张左右。2.3 目录划分与训练集结构工程上最稳妥的结构是独立的images和labels目录内部再分train、val、testcat_emotion_dataset/ ├── images/ │ ├── train/ # 2240张 │ ├── val/ # 640张 │ └── test/ # 320张 └── labels/ ├── train/ ├── val/ └── test/划分比例是7:2:1核心原则是test集合必须是不参与任何训练决策的“盲测集”。我自己调参时会反复用val集观察损失曲线但绝不看test集的预测结果等模型彻底冻结后再跑一次test做最终评估。另外划分时尽量按场景而不是按单张图切同一只猫、同一个角落连续拍的10张图尽量全部塞进同一个集合防止信息泄漏否则最终评估指标会虚高。提示调参期间永远只用val集反馈test集只许看一次。这条纪律能救你于无数个“指标很高但现场翻车”的瞬间。3. YOLO训练全流程从预训练权重到两阶段微调3.1 环境配置与模型选型训练基于Ultralytics YOLOv8完成。选它而不是更早的YOLOv5一个重要理由是生态干净——一条命令就能跑训练、验证、导出模型对数据集项目来说是决定性的效率优势。模型体量选了yolov8s而不是更小的n或更大的m。原因很实际n的参数量在情绪这种细粒度任务上容易欠拟合m对3200张的数据量会明显加重过拟合风险s正好是平衡点。环境配置很简单显存12GB的RTX 3060或4060都能跑。依赖就一个pip install ultralytics3.2 数据配置与关键超参数把数据集配置写成一个yaml文件path: /home/user/cat_emotion_dataset train: images/train val: images/val test: images/test names: 0: relaxed 1: tensed 2: aggressive 3: fearful训练可以用命令行也可以写成脚本。我习惯用脚本因为两个阶段之间的衔接更灵活from ultralytics import YOLO model YOLO(yolov8s.pt) model.train( datacats.yaml, epochs30, imgsz640, batch16, freeze10, lr00.01, lrf0.01, ampTrue, seed42, namecat_stage1, )这里解释几个容易纠结的参数。imgsz640对应YOLO家族的默认输入尺寸这批图分辨率普遍在800到1200之间缩到640既保证推理速度也不丢细节。batch16取决于显存12GB卡跑s模型够用。freeze10表示冻结前10层——这些层承载了COCO预训练学到的通用视觉特征对猫毛、纹理、边缘已经足够好先不动它们分类头和检测头从随机初始化开始学情绪特征。好处是前期训练稳定不会一上来就把预训练特征冲垮。3.3 两阶段训练先冻结后微调效果确实更稳第一阶段的30轮主要是让检测头和分类头在相对稳定的特征上快速收敛。训练结束后把runs/detect/cat_stage1/weights/last.pt作为第二阶段训练的起点model YOLO(runs/detect/cat_stage1/weights/last.pt) model.train( datacats.yaml, epochs120, imgsz640, batch16, freeze0, lr00.001, lrf0.01, namecat_stage2, )第二阶段的关键变化在freeze0和lr00.001。解冻全部层是为了让backbone的特征也朝情绪语义方向调整学习率降一个量级是防止对整个网络做大幅更新把第一阶段学到的知识破坏掉。打个比方这有点像新员工先进组熟悉环境再带着明确目标去精进核心技能——急不得。第二阶段设了120轮实际跑的时候开early stoppingpatience设为20也就是连续20轮val指标不涨就自动停。这个配置在RTX 3060上总耗时大概3到4个小时很快。3.4 指标评估与真实推理验证训练完看指标不能只盯着mAP。YOLO训练日志会输出每轮的分类损失、框回归损失和各项mAP我重点看的是混淆矩阵因为它能直接告诉我哪两个情绪互相认错。我这份数据集在val集上的参考结果大致是情绪类别PrecisionRecallmAP0.5relaxed0.830.870.86tensed0.760.740.75aggressive0.780.730.76fearful0.800.820.81tensed和fearful的mAP偏低这符合直觉——两者都有瞳孔放大、身体紧绷的共同特征区分它们更多靠尾巴姿态和整体动作的细节差异。因此情绪检测的理想判据不能只看静态画面还要结合连续帧的运动信息后面部署部分会再展开。推理验证阶段我推荐直接用Python调用模型from ultralytics import YOLO model YOLO(runs/detect/cat_stage2/weights/best.pt) results model.predict(demo.jpg, saveTrue, conf0.35) for r in results: for box in r.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) print(r.names[cls_id], round(conf, 3), box.xyxy[0].tolist())conf阈值我习惯设在0.35而不是默认的0.25因为情绪分类错误比漏检更难解释宁可让模型少报也不让它瞎报。4. 常见问题排查实录我在这份数据上踩过的坑4.1 训练到一半loss直接变成NaN第一次跑的时候撞上过loss变NaN排查下来是学习率过大加上某个batch里出现了极端增强样本尤其是Mosaic拼接图像素叠加后在深层特征里爆了。解决办法很简单把lr0从0.01降到0.008或者把Mosaic比例调低。另外注意Ultralytics框架在训练最后10轮会自动关闭Mosaic这是默认行为不要反手又给它强制打开。4.2 深色猫、黑猫检测不到这个坑养黑猫的人应该都懂深色猫在暗光下几乎和背景融为一体训练集里黑猫样本偏少会导致漏检。我的对策有三个第一训练时增加亮度扰动把暗部细节拉出来第二标注时对深色猫的框适当外扩一圈因为黑猫边缘在视觉上有“收缩”效应框越贴近毛边越容易被背景吃掉第三补充真实场景中的暗光图片这个效果任何增强手段都替代不了。4.3 过拟合的信号与处理小数据集最大的敌人是过拟合。有几个信号需要特别留意训练损失持续下降但val损失在第80轮左右开始回升或者mAP在val集上不再增长、却仍在train集上爬升。这都属于典型过拟合预警。处理方法按优先级排先加大增强强度比如旋转从10度放宽到12度、Mosaic比例从0.5提到0.8再考虑从s模型换成n模型如果效果还不明显最后才是加数据用手机在自己的猫身上拍几十张补进对应类别。4.4 远处趴着的小猫总是漏检客厅角落趴一只猫在640分辨率下可能只占几十个像素这就是小目标问题。YOLO系列对小目标天生不敏感最有效的办法是提高输入分辨率。我试过把imgsz从640提到800小目标AP明显上升但训练时间也同步增大约50%。如果部署环境性能允许建议用imgsz768性价比比较高。4.5 换个环境就崩场景泛化问题有一阵子我觉得模型已经调得很好了直到把摄像头挪到窗户边——阳光从侧面照进来猫的毛色和阴影全变了检测框开始乱跳。这类问题本质是训练集场景多样性不足。补救方式是在部署场景采集5到10分钟视频抽帧100到200张人工标注后把新数据按val反馈结果接入训练。这个操作俗称“场景热启动”一次能提升三五个点的mAP是工程上最值钱的优化。5. 模型部署与情绪系统的扩展方向5.1 模型导出与后端加速训练完的模型是PyTorch格式跑部署得先转换。Ultralytics一条命令就能导出最常见的三个目标格式是ONNX、TensorRT和OpenVINOyolo export modelbest.pt formatonnx imgsz640 yolo export modelbest.pt formatengine imgsz640 halfTrue yolo export modelbest.pt formatopenvino imgsz640TensorRT的engine格式只在NVIDIA GPU上能跑适合Jetson或桌面显卡OpenVINO适合Intel CPU核显很多工控机走这个路线NCNN则用在手机端。别一开始就贪格式多我的习惯是先导出ONNX把它当中间格式再转其他后端排查问题也方便。5.2 边缘设备实测树莓派到Jetson在Jetson Orin Nano上把engine格式部署好以后FP16推理速度大约每秒30到50帧跑实时情绪监控绰绰有余。树莓派5配8GB内存跑NCNNCPU推理每秒大概6到10帧做轮询检测也够用。这里有个小经验实时视频流不用逐帧检测做成每3帧检测一次中间两帧用KCF跟踪算法把已有框平滑跟住CPU占用能降一大截画面上看起来还更流畅。5.3 从单帧检测到情绪变化趋势单帧检测只是第一步。猫的情绪表达有很强的时序特征——它的愤怒从来不是突然出现的往往是紧张持续一段时间后升级成攻击。把检测框按时间串联起来用滑动窗口统计各个情绪类别的占比变化就能实现“焦虑累积预警”这类更高级的应用在它真正发作前提醒主人介入。情绪和声音是天然互补的。猫害怕时有低鸣或急促喵叫攻击时有哈气声配合麦克风采集的音频特征做多模态融合准确率会比纯视觉高一个台阶。这也是这份3200张数据集最自然的扩展方向——回到最初的问题读懂猫咪情绪的最终目的是让养猫的人能在它崩溃之前就干预而不是等它炸完毛再收拾残局。这个项目给了我一个又实用又让人上瘾的切入点如果你也打算试试我的建议是先认真清洗一遍数据再开始刷训练指标那才是真正决定成败的起点。
返回列表