ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

生猪检测数据集YOLOV5格式整理与训练避坑指南

生猪检测数据集YOLOV5格式整理与训练避坑指南 简介猪圈摄像头场景下的生猪检测数据集面向目标检测入门与实战人群解决猪场监控画面中密集目标识别与标注数据缺乏的问题。数据为640-1080分辨率的RGB图像每张包含多个目标统一标注为单一类别pig并按YOLOv5标准目录整理出训练集与验证集txt标签与图片一一对应下载后无需额外处理即可直接送入模型训练。从内容预览看图像多来自监控视频画面视角贴近实际养殖场景。压缩包共2000个文件以jpg图像、txt标签为主另附一个可直接运行的Python可视化脚本可随机读取图片并绘制边界框方便快速预览标注质量与密集场景效果。整体约97MB轻量易用。目前已有608人浏览学习适合需要标准格式猪只检测数据用于算法验证或课程设计的开发者。1. 生猪检测数据集不是把照片塞进文件夹就完事养猪场里装摄像头容易让算法在猪圈这种又脏又暗、猪还老挤在一起的环境里把每头猪数清楚就是另一回事了。市面上的开源数据集大多是行车记录仪视角或者农场俯拍真正贴着猪圈摄像头拍出来的、带遮挡和弱光的样本少得可怜。如果要做猪场盘点、异常行为预警或者出栏计数第一步卡住你的往往不是模型而是一份整理干净的、符合YOLOV5目录格式的生猪检测数据集。这个标题里的数据集只有1个类别意味着所有标注框都指向“猪”不需要区分母猪、仔猪还是育肥猪恰好是能把检测流程跑通的最小闭环。本文会按我实际整理这一类数据集的路径来写从摄像头场景下的采集和标注到组装出标准YOLOV5目录再到训练校验和常见翻车点。目标很明确——你照着做能把一份猪圈场景图片变成可以直接丢进YOLOV5训练的数据集并且知道每个参数为什么这么设、出错了看哪里。新手能跟着搭完熟手可以把我写的边界条件当对照清单。2. 采集与标注猪圈摄像头场景下先把图片和标签搞干净2.1 摄像头怎么架、选什么时段拍数据分布决定模型上限很多人的第一反应是直接把监控录像抽帧但录像抽出来的帧相邻之间高度相似模型在几乎一样的图上反复迭代泛化能力很差。我常用的做法是把摄像头按不同机位拍尽量覆盖栏位全景、食槽近景和通道尽头三个角度然后每隔5秒抽一帧再手动剔除连续帧和完全模糊的帧。猪圈里的猪不是静止的5秒间隔基本能保证同一头猪在相邻帧里有位移避免训练集和验证集之间出现太多“双胞胎图”。时段上白天自然光、夜间红外补光、黄昏这种光线变化剧烈的时刻都要分别抽帧。这里有个反直觉的点夜间红外图虽然人在肉眼看时对比度低、偏灰白但猪的体温区和环境温差在红外下边界反而清晰模型往往能学到比白天更强的轮廓特征。所以不要因为肉眼觉得暗就删掉夜间帧这类帧往往是夜间巡检场景的主力样本。抽帧之后要做初筛把没有猪的空栏位图、维修人员入镜的图、镜头被猪拱歪导致的大面积遮挡图挑出去。这一步骤不能省它直接影响标注工时——你找一个标注员标1000张全是猪的图和标1000张只有300张有猪的图成本差好几倍。2.2 标注工具选型LabelImg与CVAT的取舍单机小规模标注用LabelImg就够它输出的是Pascal VOC格式的XML后续可以转成YOLO的txt。但LabelImg有个让人烦躁的点它保存的是XML路径如果你移动了图片目录再次打开会提示找不到图片需要重新选择目录。我的习惯是一开始就把图片集和标注目录的相对路径固定下来比如workdir/images和workdir/annotations整个标注期间不去移动任何文件。如果是多人协作标几千张图我会推荐CVAT。CVAT可以部署在带Docker的服务器上三个人同时标同一个任务标注结果导出为YOLO格式时它会自动生成每个类别对应的txt文件省去了自己写XML转txt脚本的步骤。但CVAT的问题在于部署和权限配置有点繁琐团队里没人熟悉Docker的话学习成本会把标注效率拖垮。标注框的大小和紧致度也直接影响训练结果。我见过不少人把猪连同栏杆、食槽一起框进去以为框大一点“背景信息多模型更好学”。实际上YOLO系列是回归框坐标的背景噪点太多会拉偏回归目标。正确做法是框紧贴猪的可见轮廓——如果猪头被栏杆挡住那就只框露出来的身体部分那截栏杆不要包含进框里。遮挡严重的猪可以单独标一个尽量贴合可见区域的框模型会通过大量这样的样本学会“只检测可见部分”。2.3 标注规范母猪、仔猪怎么定义边界这个数据集只有1个类别看起来标注规则很简单实际协作时最容易出分歧。比如产房栏位里母猪身下趴着一堆仔猪有的标注员把整片猪群框成一个框有的则每头仔猪单独框。这两种框法训练出来的模型行为完全不同反复输入整片框模型学到的是“检测猪群区域”反复输入单独框模型学到的是“检测每头猪个体”。如果你的最终目标是盘点数量那应该选后者哪怕仔猪被母猪挡住一大半只要肉眼能分辨边界就单独框。我一般会写一份极简标注说明放在数据集根目录类别ID为0只有一个类别从0开始可见面积大于整头猪20%的个体必须单独框完全无法分辨边界的重叠区可以不标同一帧画面中同一头猪在两个框中不得重复出现。标注说明这步看似琐碎但在你后续扩展数据集、换标注员的时候能省掉大量返工。3. 组装YOLOV5目录格式目录树、分割脚本与yaml配置3.1 标准目录树与命名规则YOLOV5的目录格式有严格的约定但它的要求其实比很多人想象中简单images放图片labels放对应的txt标注两个目录下按train和val再分一层。目录树长这样pig_dataset/ ├── images/ │ ├── train/ │ │ ├── 001.jpg │ │ └── 002.jpg │ └── val/ │ ├── 003.jpg │ └── 004.jpg ├── labels/ │ ├── train/ │ │ ├── 001.txt │ │ └── 002.txt │ └── val/ │ ├── 003.txt │ └── 004.txt └── pig_data.yaml注意标注文件的主文件名必须和图片完全一致只是后缀从.jpg变成.txt。YOLOV5在训练时是根据这个同名规则去找标注的文件名对不上会直接报错或者跳过该图。图片格式上jpg和png都能用但建议统一不要混着放——有些图像处理库对单通道png和四通道png的处理逻辑不一样混用容易在数据加载时报错。3.2 数据集划分脚本随机还是按时间切划分训练集和验证集时不要直接随机全量打乱。猪圈场景有个特殊问题同一天同一个栏位的猪姿态和位置有一定连续性如果随机划分验证集里可能混入大量与训练集高度相似的帧导致验证指标虚高。等你部署到新猪舍时性能立刻现原形。我一般按时间切分比如取前70%天数的帧做训练后30%天数的帧做验证这样才能测出模型面对“没见过的时间段”时的表现。下面这个Python脚本做的事情是读取图片列表按文件名中的时间戳排序然后按比例切成train和val两组再为每组生成对应的目录和标注文件import os import shutil from glob import glob # 按时间戳切分数据的示例脚本 image_dir raw_frames train_ratio 0.7 images sorted(glob(os.path.join(image_dir, *.jpg))) split_idx int(len(images) * train_ratio) train_images images[:split_idx] val_images images[split_idx:] # 建立目录结构 for subset in [train, val]: os.makedirs(fpig_dataset/images/{subset}, exist_okTrue) os.makedirs(fpig_dataset/labels/{subset}, exist_okTrue) for img_path in train_images: shutil.copy(img_path, pig_dataset/images/train/) txt_path img_path.replace(.jpg, .txt).replace(raw_frames, labels) if os.path.exists(txt_path): shutil.copy(txt_path, pig_dataset/labels/train/) for img_path in val_images: shutil.copy(img_path, pig_dataset/images/val/) txt_path img_path.replace(.jpg, .txt).replace(raw_frames, labels) if os.path.exists(txt_path): shutil.copy(txt_path, pig_dataset/labels/val/) print(ftrain: {len(train_images)}, val: {len(val_images)})这段代码里排序是关键文件名里如果没有时间信息需要先从数据库或监控系统的导出表里把拍摄时间关联上再按时间排序。如果素材来源不统一、时间戳缺失退而求其次的做法是按栏位ID分桶同一个栏位的所有帧要么全进train要么全进val避免训练时“见过这个栏位”的假象。3.3 类别yaml与校验脚本train能跑通才算数pig_data.yaml是YOLOV5的数据配置入口内容很少但容易写错路径# pig_data.yaml train: /absolute/path/to/pig_dataset/images/train val: /absolute/path/to/pig_dataset/images/val nc: 1 names: [pig]这里的train和val指向的是images目录不是labels目录。YOLOV5会自动把路径里的images替换成labels来找标注文件如果你在yaml里写了labels路径训练时会报找不到文件。nc是类别数只有一个类别就写1别写成0。names列表的长度必须和nc一致不然训练启动时就崩。写好后先跑一遍校验脚本看每个标注文件是否有效python -c from pathlib import Path import cv2, numpy as np labels_dir Path(pig_dataset/labels/train) imgs_dir Path(pig_dataset/images/train) bad 0 for txt in labels_dir.glob(*.txt): img_path imgs_dir / (txt.stem .jpg) if not img_path.exists(): print(missing image:, img_path) bad 1 continue h, w cv2.imread(str(img_path)).shape[:2] if len(txt.read_text().strip().split(chr(10))) 0: print(empty label:, txt) bad 1 continue for line in txt.read_text().strip().split(chr(10)): parts line.split() if len(parts) ! 5: print(bad format:, txt, line) bad 1 x, y, bw, bh map(float, parts[1:]) if x 0 or y 0 or x 1 or y 1 or bw 0 or bh 0: print(out of range:, txt, line) bad 1 print(done, bad files:, bad) 这个脚本会检查三件事图片文件是否存在、txt内容是否为空、坐标是否超出[0,1]范围。坐标超出范围是最常见的坑比如标注框贴边时归一化后的中心点坐标可能变成1.0000001这类微越界数值训练时模型可能忽略这一行或直接崩。发现越界不要手动改txt回到LabelImg里重新保存一遍最稳妥——手动改坐标容易把中心点x改成别的数据反而引入新错误。4. 训练与验证超参数、类别权重与指标解读4.1 数据配置img、batch、epochs怎么定数据准备好了第一次训练的参数设置我一般按基准配置来img分辨率选640batch选16显存不够就降到8epochs先跑100轮。分辨率这里有个权衡猪圈摄像头大多是2K或4K的鱼眼或广角画面直接缩到640会丢失小目标细节——那些分散在画面远处的仔猪可能只有二三十个像素。但你把分辨率拉到1280显存占用会翻好几倍训练速度也直线下降。我的建议是第一版跑640把流程跑通确认loss下降趋势正常再针对小目标漏检的问题专门用1280精调一版。训练启动命令python train.py --data pig_data.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --project pig_run--project pig_run指定输出目录YOLOV5会在里面按每次运行时间自动建子目录保存权重和日志。用yolov5s.pt作为预训练权重比从零训练收敛快得多COCO上预训练出来的底层特征对猪的轮廓、纹理有一定迁移价值。如果是新手不要一上来就换yolov5x或yolov5m训练时间和显存占用都会放大而且在这个数据集规模下精度提升有限。训练过程中主要看两个东西box_loss和obj_loss是否持续下降以及验证集上的mAP0.5是否在稳步提升。如果loss前几十轮不降反升大概率是数据配置有问题先停掉排查别硬等100轮跑完。4.2 类别权重与图像数量不平衡只有一个类别时类别不平衡的问题基本不存在但样本难度不平衡是真实存在的。比如大部分图片里的猪都是站立状态卧着的猪样本很少。模型会把“卧姿”当成一种少见变异漏检率明显升高。解决思路有两个一个是数据层面多抽卧姿的帧另一个是训练时提高难例权重——但YOLOV5原版并没有直接暴露这个参数常见的做法是调整训练集里卧姿图的比例而不是去改损失函数。还有个容易被忽略的不平衡是尺寸不平衡。猪圈摄像头通常架在高处往下俯拍近处的猪可能占据半个画面远处的猪可能只有几十像素。YOLOV5本身的anchor机制能处理一定尺度变化但跨度太大的话大目标会把小目标的梯度淹没。我一般会在训练前统计一下所有标注框的面积分布如果最大值和最小值差两个数量级以上考虑把图片按远近距离切分成两组分别训练再在推理时合并结果。这个方案工程量大但对猪舍这类固定场景很有效——你甚至可以针对每个摄像头单独训练一个模型。4.3 训练结果指标P、R、mAP0.5到底看哪个训练结束会输出一堆指标最常用的三个是Precision、Recall和mAP0.5。对于猪场盘点场景我优先看Recall——漏检一头猪比误检一头猪严重得多漏检意味着数量统计错误而误检可以通过后续的时间序列滤波比如连续N帧都检测到才算有效来消除。如果P很高但R很低说明模型趋于保守这时可以降低置信度阈值到0.15左右再测一次如果R很高但P很低说明模型把食槽、水渍、墙上的污渍都当成了猪这时要回看训练集的负样本是否太少。YOLOV5的验证命令会输出confusion matrix和PR曲线python val.py --data pig_data.yaml --weights runs/train/exp/weights/best.pt --img 640best.pt是训练过程中在验证集上mAP最高的权重做实验对比时用它不要用last.pt。如果PR曲线在低置信度区间出现明显掉点说明模型对难样本的响应差优先去补难样本而不是调超参数。训练产生的results.png里还有每一轮的指标曲线注意看val曲线在训练后期是否出现震荡——如果震荡幅度很大是lr过高的信号把--lr0从默认的0.01降到0.005重跑一版。5. 避坑清单猪圈场景下的数据坑一次说清标注了这个数据集的坑挑几个一定会遇到的写在这里每一条都是真实翻车场景。5.1 夜间红外模式下猪眼反光被误检成多个小目标现象模型在白天测试集上P和R都超过0.9一到夜间红外画面猪的眼睛和反光的耳标被检测成若干小框同一头猪出现三四个框。原因不是模型变笨了而是夜间帧里猪体边界低对比度、眼睛高对比度的纹理特征和白天样本差异巨大模型没学会“猪的轮廓在红外下长什么样”。解决方法是刻意的在夜间帧上做数据增强把训练集里的夜间图做高斯模糊、亮度扰动、局部对比度拉伸让模型适应红外图像的纹理分布。更直接的思路是先统计夜间帧的误检率把误检框当成负样本单独存一份下次训练时加入这些图的背景区域作为hard negative。5.2 同一头猪在连续帧里被分配不同ID导致数量统计翻倍现象模型逐帧检测都正常但把连续帧的检测结果叠加统计数量时猪的总数远超实际存栏数。原因是相邻帧之间同一头猪的检测框位置有轻微偏移没有做IOU匹配或跟踪算法直接按每帧独立计数。这不是数据集的问题而是评估方式的问题但很多人会误以为是模型不稳定反复调整训练参数。正确做法是用简单的IOU追踪或者直接按检测框中心点做最近邻匹配连续帧IOU大于0.5就判定为同一头猪。用代码验证时可以先将测试视频按帧检测后用deep_sort或最简单的bytetrack跑一遍再统计。5.3 标注框坐标越界导致训练直接报错现象训练启动后几秒钟就报assert (cx 0.0 and cx 1.0)类错误。原因是标注时框边缘贴着图片边界保存出来的归一化坐标中心点等于1.0000或者宽高比画幅还大。LabelImg默认不会阻止这种边缘框所以容易出现越界值。解决方法是跑一遍我在3.3节写的校验脚本把所有越界txt找出来回LabelImg里重新保存或手动把坐标修正到0.999以内。不推荐写代码批量clip坐标值——clip会把框中心点也移动掉导致框整体偏移模型学到的是偏移后的错误位置。5.4 验证集和训练集图片高度相似mAP虚高现象训练结束所有指标都好得吓人mAP0.5接近1但一部署到新猪舍就崩。原因是抽帧间隔太短相邻帧几乎一样随机划分后同一天同一角度的相似帧被分到了两边。这类问题只能靠划分策略来防按时间段或按栏位划分而不是按整张图片随机划分。验证集的作用是模拟“第一次见到这个场景”如果验证集的图片在训练集里能找到近乎复制品它就没有任何说服力。5.5 标注文件里用tab分隔而不是空格训练时数据解析失败现象训练时loss正常下降但某个epoch突然报错或者记录大量WARNING: ignoring corrupt image/label。原因是某些标注工具默认用tab分隔字段而YOLOV5的解析器只接受空格。肉眼看着一样的txt读进去字符编码完全不同。解决方法是先跑一次批量替换把\t替换成空格再检查文件行尾是否统一为\n而不是\r\n——Windows下编辑过的txt很容易带\r会在解析时悄悄引入空行。这类问题在单机标注时几乎不会出现一旦用了Excel或者某些在线标注平台导出就很容易踩到。5.6 图片EXIF方向信息导致检测框错位现象标注时看到的猪是正的训练出来的模型在部分图片上检测框整体偏移约90度。原因在手机或部分监控截图带有EXIF旋转信息标注工具读取时自动校正了方向但YOLOV5在训练时用OpenCV读图不会读EXIF方向导致图片是旋转过的而标注框坐标没跟着转。猪圈摄像头一般不存在这个问题但如果你的素材里混入手机拍摄的照片就一定要在预处理阶段全部去掉EXIF信息或者统一旋转回标准方向。脚本很简单用PIL打开图片后img ImageOps.exif_transpose(img)再覆盖保存。6. 进阶难例挖掘与增量训练让数据集滚起来6.1 难例挖掘先训一版再挖误检补数据第一版数据集训完之后不要急着部署先做一轮难例挖掘。把训练集和验证集里所有的图片用训练好的模型跑一遍推理把那些漏检或者误检的帧单独拷出来——漏检的猪如果在画面里肉眼清晰可见说明标注漏标了补标误检的帧说明模型对背景纹理没学明白把这些帧作为纯负样本加入训练。YOLOV5的数据加载器遇到完全没有标注框的图片不会报错但需要在labels/train里放一个空txt否则图片会被跳过。这个过程可以迭代三轮以上。第一轮补漏标的图第二轮重点加夜间和逆光的图第三轮加入摄像头被猪拱歪时产生的极端视角图。三轮下来数据集规模可能只增加了20%但模型在真实场景的表现往往能提升一个档次。难例挖掘本质上是把模型当成标注检查员用它的错误告诉你数据缺什么。6.2 增量训练老数据集与新数据集的合并策略猪场场景有个实际问题老猪舍的数据和新猪舍的摄像头角度、栏位颜色、光照条件都不一样。如果新数据来了直接和老数据合并重新训练训练时间翻倍不说老数据里那些低质量样本还会拖累新场景的精度。我一般用两段式策略先用老数据集训练到收敛再用新数据集以较小的学习率--lr0 0.001继续训练50轮左右老数据集按10:1的比例混入新数据防止模型遗忘老的通用特征。这个策略的触发条件是新场景的验证集mAP低于0.5且新数据量小于老数据量的三分之一。如果新数据量已经超过老数据量直接合并重训更合适。增量训练不是万能药它对数据集分布偏移较小的场景有效如果新旧数据之间差异极大——比如从白天监控变成夜间热成像——那还是从头训一版更靠谱。6.3 部署前验证用TensorRT量化检查数据质量问题训练完的模型要上树莓派或Jetson这类边缘设备一般会转成TensorRT的engine格式。不少人以为TensorRT只是加速其实它还能暴露数据质量问题——INT8量化对数据分布非常敏感如果训练集和实际部署场景的亮度分布差距大量化后精度会断崖式下跌。我遇到过训练时验证mAP有0.92转成INT8后掉到0.71的情况回查发现是训练集里夜间帧占比不到5%而部署现场夜间是主要使用时段。解决办法是在量化校准阶段单独准备一组校准图这批图不要从训练集里随机抽而是从现场摄像头的历史录像里抽数量在500到1000张之间覆盖白天、黄昏、夜间、雨天四种光线条件。校准图的分布决定了量化后各层参数的敏感度用现场真实光线去校准比堆更多训练图更直接有效。这个步骤做完就说明你的数据集和模型真正适配了实际猪圈场景可以放心用了。做数据集这件事我栽过最多跟头的地方不是模型训练而是前期数据分布没想清楚就猛干标注。现在每拿到一批新数据我第一件事是看摄像头机位图和时间覆盖范围而不是急着开LabelImg。先想清楚模型要在什么条件下跑再决定数据集怎么摆布整个流程能顺很多。希望帮到你。本文还有配套的精品资源点击获取
返回列表