
简介这份目标检测猪群数据集面向从事计算机视觉与深度学习的学习者和开发者尤其适合正在实践Faster R-CNN、YOLO、SSD等检测模型、需要真实农业场景数据练手的人群。数据集聚焦猪群识别与定位可服务于农业监控、动物健康监测、农场数量统计等应用方向帮助解决真实场景下目标检测训练样本不足的问题。压缩包共2000个文件以1448张jpg原始图像和1448个xml标注文件为主整体约31.79MB图像用于模型特征学习xml由labelimg生成记录每张图中猪群的边界框坐标与类别标签二者一一对应构成可直接投入训练的标注数据。目录按Annotations、JPEGImages等模块组织结构清晰便于快速接入主流检测框架。目前已有767人学习下载适合希望从数据标注到模型训练完整走通一遍目标检测流程的读者参考使用。1. 猪群目标检测数据集从“猪脸识别”到“数猪”的落地真相猪场里装摄像头不稀奇稀奇的是让算法真正数清楚栏里到底有几头猪。目标检测猪群数据集解决的就是这个问题把猪的个体、姿态、遮挡关系标注成机器能学的格式让模型在复杂猪舍环境下输出每头猪的边界框。它适合三类人做智慧养殖的算法工程师、需要复现论文的在校研究生、以及想用 YOLO 系列跑通第一个垂直场景的零基础开发者。和 COCO、VOC 这类通用数据集不同猪群数据集的难点不在类别多而在目标密集、互相遮挡、光照极端、排泄物干扰——这些才是决定模型能不能上生产的关键。我见过太多人拿公开数据集训出 0.9 的 mAP一进真实猪舍就掉到 0.4问题几乎都出在数据分布而不是模型结构上。这一篇就把从数据获取、标注、格式转换到训练调参的完整链路拆开讲能抄的代码直接给踩过的坑也一并说清楚。2. 猪群数据集从哪来采集、标注与格式选型2.1 公开数据集与自采集的取舍目前公开的猪群检测数据集规模普遍偏小常见的是几百到几千张的固定摄像头视角图像标注以边界框为主部分带行为标签。如果你只是做算法验证公开数据集够用但要落地到具体猪场自采集几乎是绕不开的。自采集的核心不是买多贵的摄像头而是固定安装高度和俯角。我一般用 2.8mm 到 4mm 焦距的枪机安装在栏舍上方 2.5 到 3 米俯角 30 到 45 度这样能最大程度减少猪只之间的完全遮挡。分辨率建议 1920×1080 起步帧率不用高抽帧到 1 到 2 fps 就够因为猪的活动速度远低于车辆行人。采集时要注意时间跨度。只采白天的数据模型一到晚上就废。常见做法是连续采集 7 天覆盖早中晚三个时段每个时段至少 2 小时。如果猪舍有红外补光夜间图像会是灰度图这时候要么单独标注一批灰度数据要么在训练时做强灰度增强。别指望模型自己学会跨模态血泪经验是灰度图和彩色图混训mAP 会掉 5 到 10 个点。2.2 标注规范什么该标什么不该标猪群标注最容易翻车的地方是“标不标重叠猪”。我的原则是可见面积超过 30% 就标低于 30% 的归为“忽略区域”在标注文件里用特定类别或直接不标但记录在案。如果全部硬标模型会学到大量模糊边界导致推理时框抖动如果全不标召回率又上不去。实操中我会在 LabelImg 或 CVAT 里把遮挡严重的猪标成pig_ignore类训练时通过损失函数屏蔽掉。另一个坑是类别定义。如果你只做“数猪”一个pig类就够了。但如果要做行为分析比如区分“站立”“躺卧”“进食”那就得在标注时同时记录姿态。建议初期只标边界框行为标签用单独的分类模型做别把检测和分类混在一个头里否则标注成本翻倍模型也难收敛。2.3 格式转换VOC 转 YOLO 的脚本与边界坑公开数据集很多是 VOC 格式的 XML而 YOLO 系列吃的是归一化后的 txt。转换脚本网上一搜一大把但真正跑起来总会遇到边界问题。下面这个脚本是我用了三年的版本处理过猪群、牛羊、鸡鸭多种场景重点是加了越界裁剪和空文件过滤。import xml.etree.ElementTree as ET import os from pathlib import Path def voc_to_yolo(xml_dir, img_dir, out_dir, classes): xml_dir: VOC标注文件夹 img_dir: 对应图片文件夹用于读取宽高 out_dir: 输出YOLO txt文件夹 classes: 类别列表如 [pig] os.makedirs(out_dir, exist_okTrue) for xml_file in Path(xml_dir).glob(*.xml): tree ET.parse(xml_file) root tree.getroot() # 读取图片尺寸优先从XML里取取不到再从图片读 size root.find(size) if size is not None: w int(size.find(width).text) h int(size.find(height).text) else: from PIL import Image img_path Path(img_dir) / (xml_file.stem .jpg) with Image.open(img_path) as im: w, h im.size lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 越界裁剪这是猪群数据最常见的坑 x1 max(0, min(x1, w)) y1 max(0, min(y1, h)) x2 max(0, min(x2, w)) y2 max(0, min(y2, h)) if x2 x1 or y2 y1: continue # 过滤无效框 # 归一化YOLO格式为中心点宽高 cx (x1 x2) / 2.0 / w cy (y1 y2) / 2.0 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) if lines: # 只有非空才写文件 out_path Path(out_dir) / (xml_file.stem .txt) out_path.write_text(\n.join(lines)) # 调用示例 voc_to_yolo(annotations/, images/, labels/, [pig])这段代码的关键在越界裁剪和空文件过滤。猪群数据里经常出现标注框超出图像边界的如果不裁剪归一化后坐标会小于 0 或大于 1YOLO 训练时直接报错或产生 NaN。另外有些图片可能一张猪都没有转换后是空 txt如果保留会导致训练时正负样本失衡建议直接跳过。参数上classes列表的顺序必须和后续训练配置文件里的names完全一致差一个顺序模型就学歪。3. 用 YOLOv8 训练猪群检测配置、参数与显存控制3.1 环境配置与数据组织YOLOv8 的环境配置已经被说烂了但猪群场景有几个特殊点。首先是 Python 版本建议 3.8 到 3.10太高了有些标注库不兼容。CUDA 版本跟着显卡走30 系卡用 11.7 或 11.8 都行。安装命令就一行pip install ultralytics opencv-python pillow数据组织按 YOLO 的标准来dataset/ images/ train/ val/ labels/ train/ val/然后写一个pig.yamlpath: /home/user/dataset train: images/train val: images/val names: 0: pig这里有个容易忽略的点path最好用绝对路径相对路径在不同工作目录下跑会找不到文件。另外猪群数据的训练集和验证集划分不能随机分要按摄像头或时间段分。随机分会导致同一头猪的相邻帧同时出现在训练和验证集里验证指标虚高实际部署就露馅。3.2 训练参数从 batch size 到学习率的实操设置猪群检测的显存占用比通用目标检测高因为单张图里猪的数量可能几十头正样本多梯度大。8GB 显存跑 YOLOv8sbatch8是安全线imgsz640。如果显存够batch16能更稳。学习率用默认的0.01配合余弦退火就行但猪群数据如果很少低于 2000 张建议降到0.001否则容易过拟合。yolo detect train \ datapig.yaml \ modelyolov8s.pt \ epochs200 \ imgsz640 \ batch8 \ lr00.01 \ lrf0.01 \ patience50 \ augmentTrue \ mosaic1.0 \ mixup0.1 \ degrees10 \ translate0.1 \ scale0.5 \ fliplr0.5 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4参数说明mosaic1.0是 YOLOv8 默认开启的对猪群密集场景很有用能合成更多遮挡样本。mixup0.1别开太高猪群图像混叠后语义太乱。degrees10做小角度旋转因为摄像头安装一般不会歪太多。hsv_s0.7和hsv_v0.4是颜色增强对猪舍光照变化大的场景很关键。patience50表示 50 轮没提升就早停省时间。训练过程中重点看metrics/mAP50-95和val/box_loss。如果box_loss震荡不降大概率是学习率太高或标注框质量差。如果mAP50很高但mAP50-95很低说明框的位置不够准检查标注是否贴合猪体边缘。3.3 推理与部署从 PyTorch 到 ONNX 的加速训练完的best.pt直接推理就行from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model(test.jpg, conf0.4, iou0.5) for r in results: boxes r.boxes for box in boxes: cls int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(fpig {conf:.2f} at {xyxy})conf0.4是猪群场景的经验值太低会误检栏杆、食槽太高会漏掉遮挡猪。iou0.5用于 NMS猪群密集时 NMS 容易把相邻猪框合并可以适当提高到 0.6 到 0.7但太高会保留重复框。部署到边缘设备建议导出 ONNXyolo export modelbest.pt formatonnx opset12 simplifyTrueopset12兼容性好simplifyTrue会做图优化。导出后在 TensorRT 或 OpenVINO 上跑1080p 图像在 Jetson Xavier 上能到 30fps 以上够实时数猪了。4. 猪群检测避坑与排查标注、训练、部署的五个翻车现场4.1 现象模型把食槽和猪一起框进去原因标注时偷懒把食槽边缘和猪体一起标了模型学到了错误的上下文关联。猪群数据里食槽、水嘴、栏杆和猪的像素距离很近标注不精细就会污染。解决重新标注严格贴合猪体可见轮廓。如果食槽遮挡严重把该猪标为忽略区域。训练时开启rectTrue做矩形推理减少 padding 带来的干扰。4.2 现象夜间红外图像漏检严重原因训练集全是彩色图模型没学过灰度分布。红外图像对比度低猪体边缘模糊和背景的纹理差异小。解决采集夜间红外数据至少占训练集 20%。训练时加hsv_h0、hsv_s0、hsv_v0.5的强灰度增强或者直接把彩色图转灰度做增广。如果红外补光不均匀先做 CLAHE 直方图均衡再送模型。4.3 现象验证集 mAP 0.9实际部署掉到 0.5原因训练集和验证集随机划分同一头猪的相邻帧同时出现在两边模型记住了猪的花纹而不是学会了检测。这是猪群数据集最隐蔽的坑。解决按摄像头编号或时间段划分确保验证集的猪和训练集的猪不重叠。如果只有一个摄像头按天划分训练用前 5 天验证用后 2 天。重新划分后 mAP 会降但那个数字才是真实的。4.4 现象训练到一半 loss 变成 NaN原因标注框越界或宽高为 0归一化后出现非法值。猪群数据里常见于猪只部分出画的情况。解决用第 2 章的转换脚本做越界裁剪和空框过滤。训练前跑一遍数据校验import numpy as np from pathlib import Path for txt in Path(labels/train).glob(*.txt): data np.loadtxt(txt, ndmin2) if data.size 0: continue assert np.all(data[:, 1:] 0) and np.all(data[:, 1:] 1), f越界: {txt} assert np.all(data[:, 3:] 0), f宽高为0: {txt}4.5 现象ONNX 推理结果和 PyTorch 不一致原因导出时opset版本不对或者预处理没对齐。YOLOv8 导出 ONNX 后输入需要是 RGB、归一化到 0-1、维度 NCHW。很多人直接拿 OpenCV 的 BGR 图送进去结果框全偏。解决导出时加simplifyTrue推理时严格按1/255.0归一化并做 BGR 到 RGB 转换。用onnxruntime跑一遍和 PyTorch 对比IoU 差异超过 0.01 就检查预处理。5. 猪群检测的进阶技巧用热力图和特征图验证模型到底在看哪训练完模型别只看 mAP那个数字会骗人。我习惯用热力图和特征图做一次“模型体检”看看它到底在关注猪的哪个部位。如果热力图集中在猪背上说明模型学到了猪的纹理如果集中在食槽或地面那模型就是靠上下文作弊换个猪舍就废。具体做法是用 YOLOv8 的 hook 抓中间层特征然后叠加到原图上。下面这段代码抓的是最后一个 C2f 层的输出做通道平均后归一化import cv2 import numpy as np import torch from ultralytics import YOLO model YOLO(best.pt) model.model.eval() # 注册hook抓特征 features [] def hook_fn(module, input, output): features.append(output.detach().cpu()) # 假设第9层是感兴趣的C2f层实际层号用model.model打印确认 handle model.model.model[9].register_forward_hook(hook_fn) img cv2.imread(test.jpg) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) results model(img_rgb, conf0.4) handle.remove() # 取特征图通道平均 feat features[0][0] # [C, H, W] heat torch.mean(feat, dim0).numpy() heat (heat - heat.min()) / (heat.max() - heat.min() 1e-6) heat cv2.resize(heat, (img.shape[1], img.shape[0])) heat np.uint8(255 * heat) heat_color cv2.applyColorMap(heat, cv2.COLORMAP_JET) # 叠加 overlay cv2.addWeighted(img, 0.6, heat_color, 0.4, 0) cv2.imwrite(heatmap.jpg, overlay)跑完看heatmap.jpg如果高亮区域和猪的边界框重合度高说明模型关注点正确。如果高亮散乱或集中在背景就得回头检查数据增强是不是太激进或者标注里混入了背景噪声。另一个技巧是用model.model.model打印每一层的输出尺寸确认特征图分辨率。猪群检测里小目标不多但密集目标需要足够的空间分辨率P3 层80×80的特征图不能太弱。如果 P3 层被下采样太狠小豬和远处豬就检测不到。可以在yolov8.yaml里调整depth_multiple和width_multiple但更简单的办法是提高输入分辨率到imgsz960代价是显存和推理时间增加。我自己的习惯是每训完一个版本先跑 20 张验证集图片的热力图肉眼过一遍。如果热力图看起来“对”再去看 mAP如果热力图看起来“飘”mAP 再高我也不敢部署。这个习惯帮我省了至少三次返工。猪群检测不是刷榜是真正要在猪场里跑起来的模型看哪里比模型考多少分重要得多。希望帮到你。本文还有配套的精品资源点击获取