news 2026/10/5 4:01:04

猪行为识别数据集实战:从COCO标注到YOLOv8训练与部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
猪行为识别数据集实战:从COCO标注到YOLOv8训练与部署

简介:这份猪圈猪行为识别数据集面向智慧养殖、动物行为分析与计算机视觉方向的研究者及算法工程师,用于构建猪只日常行为自动监测模型,可识别喝水、进食、睡觉、站立等典型动作,平均正确识别率达92.6%,适合目标检测与行为分类任务的训练与验证。资源包共1275个文件,其中1272张jpg图像构成主要样本,另有3个json文件提供COCO格式标注,涵盖类别与边界框信息,压缩包整体约85.57MB,目录结构便于直接接入主流检测框架。目前已有214人学习下载,可作为养殖场景行为识别的实用数据基础。图像覆盖多段视频抽帧,包含不同光照与栏舍环境下的猪只姿态,标注规范统一,能帮助读者省去繁琐的数据采集与标注环节,快速投入模型训练、迁移学习与效果对比,也可用于验证算法在真实猪圈场景中的鲁棒性。

1. 猪圈里的猪行为识别数据集:1272 张图、92.6% 识别率,这套数据到底能不能直接上手

猪行为识别这件事,真正卡住人的从来不是模型结构,而是数据。你打开 GitHub 想找一个能直接用的猪行为识别数据集,翻到的要么是几十张图的 demo,要么是只有检测框没有行为标签的半成品,要么标注格式跟你的训练框架对不上。这个数据集的价值就在于它把三件事同时做完了:1272 张真实猪圈场景图片、覆盖喝/吃/睡觉/站立等核心行为类别、标注格式是 coco json。平均正确识别率 92.6% 这个数字,放在实际猪圈光照不均、猪只互相遮挡的条件下,已经属于能落地的水平。它适合两类人:一类是想做智慧养殖行为识别但苦于没有标注数据的算法工程师,另一类是手里有猪场摄像头画面、想把行为统计跑起来但不想从零标数据的落地团队。下面我按「数据长什么样 → 怎么转成训练格式 → 怎么训 → 坑在哪」的顺序,把这条路走一遍。

2. 先看清数据:coco json 里到底存了什么,1272 张图够不够训

2.1 coco json 的结构与行为类别的映射关系

拿到一个 coco json 格式的数据集,第一件事不是急着写 dataloader,而是把 json 拆开看 categories 和 annotations 两个字段。coco 的结构是固定的:images 数组存每张图的文件名、宽高、id;annotations 数组存每个标注的 bbox、category_id、image_id;categories 数组存类别 id 和类别名。猪行为识别数据集的关键在于 categories 里到底有哪几类。按标题描述,至少包含喝、吃、睡觉、站立四类,实际拿到后你要确认是否还有「行走」「打架」「拱地」等扩展类。

import json with open("pig_behavior/annotations/instances_train.json", "r") as f: data = json.load(f) # 看类别定义 for cat in data["categories"]: print(cat["id"], cat["name"]) # 统计每类标注数量 from collections import Counter cat_counter = Counter(ann["category_id"] for ann in data["annotations"]) for cid, cnt in cat_counter.items(): name = next(c["name"] for c in data["categories"] if c["id"] == cid) print(f"{name}: {cnt} 个标注框") # 看图片总数和尺寸分布 print("图片总数:", len(data["images"])) sizes = [(img["width"], img["height"]) for img in data["images"]] print("尺寸样例:", sizes[:5])

这段代码做三件事:打印类别名、统计每类标注框数量、看图片尺寸分布。逻辑很直白,但输出结果决定了你后面所有决策。如果某一类标注框数量不到总数的 5%,比如「喝」只有 40 个框,那训练时这一类几乎必然欠拟合,需要考虑过采样或数据增强。参数上注意 category_id 不一定从 0 连续,coco 允许跳号,写映射表时别用列表下标去取类别名。

2.2 1272 张图在行为识别任务里算什么量级

1272 张图放在目标检测里不算多,但放在猪行为识别这个垂直场景里,要分情况看。如果四类行为分布均匀,每类大约 300 张图对应的标注,配合迁移学习和强增强,训一个能用的模型是够的。但如果你的猪圈场景和数据集采集场景差异大——比如数据集是保育舍、你要用在中大猪舍——那 1272 张图的泛化能力会明显吃紧。

