☰
1272张图实现92.6%识别率:YOLOv9猪行为识别数据集全解析
2026/10/5 15:54:53 网站建设 项目流程

简介:面向猪只行为识别与智慧养殖场景,这份数据集以猪圈实拍图像为基础,标注了喝、吃、睡觉、站立四类常见行为,平均正确识别率可达92.6%,既可直接用于YOLOv9目标检测模型的训练与验证,也适合初学者接触行为识别任务时进行数据准备和模型调优练习。资源整体为zip压缩包,共2000个文件,包含1272个txt标注文件、727张jpg原始图像和1个yaml配置文件,压缩包大小约85.86MB;其中txt与jpg按图像一一对应,yaml内定义了类别名称与路径,加载到YOLOv9工程后即可使用。目前已有251人学习浏览,对需要真实猪圈场景数据、希望节省采集与标注时间的用户来说,可直接用于实验对比或模型迭代。基于视频帧提取的图像保留了不同时刻、不同圈舍环境下的猪只姿态,涵盖多种光照与遮挡情况,有助于提升行为检测模型的泛化能力,也可作为其他畜禽行为识别项目的参考数据。

1. 猪圈行为识别数据集的真相:1272 张图如何支撑 92.6% 的平均识别率

养猪查栏是笔辛苦账:三百头猪挨个看,哪头没吃、哪头一直趴着、哪头在饮水器前站太久,全靠肉眼硬盯,发现异常时往往已经掉膘两三天。这份猪行为识别数据集解决的就是这个痛点——1272 张从多个栏位监控视频抽帧的图片,逐张标注出喝、吃、睡觉、站立四类行为,直接采用 YOLOv9 标注格式,平均识别率 92.6%。它不是演示效果的展示包,而是能直接喂给训练脚本的现成数据。适合做智慧养殖算法验证的工程师、行为识别方向的毕设学生,以及想用现成数据把 YOLOv9 全流程跑通再迁移到自己场景的人。

2. 解构猪行为数据集:YOLOv9 格式的目录、标注与行为边界

2.1 从文件名读出数据来源与采集策略

拿到资源第一步,别急着解压训练,先把文件名读一遍。这份数据集的图片命名是一个信息量很大的编码,比如9_1_mp4-6_jpg.rf.020dcb2ff96b0599565b00043dfe8dc5.jpg,拆开能读出三条关键信息。

9_1是栏位编号,对应一个具体的猪栏摄像头视角;mp4-6表示这一帧取自第 6 段视频素材,_jpg后缀说明原始采集是视频流,后转成了静态帧;rf.后面跟的 32 位十六进制哈希,是 Roboflow 导出时生成的去重指纹。哈希的目的是给每一帧唯一的身份标识,防止同一个画面在数据增强或反复导出中被重复计入。浏览完整目录会发现视频编号从0延伸到49,栏位来源涵盖9_1、9_7、10_00三个视角,说明数据不是单一猪栏的连续录像,而是多栏位、多时间片的采样。这个多样性对训练极其有利——背景、光照、猪只密度都不同,模型的泛化能力才有保证,不会只认得某一个猪栏的瓷砖墙和食槽位置。

从文件名还能推测采集节奏:大量相邻编号的帧对出现在最终数据集里,比如mp4-6和mp4-7同时存在,但数量没有膨胀到几千张,说明采集时做了均匀抽帧,抽完又做了相似度去重。这种「先抽帧、再去重」的策略,是行为识别数据集最常见也最稳妥的做法。

2.2 YOLOv9 标注格式:一行一个目标的归一化坐标

YOLOv9 与 YOLOv5、YOLOv8 共用同一套 txt 标注规范,这也是这份数据集能无缝喂进训练脚本的关键。每张 jpg 图片对应一个同名前缀的 txt 文件,里面每一行代表一个目标框,五个字段依次是:类别 ID、目标中心点 x 坐标、中心点 y 坐标、目标框宽度、目标框高度,后四个值全部除以图片宽高做了归一化,取值在 0 到 1 之间。

一份典型的标注文件长这样:

0 0.483211 0.310546 0.240625 0.333984 2 0.712500 0.583594 0.251563 0.443750

