简介:这是一份面向家禽养殖监测与计算机视觉研究的高质量鸡状态图像数据集,聚焦正常鸡与异常鸡的识别,可用于目标检测和图像分类任务,从而帮助养殖场及时预警异常状态。压缩包共含2000个文件,其中1997张JPG图片为不同场景下的鸡体图像,3个JSON文件为COCO格式标注数据,整体大小约451.26MB,标注信息包含目标类别与边界框位置。数据整体标注规模约3749张训练集图片,正常状态识别准确率约91.8%,可直接配合YOLO、MMDetection等框架进行模型训练与验证,也能用pycocotools快速读取。目前已有410人学习下载,适合从事智慧农业、动物行为分析或目标检测算法研究的学生与开发者。用户拿到这份数据集后,可省去采集与标注成本,直接基于带精细标注的样本开展异常状态识别实验,快速验证算法效果。
1. 鸡状态数据集:识别正常与异常家禽的目标检测标注资源
做监控场景下的目标检测,最头疼的往往不是模型选型,而是数据集和标注格式对不对路。最近我拆了一个专门针对家禽鸡状态识别的数据集,3749 张训练图片,标注区分正常鸡和异常鸡,用 COCO JSON 格式输出,平均正常识别率在 91.8% 左右。这个数据集的定位很清晰:给养殖场智能监控、家禽健康状态自动巡检这类场景用的,目标类别就两个——normal 和 abnormal,不需要你去处理几十类的复杂标签体系,模型训练和评估的门槛都低很多。适合谁?做农业 AI、养殖场视觉监控、边缘端家禽检测的工程师,或者拿现成数据练 COCO 格式目标检测流程的初学者。这篇笔记我会从数据特点、标注结构、训练配置到踩坑记录完整拆一遍,最后给出验证模型效果的具体方法。
2. 数据集的构成与标注规范:先看 COCO JSON 里到底有什么
2.1 两类目标的定义边界
这套数据的核心是二分类目标检测:normal(正常鸡)和 abnormal(异常鸡)。正常鸡就是我们日常看到的站立、行走、啄食状态下的鸡只;异常鸡涵盖的行为和外观特征包括卧地不起、精神萎靡、羽毛蓬乱、缩颈垂翅、行动迟缓等。这里有一个非常关键的判断逻辑需要先理解:abnormal 不是一个精细的病症分类,而是一个状态集合——只要鸡只表现偏离正常行为模式,就归入这一类。
这个定义直接决定了标注策略。实际标注的时候,标注人员不需要判断鸡具体得了什么病,只需要判断这只鸡此刻的状态是否偏离正常。这种做法的好处是标注一致性容易保证,因为「正常行为」的共识度比较高;坏处是如果后续你要细分疾病类型,这套标注就不够用了,只能作为状态检测的基座数据。
2.2 COCO JSON 标注的文件结构
这套数据集采用的是 COCO JSON 格式,这是目前目标检测领域最通用的标注格式之一,MMDetection、Detectron2、YOLOv5(转换后)都能直接消费。核心文件一般有三个组成部分:
{ "images": [ { "id": 1, "file_name": "train_00001.jpg", "width": 1280, "height": 720 } ], "annotations": [ { "id": 1, "image_id": 1, "category_id": 1, "bbox": [x, y, width, height], "area": width * height, "iscrowd": 0 } ], "categories": [ {"id": 1, "name": "normal"}, {"id": 2, "name": "abnormal"} ] }这里要特别说明 bbox 的坐标约定:COCO 格式的 bbox 是[左上角x, 左上角y, 宽度, 高度],不是中心点坐标。很多人第一次拿 COCO 数据转 YOLO 格式的时候在这里翻车,转出来的框偏移一大截。area 字段是 bbox 的宽高乘积,但如果你用分割标注,area 应该是多边形面积而不是 bbox 面积,需要额外计算。
2.3 类别映射与数据划分建议
原始数据集提供了 3749 张训练图片,但并没有固定告诉你验证集怎么切。我一般的做法是按照 8:1:1 的比例切成训练、验证、测试三份,而且要保证 normal 和 abnormal 在三个子集里的比例和全集基本一致——这个叫分层采样。如果直接随机切,可能出现验证集里 abnormal 占比偏低的情况,导致验证指标虚高或虚低。
类别 ID 的映射也很重要。COCO JSON 里 category_id 是 1 和 2,但 YOLO 格式只需要类别索引 0 和 1,做转换的时候必须减去 1。这个细节很多人都容易漏,训练到一半发现 loss 不降,结果回头一看是标签映射错了。
3. 数据训练前的关键准备:从 COCO 到模型输入格式的转换
3.1 为什么不能直接拿 COCO JSON 喂 YOLO
YOLO 系列模型训练通常用 TXT 格式的标签文件,每行表示一个目标,格式是class_id x_center y_center width height,注意这里是归一化后的中心点坐标和宽高。而 COCO JSON 给的是像素坐标的左上角点和宽高,两者之间需要一套完整的转换逻辑。
如果你用的是 MMDetection 或者 Detectron2,那可以直接读 COCO JSON,不需要转换;但如果想用 YOLOv5/YOLOv8/YOLO11 来训练,就必须把 COCO 格式转成 YOLO 的 TXT 格式。我这里给出一个我在实际项目里用的转换脚本片段:
import json import os def coco_to_yolo(coco_json_path, output_dir, img_width, img_height): with open(coco_json_path, 'r', encoding='utf-8') as f: coco_data = json.load(f) # 建立 category_id 到 yolo_class_id 的映射,这里假设 categories 顺序固定 cat_id_map = {} for idx, cat in enumerate(coco_data['categories']): cat_id_map[cat['id']] = idx # 建立 image_id 到文件名的映射 img_id_to_name = {} for img in coco_data['images']: img_id_to_name[img['id']] = img['file_name'] # 按图片分组所有标注 anns_by_image = {} for ann in coco_data['annotations']: img_id = ann['image_id'] if img_id not in anns_by_image: anns_by_image[img_id] = [] anns_by_image[img_id].append(ann) os.makedirs(output_dir, exist_ok=True) for img_id, anns in anns_by_image.items(): img_name = img_id_to_name[img_id] txt_name = os.path.splitext(img_name)[0] + '.txt' lines = [] for ann in anns: x, y, w, h = ann['bbox'] # 归一化:除以图片宽高 cx = (x + w / 2) / img_width cy = (y + h / 2) / img_height nw = w / img_width nh = h / img_height yolo_cls = cat_id_map[ann['category_id']] lines.append(f"{yolo_cls} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}") with open(os.path.join(output_dir, txt_name), 'w', encoding='utf-8') as f: f.write('\n'.join(lines)) print(f"转换完成,共处理 {len(anns_by_image)} 张图片的标注") coco_to_yolo('train.json', 'yolo_labels', 1280, 720)这个脚本的逻辑其实很直接:遍历每个 annotation,把 bbox 从左上角坐标转成中心点坐标并做归一化。但我实际使用中会加两个额外的防御逻辑:一是要检查 bbox 是否超出图片边界,因为有些标注工具会产出越界框;二是要检查宽高是否为负值,出现负值说明原始标注里有脏数据。这两个检查能在训练之前拦截大部分数据质量问题,省得训练到一半开始怀疑人生。
3.2 训练集与验证集的目录组织
转换完成后,目录结构需要按照训练框架的约定组织。拿 YOLOv5 来说,标准的目录结构是这样的:
dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml 是整个训练配置的核心,里面的关键参数包括:
path: dataset/ train: images/train val: images/val nc: 2 names: ['normal', 'abnormal']这里的nc是类别数量,必须和 names 列表的长度一致。很多人在这个文件上出问题:路径写绝对路径导致换机器训练就报错,或者 names 顺序和转换脚本里的 class_id 对应不上。我的习惯是用相对路径,并且专门写一个脚本去校验 images 和 labels 的文件名一一对应,防止有图没标签或有标签没图的情况。
3.3 数据增强策略的选择
3749 张训练图不算多,尤其对目标检测来说。如果不做数据增强,模型很容易过拟合。我在这类家禽检测场景里常用的增强策略是:Mosaic(在训练前中期开启)、随机仿射变换、HSV 色域扰动、随机翻转。
但这里有一个血泪经验需要提醒:Mosaic 增强在训练后期要关掉或者降低概率。YOLOv5 和 YOLOv8 都支持通过超参数控制 Mosaic 的概率,一般在最后 10 个 epoch 把 Mosaic 关闭,让模型在接近真实分布的数据上微调收敛。不关的话,可能会出现验证集 mAP 在最后几个 epoch 震荡不降的情况。
4. 模型训练配置与参数调优:从 YOLOv8 到 MMDetection 的实战对照
4.1 YOLOv8 训练命令与关键参数
如果你选用 YOLOv8 来训练这套鸡状态数据集,训练命令基本是这个样子:
yolo detect train \ data=data.yaml \ model=yolov8n.pt \ epochs=150 \ imgsz=640 \ batch=16 \ patience=20 \ project=runs/chicken_state \ name=yolov8n_exp1这些参数里,我重点说几个实际影响结果的:imgsz决定了输入分辨率,640 是速度和精度的平衡点,但如果你部署在边缘设备(比如树莓派或 Jetson Nano),建议用 416 或 320 并重新训练,而不是直接拿 640 的权重部署——输入尺寸变了模型结构虽然不变,但特征尺度分布会不匹配;patience是早停 patience,20 的意思是最多容忍 20 个 epoch 验证指标不提升就停止训练,这个参数能帮你省时间,但也别设太小,否则可能在 mAP 还在上升期的时候提前掐断。
还有一个容易被忽略的参数是cache=True,开启后会把训练图片缓存到内存或磁盘,能显著减少数据加载的瓶颈。3749 张图不大,完全可以直接cache=True(默认是 RAM 缓存)。如果你的机器内存不够,可以用cache=disk做磁盘缓存。
4.2 类别不平衡问题的处理
这套数据集的 normal 和 abnormal 数量大概率是不平衡的——正常鸡的样本通常比异常鸡多得多。如果直接训练,模型会偏向预测 normal,abnormal 的召回率会比较难看。
我一般的处理方式有两种。第一种是调整 loss 权重,在 YOLOv8 里可以通过自定义 loss 或者用cls参数调节,但对不熟悉源码的人来说门槛偏高;第二种更实用——在数据层面做处理,对 abnormal 类的图片做过采样,或者对 abnormal 目标做复制粘贴增强。复制粘贴增强的意思是把 abnormal 类别的目标从原图中裁剪出来,贴在另一张图上,同时更新标签。
这里给出一个简单的 abnormal 过采样脚本思路:
import os import shutil import random # 统计每个类别的图片数量 def count_class_samples(label_dir): class_count = {0: 0, 1: 0} for txt_file in os.listdir(label_dir): with open(os.path.join(label_dir, txt_file), 'r') as f: for line in f: cls = int(line.split()[0]) class_count[cls] = class_count.get(cls, 0) + 1 return class_count counts = count_class_samples('yolo_labels') # 如果 abnormal 目标数量明显少于 normal,则对包含 abnormal 的样本做多倍备份 # 实际上更推荐的是在训练时用 sampler 控制采样权重 print(f"normal 目标数: {counts[0]}, abnormal 目标数: {counts[1]}")不过说实话,我更推荐的是直接在训练框架层面解决:在 YOLOv8 的 dataloader 里自定义 sampler,或者简单粗暴地把包含 abnormal 的图片在数据集目录里复制几份。后者虽然不优雅,但效果直接,而且不会改变标签文件结构。
4.3 MMDetection 路线:如果不用 YOLO 的话
有些场景你需要更强的模型可解释性或者要和其他检测任务共用一套代码库,那 MMDetection 是更好的选择。用 MMDetection 训练,不需要做 COCO 到 YOLO 的格式转换,直接把 COCO JSON 和图片目录按照它的格式组织好就行:
python tools/train.py configs/yolox/yolox_s_8x8_300e_coco.py然后修改数据集路径和类别数。这里要改的是data_root、metainfo里的classes,以及num_classes配置。MMDetection 的配置文件层级比较多,改的时候要留意是否所有用到num_classes的地方都改了——这个项目的早期版本里,有些模型配置会从 pretrained 权重继承类数,导致 head 输出维度不匹配,报错信息还特别晦涩。
4.4 训练过程中的监控指标
训练到什么程度算好?不要只盯着 loss 曲线,loss 降了不代表检测效果好。我看训练状态的核心指标是验证集的 mAP@0.5 和 mAP@0.5:0.95,其次分别看 normal 和 abnormal 两个类别的 AP。特别是 abnormal 的 AP,这才是这套数据集的核心价值——如果 normal 的 AP 很高但 abnormal 的 AP 不到 70%,说明模型倾向于把所有目标都判成 normal,实际部署的时候异常鸡只根本报警不出来。
5. 避坑与常见问题:3749 张图训练时最容易踩的五个坑
5.1 标注框越界导致训练 loss 异常
现象:训练开始后 loss 数值明显偏大,或者出现 NaN。检查输入的标签,发现部分 bbox 的 x + width 超过了图片宽度,或者 y + height 超过了图片高度。
原因:COCO JSON 转 YOLO 格式时没有做边界裁剪。原始标注里偶尔会有超出图像边缘的框,可能是标注人员的疏漏,也可能是目标本身在图像边缘被裁切了一半。
解决:在转换脚本里加边界裁剪逻辑——把 x 限制在 [0, img_width] 之间,w 限制在 [0, img_width - x] 之间,y 和 h 同理。裁剪后如果框的面积小于原面积的 30%,直接丢弃这个标注,因为它已经失真了。
5.2 类别权重失衡导致 abnormal 被吞
现象:验证集 mAP 看着不错(比如 90%),但单独看 abnormal 类别的 AP 只有 60%,混淆矩阵里大部分 abnormal 目标被预测为 normal。
原因:abnormal 样本在数据集中占比低,模型在 loss 优化过程中对 abnormal 类别的梯度贡献太小。
解决:先统计两个类别的目标数量,如果 abnormal 目标数不足 normal 的 30%,需要做类别重加权或数据过采样。我实际测试中,把包含 abnormal 的图片复制两到三份参与训练后,abnormal 的 AP 能从 62% 提升到 78% 左右,但要注意过采样倍数太高容易过拟合,验证集上 normal 的 AP 可能会轻微下降。如果过采样倍数超过 4 倍效果反而变差,说明模型已经开始记忆特定样本而不是学习泛化特征。
5.3 数据划分不均匀导致指标波动
现象:每次重新切分训练验证集后,abnormal 的 AP 波动超过 5 个百分点,模型训练结果不稳定。
原因:随机切分时没有做分层采样,导致验证集里 abnormal 目标数量时多时少。
解决:用 sklearn 的train_test_split配合stratify参数,或者自己写分组逻辑——先按图片 ID 做 group,再按类别比例分配组合。确保三个子集中每个类别的目标占比和全集一致。
5.4 图像分辨率差异导致小目标检测失效
现象:训练时 imgsz 设的是 640,但原始图片里有相当一部分是远距离拍摄的,鸡只目标在整幅图中占比很小,检测时漏检严重。
原因:数据集里图像的拍摄距离不统一,远处的鸡目标在缩放后只有几十个像素,模型难以提取有效特征。
解决:第一,用imgsz=1280重新训练,YOLOv8 支持大分辨率输入,换取小目标召回率的提升;第二,检查目标尺度的分布,统计所有标注框的宽高比和面积分布,如果大量目标面积占图面积比小于 0.01,就需要考虑切图训练——把大图切成若干小块再训练,同时处理跨块目标。切图训练虽然增加工作量,但往往是最有效的。
5.5 训练后期 mAP 震荡不收敛
现象:最后 30 个 epoch 验证集 mAP 在 89% 到 92% 之间来回震荡,loss 已经不再下降。
原因:Mosaic 数据增强在小数据集上容易造成分布偏移,训练后期模型在这类增强后的数据上「迷路」;另外学习率衰减策略可能需要调整。
解决:关闭 Mosaic 增强(YOLOv8 中设置mosaic=0.0),同时把学习率衰减改成余弦退火,在最后 20 个 epoch 内把学习率线性降到接近 0。用这套组合拳,大部分情况下能让 mAP 稳定到一个固定值附近而不是持续震荡。
6. 模型验证与部署:用 mAP、混淆矩阵和实际推理三重确认效果
训练完成后,最忌讳的事情就是只盯着训练日志里的 mAP 数字就觉得万事大吉。我的习惯是三层验证:指标层验证、可视化层验证、真实场景验证。
第一层是指标层。用yolo detect val命令跑验证集,重点看两个类别的 AP 和混淆矩阵。
yolo detect val \ model=runs/chicken_state/yolov8n_exp1/weights/best.pt \ data=data.yaml \ imgsz=640 \ conf=0.25输出里要重点看per-class AP和confusion matrix。如果 abnormal 类别的 AP 低于 75%,我基本不会把这套权重拿去部署,会回头检查训练配置和数据划分。
第二层是可视化层。直接跑推理,把标注预测框保存下来和原图一起看:
yolo predict \ model=runs/chicken_state/yolov8n_exp1/weights/best.pt \ source=sample_images/ \ conf=0.25 \ save=True \ save_txt=True看什么?不是看预测得准不准,而是看两类错误:一是漏检的 abnormal 长什么样(是不是拍摄距离远、光线暗、遮挡严重),二是误检的 normal 长什么样(是不是某些特殊姿势比如低头啄食被当成了异常)。这两种错误形态直接决定了你要不要补数据、调阈值还是改分辨率。有一次我发现误检的样本集中在逆光环境下,后来在训练集里补充了逆光图片,abnormal 的误检率降了一多半。
第三层是真实场景验证。拿模型去跑一段养殖场监控视频,统计每帧的检测结果,设置一个状态判定逻辑——比如连续 N 帧检测到 abnormal 才触发告警,避免单帧误检导致的频繁误报。这个阈值 N 直接影响报警灵敏度和误报率,需要根据实际场景调。常见设置是三秒内超过 15 帧检测到 abnormal,才输出告警信号。
部署层面的实践我会这样处理:如果目标是边缘设备,先用 TensorRT 对模型做 FP16 量化加速,3749 张图训练出来的模型体积不大(YOLOv8n 的权重在 6MB 左右),量化后推理速度在 Jetson Nano 上能跑到 30ms 每帧。如果目标是服务器端,直接用原模型做 batch 推理即可。
这套鸡状态数据集加上正确的训练配置,绝大部分人收到的正确率在 91% 左右,但能不能真正用起来,关键还是看数据预处理和类别不均衡的处理是否到位。算法选型反而是最不费脑子的环节。希望这篇拆解能帮你在自己的场景里少走几个弯路。
本文还有配套的精品资源,点击获取