ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

基于YOLO的狗狗行为识别:数据集构建与训练实战

基于YOLO的狗狗行为识别:数据集构建与训练实战

做宠物AI的同行应该都有同感:模型结构好抄,真正要命的是一份靠谱的训练数据。我最近在折腾一套狗狗6种行为识别检测项目,用到的核心训练集是近3000张已标注图片,格式直接兼容YOLO系列,拿到手上就能开始训练。这篇文章准备把这套数据集的类别设计、标注思路、YOLO训练全流程和我在实际跑模型时踩过的坑一次说清楚。适合正在做宠物行为识别、想快速验证算法效果,或者准备做智能宠物设备的开发者参考,内容也尽量覆盖从数据到模型落地这条完整链路。

1. 狗狗6种行为识别数据集:类别设计与项目定位

1.1 6种行为类别是怎么选出来的

这套数据集的核心是识别狗狗的六种行为:坐、卧、站、走、跑、吠叫。不同版本的狗狗行为数据集在类别清单上会有细微出入,有的会把跳跃、啃咬、摇尾巴也放进来,但“坐卧站走跑吠”这套组合在宠物行为监测里是最常被点名的六种状态。选择它们的逻辑很朴素:覆盖了狗狗日常行为的高频区域,而且对后续应用有明确的区分度。

举个例子,智能宠物摄像头如果只知道“狗在活动”没有一个具体行为标签,很难产生有用告警;但如果能分辨“它在吠叫”和“它在跑”,就可以分别触发噪音提醒或运动量统计。训犬辅助设备也一样,主人想知道“坐下”“趴下”这些指令有没有被执行,本质上就是在做单帧行为分类。所以这份数据集从一开始就不是为了炫技术,而是贴着真实需求走的。

1.2 为什么用目标检测而不是姿态估计

一套行为识别项目可以走姿态估计路线,也可以走目标检测路线。姿态估计能把关键点坐标标出来,理论上信息量更大,但关键点的标注成本几乎是检测框的三到五倍,而且遇到遮挡、幼犬、多只狗同框时,关键点很容易丢失。目标检测只需要一个边界框加一个类别ID,标注门槛低,模型对遮挡也更宽容,跑起来快,部署到树莓派这类边缘设备也更现实。

从我的实操经验看,单张图片的目标检测就能稳定区分坐、卧、站这类静态姿势;对于走、跑、吠叫这类动态行为,单帧检测也能给一个初步判断,配合连续帧的投票逻辑可以大幅提升准确率。这个后处理技巧后面单独说。总之,在“快速拿到可用模型”这个目标下,YOLO目标检测是性价比最高的解。

2. 近3000张图片如何组织成一盘好棋

2.1 数据规模与分布:数量不等于质量

这套数据集接近3000张,按六类行为平分的话,每类大约有450到500张。这个体量在目标检测里不算大,但足够训练出一个能用的基线模型。关键在于图片内容是否足够多元。如果所有图片都是同一只狗、同一个客厅、同一个角度,那3000张等于白给。我拿到数据后第一件事就是检查分布:是否包含不同品种、不同体型、室内室外、白天夜晚、远近景和遮挡情况。

实际检查时发现,有些类的差异很大。狗的品种差异会导致外观千差万别,同一个“坐”的动作,柯基和边牧拍出来边界框比例完全不同。光照影响也很明显,逆光时深色狗的轮廓几乎融进背景。这些都是标注阶段就要考虑的干扰因素,不是靠换模型能解决的。

2.2 标注工具与标注格式:能导出YOLO格式是底线

这份数据集的标注格式是YOLO的txt文件,每张图片对应一个同名txt,每一行代表一个目标:

类别ID x_center y_center width height

坐标全部归一化到0到1之间。这种格式的好处是跟YOLO训练脚本无缝衔接,不用自己写转换器。如果以后要拿它做分割或者转成COCO格式,也能通过脚本转过去。

标注时用的工具,社区最常见的方案就是LabelImg,其次CVAT也支持导出YOLO格式。我个人更推荐在团队协作场景用CVAT,因为能多人标注、自动检查漏标,但自己一个人整理小数据集用LabelImg最顺手,开箱即用。不管用哪种,关键检查点只有两个:一是每张图是否有对应txt,二是txt里的坐标有没有超出图像边界。边界框坐标算错在手工标注里非常常见,尤其是标到边缘时,很多新手会把框的右下角拖出画面,YOLO训练时虽然不一定会报错,但会干扰损失计算。

2.3 标注一致性:同一类行为必须“长一个样”

数据集的质量问题通常不是标注错,而是标准不统一。比如“坐”这个行为,到底框是全身体,还是只框躯干?另一个标注员可能把尾巴也框进去。一个人标的时候,前500张身体连尾巴,后500张只框躯干,模型就会很困惑。

