ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

猪行为识别数据集:从COCO标注到YOLOv8训练的完整实践

猪行为识别数据集:从COCO标注到YOLOv8训练的完整实践 简介一套面向智慧养殖场景的猪行为识别数据集适合计算机视觉研发人员、农业工程研究者及畜牧智能化项目开发者使用。数据集聚焦猪圈内猪只的日常行为自动识别覆盖喝、吃、睡觉、站立四个关键动作类别标注文件采用COCO JSON格式可直接用于目标检测、行为分类等模型的训练与评测免去自行采集和标注的繁琐流程。整套资源共1275个文件包含1272张JPG图像与3个JSON标注文件压缩包约85.57MB图像主要来自猪舍监控视频抽帧视角和光照条件多样有助于提升模型在实际场景下的泛化能力。数据集的平均正确识别率达92.6%说明标签质量和可训练性较好在同类小型行为数据集中具有较高的参考价值。目前已有213人学习浏览适合需要快速获得带标注猪行为样本、开展算法对比实验或搭建智慧养殖监测系统的用户。1. 猪行为识别数据集从 1272 张图到 92.6% 正确率的落地路径当摄像头对着猪栏时真正难的不是检测出一头猪而是判断这头猪正在喝、吃、睡觉还是站立。猪圈光线暗、猪体互相遮挡、目标尺度变化大通用检测器在这一场景下的行为分类精度很容易掉到 85% 以下。这套猪行为识别数据集正好补上这块缺口1272 张猪圈实拍图像标注覆盖喝、吃、睡觉、站立四类常见行为平均正确识别率达到 92.6%标注格式为 COCO JSON可直接用 pycocotools 读取也可以作为 YOLOv8 等检测框架的训练语料。本文先从数据组织方式说起再给出基于 CVAT 的标注、COCO 转 YOLO 切分、YOLOv8 训练评估最后落到一个复现高正确率的验证技巧。适合正在做智慧养殖、目标检测或行为识别落地的算法工程师和数据集生产者。2. 解构猪行为识别数据集COCO JSON 的类别、标注与统计2.1 四类行为标注的定义与数据分布行为识别的第一件事是定义“谁在干什么”。在本数据集中四类行为的标注口径并不仅看猪的静态姿态还会参考头部所在位置和运动状态喝猪的嘴部靠近饮水器或水槽头部有规律抬起下压动作吃嘴部位于料槽内伴随咀嚼有时前腿跨入料槽睡觉身体趴卧或侧躺头部贴地或闭眼持续数秒不动站立四腿支撑躯干直立移动或静止都算。从数据分布看站立往往占比最高因为猪在栏内的日常时间大量处于站立调温、观望状态睡觉次之喝和吃是短时行为数量相对少。表里是常见的数据分布形态具体数字以标注文件为准category_id行为类名典型姿态易混淆行为0drinking嘴部接触水嘴/水槽eating头部压低1eating嘴部在料槽内并咀嚼drinking头部位置低2sleeping卧倒、闭眼、持续静止standing四肢蜷缩3standing四肢支撑、身体直立eating低头时如果训练时发现类别严重不平衡常见做法是给少数类提高 loss 权重或者在图像增强阶段对包含 drinking/eating 的样本做随机裁剪复制让模型不会把所有矮姿态都判定成睡觉。2.2 用 Python 统计 COCO JSON 中的类别与框信息拿到 COCO JSON 后别急着灌进模型。先用一段脚本确认类别 ID 是否连续、单图标注密度是否合理。这里用纯 json 解析避免额外安装 pycocotoolsimport json from collections import Counter def inspect_coco(coco_path): with open(coco_path, r, encodingutf-8) as f: data json.load(f) cat_name {cat[id]: cat[name] for cat in data[categories]} ann_count Counter() img_annotations {img[id]: [] for img in data[images]} for ann in data[annotations]: ann_count[cat_name[ann[category_id]]] 1 img_annotations[ann[image_id]].append(ann) print(总图像数:, len(data[images])) print(总标注框数:, len(data[annotations])) print(每类标注数:, dict(ann_count)) print(平均每图标注数: {:.2f}.format( sum(len(v) for v in img_annotations.values()) / len(data[images]))) inspect_coco(pig_behavior_coco/annotations/instances_train.json)逻辑说明data[images]保存图片宽高data[annotations]里的 bbox 字段是[x, y, width, height]坐标原点在图像左上角单位是像素。代码先把 category_id 映射成可读名称再统计各类标注总数与单图密度。参数说明如果 annotation 文件很大可以考虑将 images/annotations 分别读入后用 image_id 建立索引而不是每次循环都遍历 imagesCOCO 官方推荐用 pycocotools 的 loadRes但在工程脚本里用字典索引更快。若打印出某类数量为 0说明标注文件类别不均衡或导出的 categories 字段没有包含该类需要回到标注工具里检查。2.3 用宽高比和面积评估小目标与长条框行为识别对框的形状也很敏感。卧睡的猪通常框宽而矮站立的猪框高而窄如果数据里这类极端长宽比过多模型对锚框尺寸的选择就需要相应调整。下面这段脚本可以输出 bbox 面积分布和长宽比分布import json from statistics import mean, median def bbox_stats(coco_path): with open(coco_path, r, encodingutf-8) as f: data json.load(f) areas, ratios [], [] for ann in data[annotations]: x, y, w, h ann[bbox] areas.append(w * h) ratios.append(w / h if h 0 else 0) print(平均框面积:, int(mean(areas))) print(框面积中位数:, int(median(areas))) print(宽高比中位数:, round(median(ratios), 3)) bbox_stats(pig_behavior_coco/annotations/instances_train.json)参考指标如果面积中位数小于整张图面积的 1%说明小目标比例高这时建议把 YOLO 的 imgsz 调到 1280或者用切片推理来召回漏检。宽高比中位数如果明显偏离 1说明大部分行为是卧倒姿态后续对锚框比例做针对性聚类会有效果。3. 用 CVAT 标注猪行为数据到 COCO JSON 并切分训练集3.1 CVAT 标注工具的标签配置与导出流程标注是数据集质量的最大变量。猪圈监控视频里猪只叠在一起单帧标注需要统一“哪个目标算有效”通常只标注身体面积超过 20×20 像素的猪且躯干可见度超过一半才打框被遮挡面积大于一半的猪不标或标为 ignore 类别。这里推荐使用开源标注工具 CVAT 做矩形框标注。操作流程按以下顺序创建项目在 Labels 里依次添加四个行为标签名称写成单数小写drinking、eating、sleeping、standing。创建任务时上传猪圈抓拍图片建议每张图包含不同光照、不同栏位确保行为模式多样。进入标注界面用矩形框圈住整头猪注意框不要刻意收得很贴身给头颈动作留出余量。对同一头猪连续多帧标注时保持框大小一致避免同一行为类别的框尺寸剧烈抖动。完成后点击导出任务数据集格式选 COCO JSON 1.0下载包解压后得到 annotations/instances_default.json 和 images 目录。导出后的 JSON 里licenses 和 info 字段会写默认值categories 通常按添加标签的顺序重新编号。一个常见坑是标签名为中文时导出文件会出现编码问题因此建议始终使用英文标签中文名称只写在备注里。如果你手头已经有 YOLO 矩形框的预标注结果可以在 CVAT 里用“自动标注”功能加载模型让人工只修正错误框这能明显缩短“吃/喝”这类小目标的标注工时。3.2 将 COCO JSON 转换为 YOLO 格式的数据划分脚本YOLOv8 训练时不直接读 COCO JSON它要求每个图像对应一个同名的 txt 文件每行是“类别 中心x归一化 中心y归一化 宽度归一化 高度归一化”。下面脚本把 COCO 标注按 8:1:1 划分并输出 YOLO 格式标签import json import random from pathlib import Path def coco_to_yolo_split(coco_json, output_dir, split_ratio(0.8, 0.1, 0.1)): with open(coco_json, r, encodingutf-8) as f: data json.load(f) cats {cat[id]: idx for idx, cat in enumerate(data[categories])} imgs {img[id]: img for img in data[images]} anns_by_img {} for ann in data[annotations]: anns_by_img.setdefault(ann[image_id], []).append(ann) img_ids list(imgs.keys()) random.seed(42) random.shuffle(img_ids) n len(img_ids) train_end int(n * split_ratio[0]) val_end train_end int(n * split_ratio[1]) split_map {train: img_ids[:train_end], val: img_ids[train_end:val_end], test: img_ids[val_end:]} for split_name, ids in split_map.items(): out_dir Path(output_dir) / split_name / labels out_dir.mkdir(parentsTrue, exist_okTrue) for img_id in ids: img_info imgs[img_id] stem Path(img_info[file_name]).stem with open(out_dir / f{stem}.txt, w, encodingutf-8) as f: for ann in anns_by_img.get(img_id, []): x, y, w, h ann[bbox] dw, dh img_info[width], img_info[height] cx (x w / 2) / dw cy (y h / 2) / dh f.write(f{cats[ann[category_id]]} {cx:.6f} {cy:.6f} {w/dw:.6f} {h/dh:.6f}\n) coco_to_yolo_split(instances_default.json, pig_dataset/labels)逻辑说明代码先建立 category_id 到连续索引的映射因为 YOLO 类别下标必须从 0 开始。随后把每个 image_id 对应的标注框换算成归一化中心坐标和宽高写入以图像名命名的 txt。划分时用随机种子固定顺序保证训练、验证、测试三部分没有重叠图像。参数说明split_ratio 三个数值按顺序对应 train/val/test如果只需要训练和验证可以设置 (0.9, 0.1, 0.0)。1272 张图按 8:1:1 大约得到如下划分数据集图像数按 8:1:1说明train1018用于模型参数学习val127用于调整超参数和早停test127用于最终正确率评估图像文件需要与 labels 目录保持同样的子目录结构pig_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/3.3 标注质量校验处理空标签与越界框转换完成后常见问题是某些图像没有任何标注但 train 目录里会有对应的空 txt。YOLO 训练会忽略空标签若空标签占比过高超过 5%模型容易把背景学成目标。建议用下面命令统计空标签数量find pig_dataset/labels/train -name *.txt -empty | wc -l如果统计结果偏大回到 COCO JSON 里检查是图片没有标注还是导出时丢失了 annotations。越界框也要处理COCO 允许框超出图像边界但 YOLO 归一化后坐标可能在 0 到 1 之外训练时容易报错。下面一段 Python 用来裁剪越界框到图像范围内再归一化def clamp_bbox(x, y, w, h, img_w, img_h): x2, y2 min(x w, img_w), min(y h, img_h) return max(x, 0), max(y, 0), x2 - max(x, 0), y2 - max(y, 0)对每张图像先读取宽高再用 clamp_bbox 修正最后写入 txt。这一步放在模型训练前能省掉大量“训练中途出现 nan”的排错时间。注意如果框被裁剪后面积小于原面积 30%建议直接丢弃该框因为它们通常是遮挡严重的伪标注。4. 基于 YOLOv8 训练猪行为识别模型的关键参数与评估4.1 配置 data.yaml 与模型选型行为识别在工程上通常拆成“检测帧级行为分类”YOLO 这类目标检测器天然适合这个任务。模型选型要看部署端算力边缘盒子用 YOLOv8n 或 YOLOv8s服务器训练可以上 YOLOv8m。下面是不同模型的参考对比具体数值会随数据分布变化模型参数量预期 mAP50 区间推理平台建议YOLOv8n3.2M0.80-0.88嵌入式设备YOLOv8s11.2M0.84-0.92工控机/单卡YOLOv8m25.9M0.86-0.94带 GPU 的服务器数据配置文件是训练入口建议放在数据集根目录下path: /data/pig_dataset train: images/train val: images/val test: images/test names: 0: drinking 1: eating 2: sleeping 3: standing逻辑说明path 指向包含 images 和 labels 的根目录train/val/test 使用相对 path 的子目录。第一次在本地跑通时使用绝对路径可以减少相对路径错误模型发布时再改为相对路径方便部署到其他机器。参数说明names 顺序必须和 3.2 转换脚本中 enumerate(data[categories]) 的顺序一致。如果 CVAT 导出的 classes 顺序是 drinking、eating、sleeping、standing那么这里固定不变训练中途不要随意改类别顺序否则会导致旧的 txt 标签全部错位。4.2 YOLOv8 训练命令与关键参数使用 YOLOv8 官方 CLI 训练自己的数据集命令如下yolo detect train \ datapig_behavior.yaml \ modelyolov8m.pt \ epochs150 \ imgsz1280 \ batch16 \ device0 \ patience30 \ project./runs \ namepig_behavior逻辑说明modelyolov8m.pt 会加载 COCO 预训练权重迁移学习能大幅缩短训练时间。epochs 设 150 是为了让“喝/吃/睡觉”这类细微姿态充分收敛patience30 表示验证集指标连续 30 轮不提升就早停。imgsz 从默认 640 提到 1280是因为猪圈图像中单头猪可能只占很小面积提高输入分辨率能直接提升小目标召回率。参数说明batch 根据 GPU 显存调整12GB 显存跑 1280 分辨率建议 batch824GB 可以到 16如果出现“CUDA out of memory”优先降低 batch、保留 imgsz因为低分辨率对行为识别的影响比小 batch 更致命。device0 使用第一块 GPU没有 GPU 可以改成 cpu但训练速度会慢很多。训练完成后权重保存在 runs/detect/pig_behavior/weights/best.pt。选择 best 而不是 last因为 best 保存的是验证集上 mAP 最高的那一轮。用下面的命令看训练曲线tensorboard --logdir runs/detect/pig_behavior4.3 评估指标正确识别率 92.6% 到底衡量什么多数目标检测项目用 mAP 代表精度而标题里的“平均正确识别率 92.6%”更像是对每个检测框做行为分类的准确率或者对每一帧图像做行为判别的准确率。两者口径完全不同复现时要先定清楚。如果按逐帧图像评估流程是先用检测器输出每个框的行为类别再与标注框做 IoU 匹配IoU≥0.5 的框计入分母将预测类别与真值类别一致才算正确。按逐实例评估则不需要考虑视频连续性。以下是一段计算逐实例行为准确率的演示代码import numpy as np def behavior_accuracy(pred_boxes, pred_cls, gt_boxes, gt_cls, iou_thr0.5): correct 0 total 0 # 这里用简单的一对一贪心匹配正式评估可用 pycocotools for pb, pc in zip(pred_boxes, pred_cls): best_iou, best_g 0, -1 for gi, (gb, gc) in enumerate(zip(gt_boxes, gt_cls)): iou compute_iou(pb, gb) if iou best_iou: best_iou, best_g iou, gi if best_iou iou_thr: total 1 if pc gt_cls[best_g]: correct 1 return correct / total if total 0 else 0逻辑说明该函数先用 IoU 把预测框匹配到真值框再比较类别是否一致。由于没有排除已经匹配过的真值框这里只是演示实际评估建议直接用 pycocotools 的 COCOeval它会处理多标签、IoU 阈值变化和平均 AP 指标。参数说明iou_thr 针对猪这种遮挡多的场景往往从 0.5 放宽到 0.4 更能反映实际可用性但对外报告精度时建议统一用 0.5否则数字不可比。如果你在自己的测试集上复现准确率低于 92.6%优先检查两部分一是验证集是否有与训练集同帧的图片二是标注类别是否错位。5. 复现 92.6% 正确率的验证技巧混淆矩阵与行为判定边界5.1 用混淆矩阵定位喝/吃/站立三类易混行为如果你在测试集上跑出的结果与 92.6% 有差距先不要急着调网络结构构建一份混淆矩阵往往能直接指出问题。喝和吃都是低头靠近食槽站立的猪低头也容易被判成喝。建议把测试集的预测结果整理成下面格式然后绘制混淆矩阵import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay y_true [...] # 真值行为类别id y_pred [...] # 模型预测行为类别id classes [drinking, eating, sleeping, standing] cm confusion_matrix(y_true, y_pred) disp ConfusionMatrixDisplay(cm, display_labelsclasses) disp.plot(cmapBlues, xticks_rotation45) plt.savefig(pig_behavior_cm.png, dpi150)该脚本不需要额外标注只要记录每个测试框的预测类别和真值类别即可。混淆矩阵中如果 eating 的行上出现大量 drinking说明两者在视觉特征上高度相似可以通过“观察持续帧数”做后处理喝水时头部会周期性抬起吃料时头部连续低位更久利用跟踪算法关联前后帧对短于 N 帧的 drinking 抖动做类别平滑能够把准确率再提高 23 个百分点。5.2 真正值得盯的两个验证细节第一测试集里不应出现训练集中同一段视频的连续帧。猪行为变化慢相邻帧高度相似如果切分时没有按视频时间戳分组验证集会虚高。常见做法是将视频按时间片段做分组再按组切分而不是按单帧随机切分。第二对小目标单独算一类准确率。把框面积小于 16×16 像素的检测结果单列统计如果这部分准确率低于 80%建议使用切片推理或在训练时加入 Mosaic 增强而不是整体调大模型。以上两个验证点做到位后再回头看 92.6% 这个数字它应该是在固定 IoU 阈值、固定类别顺序、固定测试集划分下的可复现结果。将这些判断规则写进后处理配合 YOLOv8 输出的类别置信度可以让模型在真实猪栏中更稳定。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

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