ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv7的猪只行为检测:从数据集构建到部署验证全流程

基于YOLOv7的猪只行为检测:从数据集构建到部署验证全流程 简介这份资源面向从事智慧养殖与计算机视觉的算法工程师、研究生及竞赛选手提供基于YOLOv7的养殖场生猪行为状态检测训练权重与配套数据集可直接用于猪只进食、站立、躺卧、攻击四类行为的识别任务解决从零采集标注数据成本高、模型难以快速复现的问题。压缩包共约2000个文件以1211个txt标签、680张jpg图像为主另含49个yaml配置、31个py脚本及多个ipynb实验笔记整体约608MB目录已按train、val、test划分并附data.yamlYOLOv5至YOLOv9等算法均可直接开训。目前已有244人学习下载。资源还包含TensorRT、ONNXRuntime动态批量推理及YOLOv7与YOLOv5多组对比实验笔记便于读者快速验证模型精度、复现训练流程并迁移到自有养殖场景。1. 猪只行为检测为什么值得用 YOLOv7 做一遍养殖场里最耗人力的活儿不是喂料是盯着猪看。一头猪从站立到躺卧、从采食到打架这些行为状态直接反映健康、发情和栏舍舒适度。传统做法靠饲养员巡栏记录一天走几万步数据还未必准。用视觉方案替代人工核心难点在于猪只互相遮挡严重、光照变化大、行为动作幅度小通用检测模型直接跑往往翻车。YOLOv7 在这个场景里被反复提起不是因为它最新而是它在单阶段检测器里对中小目标的召回和推理速度平衡得比较好训练权重和数据集也相对好找。这篇笔记面向想自己训一版猪只行为检测模型的工程师从数据集组织、权重加载、训练参数到部署前验证把能复现的路径和踩过的坑讲清楚。如果你手头有栏舍摄像头想跑通一个能识别站立、躺卧、采食、打架四类行为的检测器下面的内容可以直接照着做。2. 数据集怎么组织才能让 YOLOv7 吃得下2.1 猪只行为类别的定义与标注边界行为检测和普通目标检测最大的区别在于类别定义直接决定标注一致性。我一般把猪只行为收敛到四类站立、躺卧、采食、打架。站立和躺卧的边界在猪只侧躺但抬头时容易混淆标注规则要写死——以躯干主轴与地面夹角小于 30 度算躺卧大于 60 度算站立中间区间归入躺卧因为养殖场更关心是否长时间不起。采食限定为头部进入料槽区域且持续超过 2 秒打架限定为两头猪头部接触且伴随快速位移。标注时用矩形框而不是多边形原因是 YOLOv7 默认输出矩形框多边形标注转矩形会引入背景噪声反而拉低精度。每类至少准备 800 到 1200 个实例打架类如果样本少可以用数据增强里的马赛克和随机缩放补但不要用翻转猪只左右翻转后行为语义不变上下翻转会破坏躺卧和站立的视觉先验。2.2 从原始视频到 YOLO 格式的转换脚本拿到栏舍摄像头视频后先抽帧再标注。抽帧间隔按行为持续时间定采食和打架动作快建议每 5 帧抽一张站立和躺卧变化慢每 15 帧抽一张。抽完用 labelImg 或 CVAT 标导出 YOLO 格式。下面这个脚本把标注好的 xml 转成 YOLOv7 需要的 txt并生成训练集和验证集的路径文件。import os import xml.etree.ElementTree as ET import random # 类别映射顺序必须和训练时的 names 一致 CLASS_MAP {stand: 0, lie: 1, eat: 2, fight: 3} def xml_to_yolo(xml_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in CLASS_MAP: continue cls_id CLASS_MAP[cls_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) # YOLO 格式要求中心点和宽高都归一化到 0-1 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 lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return lines def build_dataset(img_dir, xml_dir, out_dir, val_ratio0.2): os.makedirs(out_dir, exist_okTrue) pairs [] for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue img_file xml_file.replace(.xml, .jpg) img_path os.path.join(img_dir, img_file) if not os.path.exists(img_path): continue # 这里假设图片尺寸统一实际项目里用 PIL 读真实尺寸 img_w, img_h 1920, 1080 lines xml_to_yolo(os.path.join(xml_dir, xml_file), img_w, img_h) if not lines: continue txt_name xml_file.replace(.xml, .txt) with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) pairs.append(img_file) random.shuffle(pairs) split int(len(pairs) * (1 - val_ratio)) with open(os.path.join(out_dir, train.txt), w) as f: f.write(\n.join([os.path.join(img_dir, p) for p in pairs[:split]])) with open(os.path.join(out_dir, val.txt), w) as f: f.write(\n.join([os.path.join(img_dir, p) for p in pairs[split:]])) print(ftrain: {split}, val: {len(pairs)-split}) if __name__ __main__: build_dataset(./images, ./annotations, ./labels)脚本里CLASS_MAP的顺序必须和后面训练配置文件里的names完全一致否则类别会错位。val_ratio控制验证集比例猪只行为数据建议留 20%因为打架类样本少验证集太小会导致评估指标波动大。图片尺寸我写死了 1920x1080实际用的时候改成从图片读不然标注框会偏。转换完检查一下 txt 里的数值有没有超过 1超过说明归一化算错了。2.3 数据集划分与类别不平衡的处理猪只行为数据天然不平衡躺卧和站立占 70% 以上打架可能不到 5%。直接训会让模型偏向多数类打架召回率极低。常见做法是在train.txt里对少数类样本重复采样或者用 YOLOv7 自带的--balance参数做类别加权。我一般先统计每个类别的实例数如果最多和最少差 10 倍以上就在数据加载阶段给少数类乘一个权重系数。权重不要超过 3否则模型会过拟合少数类。另外验证集必须保持原始分布不能也做重采样否则评估指标虚高部署到真实栏舍就翻车。3. 训练权重怎么选、怎么加载、怎么调3.1 预训练权重的来源与加载方式YOLOv7 官方发布的预训练权重是在 COCO 上训的直接拿来训猪只行为属于迁移学习。加载方式有两种一种是用--weights yolov7.pt让训练脚本自动加载骨干网络权重另一种是手动改cfg文件里的anchors和nc。我一般用第一种因为官方脚本会跳过类别数不匹配的输出层只加载 backbone 和 neck 部分。命令如下python train.py \ --weights yolov7.pt \ --cfg cfg/training/yolov7-custom.yaml \ --data data/pig_behavior.yaml \ --hyp data/hyp.scratch.custom.yaml \ --epochs 150 \ --batch-size 16 \ --img-size 640 640 \ --device 0 \ --workers 8 \ --name pig_behavior_v1--weights指向预训练权重--cfg里要把nc改成 4--data指向数据集配置文件。--hyp用自定义超参文件不要直接用默认的因为猪只行为场景的锚框尺寸和 COCO 差别大。--img-size设 640 是速度和精度的折中如果打架动作小可以提到 1280但显存要够。--batch-size根据显卡定16 是 8G 显存的安全值。--workers设成 CPU 核数的 2 倍数据加载才不会拖后腿。3.2 锚框重聚类与超参数调整COCO 的锚框是针对人、车、动物等通用目标猪只的宽高比更接近 1:1 到 2:1直接用会降低回归精度。训练前用 k-means 对标注框重新聚类生成 9 个锚框。下面这段代码读所有 txt 标注跑 k-means 输出新的 anchors。import numpy as np from sklearn.cluster import KMeans def load_boxes(label_dir): boxes [] for txt in os.listdir(label_dir): if not txt.endswith(.txt): continue with open(os.path.join(label_dir, txt)) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue _, _, _, w, h map(float, parts) boxes.append([w, h]) return np.array(boxes) def cluster_anchors(boxes, k9): kmeans KMeans(n_clustersk, random_state42).fit(boxes) centers kmeans.cluster_centers_ # 按面积排序YOLO 要求 anchors 从小到大 centers centers[np.argsort(centers[:, 0] * centers[:, 1])] return centers if __name__ __main__: boxes load_boxes(./labels) anchors cluster_anchors(boxes) for a in anchors: print(f{a[0]:.4f} {a[1]:.4f})聚类完把结果填到yolov7-custom.yaml的anchors字段。注意这里用的是归一化后的宽高填进去之前不用再乘 640。超参方面学习率初始值设 0.01用余弦退火降到 0.0001权重衰减 0.0005动量 0.937。如果训练 loss 震荡先把学习率降到 0.001 试。数据增强里马赛克概率设 0.5猪只场景里马赛克能提升遮挡鲁棒性但太高会让打架类样本被切碎反而学不到动作。3.3 训练过程监控与早停策略训练时看三个指标box_loss、obj_loss、cls_loss。正常情况三个都下降如果obj_loss不降反升说明锚框和真实框匹配差回去检查锚框聚类。cls_loss震荡大通常是类别不平衡加类别权重。验证集 mAP 连续 20 个 epoch 不提升就早停别硬训到 150 轮过拟合后部署效果更差。我一般把--patience设成 20YOLOv7 训练脚本里没有直接参数需要在train.py里加回调或者手动看results.txt决定什么时候停。训练完的权重在runs/train/pig_behavior_v1/weights/best.pt这个才是后面部署要用的。4. 避坑与排查猪只行为检测里最容易翻车的五件事4.1 现象训练 mAP 很高部署到新栏舍掉一半原因训练集和验证集来自同一批摄像头光照、角度、猪只品种都相似模型学到了背景捷径。解决训练时强制留一个不同栏舍的视频做测试集不参与训练。如果 mAP 掉超过 20%说明泛化差加随机亮度、对比度扰动或者用 CutMix 把不同栏舍的猪只拼到一起。4.2 现象打架行为几乎检不出来原因打架样本少且动作快抽帧间隔太大导致漏标。解决对打架片段用 2 帧间隔重新抽单独统计实例数如果不到 500用复制粘贴增强把打架猪只贴到其他背景上。另外把--img-size提到 1280小动作在 640 下特征太弱。4.3 现象躺卧和站立混淆严重原因标注边界模糊或者锚框宽高比不匹配。解决重新检查标注规则把夹角在 30 到 60 度之间的样本统一归到躺卧。锚框聚类时把这两类的框单独拿出来看如果宽高比集中在 1.5:1 左右说明锚框要调宽。4.4 现象训练 loss 正常但推理框乱飞原因data/pig_behavior.yaml里的nc和names数量不一致或者train.txt路径里有中文。解决检查 yaml 文件nc: 4对应四个类别名。路径全部用英文Windows 下尤其注意反斜杠转义。4.5 现象显存溢出batch 降到 4 还报错原因--img-size太大或者--workers太多导致内存泄漏。解决先把 img-size 降到 640workers 降到 4。如果还不行检查hyp文件里的mosaic和mixup是不是同时开了两个都开显存占用翻倍关掉 mixup。5. 部署前怎么验证模型真的能用训完best.pt别急着上生产先跑一遍验证脚本看混淆矩阵和 PR 曲线。混淆矩阵能看出哪两类互相误判PR 曲线看每个类别的召回和精度平衡点。我一般用test.py跑测试集命令如下python test.py \ --weights runs/train/pig_behavior_v1/weights/best.pt \ --data data/pig_behavior.yaml \ --img-size 640 \ --batch-size 8 \ --task val \ --name pig_behavior_eval跑完在runs/val/pig_behavior_eval/下看confusion_matrix.png。如果打架类的召回低于 0.6说明样本还是不够回去补数据。另外用几段没参与训练的栏舍视频做推理看连续帧的检测框有没有跳变。猪只行为是时序相关的单帧检测器会有闪烁部署时加一个简单的跟踪算法比如 ByteTrack把同一头猪的框关联起来再对轨迹做投票行为状态才稳定。这个方案值不值得做取决于你能不能接受 80% 左右的单帧精度加跟踪后处理。如果栏舍光照可控、猪只不密集YOLOv7 加跟踪能到 90% 以上可用性。我自己的习惯是任何检测模型上线前先拿一周的录像跑离线推理人工抽检 200 个片段算一下漏检和误检的实际业务影响再决定要不要调阈值。希望帮到你。本文还有配套的精品资源点击获取
返回列表