我一般会先做一个场景相似度检查:从数据集里抽 20 张图,和自己摄像头截 20 张图放一起,肉眼看光照、地面材质、猪只品种、摄像头角度四个维度。如果超过两个维度差异明显,就要么补采数据,要么在训练时加大颜色抖动和随机裁剪的强度。1272 张图的价值不在于数量本身,而在于它省掉了你从零标注的时间——按一张图 30 秒标注算,1272 张就是 10 个工时以上,这还没算质检返工。

2.3 行为识别和普通目标检测的区别在哪

很多人拿到这个数据集第一反应是当普通检测任务训,这是最大的认知偏差。猪行为识别里,「睡觉」和「站立」的视觉差异可能只是身体长宽比和姿态角度的细微变化,而「吃」和「喝」的差异可能只在于头部朝向料槽还是水嘴。这意味着单纯靠 bbox 回归,模型很难区分这些类间差异极小的行为。

常见做法是两条路:一条是把行为识别当细粒度分类做,在检测框基础上加一个分类头,用 RoI Align 提取特征再分类;另一条是直接上姿态估计,先定位猪只关键点,再根据关键点几何关系判断行为。前者实现简单、和 coco 格式兼容好,后者精度上限高但需要关键点标注,这个数据集不一定有。我一般先用第一条路跑 baseline,看混淆矩阵里哪两类最容易混,再决定要不要上姿态。

3. 把 coco json 转成 YOLO 格式:转换脚本与四个边界坑

3.1 转换脚本:从 coco bbox 到 YOLO txt

YOLO 系列训练需要的是每张图一个 txt,每行格式为class_id x_center y_center width height,且坐标要归一化到 0-1。coco 的 bbox 格式是[x_min, y_min, width, height]绝对像素值,转换时要做两步:先算中心点,再除以图片宽高归一化。

import json import os def coco_to_yolo(json_path, img_dir, out_dir): with open(json_path) as f: data = json.load(f) # 建立 image_id -> (filename, width, height) 映射 img_info = {img["id"]: img for img in data["images"]} # 建立 category_id -> 连续 class_id 映射 cat_ids = sorted(c["id"] for c in data["categories"]) cat2cls = {cid: i for i, cid in enumerate(cat_ids)} os.makedirs(out_dir, exist_ok=True) # 按 image_id 聚合标注 from collections import defaultdict ann_by_img = defaultdict(list) for ann in data["annotations"]: ann_by_img[ann["image_id"]].append(ann) for img_id, anns in ann_by_img.items(): info = img_info[img_id] w, h = info["width"], info["height"] lines = [] for ann in anns: x, y, bw, bh = ann["bbox"] # 过滤掉宽高为 0 的脏标注 if bw <= 0 or bh <= 0: continue xc = (x + bw / 2) / w yc = (y + bh / 2) / h nw = bw / w nh = bh / h # 裁剪到 [0,1] 防止越界 xc, yc = min(max(xc, 0), 1), min(max(yc, 0), 1) nw, nh = min(nw, 1), min(nh, 1) cls = cat2cls[ann["category_id"]] lines.append(f"{cls} {xc:.6f} {yc:.6f} {nw:.6f} {nh:.6f}") # 没有有效标注的图不生成空文件 if lines: name = os.path.splitext(info["file_name"])[0] + ".txt" with open(os.path.join(out_dir, name), "w") as f: f.write("\n".join(lines)) coco_to_yolo("pig_behavior/annotations/instances_train.json", "pig_behavior/images/train", "pig_behavior/labels/train")

逻辑说明:先建两个映射表,一个是 image_id 到图片信息的映射,一个是 category_id 到连续 class_id 的映射。coco 的 category_id 可能不连续,YOLO 要求 class_id 从 0 开始连续,所以必须重映射。然后按 image_id 聚合标注,逐条转换坐标。参数上注意三点:一是过滤宽高为 0 的脏标注,这种标注在 coco 里合法但在 YOLO 里会导致 NaN;二是坐标裁剪到 0-1,有些标注框会超出图片边界;三是没有有效标注的图不生成空 txt,否则训练时会被当成负样本。

3.2 四个边界坑:越界框、空标注、类别跳号、文件名不匹配

第一个坑是越界框。coco 允许 bbox 超出图片边界,比如 x_min 为负、x_min+width 大于图片宽。转换后 x_center 可能小于 0 或大于 1,YOLO 训练时直接报错或产生异常梯度。解决就是在转换时做 clamp,上面代码已经处理。

