
简介面向猪舍智能化监控的猪只行为识别数据集聚焦喝、吃、睡觉、站立四类日常行为平均正确识别率达92.6%可直接支撑猪舍场景下的动作分析与异常预警。数据来源于多段猪圈视频截帧共1272张图片覆盖不同个体、角度与光照条件适合目标检测、行为识别研究也可用于智慧养殖项目原型验证。压缩包共2000个文件包括727张jpg图像、1272个txt标注文件及1个yaml配置文件整体大小85.86MBtxt采用YOLOv9格式与图片一一对应yaml中预置类别名称解压后即可接入训练流程。目前已有251人学习下载适合有一定目标检测基础的研究者、竞赛选手或养殖系统开发人员。价值方面可直接依据yaml划分训练集与验证集在YOLOv9、YOLOv8等框架中快速迭代并进一步部署到边缘设备形成猪只行为监测应用降低人工巡查成本。1. 猪圈里的行为识别1272张图92.6%正确率能落地吗猪只行为识别这几年在规模化猪场里越来越刚需但真正能直接用的数据集反而稀缺。这个标题里的数据集给出一个很具体的承诺1272张标注图片覆盖喝、吃、睡觉、站立四类行为平均正确识别率92.6%并且直接提供yolov9格式的标注。对做农业AI、养殖物联网或者算法落地的人来说这个数据集最大的价值不是“大”而是“准”和“够用”——1272张图对单场景行为分类任务来说只要分布均衡、标注干净效果可以胜过一万张粗标数据。它适合的目标人群很明确想快速验证猪只行为识别方案、做监控摄像头实时分析、或者做毕业设计和横向项目的人。这篇笔记就沿着这套数据集的构成、格式、训练和踩坑一路讲到底。2. 数据集的底细1272张图里到底有什么为什么这个数字够用2.1 四类行为的定义边界喝、吃、睡觉、站立的判定标准这个数据集的标注类别不多但每类都对应着实际生产里关心的事件。吃的定义比较直观猪的嘴部接触料槽、有明显咀嚼动作或者头部伸入料槽区域持续超过某段时间。喝的定义则需要区分饮水器和料槽的位置通常标注的是猪的头部靠近饮水器、嘴巴触碰饮水嘴的区域如果猪只是路过饮水器不应当算喝。睡觉的判定有两个层次一是躺卧且闭眼二是躺卧但没有明显睁眼活动严格的数据集通常只把前者标成睡觉后者可能标成躺卧。而这个数据集里只有四类没有单独躺卧所以标注者一般会把“卧着没睡着”也归入睡觉这一点在训练时要留意。站立的定义看着最简单但坑最多。猪不是人站立时头可能朝向任意方向身体也可能弯曲如果以目标检测的方式去框站立的框和吃的框经常重叠——猪站着的时候刚好在吃料。所以这个数据集的标注规范里我猜测站立的判定是以“身体直立、没有进食和饮水动作”为准并且要求标注框尽量贴近身体轮廓避免把料槽、栏杆、地面反光大量包进框里。如果做迁移学习或自行扩充标注这四个类的边界必须提前定死否则模型会学到“头部靠近料槽吃”这种难看但短期有效的伪特征。2.2 1272张的样本量够吗算一笔训练账目标检测任务里常见的直觉是数据越多越好。但对猪行为识别这样的单场景、固定机位、类别少的任务1272张图往往是够用的。简单算一笔账假设每张图平均有2.5头猪那么标注实例大概在3000个左右四个类别平均每类约750个实例。以YOLOv9这样的模型来看每个类别有500个以上的实例基本可以训练出一个可用的检测器如果把数据集扩增到3000张以上能提升的主要是不同光照和猪姿态的泛化能力。还需要考虑的是现场部署时的场景复杂度。如果摄像头位置固定猪圈的布局不变1272张图里包含的视角变化基本能覆盖大多数时段。但如果要换猪圈、换摄像头角度、换光照条件这个数据量就不够了必须做迁移学习和现场数据补充。我的经验是先用这套数据训练出基线模型再在现场采集500-1000张不标注的图做伪标注和人工修正比一开始就攒大量粗糙标注要实际得多。2.3 图片属性与标注质量的隐形指标分辨率、遮挡、清晰度的取舍图片数量和类别只说明数据集的一部分真正影响训练效果的是图片质量和标注一致性。理想情况下这个数据集的图片应该来自固定机位的1080P监控画面每帧间隔不低于1秒避免连续帧高度雷同。标注框应该紧贴猪只轮廓尤其是睡觉姿势下猪体收缩、站立时身体拉长框的长宽比变化很大这对模型的锚框选择有直接影响。遮挡问题几乎是猪圈场景里无法避免的硬伤。猪与猪之间互相遮挡、猪身沾着粪便导致纹理混乱、料槽栏杆挡住下半身——这些情况在1272张图里如果占比过高模型就会学到“只露半边身体也能识别”。这种模型在单头猪场景里可能很准但一进真实猪圈就翻车。建议拿到数据集后先做一轮遮挡比例统计人工抽查100张图统计每类行为中标注框内被遮挡或目标不完整的比例如果超过20%就要考虑补充少量针对性数据否则92.6%的正确率很可能只是测试集上的数字。3. 把标注变成训练燃料yolov9格式的目录结构、标签文件与转换细节3.1 yolov9格式到底长什么样目录、图片、标签三个硬要求yolov9格式和yolov8、yolov5一脉相承本质上就是Ultralytics系列通用的数据组织方式。拿到这个数据集后首先要检查的是目录结构和标签文件是否规范。一个标准的yolov9数据集目录结构大致如下pig_behavior_dataset/ ├── images/ │ ├── train/ # 约900张 │ └── val/ # 约300张 ├── labels/ │ ├── train/ # 与images/train一一对应的txt文件 │ └── val/ # 与images/val一一对应的txt文件 ├── data.yaml # 数据集配置文件 └── classes.txt # 类别名文件可选标签文件的命名必须与图片完全一致图片是IMG_0001.jpg标签必须是IMG_0001.txt扩展名从.jpg换成.txt。每一行标签的格式是五列以上第一列是类别ID从0开始后面跟着归一化后的中心点x、中心点y、宽度、高度。如果这个数据集还附带了分割标注或其他额外信息yolov9的目标检测格式只会读取前五列多余字段会被忽略。验证数据集是否规范最好的方式是写一个快速检查脚本统计标签文件数量和图片数量是否一致、是否有空的标签文件、是否有坐标值超出[0,1]范围的情况。我一般会先跑一遍这个脚本再开始训练避免训练到一半才发现数据有问题。3.2 data.yaml怎么配置路径、类别名、训练集划分缺一不可data.yaml是YOLOv9训练时的“总开关”路径写错会导致训练直接报错。一个参考配置如下# data.yaml path: ./pig_behavior_dataset # 数据集根目录 train: images/train # 训练图片相对路径 val: images/val # 验证图片相对路径 test: # 可不填 nc: 4 # 类别数必须是4 names: [drink, eat, sleep, stand]这里的path既可以是相对路径也可以是绝对路径。如果使用Windows系统建议把path写成绝对路径并统一用正斜杠Linux和服务器环境下相对路径更稳妥。train和val填的是相对路径要注意不要写成./images/train开头因为yaml里已经指定了path再次拼接会产生路径错误。有些版本还支持train_images和val_images字段但以Ultralytics的实现为准最稳妥的还是用train和val这两个固定键名。3.3 非yolov9格式标注如何转换VOC、LabelMe、JSON的方法与三个边界坑如果这个数据集买到手时提供的是VOC格式的XML或者LabelMe格式的JSON需要转成yolov9格式。转换的核心逻辑是从XML或JSON中读出目标框的像素坐标经过归一化后写入txt文件。下面给出一段处理VOC格式的参考代码# voc_to_yolo.py import os import xml.etree.ElementTree as ET def convert_voc_annotation(xml_file, classes_mapping, output_dir): tree ET.parse(xml_file) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in classes_mapping: continue # 跳过未知类别 class_id classes_mapping[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化坐标注意边界裁剪 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 防止越界浮点误差或标注越界导致的值小于0或大于1 x_center max(0.0, min(1.0, x_center)) y_center max(0.0, min(1.0, y_center)) w max(0.0, min(1.0, w)) h max(0.0, min(1.0, h)) lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) # 输出txt文件文件名与xml同名放在labels目录下 base os.path.splitext(os.path.basename(xml_file))[0] out_path os.path.join(output_dir, base .txt) with open(out_path, w) as f: f.write(\n.join(lines))转换时最常遇到三个坑。第一VOC的width和height是图片的真实尺寸但如果图片被缩放或裁剪过XML里的尺寸与图片文件的实际尺寸不一致归一化坐标就全错了训练时不报错但精度极差。第二有些标注工具导出的XML里xmin和xmax是整数而经过图像缩放后可能出现小数直接float()不会有问题但要注意某些数据里xmin xmax的情况通常是标注工具导出时的顺序写反了。第三类别映射字典的顺序必须固定排序方式可以用名称字母序或自定义但转换后要和data.yaml里的names完全对应否则模型会把“吃”当成“喝”来学看起来loss正常下降推理时行为全偏。4. 用自己的数据训练一个猪行为检测器YOLOv9训练流程与参数调整4.1 环境准备从zero到能跑通的三个步骤用YOLOv9训练最基础的前置条件是Python环境、PyTorch和对应的依赖库。建议使用GPU服务器或本地显卡训练CPU训练1272张图的速度会慢到让人失去耐心。环境安装步骤一般如下# 1. 安装PyTorch根据CUDA版本选择合适的命令 # CUDA 11.8 版本示例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 2. 获取yolov9代码常见的自动下载方式是使用lipku的yolov9仓库 git clone gitgithub.com:WongKinYiu/yolov9.git cd yolov9 # 3. 安装其他依赖 pip install -r requirements.txt安装依赖时最容易出问题的是torch与CUDA版本不匹配。如果服务器上已经装好了CUDA和cuDNN可以用nvidia-smi查看CUDA版本再反查PyTorch对应的安装命令。有些版本的yolov9仓库还需要安装额外的deepspeed或tensorboardrequirements.txt里一般都有如果报错缺少某个包直接pip install 包名补齐即可。如果你不想从仓库源码训练也可以使用Ultralytics的YOLO生态用from ultralytics import YOLO的方式改写配置文件来训练。两种方式的训练效果差别不大但Ultralytics的API更稳定适合直接上手源码仓库则更适合需要修改网络结构或自定义损失函数的场景。4.2 最小训练命令与每行参数的用途数据集与配置准备好后最小训练命令如下python train.py --data data.yaml --weights yolov9c.pt --img 640 --epochs 100 --batch-size 16 --device 0 --project ./runs_train --name pig_behavior_v1各参数的参考取值和调整逻辑--weights yolov9c.pt预训练权重yolov9c是一个参数量适中的版本适合单尺度目标检测。如果GPU显存只有6GB建议换成yolov9s.pt如果显卡是3090或以上可以直接用yolov9e.pt。--img 640图片缩放到640x640输入模型。猪只行为识别场景中主体占比大640是默认值的合理选择如果希望检测更小的目标可以改成960但训练时间和显存占用会同步上升。--epochs 100训练轮数1272张图100轮足够模型收敛通常到80轮以后mAP增长就非常平缓了。--batch-size 16每批次图片数量受显存限制。如果训练时爆显存优先把batch-size降到8而不是改小--img。--device 0选择第一张GPU卡多卡时用0,1,2,3。训练过程的日志里重点看val Box P、val Box R和mAP0.5的变化趋势。如果mAP0.5在第50轮后依然缓慢上升可以歇会儿去看loss曲线确认没有发散后再等最后10轮收敛。4.3 数据增广对猪圈场景的影响flip、mosaic、hsv的合理区间YOLOv9自带数据增广策略但默认参数并不一定适合猪行为识别。猪圈场景里有一个很特殊的地方地面、墙壁、料槽都带有大量纹理干扰过强的增广会让模型学到环境噪声。实际操作中我一般关闭或调低两个参数一是fliplr水平翻转猪的行为姿态左右不对称的情况不多但确有比如饮水和采食时头部朝向不同水平翻转对“喝”和“吃”这种和头部动作相关的类别影响不大但如果你发现验证集精度反而下降可以试着把它设成0.5二是mosaic的拼图增广YOLOv9默认开启mosaic1.01272张图里如果mosaic的强度太高模型会看到大量拼接成的假猪对边缘光晕和遮挡的判断反而变差。推荐的参考区间是mosaic0.5~0.8hsv_h0.015、hsv_s0.5、hsv_v0.4这样能在保留颜色信息的同时增强光照鲁棒性。4.4 92.6%正确率是怎么换算的正确率、mAP和类别间差距不是一回事92.6%这个数字进入视野后第一反应是“还行能上生产”但冷静下来要问一句这是哪个指标的正确率目标检测任务里常见的评估指标包括按图像级别的正确率、按框级别的精确率/召回率、以及mAP。如果92.6%是按图像级别计算即每张图模型输出的主行为与真实标签是否一致那这个数字会明显高于框级别的精确率。实际部署中我们关心的是框级别指标即模型能不能在正确的位置框出每头猪的行为。训练时应同时关注mAP0.5和mAP0.5:0.95两个值前者表示粗略定位的准确度后者表示定位精度更严格的情况。对猪行为标识来说mAP0.5能达到88%以上就算是一个很好的基线。5. 避坑指南训练猪行为识别数据集时最常踩的五个坑5.1 标签类别不平衡睡觉样本过多导致模型变瞎子现象训练好的模型把大部分猪都识别成“睡觉”即使猪正在站立吃料。原因猪圈这个场景里一天之中猪睡觉的时间最长数据采集时如果随机抽帧睡觉类占比可能高达60%以上模型学到最简单的“分类策略”就是看到猪就输出占比最高的类。解决先用脚本统计标签类别的分布把占比最高的类别在上采样或复制增广上做限制例如用ImageFolder或YOLO数据的cls权重参数或直接用--class-weight训练。更省事的办法是去掉睡觉类中超过300张的冗余图让每一类尽量均衡在250-350张之间。5.2 同一头猪的多行为交叉标签互相覆盖吃和站分不清现象验证集里吃类的召回率很高但精确率只有60%大量站立的行为被误判为吃测试集上正确率高达92%到了真实场景里就明显下降。原因猪在站立状态下探头到料槽附近视觉特征与吃高度重合如果标注边框过大把料槽含进去了模型就会把料槽当成关键特征来学习站立的猪一旦靠近料槽就被误判。解决第一步先检查标签框的大小看看框内是否包含大量背景或料槽第二步是重新审视类别定义在数据标注时把“靠近料槽但嘴部没有接触料槽”的情况排除在吃之外第三步可以选择用行为序列的方式做时间平滑而不是只用单帧检测。单帧检测的缺点在行为识别场景里暴露得最明显。5.3 数据泄露训练集和验证集来自同一段视频片段现象训练时mAP能到95%但现场测试效果很差。原因数据按文件名随机划分了训练集和验证集而所有图片其实来自同一段连续监控视频的抽帧相邻帧里猪的姿态几乎一样造成了验证集“变相泄露”到训练集里。解决按时间段划分。采集数据时至少要在3个不同时段录制视频比如上午、中午、夜间训练集和验证集按时间段划分而不是按文件名随机打乱。检查数据集的划分方式时可以按文件名前缀统计每段视频对应的图片数量。5.4 光照变化和夜间场景模型在白天好用夜间集体翻车现象白天测试集正确率很高一到了夜间红外/NIR模式下所有类别全部混乱尤其是睡觉和站立分不清。原因猪舍的光照条件一天之内变化很大——自然光、日光灯、红外补光的数据分布完全不同。1272张图如果绝大多数是白天或标准灯光下拍的模型根本没有机会学到夜间的视觉特征。解决有三种常用手段。第一在hsv增广里把亮度变化范围调大模拟不同光照第二训练后用现场采集的夜间数据进行一次short-term微调只训练50轮学习率调低到0.0001第三在数据采集阶段直接按昼夜比例分配建议夜间图片占比不低于20%。5.5 视频帧间抖动造成标注偏移框和猪对不上现象人工在视频里逐帧标注时猪移动很快标注框会滞后于猪的实际位置导致模型学习的边界不固定训练过程中的loss震荡明显。原因标注工具里逐帧标注时标框依赖人的目测判断猪一移动就会产生偏差。更常见的是直接由标注平台自动跟踪生成框但跟踪算法稍差就会偏移。解决这类问题的排查办法是抽检标签框和图片叠加后的视觉一致性用代码画框导出视频手动看20帧的输出即可发现。如果偏移明显可以对标签做简单的平滑处理比如连续帧间的框坐标做线性插值。轻量级修正建议在标注侧就解决不要依赖训练时增加数据增广来硬扛。6. 训练后的现场验证用一段20秒真实视频检验模型的四步法训练完模型之后不要急着上生产先做一段现场验证。最直接的方式是录制一小段猪圈的真实监控视频时长大约20秒里面能覆盖吃、喝、睡、站四个行为并且包含至少两次猪只走动或姿态切换。然后把视频切成帧序列用训练好的模型对每一帧进行检测统计每一帧的行为输出。验证脚本可以参考下面这个框架# validate_video.py from ultralytics import YOLO import cv2 model YOLO(runs_train/pig_behavior_v1/weights/best.pt) video_path test_pig_pen_night.mp4 cap cv2.VideoCapture(video_path) drink_count, eat_count, sleep_count, stand_count 0, 0, 0, 0 while True: ret, frame cap.read() if not ret: break results model.predict(frame, conf0.5, imgsz640, verboseFalse) boxes results[0].boxes for box in boxes: cls_id int(box.cls[0]) if cls_id 0: drink_count 1 elif cls_id 1: eat_count 1 elif cls_id 2: sleep_count 1 else: stand_count 1 cap.release() total drink_count eat_count sleep_count stand_count print(fdrink: {drink_count/total:.2f}, eat: {eat_count/total:.2f}, fsleep: {sleep_count/total:.2f}, stand: {stand_count/total:.2f})这个脚本的核心是统计每一个被检测到的框并输出各行为在总检测框中的占比。如果视频里猪的实际行为序列是“吃30秒、睡10秒、站起来5秒、喝水15秒”那输出占比应该接近这个时间比例。如果输出的占比中睡觉占80%而视频里猪明明在吃东西就要怀疑模型是不是把“猪在圈里不动”当成了“睡觉”。进一步可以做一个更细的验证手动把20秒视频切成10个关键片段记录每一段的真实行为标签然后让模型输出每一段的主导行为做一个2-3行的混淆矩阵。这个矩阵是判断模型是否真正学到行为判别能力的唯一标准。如果混淆矩阵里“吃”和“站”相近说明类别边界定义有歧义如果“睡”和“站”混淆大概率是光照或遮挡问题。最后一个习惯性检查用conf阈值0.7跑一遍同一段视频对比框数量和类别分布的变化。如果阈值提高后某一类的框数量骤降说明该类的置信度分布偏低模型对该类行为不够自信。这种情况在部署时可以考虑把阈值区分类别设置——比如对吃和喝用0.6对睡和站用0.7但这只是临时补丁更合理的做法是回到数据侧为置信度低的类别补充针对性图片重新微调一轮。测试部署时我会把验证视频完整保留着每次改数据、改参数、换模型版本都用同一段视频跑同一套统计脚本做回归比对防止模型迭代后行为混淆不降反升。希望这套做法对你评估手上的猪行为识别项目有帮助。本文还有配套的精品资源点击获取