ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

鸡状态数据集转换与YOLOv8训练实战:从COCO JSON到目标检测模型

鸡状态数据集转换与YOLOv8训练实战:从COCO JSON到目标检测模型 简介在智慧养殖与家禽健康监测场景中该鸡状态图像数据集用于识别正常鸡与异常鸡可支撑自动化巡检、疾病预警等应用开发。资源包共2000个文件包含1997张JPG图像与3个COCO格式JSON标注文件压缩包容量约451.26MB可直接接入MMDetection、YOLO等主流目标检测框架。已有410人学习该资源适合计算机视觉算法工程师、养殖监控系统研发者及农业智能化研究者作为模型训练与效果验证的基础数据。数据集提供3749张训练图像正常状态识别平均准确率约91.8%覆盖不同光照、姿态与饲养环境下的鸡只样本结构化标注清晰便于数据划分与指标复现有效降低标注和预处理成本。整体而言该资源能帮助团队快速搭建家禽状态识别基线并在此基础上迭代优化模型性能。1. 鸡状态数据集到底是什么一套能落地的家禽监控训练资粮凌晨两点的鸡舍灯刚打开鸡群同时起身抢食。缩在角落不动的那只、羽毛蓬松的那只、走路打晃的那只才是养殖监控最需要盯住的“异常鸡”。鸡状态数据集就是为这个场景准备的一套目标检测训练集3749张训练集图片COCO JSON格式标注目标通常只有两类——正常的鸡和异常的鸡平均正常识别率在91.8%左右。这个数值得当参考基线看别当上线保证。适合两类人来用一是做养殖监控、家禽巡检的算法工程师二是想完整过一遍“目标检测常用标注工具 → COCO JSON转换 → YOLOv8训练自己的数据集”路径的入门开发者。数据本身不复杂复杂的是把格式吃透、把标注边界踩平。2. 把这份 COCO JSON 转成 YOLOv8 目录转换脚本、归一化与三个自检2.1 为什么先转格式COCO JSON 与 YOLO txt 的字段差异COCO JSON 是目标检测里最常见的“交换格式”而不是直接喂给训练器的格式。它把信息拆在三组数组里images记录文件名、宽高annotations记录每一条 bbox 坐标和类别 idcategories记录类别名称。这套鸡状态数据集标成 COCO JSON意味着 Detectron2、MMDetection 这类框架能直接读但 YOLOv8 默认不读 JSON它只认图片旁边同名的.txt文件每行一个目标写法是class_id cx cy w h四个坐标值都归一化到 0~1。转换的核心有三件事把 bbox 从“左上角 x、左上角 y、宽、高”换成“中心点 x、中心点 y、宽、高”除以图片宽高做归一化按image_id把images和annotations对应起来。听起来像套公式实际上大多数人第一次写都会漏掉越界处理和类别 id 偏移。内容COCO JSON 里的形式YOLO txt 里的形式bbox[x, y, width, height]左上角像素坐标cx, cy, w, h全部除以图片宽高类别 idcategory_id取值看 categories 数组从 0 开始的整数对应 data.yaml 里 names 的下标图片关联annotation.image_id → images.id图片同名 .txt 文件靠文件系统关联2.2 最小转换脚本 coco_to_yolo.py参数与边界处理常见做法是写一个几十行的独立脚本别用在线转换页面数据量一大在线工具就超时。下面这个脚本按图片 id 做 8:2 随机切分同时处理了iscrowd、小框过滤和越界裁剪。import json import random from pathlib import Path from collections import defaultdict def coco_to_yolo(json_path, img_dir, out_dir, split_ratio0.8, seed42): with open(json_path, encodingutf-8) as f: coco json.load(f) # 建立 image_id - 图片信息的映射后面要用到宽高 img_id_to_info {} for img in coco[images]: img_id_to_info[img[id]] img # iscrowd1 的标注通常是大群鸡YOLO 单框检测学这种目标容易变成玄学 ann_by_img defaultdict(list) for ann in coco[annotations]: if ann.get(iscrowd, 0) 1: continue ann_by_img[ann[image_id]].append(ann) out_dir Path(out_dir) for split in (train, val): (out_dir / labels / split).mkdir(parentsTrue, exist_okTrue) (out_dir / images / split).mkdir(parentsTrue, exist_okTrue) img_ids list(img_id_to_info.keys()) random.Random(seed).shuffle(img_ids) n_train int(len(img_ids) * split_ratio) for i, img_id in enumerate(img_ids): img img_id_to_info[img_id] split train if i n_train else val src Path(img_dir) / img[file_name] if not src.exists(): print(f[skip] {src} 不存在) continue # 图片复制到新目录txt 用同名 dst out_dir / images / split / src.name dst.write_bytes(src.read_bytes()) lines [] for ann in ann_by_img[img_id]: x, y, w, h ann[bbox] # 小于 10 像素的框一般是标注噪声直接丢 if w 10 or h 10: continue # 原标注可能越界先裁回图片范围内 x1 max(0, x) y1 max(0, y) x2 min(img[width], x w) y2 min(img[height], y h) if x2 - x1 0 or y2 - y1 0: continue cat_id ann[category_id] nw (x2 - x1) / img[width] nh (y2 - y1) / img[height] cx (x1 (x2 - x1) / 2) / img[width] cy (y1 (y2 - y1) / 2) / img[height] # COCO 的 category_id 从 1 开始YOLO 从 0 开始 lines.append(f{cat_id - 1} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) if lines: label_path out_dir / labels / split / (src.stem .txt) label_path.write_text(\n.join(lines), encodingutf-8) if __name__ __main__: coco_to_yolo(chicken_annotations.json, images, yolo_dataset)逻辑说明脚本先用img_id_to_info记住每张图的宽高这是归一化必需的iscrowd1的标注在 COCO 里表示“无法数清的一群”这种目标不应该进单框检测训练集。越界裁剪是刚需很多标注工具生成的 bbox 会超出图片边界几像素直接归一化会出现大于 1 的坐标训练早期 loss 直接 nan。参数说明split_ratio0.8是按图片 id 维度切不是按 annotation 切因为同一张图的多条标注必须待在同一个集合里否则验证集等于被训练集剧透过。cat_id - 1成立的前提是这份数据的 categories 顺序就是 normal_chicken、abnormal_chicken 且 id 为 1、2如果你拿到的 JSON 里 id 不连续这段要改成显式映射字典。2.3 转换后的三个自检同名匹配、越界校验、抽样画框转换完成先别急着训练。第一步检查图片和 txt 数量差多少ls yolo_dataset/images/train | wc -l ls yolo_dataset/labels/train | wc -l数量不齐大概率说明有图片没有任何标注。这种情况要么是原标注漏标要么是脚本里if lines跳过了空标注。开发集里留一部分背景图没问题但你要知道它们在哪里否则后期统计类别分布会被误导。第二步抽查 txt 坐标范围。正常值的范围一定是 0~1出现负值或超过 1 的值就是归一化没做对。用一条 Python 命令批量扫from pathlib import Path for p in Path(yolo_dataset/labels).rglob(*.txt): for line in p.read_text().strip().splitlines(): parts list(map(float, line.split())) assert all(0 v 1 for v in parts[1:]), f{p}: {line}第三步抽样画框。用 OpenCV 把训练集的 20 张图画上框人眼过一遍。重点看两件事框有没有框住整只鸡还是只框住半只有没有把两只靠在一起的鸡圈在同一个框里。这一步在 30 分钟内能做完却能提前暴露这个数据集的“合框”问题后面第 5 章专门讲。3. 用转换后的数据训练 YOLOv8最小命令、类别权重与精度对照3.1 先写 data.yamlnc、names 与路径的三个约定YOLOv8 训练自己的数据集第一件事不是调模型是写data.yaml。写错names顺序是训练阶段最常见的翻车根源。文件长这样path: /absolute/path/to/yolo_dataset train: images/train val: images/val nc: 2 names: 0: normal_chicken 1: abnormal_chicken关于names有一个易错点刚才转换脚本里用cat_id - 1得到 0 和 1如果这份鸡状态数据集在 categories 数组里把 abnormal 排在 normal 前边你的names列表顺序就必须跟着换否则模型会把“精神萎靡的鸡”学到 normal 这个类别上训练日志看着 loss 在降实际学的东西完全反了。路径尽量写绝对路径。path写相对路径在换机器训练时经常因为当前工作目录不同而全盘报错把时间省下来留给后面排查。图片后缀名不统一也要统一成 .jpgYOLO 系列对图片名和后缀的依赖比想象中强。3.2 最小训练命令epoch、imgsz、batch、patience 的选择常见做法是先用yolov8m起步不要一上来就yolov8x3749 张训练集撑不起超大模型。最小训练命令pip install ultralytics yolo train datachicken.yaml modelyolov8m.pt epochs80 imgsz640 batch16 patience15 device0参数说明imgsz640是速度与精度的平衡点。监控画面里的鸡通常只占几十像素如果用小目标专项经验可以试imgsz960显存占用和训练时间都上浮但小目标漏检会明显改善。patience15是早停参数连续 15 轮验证集指标不涨就停这份数据量一般 60~80 轮能收敛硬跑 300 轮纯属浪费时间。batch16在 16G 显存上跑yolov8m刚好够用显存小的直接降 batch但别降到 1BN 层在小 batch 下学不稳最终 mAP 掉两个点都正常。训练时盯着终端里P / R / mAP50这几个数。前 20 轮数字突然跳一下是正常现象模型正在换尺度。如果不到 10 轮 P 就冲到 0.92要怀疑验证集是不是被训练集污染了回头查切分逻辑。这种小数据集不需要跑满早停触发就收工。3.3 正常/异常类别不平衡先看 per-class recall 再调权重“平均正常识别率 91.8%”这个数字是这类数据集的参考基线但它是“平均”对异常鸡这一类的 recall 通常要低不少。训练完先跑验证看 per-class 指标yolo val modelruns/detect/train/weights/best.pt datachicken.yaml输出里会包含 normal_chicken 和 abnormal_chicken 各自的 precision 和 recall。如果 normal 有 0.9 而 abnormal 只有 0.6就是类别失衡。此时别急着调权重先在验证集上想清楚一个问题这个模型将来漏掉一只异常鸡的成本远高过把正常鸡误判成异常鸡。报警频繁可以人工复核漏检一晚上就是实打实的养殖损失。YOLOv8 没有直接暴露class_weight接口常见做法是先用增强参数小幅加大异常类样本的上下文变化比如mosaic1.0保持默认再调低置信度阈值做漏检分析。最有效的始终是数据层面把验证集里被漏判成 normal 的 abnormal 样本捞出来补进训练集重训。调权重是缓解补样本才是根治。验证后还可以看一眼runs/detect/val/confusion_matrix.png。abnormal 那一列被误判成 normal 的数量如果超过三成说明边界样本缺失调 augment 的收益远不如去现场补几张图。4. 3749 张图的标注质量与分布陷阱为什么 91.8% 到不了现场4.1 categories 字段与“正常/异常”定义先过一遍标注口径拿到 COCO JSON 别急着转格式先花十分钟读categories数组和统计类别数量。鸡状态数据集最常见的坑是“正常/异常”的定义不统一有的标注把“精神萎靡”和“受伤倒地”都归到 abnormal有的只把“躺倒不动”归进去还有的颜色异常、羽毛蓬松但能走动的鸡被标成了 normal。标注口径直接决定模型边界。你线上监控如果出现数据集没覆盖的异常状态模型会理所应当地判成 normal这是数据本身的边界不是训练能救回来的。先跑一段小脚本import json from collections import Counter with open(chicken_annotations.json, encodingutf-8) as f: coco json.load(f) for c in coco[categories]: print(c[id], c[name]) cnt Counter(a[category_id] for a in coco[annotations]) print(cnt)如果两个类别的框数量差出 4 倍以上训练时就得做平衡。这份数据“平均正常识别率 91.8%”能成立的前提通常是正常鸡的图像占了大多数异常鸡是少数类。单靠这个数字撑起生产系统是不现实的它更像是数据集作者在自己划分上跑出来的“参考分数”。4.2 场景分层划分避免验证集虚高随机按图片 id 切 80/20 看起来公平但监控数据分时段、分光照如果某个时段的光线只在 train 或只在 val 里出现验证集结果就是个黑匣子看起来 90%现场一跑 60%。手工分区太费时间最少做两步。第一步统计文件路径里的分组信息。很多监控数据集的file_name会带 cam1/cam2、day/night 这类前缀写脚本把前缀分布拉出来CTRLF 翻一遍。第二步按每个分桶内部再随机切 train/val保证每个摄像头、每个时段的图片都按比例进两边。如果这份数据只在一个固定摄像头下采集那这个坑会更隐蔽——你验证集里没有其他角度的图片现场换一个安装位置分布立刻漂移。文件清单之外再对亮度分布做个直方图。用 OpenCV 把每张图转灰度算均值输出 top 暗和 top 亮的各 50 张图肉眼确认夜间图是不是集中出现在同一边。这个检查 5 分钟能跑完能提前避开“验证集里全是白天图”的尴尬。4.3 补数据与复核用预标注修模型不认识的鸡3749 张训练集做监控还偏小现场摄像头角度一变精度肉眼可见地掉。性价比最高的补数据路径是“预标注 人工修框”。常见标注工具里CVAT 和 LabelStudio 都支持直接导入 COCO JSON也支持把训练好的模型接到后端做自动预标注标注员只修不重画。工具导出格式适合场景CVATCOCO JSON / YOLO txt团队协作标注多人同时处理监控抽帧LabelImgPascal VOC / YOLO单机小批量导出 COCO 要自己写转换Labelme自定义 JSON多边形原始标注是分割框时要先算外接矩形LabelStudioCOCO / JSON预标注人工修正适合主动学习循环补数据的操作流程是现场视频每 10 秒抽一帧 → 模型跑一遍自动标注 → 标注员在 CVAT 或 LabelStudio 里筛掉置信度低于 0.3 的预测框再手动补上模型漏掉的那只蔫鸡 → 导出 COCO JSON → 追加进原训练集重训。自动标注漏掉的目标往往正是模型不认识的新样本这类图比随机抽帧补数据涨点快得多。这个“预标注 → 人工修正 → 重训”的闭环跑一轮通常比调一周参数有效。跑闭环时留意一个细节从视频抽帧做预标注前先把连续帧去重否则同一只鸡在相邻帧里被标几十次会把类别分布学歪。5. 鸡状态检测训练避坑清单5 个真实踩坑现场5.1 现象loss 正常下降val mAP 只有 6 成原因类别 ID 错位。COCO JSON 里的 category_id 不一定是 1、2如果原始数据里 abnormal 的 id 是 0转换脚本里无脑减 1 后会输出 -1YOLO 要么拒绝写入要么把 0 当成换行如果写成 0就把 normal 和 abnormal 互换了。模型在训练日志上看起来正常实际学的是“带病鸡当成正常鸡”。解决训练前统计所有 txt 第一列的取值集合确认是 0 和 1再跟 data.yaml 的 names 顺序做一次显式映射。别省这一步它 5 分钟能做完能省两小时排查时间。5.2 现象全部预测成 normalabnormal recall 为零原因类别失衡。3749 张图里如果只有 3% 的标注是 abnormal模型学到的先验就是“世界上没有异常鸡”分类边界全被 majority class 带走。解决验证阶段别只看整体 accuracy单独看 abnormal 的 recall。训练时把异常类样本做简单复制采样或者手动把每个 epoch 里 abnormal 的抽帧比例提高。从数据层面补样例始终是第一推荐调 loss 权重是缓解而不是根治。5.3 现象验证集 mAP 不错现场晚上全翻车原因训练集里夜间和白天光照分布失衡。模型学会了“白天鸡舍的鸡是正常的”遇到夜晚红外摄像机拍出来的灰度鸡头就懵。解决按光照分桶再做分层划分重新切 train/val。夜间图少就先把夜间图复制进训练集再做一次亮度增强。这里有个常见误区亮度增强只能把图变暗不能还原红外摄像机的噪声纹理最好直接补一段晚间视频的抽帧。5.4 现象一张图里几百只鸡只标了几十只recall 极低原因标注稀疏。如果数据集标注时只框了特征明显的鸡模型学不到密集鸡群的上下文——蹲着的、挡着半只的、缩在食槽后边的都没进训练信号。解决先试 imgsz960让模型有更多像素去看小目标。如果还是低走主动学习补标把验证集里漏检的图导入 CVAT 重新修框重点标“缩在角落”的个体。密集场景 mAP 的天花板往往由标注密度决定不取决于模型容量。5.5 现象两个鸡框重叠度超过 0.7预测框在视频里乱跳原因原始标注把两只靠在一起的鸡画在了一个框里俗称“合框”。模型学到的不是“单只鸡”而是“一团鸡”部署时遇到单只鸡就会反复横跳产生大量误报。解决训练前做一次质量检查统计每张图两两框之间 IoU 超过 0.5 的比例。超过 10% 的图建议人工重标便宜且有效。预测端用 NMS 融合高 IoU 框是治标数据标干净才是治本。6. 不重训就做模型验证画 50 张框、看置信度分布、录视频抽帧复检拿到一轮训练结果别急着反复改参数重训先把best.pt在验证集上画框看效果。常见做法是抽 25 张 normal、25 张 abnormal 的图把预测框和置信度都画出来人眼过一遍同时输出一份 JSON 记录所有预测结果。from ultralytics import YOLO import json model YOLO(runs/detect/train/weights/best.pt) results model.predict( sourceyolo_dataset/images/val, conf0.25, saveTrue, projectinspection, ) records [] for r in results: for cls, conf, box in zip( r.boxes.cls.tolist(), r.boxes.conf.tolist(), r.boxes.xyxy.tolist(), ): records.append({ image: r.path, class: int(cls), conf: round(conf, 3), box: [round(v, 1) for v in box], }) with open(inspection/predictions.json, w, encodingutf-8) as f: json.dump(records, f, ensure_asciiFalse, indent2)这份 JSON 能直接暴露两类问题置信度普遍偏低说明目标太小或训练分布与验证分布不一致abnormal 类大量 0.25~0.4 的预测框说明边界样本没有被训练集覆盖模型正在拿不确定度强行凑答案。25 张画框图人工看完通常比调三天参数有效。进阶做法是录一段现场视频做抽帧复检。每 10 秒抽一帧把预测框叠在画面上跟人工判断对比漏检的帧就进待标注队列。这一步把数据集的 91.8% 当成起点而不是终点——它只是模型在某个划分下的平均表现不是现场环境的性能承诺。我自己在这个方向翻过车当初只信验证集 mAP把“平均正常识别率”直接当成现场指标结果夜间监控被缩在角落的蔫鸡狠狠打脸。先画框再谈调参这个习惯帮我少熬了很多夜希望帮到你。本文还有配套的精品资源点击获取
返回列表