第二个坑是空标注图。有些图片在 coco 里没有任何 annotation,转换后不生成 txt 文件。但 YOLO 训练时如果图片目录里有图而 labels 目录里没有对应 txt,不同版本行为不一致,有的跳过有的报错。稳妥做法是给空标注图生成一个空 txt 文件,或者干脆把这类图从训练集里移走。

第三个坑是类别跳号。比如 categories 里 id 是 1、3、5、7,你直接用 id 当 class_id,YOLO 会认为有 8 个类,中间几个类永远没有样本。必须用 sorted 后重新映射,上面代码的 cat2cls 就是干这个的。

第四个坑是文件名不匹配。coco 的 file_name 可能带路径前缀或扩展名不一致,比如 json 里写的是images/001.jpg而实际文件是001.JPG。转换脚本里用os.path.splitext去扩展名时要注意大小写,最好先统一转小写再比对。

提示:转换完成后,抽 5 张图用可视化脚本把 YOLO txt 画回图上,肉眼确认框和类别都对。这一步花 5 分钟,能省掉后面几小时的排查。

3.3 数据集划分:训练集、验证集、测试集怎么分才不泄漏

1272 张图怎么分?常见做法是 8:1:1,即训练 1017、验证 127、测试 128。但猪行为识别有个特殊点:同一个猪圈、同一批猪、同一时间段采集的图片高度相似,如果随机划分,训练集和验证集里可能有几乎一样的图,验证指标虚高。

我一般按采集批次或摄像头编号做分组划分,同一批次的图要么全在训练集要么全在验证集。如果数据集没有批次信息,就按文件名前缀或时间戳排序后分段划分。这样验证指标虽然会低一些,但更接近真实部署时的表现。测试集建议单独留一个猪圈的数据,用来评估跨场景泛化能力。

4. 用 YOLOv8 训练猪行为识别:参数怎么设、指标怎么看

4.1 环境准备与数据配置文件

YOLOv8 的训练入口是yolo detect train,数据配置用一个 yaml 文件描述。假设你已经把 coco json 转成了 YOLO 格式,目录结构是 images/train、images/val、labels/train、labels/val。

# pig_behavior.yaml path: /data/pig_behavior train: images/train val: images/val test: images/test names: 0: drink 1: eat 2: sleep 3: stand

names 的顺序必须和转换脚本里 cat2cls 的映射一致,否则类别全错。path 用绝对路径,train/val 用相对路径,这是 YOLOv8 的约定。如果类别不止四类,按实际顺序往下加。

4.2 训练命令与关键参数

yolo detect train \ data=pig_behavior.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ augment=True \ mosaic=1.0 \ mixup=0.1 \ degrees=10 \ translate=0.1 \ scale=0.5 \ fliplr=0.5 \ name=pig_behavior_v8s

参数说明:model 选 yolov8s 而不是 yolov8n,是因为行为识别类间差异小,n 模型容量不够容易欠拟合;如果显存紧张可以降到 yolov8n 但 mAP 会掉几个点。epochs 设 150 配合 patience=30,意思是 30 轮验证指标不提升就早停,避免过拟合。lr0=0.01 是初始学习率,lrf=0.01 是最终学习率系数,余弦退火到初始的 1%。mosaic=1.0 开启马赛克增强,对遮挡场景帮助大;mixup=0.1 轻度混合,再高会模糊行为边界。degrees=10 做小角度旋转,猪圈摄像头一般不会大角度倾斜,所以不要设太大。

4.3 看指标:mAP50 够不够,混淆矩阵才是关键

训练完看 results.csv,重点看 metrics/mAP50 和 metrics/mAP50-95。92.6% 这个识别率如果对应的是 mAP50,那属于正常水平;如果对应的是 accuracy,那要看是 Top-1 还是加权平均。但指标只是参考,真正要看的是混淆矩阵。

from ultralytics import YOLO import matplotlib.pyplot as plt model = YOLO("runs/detect/pig_behavior_v8s/weights/best.pt") metrics = model.val(data="pig_behavior.yaml") # 打印每类 AP for i, name in enumerate(["drink", "eat", "sleep", "stand"]): print(f"{name}: AP50={metrics.box.ap50[i]:.3f}") # 混淆矩阵会保存到 runs/detect/val/confusion_matrix.png

如果「吃」和「喝」互相混淆严重,说明模型没学到头部朝向和料槽/水嘴的关联。这时候两个方向:一是补采这两个行为的边界样本,比如猪头半抬半低的过渡帧;二是加一个姿态分支,用关键点辅助分类。如果「睡觉」和「站立」混淆,通常是俯拍角度下身体长宽比接近,可以尝试加大 scale 增强或换更高分辨率输入。

