ARTICLE DETAIL

资讯详情

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

基于YOLOv8的家禽鸡行为识别:从484张数据集到落地巡检模型

基于YOLOv8的家禽鸡行为识别:从484张数据集到落地巡检模型 简介这份家禽鸡行为数据集面向智慧养殖、动物行为识别方向的算法开发者与高校研究者可用于训练目标检测模型自动区分吃食、喝水、死亡、异常行为与睡觉五类状态适用于养殖场巡检、健康预警等场景。资源包共1429个文件含714张jpg图像与714个同名txt标注另附1个yaml配置文件整体约39.33MB标注采用YOLO v11格式可直接接入主流检测框架训练。图像覆盖室内养殖、农场及特殊场景包含多段视频抽帧样本画面差异有助于提升模型泛化能力。目前已有382人学习下载。拿到后可直接获得完整训练集与标注文件省去采集与标注成本快速搭建行为识别基线并在此基础上做类别增补、数据增强或迁移学习适合作为课程设计、竞赛或论文实验的数据基础。1. 家禽鸡行为数据集484 张图、5 类行为能不能撑起一个能落地的识别模型养鸡场里最怕的不是饲料涨价而是你走进棚里才发现有几只鸡已经不动了。死亡、异常行为这类样本发现得越晚损失越大。人工巡检一天两趟中间那十几个小时就是黑匣子。所以当我看到「家禽鸡行为数据集可识别吃食、喝水、死亡、异常行为、睡觉行为484 张训练集图片yolo v11 格式标注」这个标题时第一反应不是它有多全而是它够不够我跑通一条从标注到推理的最小闭环。这个数据集的价值在于它把五类行为定义清楚了吃食、喝水、死亡、异常行为、睡觉。对做养殖巡检、边缘盒子、摄像头告警的团队来说这是一个可以直接拿来验证「行为识别到底能不能落地」的起点。它适合两类人一类是想用 yolov8 训练自己的数据集、但手头没有养殖场景样本的算法同学另一类是已经在做智慧农业、想快速验证检测精度的工程同学。484 张不算多但足够把流程跑通也足够暴露你在数据标注、类别平衡、小目标上的真实问题。2. 先搞清楚这五类行为在图像里长什么样标注边界与选型理由2.1 吃食、喝水、睡觉为什么容易混在单帧图像里鸡低头对着料槽是吃食低头对着水线是喝水缩着脖子闭眼是睡觉。问题在于这三种姿态在俯拍视角下高度相似尤其是鸡群密集时一只鸡的头可能同时压在料槽和水线之间。标注的时候如果只画一个框、给一个类别模型学到的其实是「位置 姿态」的混合特征而不是行为本身。常见做法是吃食和喝水的框尽量贴住头部和料槽/水线的接触区域而不是整只鸡。睡觉的框可以稍微放大覆盖蜷缩的整体轮廓。死亡和异常行为则相反死亡通常整只鸡侧躺、伸展异常行为包括跛行、扎堆、张口呼吸等框要覆盖全身。这样标注出来的框尺度差异会很大这也是后面训练时要重点处理的点。2.2 为什么选 yolo v11 格式而不是其他标注格式yolo v11 格式本质上是每张图对应一个 txt每行是class_id x_center y_center width height坐标全部归一化到 0 到 1。它和 yolov5、yolov8 的标注格式是同一套所以你今天用 v11 格式标好明天想换 yolov8 训练自己的数据集直接改一下 data.yaml 就能跑不用重新转。相比之下cvat 标注平台、doccano 关系标注、rectlable 标注这些工具各有各的导出格式有的带多边形有的带属性字段。如果你拿到的原始标注是 xml 或 json第一件事就是转成 yolo 格式。转换脚本不难难的是类别映射和坐标越界检查这两个坑后面会细说。2.3 484 张图怎么划分才算合理484 张图五类行为平均下来每类不到 100 张。如果按 8:1:1 划分验证集和测试集各只有 48 张左右评估结果的波动会很大。我一般会按 7:2:1 划训练集 338 张验证集 97 张测试集 49 张。如果某些类别样本特别少比如死亡只有 30 张那就要在划分时保证每个子集里都有这类样本不能随机切完发现验证集里一只死鸡都没有。子集比例图片数用途训练集70%约 338梯度更新验证集20%约 97调参、早停测试集10%约 49最终评估提示划分前先统计每类框的数量按类别分层抽样不要直接随机切。3. 用 yolov8 训练自己的数据集从 484 张图到第一个可推理权重3.1 目录结构与 data.yaml 的最小配置拿到 484 张图和对应的 txt 之后先按下面的结构放好。images 和 labels 下面再分 train、val、test 三个子目录文件名一一对应图片是 jpg 或 png标签是同名 txt。dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml 里写清楚路径、类别数和类别名。注意 nc 必须等于 names 的长度顺序要和标注时的 class_id 一致否则模型会把吃食认成喝水。path: ./dataset train: images/train val: images/val test: images/test nc: 5 names: 0: eating 1: drinking 2: dead 3: abnormal 4: sleeping逻辑说明path 是数据集根目录train/val/test 是相对路径。names 的顺序就是 class_id 的顺序0 对应 eating1 对应 drinking以此类推。参数说明如果你的图片不在 dataset 目录下path 要改成绝对路径nc 写错会导致训练时直接报维度不匹配。3.2 训练命令与关键参数怎么设用 yolov8 训练自己的数据集最小命令就是一行。但 484 张图属于小数据集参数不能照搬 COCO 的默认值。yolo detect train \ datadataset/data.yaml \ modelyolov8n.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.001 \ lrf0.01 \ patience30 \ augmentTrue \ cacheTrue \ projectruns/chicken \ nameexp1逻辑说明model 选 yolov8n.pt 是因为数据量小大模型容易过拟合。epochs 给 150配合 patience30验证集 30 轮不提升就早停。lr0 从 0.001 起步比默认的 0.01 小避免小数据集上梯度震荡。augmentTrue 开启默认增强包括随机翻转、缩放、色彩抖动。cacheTrue 把图片缓存到内存484 张图完全放得下能明显加快训练。参数说明imgsz640 是常见输入尺寸如果你要部署到边缘盒子可以改成 416 或 320但小目标召回会下降。batch16 取决于显存8G 显存跑 yolov8n 加 640 尺寸基本够用不够就降到 8。3.3 训练过程中看什么指标训练开始后终端会打印每一轮的 box_loss、cls_loss、dfl_loss 和 mAP50。小数据集上box_loss 下降快但 mAP 波动大是正常的。重点看验证集的 mAP50-95 和每类的 AP。如果某一类 AP 一直是 0大概率是这一类样本太少或者标注有问题。from ultralytics import YOLO model YOLO(runs/chicken/exp1/weights/best.pt) metrics model.val(datadataset/data.yaml, splittest) print(metrics.box.map) # mAP50-95 print(metrics.box.map50) # mAP50 print(metrics.box.ap_class_index) # 每类索引逻辑说明训练结束后用 best.pt 在测试集上跑一次 val拿到最终指标。ap_class_index 能告诉你哪些类别被评估到了如果某个类别没出现说明测试集里没有这类样本。参数说明splittest 表示用测试集改成 val 就是验证集。4. 标注转换与数据增强把 484 张图用出 2000 张的效果4.1 从 cvat 或 labelme 转 yolo 格式的脚本如果你拿到的原始标注是 cvat 导出的 xml 或 labelme 的 json需要转成 yolo 的 txt。下面这个脚本处理 labelme 格式cvat 的 xml 改一下解析部分即可。import json import os from PIL import Image def labelme_to_yolo(json_path, output_dir, class_map): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_map: continue cls_id class_map[label] points shape[points] xs [p[0] for p in points] ys [p[1] for p in points] x_center (min(xs) max(xs)) / 2.0 / img_w y_center (min(ys) max(ys)) / 2.0 / img_h w (max(xs) - min(xs)) / img_w h (max(ys) - min(ys)) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) base os.path.splitext(os.path.basename(json_path))[0] with open(os.path.join(output_dir, base .txt), w) as f: f.write(\n.join(lines)) class_map {eating: 0, drinking: 1, dead: 2, abnormal: 3, sleeping: 4}逻辑说明脚本读取 labelme 的 json拿到图片宽高和每个形状的标签、点集。把点集的最小外接矩形算出来再归一化成 yolo 需要的中心点和宽高。class_map 负责把文字标签映射成数字 id。参数说明points 如果是多边形这里用最小外接矩形近似适合矩形框标注如果是旋转框需要另外处理。4.2 小数据集该开哪些增强484 张图直接训模型见到的姿态有限。yolov8 默认增强包括 mosaic、mixup、随机翻转、HSV 抖动。对鸡行为识别我一般会额外关注这几项增强项建议值理由mosaic1.0增加密集场景模拟鸡群扎堆mixup0.1轻微混合防止过拟合degrees5.0小角度旋转模拟摄像头偏移translate0.1平移模拟鸡在画面中位置变化hsv_h0.015色调抖动适应不同光照fliplr0.5水平翻转鸡的左右姿态对称注意flipud 垂直翻转不要开鸡不会倒着走开了反而引入不真实样本。4.3 用切片推理补小目标如果部署时摄像头分辨率高鸡在画面里只占几十个像素640 输入下小目标召回会掉。常见做法是切片推理把大图切成重叠的小块分别检测再合并。ultralytics 本身不直接提供切片但可以用 sahi 库配合。from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction detection_model AutoDetectionModel.from_pretrained( model_typeyolov8, model_pathruns/chicken/exp1/weights/best.pt, confidence_threshold0.3, devicecuda:0 ) result get_sliced_prediction( test_farm.jpg, detection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2 ) result.export_visuals(export_diroutput/)逻辑说明sahi 把原图按 640x640 切片切片之间有 20% 重叠避免目标被切断。每块单独推理后用 NMS 合并结果。参数说明confidence_threshold 设 0.3 是召回优先误检可以后面用规则过滤overlap 比例太小会漏掉跨块目标太大则重复框多。5. 避坑与排查484 张图训练时最容易翻车的 5 个地方5.1 现象训练 loss 正常下降但 mAP 一直是 0原因data.yaml 里的 names 顺序和标注时的 class_id 不一致或者 nc 写成了类别数以外的值。模型学到的类别和评估时的类别对不上mAP 自然为 0。解决打开一个标注 txt看第一列的数字对照 data.yaml 的 names 顺序。比如 txt 里出现 4names 里第 5 个必须是 sleeping。改完重新训练。5.2 现象某一类 AP 特别低其他类正常原因这一类样本太少或者标注框严重不一致。比如死亡样本只有 20 张且有的框画全身、有的只画头部模型学不到稳定特征。解决先统计每类框数量少于 50 的类别考虑补充样本或过采样。标注不一致的框统一标准死亡一律画全身外接矩形。5.3 现象验证集 mAP 很高实际部署漏检严重原因训练集和验证集来自同一段视频或同一光照条件模型过拟合了场景没有学到行为本身。484 张图如果全是一个鸡舍拍的换一个棚就翻车。解决划分数据集时按视频源或时间段分层确保验证集里有不同光照、不同密度的场景。如果做不到至少做一次跨棚测试看真实差距。5.4 现象训练时显存爆了batch 降到 4 还是 OOM原因imgsz 设得太大或者 cacheTrue 把图片全部缓存到显存而不是内存。yolov8 的 cache 默认缓存在内存但如果图片分辨率很高内存也会吃紧。解决先把 imgsz 降到 416batch 设 8关掉 cache 跑一轮看显存占用。如果还爆检查是不是有多张 GPU 没指定用device0锁定单卡。5.5 现象推理时同一只鸡被框了两次类别还不一样原因吃食和喝水的特征太接近模型在两个类别上都给了高分NMS 只按框去重不按类别去重导致同一位置出现两个不同类别的框。解决推理时用类别感知的 NMS或者后处理时对 IoU 大于 0.6 且类别不同的框保留置信度高的那个。也可以在训练时把吃食和喝水合并成一个「进食」类部署时再根据位置区分。6. 把 484 张图变成可迭代的巡检能力验证方法与一个实用技巧数据集小不是问题问题是你能不能建立一个可迭代的闭环。我一般会先用这 484 张图训一个基线模型然后拿它去跑一段真实鸡舍的视频把置信度在 0.3 到 0.6 之间的框全部导出来人工复核一遍。这些框就是下一轮训练的补充样本尤其是死亡和异常行为这两类真实场景里的姿态比数据集里丰富得多。验证方法上不要只看 mAP。行为识别最终要落到告警上所以我会统计三个业务指标死亡检出率、误报率、平均检出延迟。死亡检出率是测试集里所有死亡样本被正确框出的比例误报率是正常行为被误判为死亡的次数平均检出延迟是从鸡死亡到模型第一次给出告警的帧数。这三个指标比 mAP 更能说明能不能用。一个实用技巧是在 data.yaml 里把死亡和异常行为的类别权重调高。yolov8 本身不直接支持类别权重但可以在 loss 里手动加权或者更简单——在数据集里把这两类的图片复制一份让它们在训练集中占比更高。复制时注意文件名不要冲突可以用dead_001_a.jpg这种后缀区分。import shutil import os def oversample(src_img_dir, src_label_dir, dst_img_dir, dst_label_dir, class_id, times2): for fname in os.listdir(src_label_dir): if not fname.endswith(.txt): continue with open(os.path.join(src_label_dir, fname)) as f: lines f.readlines() if any(line.startswith(str(class_id)) for line in lines): base os.path.splitext(fname)[0] for i in range(times): shutil.copy( os.path.join(src_img_dir, base .jpg), os.path.join(dst_img_dir, f{base}_os{i}.jpg) ) shutil.copy( os.path.join(src_label_dir, fname), os.path.join(dst_label_dir, f{base}_os{i}.txt) )逻辑说明脚本遍历标签目录如果某个 txt 里包含指定 class_id就把对应的图片和标签复制多份到目标目录文件名加后缀避免覆盖。参数说明times2 表示复制两份加上原图一共三份。class_id 传 2 就是过采样死亡类传 3 就是异常行为类。复制完记得重新生成 data.yaml 的路径或者直接把目标目录作为新的训练集。我自己的习惯是每训完一版模型就把误报和漏报的截图单独存一个文件夹标注修正后加进下一轮。484 张图只是起点真正让模型变强的是这个不断把现场错误喂回去的循环。别指望一次训练就上线但也别因为数据少就不开始。希望帮到你。本文还有配套的精品资源点击获取
返回列表