智慧养殖场肉鸡健康检测:VOC+YOLO数据集与YOLOv8训练实践
简介这份数据集面向智慧养殖场景中的肉鸡健康状态检测任务同时提供VOC与YOLO两种标注格式适用于计算机视觉学习者、养殖智能化项目开发者进行目标检测模型训练与效果验证。数据共涉及4657张图片的标注信息类别分为AbNormal与Normal两类总计21610个矩形框其中异常类8447个、正常类13163个类别分布较均衡。压缩包共2000个文件以1999个XML标注文件为主另含1个使用说明TXT整体大小约396.56MBXML与TXT标注文件配套使用可直接接入主流目标检测框架。压缩包内还包含“使用前必读”说明标注工具采用labelImg规则清晰便于二次整理与扩展。目前已有395人学习下载适合需要标准格式数据、希望直接开展肉鸡健康检测实验的读者使用。1. 智慧养殖场肉鸡健康状态检测4657 张图要解决“看不见的病”做过养殖场智能化的人都有体会肉鸡舍密度高、存栏大疾病一旦在鸡群里传开靠人工巡检根本来不及。鸡的精神状态、运动姿态、羽毛外观都是信号但让饲养员一天两次盯着几万只鸡看不现实。智慧养殖场肉鸡健康状态检测这个方向核心就是把目标检测模型装进鸡舍摄像头后端实时框出“状态异常的个体”。而任何检测模型落地的前提是先有一份标注可靠、格式统一的数据。这套 VOCYOLO 双格式、4657 张、2 类别的数据集解决的就是从“有原始视频”到“能直接开训练”的最后一公里。它适合做养殖 AI 的算法工程师快速验证方案也适合系统集成商在交付前评估 YOLO 系列在鸡舍场景下的可行性还适合拿真实场景做课题的学生完整跑一遍目标检测流程。2. 拆开 .7z 包VOC 与 YOLO 两套标注结构长什么样怎么互相转换2.1 一套框两种表达XML 给人看txt 给模型吃压缩包解压后你能看到三类文件jpg 图片、xml 标注、txt 标注。xml 是 PASCAL VOC 风格txt 是 Darknet/YOLO 风格两套标注描述的是同一批目标框区别在于表达方式。VOC 的 XML 结构是树形的人眼容易读annotation filenameIMG_20231105_093412_0042.jpg/filename size width1920/width height1080/height depth3/depth /size object nameunhealthy/name bndbox xmin612/xmin ymin348/ymin xmax905/xmax ymax721/ymax /bndbox /object /annotationname是类别名bndbox里是左上角、右下角的像素坐标。它适合做可视化和人工校对但 YOLO 训练框架不会直接吃这种格式需要解析成相对坐标。YOLO 的 txt 则是一行一个框五个数字各管一档0 0.3953 0.4954 0.1526 0.3458 1 0.6214 0.5128 0.2131 0.2987依次是类别 id、归一化中心点 x、归一化中心点 y、归一化宽、归一化高。归一化是除以图片的真实宽高得到的取值必然在 0 到 1 之间。这种格式 YOLO 系训练时直接读不需要二次解析这也是数据集打包成双格式的原因VOC 方便核查标注质量YOLO 方便直接进训练管线。2.2 目录结构与文件名对应先核对三件事再动手处理这类数据集我一般先做三层核对能省掉后面大半的排错时间。第一层是文件名前缀。YOLO 训练要求图片和标签是“同名不同后缀”比如IMG_0001.jpg对应IMG_0001.txt。如果压缩包里的命名是IMG_0001.jpg配image_0001.txt这就是第一个需要修的隐患。第二层是类别 id 顺序。txt 里第一列是 0 还是 1对应 data.yaml 里的哪一个名称得拿 XML 里的name字段反推确认不能靠猜。第三层是目录层级。有的打包是images/train和labels/train平级有的则在外面多套一层dataset/dataset/images路径写错时训练不会报错但会静默只跑验证集。常见目录组织如下用途路径内容训练图片images/train原始 jpg 帧验证图片images/val未参与训练的 jpgYOLO 标签labels/train与图片同名的 txtVOC 标注annotations全部 xml按需划分如果你拿到的压缩包不是这个结构直接用软链或移动命令整理成这个布局不要硬改训练代码去适配目录。2.3 手写 VOC 转 YOLO 脚本核心逻辑与两个防御点即便数据集同时给出两种格式训练前也应该以 XML 为准再做一次批量转换。原因很实际有些打包的 txt 可能是经过二次处理生成的坐标可能被工具四舍五入出问题。以 XML 做权威源重转一遍心里踏实。import xml.etree.ElementTree as ET from pathlib import Path # classes 的顺序决定 YOLO 类别 id务必和 data.yaml 保持一致 classes [healthy, unhealthy] def convert_voc_to_yolo(xml_path: Path, out_dir: Path): tree ET.parse(xml_path) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in classes: continue cid classes.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 防御点 1坐标合法性检查 if not (0 xmin xmax w and 0 ymin ymax h): print(f坐标越界: {xml_path.name} {name}) continue x_c (xmin xmax) / 2.0 / w y_c (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 防御点 2归一化结果必须在 0~1 if not (0 x_c 1 and 0 y_c 1 and 0 bw 1 and 0 bh 1): print(f归一化越界: {xml_path.name}) continue lines.append(f{cid} {x_c:.6f} {y_c:.6f} {bw:.6f} {bh:.6f}) out_dir.mkdir(parentsTrue, exist_okTrue) (out_dir / (xml_path.stem .txt)).write_text(\n.join(lines), encodingutf-8) # 批量执行 xml_dir Path(annotations) txt_dir Path(labels_yolo) for xml_file in xml_dir.glob(*.xml): convert_voc_to_yolo(xml_file, txt_dir)逻辑不复杂但两个防御点建议保留一是坐标越界检查二是不超过 1 的归一化检查。很多标注工具导出的框会偶尔跑到图像边缘外直接转进 YOLO 会让训练出现 NaN loss有这段检查能第一时间筛出脏样本。3. 用这套数据集训练 YOLOv8目录布局、data.yaml 与最小训练命令3.1 解压与目录归位先把数清对拿到.7z包后解压命令很直接7z x 智慧养殖场肉鸡健康状态检测数据集VOCYOLO格式4657张2类别.7z -o./chicken_dataset cd chicken_datasetLinux 上没装 7z 的话先apt install p7zip-fullWindows 上用 7-Zip 图形界面右键解压也行。解压后第一件事不是写配置而是数文件find . -name *.jpg | wc -l find . -name *.txt | wc -l这两条命令分别统计图片数和标签数。4657 张图对应的 yolo txt 也应该是 4657 份。如果图片有 4657 张但 txt 只有 4580 张说明有 77 张图没标注或命名对不上这种缺失要先找出来不然训练时 ultralytics 会报告 “found no labels” 之类的提示。用 PyCharm 或 VS Code 跑训练时注意工作目录一定设在chicken_dataset的上一级别让 IDE 把相对路径解析到项目根目录以外的地方很多“明明数据在却加载不到”的报错就是工作目录飘了。3.2 写 data.yamlnames 顺序错了模型会学到错误映射YOLOv8 的配置文件用 YAML 写路径用绝对路径最省事# /data/chicken_dataset/chicken.yaml path: /data/chicken_dataset train: images/train val: images/val nc: 2 names: 0: healthy 1: unhealthy这里有个高频坑names的索引顺序必须跟 txt 第一列的 id 完全对应。如果 txt 里第二类写在第一行、第一列是 1而 yaml 里0: unhealthy, 1: healthy模型就会把病鸡学成健康、健康学成病鸡训练 loss 照样下降验证 mAP 也不低但实际检测结果完全错乱。提示不要凭感觉定顺序。先head -5 labels/train/*.txt随机看几个文件的第一列再回到 XML 里找同名的name标签确认 id 0 和 id 1 分别是谁最后才写 yaml。3.3 最小训练命令与参数含义环境装好 ultralytics 后用一条命令启动训练pip install ultralytics yolo train data/data/chicken_dataset/chicken.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ patience10 \ projectruns/chicken \ nameexp01参数按需调整imgsz640是精度和速度的折中。鸡舍摄像头一般 1080p如果鸡只个体在画面里偏小可以试imgsz960或1280显存占用会明显上涨8G 显存跑 1280 基本会 OOM。batch16在 8G 显存跑 640 输入通常没问题OOM 就降到 8。patience10表示连续 10 个 epoch 验证指标没提升就早停防止周末挂着不收敛空耗电费。modelyolov8s.pt是带 COCO 预训练权重的 s 模型迁移学习比从头训练收敛快得多。两类别任务完全不需要用 yolo 官方没提供的自定义结构直接在 s 或 m 上微调即可。3.4 训练过程中的两个判断信号训练跑起来后不要干等。终端里会滚动打印 box_loss、cls_loss 和验证集 mAP50把这些信号分成两类看一类是 loss 曲线。前 20 个 epoch box_loss 快速下降是正常的如果前几个 epoch 就出现 NaN大概率是标签里有坐标越界或图片损坏回头跑一遍 2.3 节的脚本加检查。另一类是验证集 mAP50。两类别任务如果 mAP50 一直在 0.9 附近徘徊属于健康场景的正常水平如果卡在 0.4 上不去别急着调模型先检查是不是类别 id 反了或者训练集验证集混了。训练结束后的产物在runs/chicken/exp01/weights/下best.pt是验证集表现最好的权重last.pt是最后一个 epoch 的权重后续评估一律用best.pt。4. 两类别健康检测评估mAP、F1 与不平衡数据下的阈值调节4.1 验证集指标怎么读训练完用 best 权重跑一次验证yolo val modelruns/chicken/exp01/weights/best.pt \ data/data/chicken_dataset/chicken.yaml输出里重点看三列mAP50、mAP50-95、每类的 Precision/Recall。mAP50 是 IoU 阈值为 0.5 时的平均精度两类别任务想上线建议至少 0.85mAP50-95 是更严格的评估方式值低一些很正常。真正要盯的是每一类的 Precision 和 Recall因为它会暴露类别不平衡的问题。假设 healthy 类有 4000 个框、unhealthy 类只有 600 个框模型只要把全部框都预测成 healthy整体正确率就有 87%看起来不错但 unhealthy 类的 Recall 是 0实际场景里等于完全没检测。看指标时不要只看总 mAP单独点开每个类的指标看。4.2 病鸡样本少怎么办养殖场景下 unhealthy 类占比天然低于 healthy 类这是数据分布决定的不是标注偷懒。处理这种不平衡我按优先级做三件事第一是重采样。把 unhealthy 类的图片在训练时多做几次重复采样或者用ultralytics里augmentTrue的 mosaic 和 fliplr 增强让少样本类在训练中见到的次数多一些。第二是调整损失权重给少样本类的 cls_loss 加权。YOLOv8 没有直接暴露类别权重参数通常是在数据加载器里按类别频率做采样概率修正。第三是评估时别用默认置信度。默认conf0.25对少样本类太苛刻现场验证时降下来。4.3 置信度阈值漏报比误报更贵养殖场景有个特殊性漏掉一只病鸡的代价可能是一整舍传染误报一次顶多多看一眼监控画面。所以我部署时一般会大幅降低置信度阈值from ultralytics import YOLO model YOLO(runs/chicken/exp01/weights/best.pt) results model.predict( camera_frame_01.jpg, conf0.15, iou0.45, )conf0.15意味着模型只要有一点把握就报出来误报会增多但漏检会明显下降。iou0.45控制去重阈值框重叠超过 45% 就合并避免同一只鸡被框三次。置信度调多低要结合现场的复核成本看如果告警后有饲养员盯着画面二次确认低一点无妨如果告警直接联动自动化设备反而需要抬高阈值防止误触发。5. 避坑VOC 与 YOLO 双格式数据的 5 个高频坑与排查5.1 文件名大小写不同步导致“找不到标签”现象训练时 ultralytics 提示大量图片没有对应标签但 labels 目录里明明有文件。 原因Windows 打包或解压时把IMG_0001.JPG改成img_0001.jpgLinux 上大小写敏感txt 前缀匹配不上。 解决统一小写并同步改名。for f in *.JPG; do mv $f ${f%.JPG}.jpg; done改完图片名后再同步改对应的 xml 和 txt 文件名或者用脚本做批量映射。5.2 类别 id 与 yaml 顺序错位现象训练 loss 正常mAP 不低但实地检测时发现框的位置都对类别却张冠李戴。 原因txt 第一列是 0/1和names的顺序没对齐。 解决随机打开一个干净的验证结果图对照 XML 里的name和 txt 第一列反推出真实映射关系。这个坑不需要改代码只改 yaml 的names顺序即可。5.3 归一化坐标写成像素坐标现象训练早期 loss 直接变 NaN或者训练结束后模型预测框全部跑到画面边缘。 原因有人把x_center写成了 xmin 的像素值没有除以图片宽高。txt 里出现大于 1 的数基本就是这个问题。 解决用 2.3 节脚本批量重转脚本里的越界检查会把这些脏数据全部筛出来。这一步建议在训练前必做属于后悔药型的保险。5.4 训练集和验证集有重复帧mAP 虚高现象验证集 mAP 高达 0.98拿现场新画面一测立刻跌到 0.6。 原因摄像头采集的是连续视频帧按单帧随机切分时同一段视频里相邻几帧会同时混进 train 和 val模型相当于见过答案再考试。 解决切分时按视频片段切而不是按单帧切。如果压缩包内没有划分好的train/val目录自己用时间戳文件名前缀分组后整组划分。网格方法取每段视频前 80% 帧进 train后 20% 进 val杜绝时间相邻导致的泄漏。5.5 解压后多套一层目录现象配置文件写好后启动训练终端提示训练集图片数 0程序却正常跑到验证环节。 原因压缩包内层是dataset/dataset/images/...路径指到了不存在的images。 解决先跑一次 find 数文件确认实际目录层级后把path指向真正含images和labels的层级。别依赖肉眼用命令核实。6. 进阶部署把健康检测模型放到养殖场边缘设备上的三个技巧6.1 导出 ONNX 接管推理训练完的 PyTorch 权重不适合直接部署到嵌入式设备先转 ONNXfrom ultralytics import YOLO model YOLO(best.pt) model.export(formatonnx, imgsz640, dynamicFalse)导出后在 Jetson 或瑞芯微盒子上用 onnxruntime 或 TensorRT 跑推理速度比直接跑 ultralytics Python 推理快很多。动态尺寸在边缘设备上会拖慢推理固定 640 即可。6.2 抽帧检测加滑动窗口消抖鸡舍画面变化慢不需要逐帧跑检测。一般做到每秒 1 到 2 帧就足够代价是检测频次降低换来的是边缘盒子温度和功耗可控。我踩过的坑是一开始让盒子 7x24 跑满帧温度直接飙到 80 度后来改成抽帧加队列缓冲才稳定。消抖的简单做法是维护一个长度为 3 的滑动窗口记录同一目标框连续几帧的检测结果。只有当连续 3 帧都出现 unhealthy 框且框中心距离在合理范围内才确认告警能滤掉单帧误报和光线抖动。6.3 用现场数据二次验证再联报警模型在测试集上的指标是温室指标鸡舍现场的阴影、风机、光照渐变都会影响置信度。部署前留出 20% 现场数据做二次验证第一天只录像不报警第二天对照录像观察误报漏报之后再接报警联动这是最稳的上线节奏。做完这一步会发现数据集本身的标注质量决定了模型上限而现场验证质量决定了能不能落地。希望这份踩坑经验对你有帮助。本文还有配套的精品资源点击获取