注意:验证集指标高不代表部署效果好。一定要用测试集,而且测试集最好是不同猪圈的数据,才能看出真实泛化能力。

5. 避坑与排查:猪行为识别训练里最容易翻车的五件事

5.1 现象:训练 loss 正常下降但验证 mAP 一直上不去

原因通常是数据泄漏或验证集分布和训练集太像。如果按随机划分,同一头猪的连续帧可能同时出现在训练和验证集,模型记住了猪的花纹而不是行为。解决是按批次或摄像头分组划分,确保验证集的猪和训练集的猪不重叠。另一个原因是类别不平衡,某一类样本太少,模型倾向于预测多数类。解决是对少数类过采样或在 loss 里加类别权重。

5.2 现象:模型在白天图片上表现好,夜间红外图片上全错

原因是数据集的 1272 张图如果全是白天可见光,模型学到的特征高度依赖颜色和纹理,夜间红外图是灰度且纹理不同,直接翻车。解决是在训练时加颜色抖动、随机灰度化增强,让模型对颜色不敏感。如果夜间数据能采到,哪怕只有几十张,混进训练集做微调效果也很明显。常见做法是先用白天数据训 baseline,再用少量夜间数据 fine-tune 最后几层。

5.3 现象:同一张图里多头猪,标注框互相重叠,NMS 后漏检

原因是猪只密集时 bbox 重叠度高,标准 NMS 的 IoU 阈值设 0.5 会把相邻猪的框误删。解决是把 NMS IoU 阈值调到 0.6-0.7,或者改用 Soft-NMS。另外可以在训练时开启 mosaic 增强,让模型见过更多密集场景。如果漏检集中在边缘猪只,检查图片是否有裁剪导致猪只不完整,不完整的样本建议从训练集剔除。

5.4 现象:转换后的 YOLO 标签里出现坐标大于 1 或小于 0

原因是 coco 原始标注有越界框,转换时没做 clamp。上面转换脚本里已经加了min(max(xc, 0), 1),但如果你的脚本没加,训练时 YOLOv8 会直接报错或静默丢弃这些框。排查方法是写个脚本扫一遍所有 txt,找出坐标越界的行,然后回溯到 coco json 里看原始 bbox。解决就是在转换阶段统一 clamp,不要等到训练时报错才处理。

5.5 现象:训练完模型在测试集上 mAP 还行,但实际部署时帧率只有几 FPS

原因是模型选大了或输入分辨率太高。yolov8s 在 640 输入下,中端 GPU 能到 100+ FPS,但如果部署在边缘设备如 Jetson Nano,可能只有几 FPS。解决是导出 ONNX 或 TensorRT 做推理加速,或者换 yolov8n 并降低输入到 416。另一个原因是预处理用了 Python 循环而不是批量处理,部署时用 DataLoader 的 batch 推理能提升吞吐。猪行为识别不需要每帧都推理,隔几帧跑一次完全够用,行为变化是以秒为单位的。

6. 让 92.6% 再往上走:时序平滑与行为统计的落地技巧

单帧识别率 92.6% 听起来不错,但实际部署时你会发现,猪的行为是连续的,单帧抖动会导致统计结果跳变。比如猪在吃料时偶尔抬头,单帧模型可能判成「站立」,如果按帧统计,吃料时长就被切碎了。我一般会在检测后加一层时序平滑,用滑动窗口投票或卡尔曼滤波稳定行为标签。

from collections import deque, Counter class BehaviorSmoother: def __init__(self, window=15, min_votes=8): self.window = window self.min_votes = min_votes self.buffer = deque(maxlen=window) def update(self, behavior): self.buffer.append(behavior) if len(self.buffer) < self.window: return behavior # 滑动窗口投票,取出现次数最多的行为 cnt = Counter(self.buffer) top, votes = cnt.most_common(1)[0] # 票数不够则保持上一帧结果,避免频繁跳变 if votes >= self.min_votes: return top return self.buffer[-2] if len(self.buffer) > 1 else behavior smoother = BehaviorSmoother(window=15, min_votes=8) # 假设每帧检测结果依次传入 for frame_behavior in ["eat", "eat", "stand", "eat", "eat", "eat", "eat", "eat", "eat", "eat", "eat", "eat", "eat", "eat", "eat"]: stable = smoother.update(frame_behavior) print(frame_behavior, "->", stable)