我自己的做法是写一份三行标注规范:框住整个可见身体,不包括尾巴尖和项圈牵引绳;行为以躯干姿态为主,头部方向不参与判断;目标被遮挡超过30%就跳过不标。规范写清楚后,哪怕后面拉到别人一起标注,也能保持统一。这份数据集的作者显然是做了约束的,因为抽查时发现同类边界框的比例基本接近,保证规范性。

3. YOLO训练数据集实操:从文件夹到第一轮loss

3.1 目录结构与数据划分

拿到数据集后,第一步不是急着训练,而是按标准布局整理目录。YOLO训练脚本一般期望这样的结构:

dog_behavior_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/

图片和标签文件名要完全一致,只是后缀不同。先用脚本把近3000张图片按比例拆分,常见做法是训练集70%、验证集20%、测试集10%。拆分时必须保证同一只狗、同一个视频片段里的帧不要同时落在训练集和验证集里,否则验证指标会虚高。

这里有一个新手容易忽略的点:如果数据是按视频截帧来的,连续帧之间高度相似,随机划分会把“见过”的帧泄露给验证集。要用按视频ID或连续帧时间戳分组的策略,先把视频片段切开,再整段分配。我遇到过一位同学,图省事直接随机划分,训练完mAP高达0.95,换到真实摄像头画面上直接掉到0.6,这就是数据泄露的典型表现。

3.2 YOLO的配置文件怎么写

YOLO训练需要一个数据集描述文件,内容大致如下,也适配YOLO后续版本如v8和v11的常见配置:

# dog_behavior.yaml path: /data/dog_behavior_dataset train: images/train val: images/val test: images/test nc: 6 names: 0: sit 1: down 2: stand 3: walk 4: run 5: bark

注意类别顺序必须和标注txt里的ID一一对应。如果你的txt里0号是坐,配置里0号也必须是sit,顺序错位会导致模型训出来完全不可用,而且很难排查。我之前踩过一次,mAP因为类别错位看起来还行,但实际推理每个框都带错标签,原因是标注脚本里类别列表顺序和yaml不一致。

3.3 训练参数选择与模型尺寸适配

训练前需要定三个关键参数:模型尺寸、batch size和epoch。针对近3000张图的数据量,用YOLO的nano或small版本最合适,数据集规模决定了模型不宜过大,否则很容易过拟合。输入分辨率设640x640,这是精度和速度的平衡点。

batch size要看显存,8GB显存跑nano模型可以设16,跑small模型设8比较稳。epoch最初设150轮,早停机制开起来,验证指标连续20轮不涨就停。学习率用默认值,优化器选AdamW也没问题。我自己习惯先不做任何数据增强跑20轮做冒烟测试,确认loss能降下来,再开全套增强跑完整训练。

我的实际参数参考:

# 以常见YOLO开源训练器为例 python train.py --data dog_behavior.yaml \ --weights yolov8n.pt \ --imgsz 640 \ --batch 16 \ --epochs 150 \ --patience 20 \ --augment

train几百轮这个过程其实很像蒸馒头,前50轮loss下降得明显,后面就是慢慢磨。如果前20轮loss完全不动,优先检查数据集路径是否正确、标签格式是否错位,而不是调学习率。

3.4 吃数据增强提升泛化能力

数据增强在这类小数据集上是刚需。YOLO自带马赛克增强、随机翻转、HSV变换和缩放平移,默认都能开。但增强强度不能一上来就拉满,尤其是马赛克增强在训练后段会引入大量拼接噪声,影响精细行为边界的学习。

我在实际训练中会把基础增强开足,后20轮关掉马赛克,只保留几何增强,让模型在接近真实照片的分布上收敛。这套策略在狗狗行为数据上也适用。另外,行为识别对方向敏感度比较高,左右翻转通常安全,因为狗坐着翻过来还是坐着;但垂直翻转一定要关,狗不会四脚朝天的坐卧。增强策略要按任务语义定制,不能无脑全开。

4. 训练中的典型问题:排查与调优实录

4.1 类别不平衡让模型变成“偏科生”

如果某个行为出现频率明显偏低,模型会倾向于把它预测成高频类别。比如“跑”在数据里只有200张,而“坐”有800张,模型就会看到相似特征的框都往“坐”上带。解决方式优先增加对应类别数据,没有数据来源就让这个类别在增强时获得更高概率。

我另一个更可操作的办法是损失权重调整,给低频类别的分类损失乘以一个权重。这个权重不用卡得太精细,粗略按类别样本数反比设置就能看到改善。权重调整后低频类别的召回率通常能提升5到8个百分点,代价是高频类别略降,但整体F1是变好的。

4.2 边界框标注误差集中在“贴边”和“遮挡”

训练完我会做一个反向检查:把预测置信度低于0.3的框挑出来,和真实标签叠在一起看。绝大多数问题来自两类情况:一类是标注框没有完整包住狗狗身体,脚被切掉了;另一类是两只狗叠在一起,只标了前面那只。前者会让模型学到错误的尺码习惯,后者会让模型对重叠目标的输出极度不稳定。