第一行的类别 ID 是 0,按数据集约定通常代表「喝」;第二行类别 ID 是 2,对应「睡觉」。后面的四个小数就是归一化后的定位参数。务必先找到数据集里的classes.txt或data.yaml确认 ID 映射关系,我见过有人上来就训,结果模型把睡觉全预测成了喝,因为类别顺序搞反了。这种情况在推理阶段特别难排查,因为损失函数照样收敛,mAP 曲线照样下降。

归一化坐标有个好处:无论你最终训练输入尺寸用 640 还是 1280,标注文件都不需要重新换算,YOLO 系列训练脚本会自动把框映射到输入分辨率上。但这也带来一个检查盲区——你光看数字看不出框画得对不对,强烈建议写个小脚本把框可视化回图片上,眼见为实:

import cv2 img = cv2.imread('9_1_mp4-6_jpg.rf.020dcb2ff96b0599565b00043dfe8dc5.jpg') h, w = img.shape[:2] with open('9_1_mp4-6_jpg.rf.020dcb2ff96b0599565b00043dfe8dc5.txt', 'r') as f: for line in f: cid, cx, cy, bw, bh = map(float, line.split()) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cid)), (x1, y1 - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.imwrite('check_vis.jpg', img)

这段代码把归一化坐标还原成像素坐标再画框。cx - bw / 2计算的是框左上角 x,cy - bh / 2是左上角 y,乘上实际宽高w、h完成反归一化,最后用 OpenCV 的矩形和文字把目标框画出来。跑完随机抽二十张图人工过一遍,重点看两件事:框有没有完整包住整头猪而不是只包住头或半截身体;框的边沿有没有压到旁边另一头猪。如果普遍存在框偏大的情况,说明数据集的标注风格偏宽松,训练时数据增强里的scale参数要收小一点,否则预测框会在目标边缘来回抖。

2.3 四类行为的精确边界定义

行为识别最核心的工程问题不是模型结构,而是行为边界怎么划。这份数据集把行为分成喝、吃、睡觉、站立四类,类与类之间的界线有明确约定。

喝的定义是猪嘴接触饮水器或头部明显下探朝向饮水器方向,颈部前伸、嘴部动作连续;吃的定义是嘴部进入料槽区域并伴随咀嚼动作,头埋进槽里持续一段时间;睡觉的定义是身体侧躺或卧姿、腹部贴地、没有明显肢体活动;站立的定义是四肢支撑身体保持静止或缓步移动。

实际标注时最纠结的边界情况是「猪站在料槽前低头闻」。按照数据集的标注逻辑,这种情况归入站立而不是吃,因为嘴部没有进入料槽、没有咀嚼动作,行为识别的业务目标是找到真正在进食的个体,闻一下不算进食信号。另一个模糊地带是「半卧半站」,前腿跪地、后腿站立的过渡姿态,数据集倾向归入睡觉的过渡态,因为此时猪的活跃度已经明显下降。理解这套边界逻辑很重要,你换到自己的猪场场景时,栏位结构不同、料槽和饮水器位置不同,边界定义大概率要跟着微调——比如自动料槽的猪嘴只要靠近就会被识别为吃,那就得把「嘴部进入槽内」改成「在槽内停留超过 N 秒」。

3. 从视频到训练集:抽帧、清洗与数据划分的完整落地流程

3.1 抽帧策略:不要盲目均匀采样

如果你手里只有监控视频,想自己做一份同类数据集,千万别直接拿 OpenCV 每隔 N 帧暴力抽一遍,那样抽出来的帧高度相似,几乎等效于只有十几张有效图像。常见做法是按行为片段抽帧:先人工浏览录像,标记出喝、吃、睡、站四类行为出现的连续时间段,然后对每个片段分别采样。

采样的帧率我一般从 6 帧每秒起步。监控原始素材普遍是 25 帧每秒,采样到 6 帧每秒能保留猪头部动作的关键细节——猪喝水时嘴部是有明显节奏的扬动,采稀了这种节奏就丢了;再密上去又会造成大量相似帧。这份数据集的命名里mp4-6、mp4-7相邻编号成对出现,说明作者用的就是类似手法:同一段视频均匀降采样,随后做相似度去重,最终压缩到 1272 张有效帧。

抽完帧第一件事是人工快翻一遍,删掉三类废帧:画面模糊的、猪群完全遮挡目标的、以及有人员或工具入镜的。人员入镜的帧危害最大,模型会把「蓝色工作服」学成背景特征,一旦换到无人的自动饲喂场景就掉精度。

3.2 标注工具选型:本地 LabelImg 还是在线 Roboflow

做四分类目标检测标注,工具选型直接影响效率和格式一致性。如果你对数据隐私没有强制要求,直接在 Roboflow 上上传视频、在线抽帧、在线画框是效率最高的路径,导出时勾选 YOLOv9 format,拿到的就是这份数据集的同款结构:图片 + 同名 txt + 一个自动生成的data.yaml,连目录划分都给你做好了。Roboflow 的去重指纹(就是文件名里的哈希段)也正是这么来的。

如果你有私有化要求或网络受限,本地用 LabelImg 完全够用。LabelImg 保存时选择 YOLO 格式,生成的 txt 与 YOLOv9 完全兼容,因为这个格式体系向后兼容。用 LabelImg 时有一个必须守住的规矩:classes.txt里的类名顺序决定 ID 编号,新增类别只能追加在文件末尾,绝对不能插到中间,否则已有标注的 ID 全部错位,训练脚本读出来的全是错配标签,而且不会报任何错。每标完一批,我习惯写一行命令检查全部标注文件的完整性:

for f in labels/*.txt; do awk -F' ' '{if(NF!=5 || $1<0 || $2<0 || $3<0 || $4<0 || $5<0) print "BAD:", FILENAME, $0}' $f; done

这一行命令遍历所有标注文件,检查每一行是否正好五列、是否有负数。五列是 YOLO 格式的硬性要求,类别 ID 和四个坐标都不能是负值。如果有BAD:输出,说明那个文件被误编辑过,直接定位修复。批量检查在两百张图以上的项目里是刚需,人工一个个开文件翻太容易看漏。

3.3 划分 train/val/test:按视频来源分组而非按帧随机

1272 张图按 8:1:1 划成训练集、验证集、测试集是常规比例,但划分方式有一个容易被忽略的坑:必须先按视频来源分组,再在组级别上做随机分配。如果直接对全部帧做随机划分,同一段 mp4 的相邻帧会同时出现在训练集和验证集里,模型等于提前背过了验证题的答案,val 的 mAP 虚高 5% 以上,换到真实视频流上立刻现原形。

正确的做法是解析文件名里的mp4-*编号,以「视频片段」为最小单位做分组。比如 50 段视频,随机抽 40 段的全部帧进训练集,5 段进验证集,5 段进测试集,保证同源的帧只出现在一个集合。这一步也是为什么 2.1 里强调保留文件名编号信息——它是你做分组划分的核心依据。Roboflow 导出的数据通常自带划分,但建议拿到手后自己核对一遍,尤其是那些跨视频来源的数据集。

4. 用 YOLOv9 复现 92.6% 识别率:训练配置、参数调优与评估

4.1 环境准备与预训练权重选择

训练 YOLOv9 用官方仓库最省心。YOLOv9 相比 v5、v8 的核心改进是引入了可编程梯度信息(PGI)和广义高效层聚合网络(GELAN),在相近参数量下能保留更多梯度信息,对小目标行为检测的精度提升明显。这也是这份数据集选择 YOLOv9 格式作为基准的原因——它需要能扛住「猪头」这种小尺寸目标的检测压力。

git clone https://github.com/WongKinYiu/yolov9.git cd yolov9 conda create -n pig python=3.9 -y conda activate pig pip install -r requirements.txt pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121

PyTorch 的安装参数要跟你的显卡驱动匹配:cu121对应 CUDA 12.1,驱动版本不够就换成cu118,或者用 CPU 版跑训练——慢是慢,但至少能跑通流程。显存决定你选哪份预训练权重:8 GB 及以下用yolov9-c.pt,这是中等规模的版本,单卡勉强能塞进 batch size 8;16 GB 以上用yolov9-e.pt,精度更高,训练时间约多 40%。

4.2 数据配置:一行类名顺序都不能错

在yolov9/data/目录下新建pig.yaml,指向数据集的三个子集:

train: /home/user/pig_dataset/train/images val: /home/user/pig_dataset/val/images test: /home/user/pig_dataset/test/images nc: 4 names: ['drink', 'eat', 'sleep', 'stand']

路径要写到images目录,YOLOv9 会自动去同级目录下找labels/下的同名 txt 标注。nc是类别数,四类就写 4。names的列表顺序与标注文件的 ID 严格一一对应,这里写错不会报错,但训练完的混淆矩阵、PR 曲线全部错位,等于白跑一轮。如果数据集的classes.txt顺序是drink, eat, sleep, stand,这里就必须照抄。

4.3 训练命令与关键参数逐个拆解

python train.py \ --data data/pig.yaml \ --weights yolov9-c.pt \ --batch-size 16 \ --imgsz 640 \ --epochs 100 \ --device 0 \ --cache \ --patience 20

参数逐一说明:--batch-size 16是 16 GB 显存的中等配置,8 GB 显存就降到 8,batch size 太小会导致 BN 层的统计量不稳定,模型收敛变慢;--imgsz 640是输入边长,猪在画面里占的面积普遍较大,640 分辨率足够捕捉到嘴部动作,不要盲目上 1280,训练时长直接翻倍且容易过拟合;--epochs 100对 1272 张图的数据量来说是合理的,通常 60 轮以后 mAP 曲线就走平了;--cache把全部图片预加载进内存,能省三分之一到一半的训练时间,前提是内存大于 16 GB;--patience 20是早停参数,连续 20 轮验证集 mAP 不提升就自动停止,并保留历史上最好的权重。

训练过程中要盯两个指标:终端输出的train/box_loss和val/mAP@0.5。box_loss 持续下降且中途没有突然反弹,说明学习率和 batch size 配比正常;mAP@0.5 到了后期每轮涨幅低于 0.5% 就可以手动停了。我习惯在训练时顺手记录每轮 mAP 的变化曲线,这样早停条件触发时能立刻判断是收敛了还是震荡了。

4.4 评估指标:92.6% 平均识别率的含义

训练结束后用官方验证脚本评估:

python val.py \ --data data/pig.yaml \ --weights runs/train/exp/weights/best.pt \ --imgsz 640 \ --conf-thres 0.25 \ --iou-thres 0.5

--conf-thres 0.25是置信度阈值,低于 0.25 的预测框直接当背景丢掉;--iou-thres 0.5是判断预测框是否命中真值框的 IoU 下限,也就是 mAP@0.5 的判定口径。数据集宣传的 92.6% 平均识别率,指的就是四类行为各自的 mAP@0.5 的算术平均。

跑完验证脚本,打开results.csv逐类看 AP:通常「睡觉」和「站立」两类 AP 较高,能达到 94% 以上;「喝」和「吃」偏低,因为嘴部是小目标,姿态变化剧烈,单帧里嘴是否接触饮水器往往只有几个像素的差异。如果某些类的 AP 低于 85%,问题大概率出在标注边界不统一,回到 2.3 的边界定义去复审标注,而不是急着调模型。

5. 避坑指南:五个让猪行为模型翻车的典型问题

5.1 睡觉与站立互相串类,混淆矩阵一片红

现象:训练出来的睡觉和站立两个类,PR 曲线都在 0.85 上下摇摆,混淆矩阵里互相错分严重,验证集 mAP 上不去。 原因:趴卧时前腿跪地、躯干悬空的过渡姿态在 2D 图片上跟站立下蹲瞬间非常像,标注员没有统一判定标准。 解决:回到标注文件,把两类边界重新对齐——腹部贴地、四肢弯曲算睡觉;躯干离地、四肢支撑算站立。重标后用修正的标注重新训练,一般能各涨 2% 到 3% 的 AP。这种问题最好在标注阶段就定成团队规范写进标注说明文档,不然多人协作时各标各的。

5.2 喝与吃边界模糊,验证集虚高但实时推理崩

现象:验证集 mAP@0.5 显示 93%,接上实时视频流后,猪只是站在料槽前低头没吃也被框成「吃」。 原因:标注阶段大量「低头闻料槽」的画面被划进「吃」,模型学到的是「头在料槽上方就等于吃」的假规律。 解决:按数据集的边界定义,嘴部不入槽、无咀嚼动作都只能算站立。先把标签里所有「头在槽上方但嘴未入槽」的样本重新归类,再用训练好的模型在测试视频上预测一轮,找出置信度在 0.4 到 0.7 之间的模糊样本人工复核——这个置信度档位最容易暴露标注噪声。

5.3 夜间红外光照下漏检率陡增

现象:白天场景 mAP 92% 以上,切到夜间红外监控,睡觉类漏检率 30%,直立行走的猪在灰度图里几乎框不出来。 原因:1272 张图大量来自白天或灯光充足的栏位,训练分布里压根没有红外灰度帧,模型没见过这种成像特征。 解决:如果部署环境有夜班需求,必须在训练集里补入红外样本。做法是拍 200 张左右的夜间红外帧,按 2.3 的边界定义补标,然后用现有权重做冻结微调——冻结前 10 层骨干网络,只更新检测头,训练 30 个 epoch 就停。全量重训会把白天的性能稀释掉,冻结微调是性价比最高的路径。

5.4 训练集和验证集泄漏,val 指标虚高到可疑

现象:验证集 loss 比训练集 loss 还低,PR 曲线平滑得不自然,mAP 冲到 96% 以上。 原因:数据划分时直接对全部图片做随机切分,同一个视频的相邻帧同时进了训练集和验证集,模型等于默写考题。 解决:回到 3.3 的分组划分方案,按视频编号为最小单位重分三集。划分完做一个简单的相似性检查:把验证集每张图在训练集中找最相似的帧,计算结构相似度,如果出现相似度高于 0.9 的配对,说明两个集合间仍然存在泄漏,需要调整分组策略。

5.5 早停触发但保存的 best 权重不是最优 mAP

现象:训练跑到第 78 轮触发早停,脚本说保存了best.pt,但拿这个权重验证 mAP 只有 80%,比中间某轮明显低。 原因:YOLOv9 的早停逻辑默认监控验证集 loss 而不是 mAP,loss 最低的轮次并不一定对应 mAP 最高。 解决:训练结束后不要急着用best.pt,打开runs/train/exp/results.csv,找到metrics/mAP_0.5这一列的最大值对应的 epoch,去weights/里找那一轮的last.pt转成部署权重。从那以后我每次训完都会扫一遍 results.csv 再谈精度,不能只看脚本说 best 就信。

6. 部署进阶:时序平滑、ROI 联动与行为验证技巧

单帧推理在连续视频流上会暴露一个大问题:行为预测在帧与帧之间来回闪烁,上一帧是「喝」,下一帧成了「站立」,再下一帧又变回「喝」。原因是单帧模型没有时间记忆,猪喝水时的抬头换气动作在 2D 画面上确实和站立瞬间极像。我的做法是在推理输出端加两道后处理,不折腾模型本身。

第一道是滑动窗口去抖:维护一个长度 5 的窗口,把最近 5 帧的行为预测放进去,最终输出取众数。连续 5 帧里 4 帧预测是睡觉,这一秒就输出睡觉;偶尔一帧预测成站立,不会影响最终结论。窗口长度太短去抖效果差,太长会掩盖真实的行为切换——试验下来 5 帧在 25 帧每秒的视频里对应 0.2 秒的延迟,体感可以接受。

第二道是区域 ROI 联动:把料槽和饮水器的位置预先画成矩形区域,推理时校验行为输出和位置的关系。头部中心点在料槽 ROI 之外却输出「吃」的预测,直接丢弃重判;嘴部在饮水器 ROI 外却输出「喝」同理。这道校验能把不少单帧误判挡在业务逻辑之外,成本几乎为零。

验证这套链路是否有效,我习惯统计行为切换次数:把一段 10 分钟测试视频逐帧送进模型,记录行为输出的切换点数量。不接平滑逻辑时,切换次数通常在每分钟 30 次左右;接上窗口和 ROI 之后,应降到每分钟 5 次以内。同时抽查平滑后的输出有没有把短促的「喝水后抬头换气」误判成站立——如果这类误判变多,说明窗口长度太激进,调到 3 帧重新测一轮。这套流程走顺再交给业务端,模型才算真正落地。从那以后我每次做行为识别数据集,都强制走一遍分组划分、标注边界复核和后处理验证,缺一项都不敢上线。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询