这段代码的逻辑是:维护一个长度 15 的滑动窗口,每帧把检测结果放进去,当窗口满时统计出现次数最多的行为,且票数要达到 8 票才切换,否则保持上一帧结果。参数 window 和 min_votes 需要根据实际帧率调:如果摄像头 25 FPS,15 帧约 0.6 秒,适合行为切换不频繁的场景;如果行为切换快,窗口要缩短到 8-10 帧。min_votes 设太高会导致响应迟钝,设太低则平滑无效,一般取窗口的 50%-60%。

另一个落地技巧是行为统计的边界处理。猪的行为往往有过渡态,比如从站到卧的中间过程,模型可能判成「睡觉」或「站立」都不对。我一般会在统计时设一个最短持续时间阈值,比如某个行为连续出现少于 3 秒就不计入统计,这样能过滤掉过渡态的误判。统计输出按小时聚合,生成每头猪的采食时长、饮水次数、躺卧时长,这些才是养殖场真正关心的指标。

最后说个血泪经验:别追求单帧 99% 的识别率,那在猪圈场景里不现实。把精力花在时序平滑和统计逻辑上,让最终的行为时长统计误差控制在 5% 以内,比单帧指标提升两个点有价值得多。我见过太多团队卡在调模型上,结果部署时发现统计逻辑没做,数据根本没法用。先把 pipeline 跑通,再回头优化模型,这个顺序别搞反。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/5 4:00:59

卷积神经网络结合空间金字塔池化的肝脏肿瘤检测实战解析

简介&#xff1a;《基于卷积神经网络的肝脏肿瘤检测算法及应用研究》是一份面向医学图像处理、深度学习与计算机视觉从业者的学术论文PDF。资源围绕肝脏肿瘤CT图像检测这一临床痛点&#xff0c;介绍了基于VGG16网络结构改进的CNN检测模型&#xff0c;通过设计4个卷积层、4个池化…

作者头像 李华
网站建设 2026/10/5 4:00:59

HBM带宽如何决定AI智能体并发上限

1. 项目概述&#xff1a;HBM不是内存&#xff0c;是AI大模型的“供血系统”你可能已经听过太多次“HBM”这个词——在GPU发布会PPT里、在AI芯片白皮书里、在服务器采购清单里&#xff0c;它总和“带宽”“堆叠”“TSV”这些词一起出现。但真正理解它的人不多&#xff1a;HBM&am…

作者头像 李华
网站建设 2026/10/5 4:00:59

OpenLayers Map.js源码解析:渲染循环与坐标转换的核心机制

如果要在OpenLayers里挑一个必须先读的源码文件&#xff0c;我的答案永远是ol/Map.js。很多人在项目里用了很久OpenLayers&#xff0c;API文档翻得滚瓜烂熟&#xff0c;但遇到"地图为什么白屏"、"为什么坐标偏了"、"为什么某个交互不生效"这种问…

作者头像 李华
网站建设 2026/10/5 3:59:33

应急故障修复系统replace补题:AC自动机反转匹配与贪心覆盖详解

这份 U652449 应急故障修复系统&#xff08;replace&#xff09;补题报告&#xff0c;我拖了两周才写完。比赛时看到“应急故障修复系统”这个名字&#xff0c;我以为是模拟题&#xff0c;等看到题面里的 replace 又觉得是字符串替换签到题&#xff0c;结果 TLE 了整整四发。下…

作者头像 李华
网站建设 2026/10/5 3:59:25

雅思写作高分核心:从逻辑链到论证训练的完整方法

你有没有见过这样的学生&#xff1a;词汇书背了好几轮&#xff0c;长难句也练得不少&#xff0c;考场上觉得自己“写得挺顺”&#xff0c;结果雅思写作分数出来还是5.5&#xff0c;甚至5.0。我以前批改学生作文时&#xff0c;也经常看到这类情况——语法错误不算多&#xff0c;…

作者头像 李华
网站建设 2026/10/5 3:59:01

知识蒸馏压缩人脸关键点检测模型:从98MB到1.8MB的工程实践

简介&#xff1a;本资源为一份本科毕业设计级别的Python项目源码&#xff0c;主题是结合知识蒸馏训练人脸关键点检测的极小模型&#xff0c;面向计算机、人工智能、通信工程、自动化等专业的在校学生与教师&#xff0c;也适合希望入门模型压缩与轻量化部署的学习者&#xff0c;…

作者头像 李华