☰
猪只行为识别实战:1272张图YOLOv9数据集解析与训练指南
2026/10/1 11:01:03 网站建设 项目流程

简介:面向猪舍智能化监控的猪只行为识别数据集,聚焦喝、吃、睡觉、站立四类日常行为,平均正确识别率达92.6%,可直接支撑猪舍场景下的动作分析与异常预警。数据来源于多段猪圈视频截帧,共1272张图片,覆盖不同个体、角度与光照条件,适合目标检测、行为识别研究,也可用于智慧养殖项目原型验证。压缩包共2000个文件,包括727张jpg图像、1272个txt标注文件及1个yaml配置文件,整体大小85.86MB;txt采用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 git@github.com:WongKinYiu/yolov9.git cd yolov9 # 3. 安装其他依赖 pip install -r requirements.txt

安装依赖时最容易出问题的是torch与CUDA版本不匹配。如果服务器上已经装好了CUDA和cuDNN,可以用nvidia-smi查看CUDA版本,再反查PyTorch对应的安装命令。有些版本的yolov9仓库还需要安装额外的deepspeed或tensorboard,requirements.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和mAP@0.5的变化趋势。如果mAP@0.5在第50轮后依然缓慢上升,可以歇会儿去看loss曲线,确认没有发散后再等最后10轮收敛。

4.3 数据增广对猪圈场景的影响:flip、mosaic、hsv的合理区间

YOLOv9自带数据增广策略,但默认参数并不一定适合猪行为识别。猪圈场景里有一个很特殊的地方:地面、墙壁、料槽都带有大量纹理干扰,过强的增广会让模型学到环境噪声。实际操作中,我一般关闭或调低两个参数:一是fliplr(水平翻转),猪的行为姿态左右不对称的情况不多但确有,比如饮水和采食时头部朝向不同,水平翻转对“喝”和“吃”这种和头部动作相关的类别影响不大,但如果你发现验证集精度反而下降,可以试着把它设成0.5;二是mosaic的拼图增广,YOLOv9默认开启mosaic=1.0,1272张图里如果mosaic的强度太高,模型会看到大量拼接成的假猪,对边缘光晕和遮挡的判断反而变差。推荐的参考区间是mosaic=0.5~0.8,hsv_h=0.015、hsv_s=0.5、hsv_v=0.4,这样能在保留颜色信息的同时增强光照鲁棒性。

4.4 92.6%正确率是怎么换算的:正确率、mAP和类别间差距不是一回事

92.6%这个数字进入视野后,第一反应是“还行,能上生产”,但冷静下来要问一句:这是哪个指标的正确率?目标检测任务里常见的评估指标包括:按图像级别的正确率、按框级别的精确率/召回率、以及mAP。如果92.6%是按图像级别计算,即每张图模型输出的主行为与真实标签是否一致,那这个数字会明显高于框级别的精确率。实际部署中,我们关心的是框级别指标,即模型能不能在正确的位置框出每头猪的行为。训练时应同时关注mAP@0.5和mAP@0.5:0.95两个值,前者表示粗略定位的准确度,后者表示定位精度更严格的情况。对猪行为标识来说,mAP@0.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, conf=0.5, imgsz=640, verbose=False) 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(f"drink: {drink_count/total:.2f}, eat: {eat_count/total:.2f}, " f"sleep: {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,但这只是临时补丁;更合理的做法是回到数据侧,为置信度低的类别补充针对性图片重新微调一轮。测试部署时,我会把验证视频完整保留着,每次改数据、改参数、换模型版本都用同一段视频跑同一套统计脚本做回归比对,防止模型迭代后行为混淆不降反升。希望这套做法对你评估手上的猪行为识别项目有帮助。

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

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

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

立即咨询