简介一套面向目标检测算法训练与智慧农业视觉应用的家禽鸡小鸡检测数据集图片覆盖母鸡、公鸡、小鸡等不同形态统一标注为chicken类别共含六千三百五十八个手工标注框。压缩包共两千个文件核心文件类型为Pascal VOC格式xml标注文件与YOLO格式txt文件xml记录目标类别与边界框坐标txt提供YOLO训练所需的归一化坐标整体约50.18MB可直接接入主流检测框架使用。标注经labelImg逐框核对边界框贴合目标可用于训练YOLO、Faster R-CNN等模型并为家禽计数、行为分析等任务提供数据基础。目前已有四百六十三人浏览学习适合目标检测初学者熟悉数据集组织方式也可作为研究者验证算法效果的样本。目录命名与图片一一对应便于灵活划分训练集与测试集快速投入项目迭代。1. 家禽鸡小鸡检测数据集2970张手工标注图能省下你几周的标注时间如果你正在做养殖场巡检、鸡舍密度统计或者家禽行为识别大概率已经被标数据这件事卡过脖子。这个「目标检测数据集」——家禽鸡小鸡检测数据集2970张VOCYOLO格式手工标注图解决的就是最耗人力的标注环节图片已经整理好框已经画好格式已经按主流训练框架能直接读的样子备好你拿到手直接进训练流程。它的适合人群很明确想快速跑通一个鸡只检测基线模型、验证YOLO系列在自己场景里效果的从业者或学生。2970张单类目标说多不多说少不少配合预训练权重足够起步但它的双格式和手工标注质量才是决定你能不能省下时间的关键。2. 先看懂双格式再动手VOC与YOLO标注的结构差异与转换原理2.1 VOC的xml文件目标框如何用绝对坐标描述PASCAL VOC是老牌目标检测竞赛留下的标准它的标注文件是xml里面记录着图片文件名、路径、尺寸以及每一个目标的类别和边界框。打开一个典型文件你会看到类似这样的结构annotation节点下有size子节点里面是图片的width、height、depth再往下是object节点每个object对应一个目标里面有name标签和bndbox子节点bndbox里存xmin、ymin、xmax、ymax四个值。这四个值是像素坐标直接对应图片上的绝对值。一个容易忽略的点VOC的坐标是包含性的xmin和ymin从1开始计xmax和ymax是框右下角的实际坐标。换算成目标检测常用的左上角宽高表示时宽度是xmax - xmin高度是ymax - ymin没有任何加减1的操作。很多从VOC转YOLO的脚本会在这里翻车多算少算一个像素在训练里通常没事但如果你要做严格的评测指标边界框会出现系统性偏移。手工标注的xml里还会带difficult、truncated这些属性。difficult1表示这个目标很难辨认早期VOC评测里会跳过它YOLO格式没有这个字段转换时通常直接丢掉如果你在做严格指标对齐需要知道这个信息在转格式过程中是丢失的。拿到数据集时先打开一两个xml看看这些辅助字段有没有被填充能判断标注团队是认真做的还是批量生成的。2.2 YOLO的txt文件归一化坐标与类别编号YOLO格式的标注文件是同名txt每一行代表一个目标五个值依次是类别编号、x_center、y_center、width、height。前两个是目标中心点的坐标后两个是框的宽和高全部除以图片宽高做了归一化取值范围在0到1之间。类别编号是从0开始计的整数它和训练配置里names列表的下标一一对应。从VOC转YOLO的换算关系并不复杂x_center (xmin xmax) / 2 / image_width y_center (ymin ymax) / 2 / image_height box_width (xmax - xmin) / image_width box_height (ymax - ymin) / image_height整个YOLO格式的设计目标就是让标注与图片的实际分辨率解耦。你训练时imgsz设640还是960不需要回头改标注文件因为归一化坐标会跟着resize一起缩放。这也是为什么ultralytics、mmdetection这些框架普遍推荐YOLO格式的原因之一——省去每次换分辨率就重写标注的麻烦。但这个设计有个隐藏要求txt里每行的类别编号必须在names列表范围内。比如names只有鸡一个类编号写1就是越界训练时会直接报错或静默跳过。拿到数据集先统计所有txt里出现过哪些编号再和yaml里的names对齐这是十分钟能做但很多人跳过的事后面会在避坑章节展开。2.3 手工标注的价值与短板小目标、遮挡和边界框质量的检查点VOC和YOLO双格式齐全解决的是兼容性问题手工标注解决的是质量问题。这个数据集的核心卖点是手工标注不是自动标注生成的。两者在边界框质量上的差异非常大自动标注经常在目标边缘外扩一圈把背景吃进框里或者在小目标密集区域漏标手工标注只要标的人负责框通常紧贴目标轮廓。但手工标注也有固有的短板需要你拿到数据后主动检查。首先是遮挡问题。鸡舍里的鸡经常互相叠着标的人如果只标露出来的部分框会只覆盖局部如果标的人凭经验框出完整身体区域又可能把别的鸡带进来。这个数据集叫家禽鸡小鸡检测数据集小鸡目标通常很小一张图里几十只小鸡挤在一起框的IoU重叠度会很高。其次是边界情形目标在图片边缘被截断一半时框应该标到图片边界还是只标可见部分不同标注员的习惯不同这在小目标数据里会影响训练效果。检查框质量的实操方法是把标注叠回图片肉眼抽检。后面第6章会给出一个可视化脚本跑完能直观看到框和目标的贴合程度。2970张图如果每第10张抽检一张大约300张人工扫一遍耗时不超过一小时但能避免训练完才发现框质量不行、白白跑几天实验的窘境。3. 把2970张家禽数据跑通YOLO训练目录整理、数据划分与关键参数3.1 解压后的目录检查与images/labels配对脚本拿到zip解压后先别急着训练。第一步是确认目录结构。常见的数据集组织方式是images目录放图片labels目录放对应txt标注两者文件名前缀相同、后缀不同。也有把train和val直接分好的版本还有只给全部图片和标注、让你自己划分的版本。在动手之前先跑一个配对检查脚本确认图片和标注一一对应避免训练到一半才报错。from pathlib import Path img_dir Path(images) lab_dir Path(labels) img_exts {.jpg, .jpeg, .png, .bmp} imgs {p.stem: p for p in img_dir.rglob(*) if p.suffix.lower() in img_exts} labels {p.stem: p for p in lab_dir.rglob(*.txt)} missing_label imgs.keys() - labels.keys() missing_img labels.keys() - imgs.keys() print(f图片总数: {len(imgs)}标注总数: {len(labels)}) print(f有图无标注: {len(missing_label)}有标注无图: {len(missing_img)}) for name in sorted(missing_label)[:10]: print(f 缺标注: {name}) for name in sorted(missing_img)[:10]: print(f 缺图片: {name})这段脚本的逻辑很简单遍历images目录取所有图片主文件名遍历labels目录取所有txt主文件名然后用集合的差集找出两边对不上的。主文件名用Path.stem取它只取文件名去掉后缀的部分所以图片是chicken_001.jpg、标注是chicken_001.txt也能正确配对。rglob(*)是递归遍历子目录里的文件也能找到避免手动写二级目录路径出错。跑完如果发现有图无标注的存量比如多出几张空图片但训练框架能跳过但有标注无图片是更要命的问题训练时读取txt对应图片会直接报错中断。出现这种情况需要查labels目录里是否混入了非标注txt文件比如标注工具的缓存文件或说明文档把无关txt移出去就能解决。3.2 数据划分脚本与data.yaml生成配对没有问题接下来划分训练集和验证集。如果原本目录里已经有train和val子目录可以跳过这一步如果所有图片混在一起用下面这个脚本按8:2划分。值得提前说的是先按地块或拍摄批次分组再划分最后在避坑章节会专门讲数据泄漏问题。import random import shutil from pathlib import Path random.seed(42) val_ratio 0.2 images sorted(Path(images).rglob(*)) img_exts {.jpg, .jpeg, .png, .bmp} imgs [p for p in images if p.suffix.lower() in img_exts] random.shuffle(imgs) val_count int(len(imgs) * val_ratio) val_imgs set(imgs[:val_count]) for split in (train, val): (Path(dataset) / split / images).mkdir(parentsTrue, exist_okTrue) (Path(dataset) / split / labels).mkdir(parentsTrue, exist_okTrue) for img in imgs: lab Path(labels) / (img.stem .txt) target_img_dir val if img in val_imgs else train shutil.copy2(img, Path(dataset) / target_img_dir / images / img.name) shutil.copy2(lab, Path(dataset) / target_img_dir / labels / lab.name) print(f训练集: {len(imgs) - val_count} 张验证集: {val_count} 张)脚本里random.seed(42)固定随机种子保证每次划分结果一致这是复现实验的前提。shutil.copy2而不是shutil.copy是为了保留文件元数据虽然对训练没有影响但如果后续要按时间戳排查问题时会用到。val_ratio设0.2是默认值对小数据集可以用0.1留更多数据训练如果数据总量特别小甚至可以把验证集划成独立的最后一批鸡舍而不是随机抽样这在养殖场景是更合理的做法。3.3 YOLO训练命令与参数选择目录准备好后生成data.yaml。这是训练框架读取数据集的入口文件里面指定图片路径、标签路径和类别名。path: /absolute/path/to/dataset train: images/train val: images/val names: 0: chicken注意train和val的路径是基于path的目录不是完整路径。如果你把整个目录挂在不同机器上只需要改path一行train和val不用动。names的编号必须和txt里的类别编号严格对应如果labels里出现过0和1两个编号但names只写了0: chicken那编号1的类会被静默丢弃或在训练时报错。接下来是训练命令。以ultralytics的YOLO11为例yolo train datadata.yaml modelyolo11n.pt imgsz640 batch16 epochs100 device0yolo11n.pt是从官方权重继续训练的基础模型n是nano版本的缩写参数量最小、显存占用最低。如果你的显卡显存大于8G可以换yolo11s.pt甚至yolo11m.pt检测精度会更好训练时间也更长。imgsz设640是通用默认值训练时图片会先等比缩放再padding到640x640loss计算和推理都在这个分辨率上进行。batch根据显卡显存来调。显存不够时优先降batch而不是降imgsz因为batch影响的是梯度稳定性imgsz影响的是小目标检测率。epochs设100配合早停策略就够了训练脚本默认会在连续50个epoch验证集指标不再提升时自动停止不用手动盯着。device0表示用第一块GPU纯CPU训练2970张数据预计要按天计算不建议试。3.4 小目标场景下的锚框与增强配置鸡舍场景的特点是小目标密集小鸡在图里可能只有十几个像素宽。这类场景直接套默认参数最容易出现的结果是loss降得很快但验证集mAP卡在0.5以下——检出来的框要么漏掉目标要么位置偏移。常见做法是为小目标调整三处参数。第一处是imgsz。把640提到960训练时小鸡在特征图上的像素数会增加降低检测难度。代价是显存占用变大batch要跟着缩。第二处是增强策略。YOLO默认开了mosaic增强把四张图拼成一张对小目标有正面作用因为它让模型学会在小图里找小框但mosaic在小目标场景偶尔会让目标边缘被截断造成标注和内容对不上。另一个性价比高的增强是copy-paste把小目标从一张图复制粘贴到另一张图的随机位置直接增加小目标样本量。第三处是anchor或者叫auto anchor。YOLO系列训练开始时会自动从数据里重新聚类anchor如果数据集的框宽高比和COCO差异很大比如都是细长条自动聚类会覆盖默认值。这个机制是自动的你不需要手动干预但要知道训练日志里生成的anchors统计值可以直接看出框的尺寸分布。如果聚类结果里出现大量面积接近1的锚框说明标注文件里混入了和图片一样大的错误框得回到标注检查环节。4. 数据集使用避坑指南格式错乱、路径问题与类别不平衡的5个典型坑4.1 坑一txt坐标越界导致训练loss异常现象训练正常启动前几个epoch的loss明显偏高且波动剧烈或者直接出现运行时警告提示anchor从图片边界外被过滤。原因YOLO格式要求归一化坐标在0到1之间但手工标注转格式时偶尔会算出越界值。比如目标紧贴右边缘标注员把xmax画到比图片宽度还大的位置或者转换脚本在计算归一化坐标时分母不是图片宽高而是把宽高搞反了导致坐标放大或缩小。这类问题在单张图上看着不明显训练时px、py超过有效范围的anchor都会被丢掉模型能学到的信息变少指标自然上不去。解决写一个越界检查脚本遍历所有txt对每一行判断每个值是否在合法范围内把超出记录打印出来。修复方案是clip把坐标按0到1截断但要注意宽高也一并截断否则中心点坐标被截了、框的跨度没变依旧越界。最稳妥的做法是从原始VOC的xml重新转换一次确认转换脚本的分母没有写错。4.2 坑二类别编号与names对不上mAP计算全乱现象训练结束时验证集mAP看曲线是正常的但打印的类别名称和实际图片内容对不上比如显示的是0号类别chicken框里的目标确实也是鸡但precision和recall数值全在0.1以下晃。原因YOLO格式里txt的每一行只是数字编号没有类名文本。训练时框架按照data.yaml里names的下标来解释编号。如果你把names写成{0: chicken, 1: chicken}这样编号和实际标注错位或者标注里混入了非目标类别编号每个类别的统计就会乱掉。这和COCO 80类模型里的类别读取问题本质相同——编号从0开始模型输出的是coco_classes[8001]这样的下标下标错一格整个类目解释就偏掉。解决训练之前读一遍labels目录里所有txt收集出现过哪些编号得出编号全集再拿它去写data.yaml的names。如果发现编号有0、1、2而你知道这个数据集只标鸡那就要打开对应的VOC xml文件确认是否有其他类别还是标注工具导出的编号算法有偏移。这里最省时间的办法是用脚本读xml里的name字段列表直接把名称和编号对应关系打印出来再人工确认一遍。4.3 坑三Windows与Linux路径分隔符问题现象在Windows下配置好data.yaml能正常训练把整个目录拷到Linux服务器上启动训练后立刻报错找不到图片或者images和labels的相对路径配对失败。原因Windows路径用反斜杠\Linux用正斜杠/。虽然Python的pathlib能自动处理系统区分符但data.yaml里写死的路径如果是从Windows复制粘贴过来的反斜杠在Linux里会被当成转义符或非法字符。另一层隐患是yaml文件里如果写了path: C:\Users\xxx\data冒号和反斜杠组合在yaml解析时会有歧义结果是路径被截断或解析出错误目录。解决data.yaml里的path统一用正斜杠写的绝对路径在Linux服务器上重新生成一份或者在脚本里用os.path.join拼接。如果项目要求跨平台最简单的做法是让脚本自动检测当前系统并生成对应的绝对路径不把路径写死在yaml里。拿到数据集的第一天就统一这个约定能省掉后续无数问题尤其是多人协作、有人习惯Windows做标注有人用Linux跑训练时。4.4 坑四训练集和验证集样本重叠指标虚高现象训练曲线和验证曲线都很好看mAP达到0.9以上部署到真实鸡舍里就熄火漏检严重。原因数据划分时没有按拍摄场景分组。鸡舍巡检视频连续拍了几百张随机划分会让同一批鸡的相似画面同时出现在训练集和验证集里模型相当于看着答案考试验证指标虚高。这个问题在手工标注数据集中很常见因为标注员通常是对着同一个视频段一帧一帧截图的相邻帧高度相似。解决划分前先确认数据来源。如果2970张图来自若干段连续拍摄的视频按视频片段分组划分训练集和验证集保证同一段视频的所有帧只进一个集合。如果数据来自多个不同的养殖场批次优先按批次划分退而求其次才是随机划分。这一步需要在开跑训练之前做而不是等模型训完发现问题再回头重新划分重跑一整轮实验的时间成本很高。4.5 坑五小鸡目标太小默认参数检不出现象训练跑完验证集大鸡的检测框又准又稳小鸡的框要么完全缺失要么只框住一半precision和recall在小目标区间明显偏低。原因YOLO训练会把图片resize到imgsz指定的大小目标在resize后的图上如果小于几个像素宽下采样到深层特征图时可能只剩不到1个像素的信息量骨干网络根本提取不到有效特征。小鸡目标密集时还会伴随遮挡一个框里塞了两三只鸡模型学到的是模糊的混合特征。这是小目标检测的通病不是这个数据集特有的缺陷但家禽检测场景特别容易触发。解决常用手段是调大imgsz到960甚至1280让目标在输入图上占据更多像素。显存不够时可以先训一个imgsz640的模型再在它基础上用更大imgsz微调几十个epoch这类多尺度训练在ultralytics里只用改训练命令简单有效。推理阶段也有补救办法对小图切割成若干patch分别推理再合并结果等于把小目标放大了再看。最后是数据增强里的copy-paste把标注的小鸡框从原图扣出来随机粘贴到其他图的空白区域扩充小目标样本数量对密集场景的泛化有明显帮助。5. 这个数据集值不值得用场景覆盖度评估与增量补标的最小路径5.1 快速评估类别分布、拍摄视角与背景多样性拿到数据的头一小时先别急着训练先做一个使用价值评估。2970张图听着不少但如果全部是同一个鸡舍、同一个角度、同一种光照条件下拍的照片训练出的模型换个鸡舍基本就废了这就是场景覆盖度问题。打开图片扫一遍重点关注三个维度拍摄视角是俯拍还是平视俯拍模型的泛化性会比平视好很多因为俯拍的目标形状和大小变化相对单一光照条件是否多样白天强光和夜间红外补光下的鸡在特征空间里差距很大地面背景是否相似水泥地、垫料地、网床地三种背景会让模型学会背景识别捷径。再配合一张类别分布统计表把标注里每个类别的目标数、平均框面积、最小框面积列出来。检测类目标框的大小直接决定了训练难度平均框面积占全图比例如果低于5%就要按小目标策略准备。把2970张图和标注结构做成这样的评估报告一小时内能完成做一次就能判断这个数据集是直接拿来训练就能用的、还是只适合当预训练基础数据、又或者根本不够需要继续补标。5.2 漏标与错标的抽检方法可视化叠加标注评估覆盖度之后抽检标注质量。常见做法是写一个可视化脚本把标注框画回原图按每10到20张图抽1张的密度生成一张栅格图。人工扫完大约需要30到60分钟重点看三类问题边界框是否紧贴目标边缘如果框外侧留了一圈明显背景说明标注员为了省事把框画大了这会让模型学到错误的边界框和目标是移动错位的标注了左边一只鸡右边的位置这是视频帧时间戳对不上的典型症状重叠目标是否被漏标密集鸡群里一个框里挤着好几只鸡但只有一只有标注的情况这会直接拉低recall。还有一种容易忽略的错标类型是类别标签文本出错尤其是这个数据集如果包含小鸡和成年鸡两类的划分。打开标注txt第一列是0还是1再对应原图确认数字和物体是不是一致。如果标注工具导出的类别和实际画面对不上训练出来的模型会把成年鸡错认成小鸡这类错误在纯数字标注里很难用肉眼通过看框发现非要对回原图才能暴露。5.3 增量补标的最小流程把新场景数据并入现有训练2970张图覆盖度不够时正确的做法是增量补标不是推翻重标。先拿当前模型在目标新场景里跑一批推理把置信度低于0.3的检测结果和一整批漏报的截屏挑出来错误漏检的高置信度框如果对不上鸡的位置说明已经有分类偏差把这些图导出为新标注候选集。然后可以用LabelImg或X-AnyLabeling这类工具打开候选图保留置信度高的框手工调整边界漏检的框手工补画整个过程标注量远小于从零开始标一批新图。标注完成导出后转成YOLO格式并和原始数据合并。合并前跑一遍配对检查和越界检查再统一划分训练验证集。增量补标最容易被忽视的一点是新场景的图片不要直接混进随机划分里而要让新场景的图片同时出现在训练集和验证集中才能暴露模型是否在旧场景过拟合。如果新数据量只有100到200张可以先在旧模型上做少量epoch的微调比把新旧数据混在一起重训的效率更高这也是实践中更省事的做法。6. 20分钟跑完数据体检一个脚本检查格式、分布与训练可行性最后一件事也是我最建议你在拿到任何目标检测数据集后先做的事跑一个综合性体检脚本而不是直接开训练。训练一跑就是几小时甚至几天回头才发现标注有问题前后浪费的时间才是最大的成本。这个脚本把前面几章提到的检查点合并成一次运行输出20分钟内能完成。from pathlib import Path from collections import Counter lab_dir Path(labels) img_dir Path(images) num_boxes 0 cls_counter Counter() empty_files [] out_of_bounds [] box_ratio [] for txt in sorted(lab_dir.rglob(*.txt)): lines txt.read_text().strip().splitlines() if not lines: empty_files.append(txt.stem) continue for line in lines: parts line.strip().split() if len(parts) ! 5: print(f格式错误: {txt.stem}: {line}) continue cls int(parts[0]) x, y, w, h map(float, parts[1:]) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): out_of_bounds.append((txt.stem, line)) cls_counter[cls] 1 num_boxes 1 box_ratio.append(w * h) print(f目标总数: {num_boxes}) print(f类别分布: {dict(cls_counter)}) print(f空标注文件数: {len(empty_files)}) print(f越界行数: {len(out_of_bounds)}) if box_ratio: print(f框面积占比 中位数: {sorted(box_ratio)[len(box_ratio)//2]:.4%}) print(f框面积占比 最小: {min(box_ratio):.4%}最大: {max(box_ratio):.4%}) small_ratio sum(1 for r in box_ratio if r 0.01) / len(box_ratio) print(f小于1%的小目标占比: {small_ratio:.2%})脚本逐行读取所有txt标注统计目标总数和类别分布找到空标注文件、坐标越界的行以及框面积占比的分布。框面积占比是判断小目标严峻程度的关键指标——如果中位数低于1%训练参数必须按小目标场景调整。空标注文件在YOLO训练里会被当作负样本处理少量没关系数量多了会让模型倾向于输出空检测框。跑完这份体检你会得到三个层面的信息数据基本状况是否正常、类别是否平衡、小目标压力有多大。基于这些输出再决定imgsz和增强策略比自己凭感觉拍脑袋可靠得多。我自己的习惯是每拿到一份标注数据不管对方声称质量多好都要跑一遍这样的检查再进训练这个习惯帮我避开了很多训练跑一半才发现标注不可用的坑。最后提醒一句训练完成后小目标检测的推理阶段可以考虑在TensorRT上做一次INT8量化加速640分辨率在日产消费级显卡上做实时推理绰绰有余但那是模型训练完全跑通之后的事。希望这份从格式理解、数据体检到训练参数的全过程笔记帮到你少踩几个坑把时间花在真正有用的模型迭代上。本文还有配套的精品资源点击获取