
简介一套面向养殖场肉鸡识别场景的YOLO目标检测数据集适合目标检测初学者、农业智能化算法工程师及养殖项目开发者直接使用。数据集中包含大量标注好的鸡只位置采用Pascal VOC格式的xml与jpg图片一一对应可供yolov5、yolov7、yolov8等主流算法直接训练无需额外转换格式。资源共1001个文件包括500个xml标注文件、500张jpg图像以及1个txt说明文件压缩包大小为883.41MB图片与标注同名匹配、目录结构清晰便于快速划分训练集和验证集也能较好覆盖真实养殖场景下的检测需求且涵盖不同光照、角度和饲养密度下的鸡只姿态有助于提升模型泛化能力。当前已有708人学习或下载可用于鸡只计数、行为监测、养殖管理系统等方向节省自行采集与标注的时间成本。配套博文还提供了数据集构成与模型检测效果说明帮助读者更好评估和部署。1. 养殖场肉鸡目标检测数据集它解决的并不是“能认出鸡”的问题如果你手里有一批养殖场的监控视频想做一个自动数鸡、鸡群健康监测或者出栏统计的系统那么这份YOLO养殖场肉鸡目标检测数据集就是你最需要的那瓶“场景燃料”。和COCO这类通用数据集不同它拍的是真实鸡舍里的肉鸡俯视视角为主鸡群密集、互相遮挡还有低照度和地面反光的干扰在这些条件下通用预训练模型往往只能框出最显眼的几只漏检率高到没法在生产环境里用。这份数据集适合正在做农业AI监控、畜牧数字化项目或者想在目标检测里练出场景适配能力的开发者。它不负责教你YOLO是什么它负责让模型在“鸡叠着鸡”的画面里把每一只鸡的位置和数量交给你。2. 为什么养殖场检测难密集、遮挡、低照度与YOLO格式的底层逻辑2.1 养殖场场景的三个检测难点以及它们如何冲击通用模型肉鸡养殖场的目标检测和常规的车辆、行人检测有本质区别至少有三个维度是通用模型扛不住的。第一是密集平养中后期的鸡舍里每平方米能站十来只鸡鸡与鸡之间几乎没有间隙标注框大量重叠。第二是遮挡俯视摄像头往下拍上层的鸡挡住下层的鸡很多目标只能露出头或者半个背脊。第三是低照度和低对比度鸡舍为了模拟夜间休息会开暗光灯白羽肉鸡在水泥地面的反光下轮廓很淡尤其雏鸡阶段绒毛和地面颜色几乎融在一起。这三个条件放在一起对目标检测模型产生的直接冲击是特征提取阶段模型很难找到稳定的局部纹理在密集区域NMS非极大值抑制会把靠得很近的几只鸡合并成一个框在低对比度区域浅层网络学到的边缘特征会被噪声淹没。这也是为什么很多人拿通用权重直接做迁移学习loss能降但可视化结果里漏检一片。用这份数据集训练本质上不是让模型学会“鸡长什么样”而是让它学会“在这种特定光线、特定视角、特定密度下鸡的边界在哪里”。2.2 YOLO标注格式解构数据集的真实面貌和检查标注质量的方法下载这份数据集后解压出来通常就是标准的YOLO格式一个images目录放着图片一个labels目录放着同名txt标注文件。每个txt文件里的每一行对应一个目标格式是固定的五列类别id、归一化中心点x、归一化中心点y、归一化宽度w、归一化高度h。归一化指的是全部除以图片宽高所以坐标值都在0到1之间。这和VOC的像素级xml标注不同YOLO格式里你拿不到“左上角坐标”只有相对位置训练时模型读取的是相对值推理时再按输入尺寸换算回像素。拿到数据集后我建议先抽查标注质量不要直接开训。常见问题是有人把像素坐标直接除以短边长边方向的坐标就会大于1模型训练时loss曲线非常奇怪还有人把类别id从1开始而不是从0开始模型会多出一个永远学不会的类别。检查方法很简单写个脚本遍历所有标注文本先看坐标范围再看空标签分布import os import glob label_dir labels bad_files [] empty_files [] out_of_range_files [] for txt_path in glob.glob(os.path.join(label_dir, *.txt)): lines [line.strip() for line in open(txt_path) if line.strip()] if not lines: empty_files.append(txt_path) continue for line in lines: parts line.split() if len(parts) ! 5: bad_files.append(txt_path) break cls_id, cx, cy, w, h parts if not (0 float(cx) 1 and 0 float(cy) 1): out_of_range_files.append(txt_path) break print(标注格式异常:, len(bad_files)) print(空标签文件:, len(empty_files)) print(坐标越界文件:, len(out_of_range_files))这段代码的核心逻辑是快速暴露三类问题行数不是五列、坐标超过0到1的范围、以及没有任何标注的图片。空标签文件不一定有问题如果它对应的是纯背景图那这是合理的负样本后面训练时也有用。但如果大量图片都为空说明采集时漏标严重需要人工回补否则模型会把“无标注区域”默认当作背景漏检率会很高。我一般会在训练前把这三类统计结果打印出来确认异常文件占比低于1%再动手。2.3 训练前先看清目标尺寸分布别等训练完才发现小目标问题养殖场场景里有一个长期被忽略的问题肉鸡在图片上通常很小。如果监控摄像头装得高、视角覆盖整个鸡舍一只成年肉鸡在1080P画面里往往只有60~80像素宽雏鸡可能只有30像素。而YOLO的默认输入尺寸是640×640下采样到最后一层特征图时这些小目标只对应几个像素特征几乎被抹平。所以训练前必须统计一遍标注框的尺寸分布用数据决定imgsz怎么设置。import os import glob from PIL import Image import numpy as np label_dir labels image_dir images areas [] for txt_path in glob.glob(os.path.join(label_dir, *.txt)): img_path os.path.join(image_dir, os.path.splitext(os.path.basename(txt_path))[0] .jpg) if not os.path.exists(img_path): continue with Image.open(img_path) as im: img_w, img_h im.size with open(txt_path) as f: for line in f: parts line.split() if len(parts) ! 5: continue _, cx, cy, w, h parts box_w float(w) * img_w box_h float(h) * img_h areas.append(box_w * box_h) areas np.array(areas) print(标注框总数:, len(areas)) print(面积中位数:, np.median(areas)) print(小于32x32的框占比:, np.mean(areas 32 * 32))这个脚本把归一化坐标还原回像素面积重点看两个数字面积中位数和小于32×32的框占比。如果小于32×32的占比超过三成说明这份数据集里小目标数量很大训练时把imgsz从640提到960甚至1280是更合理的选择。代价是显存占用成倍上涨显存有限的显卡需要同步降低batch。这一步看起来是预处理实际上决定了后续评估的基线值得认真跑一遍而不是凭感觉。3. 把数据集跑起来划分、YAML配置与YOLOv8训练全流程3.1 关键一步按采集时间分组划分训练集和验证集而不是随机划分监控视频类数据集有一个隐藏陷阱相邻帧之间高度相似。如果按照普通图片数据集的做法随机切分同一段视频的连续几十帧会同时出现在训练集和验证集里模型在训练时已经见过验证集里几乎相同的画面验证指标虚高。等到部署时遇到新画面精度立刻打回原形。这也是很多养殖场检测项目“训练时mAP很高一上线就漏检”的首要原因。比较稳妥的划分方式是按采集时间段分组。假设采集数据时按日期或鸡舍编号建了目录每个目录里是一批连续帧划分时应该按目录切分而不是按单张图片切分。下面这个脚本就是按目录名分组把整组文件夹划入训练集或验证集import os import random import shutil src_images images src_labels labels dst_root dataset # 按目录名分组目录名通常是采集时间和鸡舍编号 groups {} for img_name in os.listdir(src_images): group_name os.path.dirname(os.path.relpath(os.path.join(src_images, img_name), src_images)) groups.setdefault(group_name, []).append(img_name) random.seed(42) group_names list(groups.keys()) random.shuffle(group_names) val_ratio 0.15 val_count max(1, int(len(group_names) * val_ratio)) for idx, group_name in enumerate(group_names): split val if idx val_count else train os.makedirs(os.path.join(dst_root, split, images), exist_okTrue) os.makedirs(os.path.join(dst_root, split, labels), exist_okTrue) for img_name in groups[group_name]: label_name os.path.splitext(img_name)[0] .txt src_img os.path.join(src_images, group_name, img_name) src_lbl os.path.join(src_labels, group_name, label_name) if not os.path.exists(src_lbl): continue shutil.copy(src_img, os.path.join(dst_root, split, images, img_name)) shutil.copy(src_lbl, os.path.join(dst_root, split, labels, label_name))这个脚本把整个分组划入同一边保证验证集和训练集不会出现来自同一时间段的高度相似帧。代码里的val_ratio取0.15如果总样本量小可以提高到0.2如果样本量很大0.1也够用。分组的关键是group_name的提取方式我这里用相对路径模拟目录分组实际项目中如果文件名本身就带时间戳也可以按文件名前缀提取时间段。3.2 编写YAML配置并启动训练参数怎么选每个参数管什么完成划分后在数据集根目录写一个data.yaml。YOLO训练时通过这个文件定位图片和标注同时声明类别数。这份数据集大概率是单类别肉鸡我从通用写法调整为单类示例# dataset/data.yaml path: /your/absolute/path/to/dataset # 修改为你的实际路径 train: train/images val: val/images nc: 1 names: 0: broilerpath字段在YOLOv8里必须写成绝对路径或者相对当前工作目录的路径写错会直接报错找不到训练图片。train和val字段是相对path的子路径。nc为1names列表只包含一个类别名。如果解压后发现labels里的类别id有0也有1那说明标注信息里其实有两个类需要先检查一下每一条标注第一列的最大值适当调整nc否则训练会报索引越界。启动训练我用YOLOv8官方CLI下面是一套适合养殖场场景的基础配置yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz960 \ batch8 \ device0 \ patience30 \ projectruns \ namebroiler_v1这里几个参数的取舍逻辑我展开说一下。模型选yolov8s而不是nano是因为密集小目标场景下nano的参数量容易欠拟合s尺寸是精度和速度的平衡点如果显卡只有6GB显存可以退回yolov8n并接受一部分精度损失。imgsz选960是基于前面第2章的小目标面积统计如果统计结果中小框占比不高用640能省将近一半的训练时间。batch设8是因为960输入下显存占用大约是640的2.25倍默认16大概率爆显存。patience设为30表示连续30个epoch验证集指标不上升就提前停止避免无效的长时间训练。device0表示用第一张显卡。3.3 训练日志、权重选择与中断恢复别让训练白跑训练启动后输出目录里会实时生成results.csv和weights目录每轮epoch的loss、精度、召回率都记录在案。我习惯每隔十来个epoch看一眼results.png里的曲线图重点看验证集mAP50的走向。正常情况是前20轮快速上升后面趋于平缓如果验证集loss在某个节点突然反弹多半是学习率过高或者数据增强过强而不是模型结构问题。训练结束后weights目录下会有best.pt和last.pt两个权重。best.pt是在验证集上表现最好的那一轮权重last.pt是最后一轮权重。部署时默认选best.pt但如果你计划继续训练或者做进一步微调last.pt更适合作为起点。如果训练中途因为断电或者显存溢出中断了可以直接续跑不需要从头再来yolo detect train resume modelruns/broiler_v1/weights/last.ptresume功能会自动读取上一次训练的状态和超参数继续从断点处开始。这里有一个我踩过的坑训练初期就中断然后resume如果原训练命令里的imgsz和batch参数影响了优化器状态恢复后的曲线会有一截异常抖动。所以训练开始前尽量确认环境稳定resume是后悔药不是常规操作。4. 评估不只盯mAP按养殖场场景对齐验证指标与Bad Case定位4.1 从results.csv里读出的不是分数而是问题很多人在训练结束后只看控制台打印的mAP50就下结论这在养殖场场景里不够。mAP50表达的是“预测框和真实框的IoU超过0.5的检测质量”它允许框有一定偏移这对鸡群计数场景确实够用。但如果只盯着mAP50会掩盖小目标漏检和密集区域合并这两个问题。评估养殖场肉鸡检测模型我建议同时看五个维度指标关注的维度在养殖场场景的解读precision查准率框出来的目标里有多少确实是鸡误检率在这里体现recall查全率真正的鸡有多少被框出来漏检率在这里体现mAP50常规定位精度落点是否够准能吃但不算严苛mAP50-95严格定位精度框的贴合程度密集场景里会显著偏低小目标AP小尺寸目标表现雏鸡和远处鸡只的可信度比mAP50更说明问题用下面脚本直接读取results.csv把关键指标打印出来import csv import matplotlib.pyplot as plt rows list(csv.reader(open(runs/broiler_v1/results.csv))) header rows[0] data rows[1:] epochs [int(r[0]) for r in data] # 假设列索引1train/box_loss, 6val/box_loss, 8metrics/mAP50(B) train_loss [float(r[1]) for r in data] val_map50 [float(r[8]) for r in data] plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.plot(epochs, train_loss, labeltrain box loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.subplot(1, 2, 2) plt.plot(epochs, val_map50, labelval mAP50) plt.xlabel(epoch) plt.ylabel(mAP50) plt.legend() plt.tight_layout() plt.savefig(my_metrics.png)scripts执行后重点看两个信息验证集mAP50是否还在涨以及train box loss和验证集mAP50之间有没有背离。如果train loss一直降但mAP50停滞说明过拟合需要增加数据增强或减少epoch。如果mAP50已经到0.9以上但后面第4.2节的视频抽帧实验里漏检仍然明显那大概率是划分阶段出了问题验证集太“简单”需要回到第3.1节重新划分。4.2 视频抽帧做一次“仿真部署”指标欺骗不了真实画面训练集和验证集都是静态图片而养殖场实际使用场景是监控视频。视频和图片之间有一个关键差异相邻帧的目标位置变化小但光照可能连续变化镜头可能轻微抖动。我最常做的一项验证是从未参与训练的一段视频里抽100帧出来跑一次批量推理保存结果图然后人工翻看yolo detect predict \ modelruns/broiler_v1/weights/best.pt \ sourcetest_frames/ \ imgsz960 \ conf0.25 \ saveTrueconf设为0.25意思是置信度低于0.25的预测框会被删除。养殖场场景里如果漏检太严重可以往下调到0.15但这会带来更多误检。我一般用0.25跑一遍重点观察三类画面鸡群密度最高的一帧、逆光导致对比度很低的一帧、以及远处鸡只较小的一帧。如果这三类画面里漏检都很明显说明模型没学好这个场景而不是置信度阈值的问题。4.3 Bad Case定位三步找到模型“看不清”的具体原因定位bad case有三个步骤。第一步跑验证集并保存预测的json结果命令里加save_jsonTrue预测框会输出为label格式文件和真实标注一一对应。第二步写一个脚本把预测框和真实框同时画在图上预测框标红真实框标绿重叠区域变成半透明人工扫一遍就能发现哪些位置漏检、哪些位置误检。第三步把置信度阈值降到0.05再跑一遍把所有低置信度预测框也画出来用于判断“模型其实检测到了只是不敢确认”还是“完全没检测到”。这两者的处理策略完全不同。如果大量目标都能被低置信度框覆盖说明模型特征提取没问题只是分类置信度校准不好部署时可以把conf调低或者用更多数据把这个场景的置信度分布拉高。如果低置信度也完全没有框说明那些区域的感受野或者特征表达缺失必须提高输入分辨率或者补数据。这一步是整个评估流程里最有价值的动作能直接决定下一步是该调阈值还是该补训练。5. 避坑记录训练肉鸡检测模型最容易翻车的五个细节5.1 三个直接影响结果的参数翻车第一条imgsz保持默认640不动小目标漏检严重。现象是训练结束mAP50不低但验证集视频里远处的鸡几乎全漏尤其是雏鸡阶段。原因很简单前面统计过小于32×32的框占比超过三成这些目标在640输入下对应到最后一层特征图只剩几个像素网络根本没有足够信息去判断边界。解决方法是把imgsz提到960或1280同时batch降下来。用960后显存占用如果超了就把batch从16降到8或者开启梯度累积。第二条随机划分训练验证集验证指标虚高。现象是训练过程一切正常mAP50到了0.93但一换新视频段就崩。原因是监控视频连续帧高度相似随机划分让同一段视频同时出现在训练和验证里模型只是在“回忆”。解决方法是按采集时间段分组划分这部分逻辑我写在第3.1节代码直接可用。第三条YOLOv8默认数据增强太强验证集上精度波动大。现象是每轮的验证mAP50忽高忽低训练集loss降得很快但泛化不行。原因在于默认参数里的HSV增强会随机改变色调饱和度而养殖场画面本身是低饱和度的暗光环境增强把颜色弄成了模型不认识的风格。解决方法是关闭或者调低hsv增强我常用的做法是把hsv_h从默认0.015降到0.005hsv_s从0.7降到0.3fliplr从0.5降到0.2甚至不开水平翻转因为鸡舍左右两侧的光线不对称。5.2 两个“玄学”问题其实都有明确原因第四条模型把食槽、运料车、走道识别成鸡。现象是单张画面里出现五六个误检框位置全在鸡舍的设备边缘。原因是训练集图片里所有帧都包含这些设备模型学会了“设备边缘的纹理特征和鸡的边缘相似”但没有足够多不含鸡的负样本让它知道“这些场景不是鸡”。解决方式是在训练集里加入几十张不包含任何肉鸡的鸡舍背景图labels目录里放空的txt文件让模型把这部分区域学习为背景。如果数据集本身没有这类图可以自己从视频里截取设备特写帧补进去加入后误检率通常能降一半以上。第五条推理时两只挨得很近的鸡被合并成一个框。现象是NMS之后保留的框数量比实际鸡数少尤其密度高的画面。原因是这两个目标的框IoU超过NMS阈值置信度低的那个被直接抑制掉。解决方法是调高NMS的IoU阈值训练阶段用nms_iou控制推理时的合并程度从默认0.5提高到0.65左右同时把conf阈值适当从0.25提到0.3让低置信度的预测框不参与后续合并。双管齐下密集场景的精度通常会明显变好。6. 进阶技巧小目标切片推理与数据增强的实战组合6.1 为肉鸡场景定制的数据增强参数如果已经按前面的流程训练了一版还想继续提升小目标召回率优先考虑两件事数据增强策略和大图切片推理。数据增强方面我在默认参数基础上做了几处针对养殖场场景的调整。把mosaic保持开启它能把四张图拼成一张模拟更密集的鸡群把hsv增强调弱保留原有暗光色彩分布scale增强开到0.3模拟不同摄像头高度下的目标大小变化translate增强开到0.1模拟镜头小幅抖动。训练命令里加一段augment参数组合yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz960 \ batch8 \ hsv_h0.005 \ hsv_s0.3 \ hsv_v0.2 \ fliplr0.2 \ scale0.3 \ translate0.1 \ mosaic0.8这一套参数的核心思路是保留养殖场真实的光线特征通过几何变换模拟不同机位不通过剧烈颜色变换制造模型不认识的样本。mosaic调配到0.8而不是1.0是为了保留一部分正常构图的样本避免模型过度依赖拼接纹理。6.2 大图切片推理解决“图很大目标很小”的终极方案监控画面的分辨率经常是1920×1080甚至更高YOLO推理时会把整张图缩放成960或640等于把原始信息压缩了一半以上。切片推理的思路是先把原始大图切成重叠的小块对每一块单独做检测再把结果合并回原图坐标系。切片边长一般取512或640重叠率取0.2左右既能保证目标不会被切成两半又不会产生太多重复检测。用SAHI这类现成工具做切片推理命令很直接sahi predict \ --model_type yolov8 \ --model_path runs/broiler_v1/weights/best.pt \ --source test_video.mp4 \ --slice_width 512 \ --slice_height 512 \ --overlap_width_ratio 0.2 \ --overlap_height_ratio 0.2 \ --postprocess_class_threshold 0.25 \ --postprocess_nms_threshold 0.6切片推理的代价是推理耗时成倍增加但它把小目标的实际像素放大到了模型能看清的范围。在鸡舍监控这种对实时性要求不极端、更看重精度的场景里用切片推理换回的小目标召回率提升非常可观。如果部署设备算力有限可以只对画面中鸡群密集的局部区域做切片其他区域用整图推理。我在处理养殖场检测项目时养成的一个习惯是拿到任何新数据第一步先做小目标面积统计和按时间分组划分然后才让训练跑起来。这个流程看起来多花一小时但能省掉后面调参和返工的好几天。希望你也在自己的数据集上先跑一遍这个流程再决定怎么训练。希望帮到你。本文还有配套的精品资源点击获取