应对方法很直接:一是用标签检查脚本自动找出宽高比严重偏离正常范围的框,单只狗全身形体的宽高比一般在0.6到1.8之间,超出这个范围的逐个复查;二是对遮挡样本单独建一个mini验证集,专门观察模型在多目标场景下的表现,不追求一开始就完美,至少要知道模型在哪类场景下会失灵。

4.3 动态行为误检:单帧检测的边界

“走”和“跑”这两类在单帧图片上有时人眼都难区分。狗小跑和中速走的步态差异,在静态画面里可能就是前后腿位置的微小差别。模型确实能把大部分分对,但会在边界样本上反复横跳。

解决思路是引入帧级后处理:连续取5帧检测结果,对行为类别做滑动窗口投票,取出现次数最多的标签作为这段时间窗口的行为结论。实测下来,动态行为分类准确率能从单帧的78%左右提升到90%左右。对“吠叫”这类带嘴部状态的行为,还可以结合单帧检测框内的局部增强样本来辅助判断。

4.4 过拟合:训练loss低但验证loss高

从近3000张训练集出来的模型,过拟合风险随时间累积。特征是训练loss持续下降,但验证集mAP不再上升甚至掉头向下。缓解手段,我按有效程度排序的经验是:数据增强、随机失活、使用预训练权重、减小模型容量。

有个容易被忽略的操作:验证集里如果混入了明显超出数据分布的特殊图片(比如狗狗人脸特写、只有尾巴的局部图),验证loss会一直高,模型未必真的不好。要把这类特殊图片从主验证集抽出来,单独做成hard case集,用来观察鲁棒性,而不是让它污染正常的早停判断。处理完之后模型早停点会往后推,最终精度会好不少。

5. 从验证集指标到部署:不只看mAP

5.1 mAP和实际体验之间的鸿沟

训练完输出mAP@0.5可能有0.9,mAP@0.5:0.95可能在0.7,看着不错,但放到真实场景完全是另一回事。原因是验证集照片是静态的、角度相对规整,而真实视频里有运动模糊、旋转视角、低分辨率和恶劣光照。我一般会把部署前的验收标准拆成三档:核心行为(坐、卧、站)的准确率、动态行为(走、跑)的时序稳定性、极端场景(强背光、多目标遮挡)的漏检率。

5.2 部署到边缘设备的工程细节

模型训练完要导出成推理引擎格式,INT8量化后nano模型大概只有几MB,在树莓派上跑能到15到25帧每秒,足够满足实时监测。部署时还有一个细节:处理视频流要做跳帧推理,每3帧或5帧推理一次,中间帧直接复制上一帧的检测结果。狗的行为变化不会在几十毫秒内闪变,跳帧能显著降低CPU功耗和发热,这个优化对端侧设备特别关键。

5.3 行为识别结果怎么变成“能用”的输出

识别出行为以后,最终用户需要的是一个结论。比如连续30秒检测到吠叫,摄像头就往主人手机推一条“狗在持续吠叫”的告警。把行为序列转成事件,靠的是状态机逻辑。在某个实际项目中,我把模型输出接一个简单的状态机,每种行为维持超过N帧才判定进入该行为状态,小于N帧的跳变直接忽略,误报率大幅下降。这套过滤逻辑比调模型本身见效更快。

6. 常见问题速查表:给新手的几条手记

问题现象可能原因处理方式
训练loss一直不降数据集路径错、标签全空、类别ID错位先跑单批次数据检查标签读取是否正确
mAP很高但实测差数据划分泄露、验证集与测试集分布太接近按视频片段分组划分,避免连续帧泄漏
坐和站分不清边界框只标躯干但标准不统一、视角样本少统一标注规范,补充侧视角和正视角样本
走和跑误检单帧视觉差异小加帧滑动窗口投票,或者接入时序模型
深色狗漏检光照对比度不足训练时增强对比度和随机亮暗,部署前用边缘端预处理提亮
模型在手机上偏慢模型偏大或未量化换nano模型、INT8量化、跳帧推理

数据盘点阶段建议拿几张小图做可视化,把标注框画在原图上,逐个类别看。这一步骤比任何指标更能发现问题。标注框颜色和图片是否匹配、类别标签和实际行为是否错位,靠记忆检查一定会漏。

我个人把这份数据处理完整跑一遍之后最大的体会是,这类行为识别项目的天花板往往不是在模型结构,而是在数据的语义一致性上。“跑”这个标签在不同场景里到底指什么,决定了模型能不能学到真正的行为边界。所以不管是自己采集数据还是买现成数据集,先花半天把类别定义和标注规范吃透,后面能省几周调试时间。

当前这套流程我还在继续扩展,下一步准备把单帧检测结果喂给一段轻量时序网络做行为序列建模,进一步解决动态行为误判的问题。如果你正准备起步做宠物AI,先拿这份数据集把YOLO链路跑通,再往场景化和部署方向深入,是条比较稳的路。

RELATED READING

延伸阅读

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