ARTICLE DETAIL

资讯详情

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

基于YOLO v11的家禽鸡行为识别:484张图数据集实战与避坑指南

基于YOLO v11的家禽鸡行为识别:484张图数据集实战与避坑指南 简介这份家禽鸡行为数据集面向智慧养殖、动物行为识别方向的算法工程师与高校研究者可用于训练吃食、喝水、死亡、异常行为、睡觉五类行为的检测模型适合作为YOLO系列目标检测项目的实训与科研素材。资源包共1429个文件包含714张jpg图像与714个同名txt标注文件另附1个yaml数据配置文件压缩包约39.33MB标注已按YOLO v11格式整理可直接接入训练流程。图像覆盖室内养殖场与特殊场景兼顾不同光照与拍摄角度便于模型学习多样化的鸡只姿态。目前已有382人学习下载读者可据此快速搭建行为识别基线验证数据增强、类别平衡与模型微调策略也能用于课堂演示或算法对比实验省去自行采集与标注的时间成本。1. 鸡舍里的 484 张图这套行为数据集到底能识别什么去年帮一个做蛋鸡养殖的朋友看监控他指着屏幕上一动不动的鸡问我这是睡觉还是死了这个问题听起来简单但真要在产线上跑起来靠人眼盯几十路摄像头根本不现实。后来我翻到这套家禽鸡行为数据集484 张训练集图片YOLO v11 格式标注覆盖吃食、喝水、死亡、异常行为、睡觉五类状态才意识到它解决的正是这种「一眼分不清」的现场问题。这套资源适合三类人做智慧养殖视觉方案的工程师、想拿真实农业场景练手 YOLO 的算法同学、以及需要给鸡舍行为识别做原型验证的产品团队。它不是那种几万张的通用数据集484 张的体量意味着你得靠数据增强和迁移学习把效果撑起来但好处是标注质量集中、类别定义贴近实际养殖场景拿来跑通流程、验证思路完全够用。文件名里能看到 Farm_indoor3、Farm_indoor4、Scary-chicken 这些来源说明采集环境有室内鸡舍也有受惊场景多样性比想象中好。2. YOLO v11 格式拆解标注文件长什么样、怎么读2.1 从文件名到标注结构先看这批图片的命名规律。Farm_indoor4_mp4-0000_jpg.rf.36b0bb2d60676eb0b6f1e7671fad3f51.jpg这种格式前缀是视频源名称中间是帧号后面是 Roboflow 处理时生成的哈希后缀。这意味着原始素材是从视频抽帧来的同一段视频的连续帧可能被拆到训练集和验证集里这是后面要重点说的坑。YOLO v11 的标注格式和 v8 一脉相承每张图对应一个同名.txt文件每行代表一个目标框格式是class_id x_center y_center width height其中坐标全部归一化到 0 到 1 之间。假设类别映射是0: eating, 1: drinking, 2: dead, 3: abnormal, 4: sleeping那么一行标注0 0.453 0.612 0.087 0.134的含义是这只鸡在吃食框中心位于图片宽度 45.3%、高度 61.2% 的位置框宽占图片 8.7%框高占 13.4%。2.2 用 Python 快速校验标注质量拿到数据集第一件事不是急着训练而是先写个脚本把标注读一遍看看有没有越界框、零面积框、类别分布是否严重失衡。下面这段代码我一般会先跑一遍import os import glob from collections import Counter # 数据集标注目录按实际路径改 label_dir ./labels/train img_dir ./images/train class_names [eating, drinking, dead, abnormal, sleeping] class_counter Counter() issues [] for txt_path in glob.glob(os.path.join(label_dir, *.txt)): base os.path.splitext(os.path.basename(txt_path))[0] img_path os.path.join(img_dir, base .jpg) if not os.path.exists(img_path): issues.append(f标注无对应图片: {txt_path}) continue with open(txt_path, r) as f: lines f.readlines() for line_no, line in enumerate(lines, 1): parts line.strip().split() if len(parts) ! 5: issues.append(f{txt_path} 第{line_no}行字段数异常: {line.strip()}) continue cls_id int(parts[0]) x, y, w, h map(float, parts[1:]) class_counter[cls_id] 1 # 检查归一化坐标是否越界 if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): issues.append(f{txt_path} 第{line_no}行坐标越界: {line.strip()}) # 检查框面积是否过小 if w * h 0.0005: issues.append(f{txt_path} 第{line_no}行框面积过小: {line.strip()}) print(类别分布:) for cid, cnt in sorted(class_counter.items()): name class_names[cid] if cid len(class_names) else f未知类别{cid} print(f {name}(id{cid}): {cnt} 个框) print(f\n发现 {len(issues)} 个潜在问题) for issue in issues[:20]: print( , issue)这段脚本做三件事统计每个类别的框数量、检查坐标是否越界、检查框面积是否过小。跑完之后你大概率会发现「死亡」和「异常行为」的样本远少于「吃食」和「睡觉」这是行为识别数据集的通病后面训练时要针对性处理。参数说明label_dir和img_dir按你解压后的实际目录结构改YOLO 标准结构是images/train配labels/train。class_names的顺序必须和data.yaml里的names完全一致否则统计出来的分布是错的。框面积阈值0.0005是我在 640 分辨率下的经验值小于这个面积的框在训练时基本是噪声。2.3 data.yaml 的写法与类别顺序YOLO v11 训练依赖一个data.yaml描述数据集路径和类别。这套数据集的类别顺序建议按行为逻辑排path: ./chicken_behavior # 数据集根目录 train: images/train val: images/val names: 0: eating 1: drinking 2: dead 3: abnormal 4: sleeping注意names的索引必须和标注文件里的class_id严格对应。如果你拿到的标注里 0 是 sleeping、4 是 eating那data.yaml就得跟着改不能想当然按语义顺序写。我见过有人训练完发现模型把睡觉识别成吃食查了半天是类别映射错位这种坑纯属低级但特别耗时间。3. 从零跑通训练YOLO v11 参数怎么设、增强怎么开3.1 环境准备与数据划分先确认你的环境。YOLO v11 通过 ultralytics 包调用Python 3.8 以上、PyTorch 2.0 以上是基本要求。安装命令很直接pip install ultralytics数据划分是第一个关键决策。484 张图如果按 8:2 分验证集只有 96 张每类平均不到 20 张评估指标会抖得厉害。我的建议是先用 9:1 划分验证集留 48 张左右同时开启交叉验证或者多跑几次不同随机种子看稳定性。划分脚本可以这样写import os import random import shutil random.seed(42) # 固定种子保证可复现 src_img ./all_images src_lbl ./all_labels dst_root ./chicken_behavior # 创建目录结构 for split in [train, val]: os.makedirs(f{dst_root}/images/{split}, exist_okTrue) os.makedirs(f{dst_root}/labels/{split}, exist_okTrue) # 收集所有图片文件名不含扩展名 names [os.path.splitext(f)[0] for f in os.listdir(src_img) if f.endswith(.jpg)] random.shuffle(names) val_count max(1, int(len(names) * 0.1)) # 10% 做验证 val_names set(names[:val_count]) for name in names: split val if name in val_names else train shutil.copy(f{src_img}/{name}.jpg, f{dst_root}/images/{split}/{name}.jpg) lbl_src f{src_lbl}/{name}.txt if os.path.exists(lbl_src): shutil.copy(lbl_src, f{dst_root}/labels/{split}/{name}.txt) print(f训练集: {len(names) - val_count} 张, 验证集: {val_count} 张)这里有个细节random.seed(42)固定种子是为了让每次划分结果一致方便对比不同训练参数的效果。val_count用max(1, ...)兜底是防止数据集太小时验证集为空。3.2 训练命令与关键参数YOLO v11 的训练入口很简洁但参数选择直接决定你能不能在这 484 张图上拿到可用模型yolo detect train \ data./chicken_behavior/data.yaml \ modelyolo11n.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.001 \ lrf0.01 \ patience30 \ augmentTrue \ mosaic1.0 \ mixup0.1 \ copy_paste0.1 \ degrees10 \ translate0.1 \ scale0.5 \ fliplr0.5 \ namechicken_behavior_v11逐个说这些参数为什么这么设。modelyolo11n.pt选 nano 版本是因为数据量小大模型直接过拟合nano 的容量反而更匹配。epochs150配合patience30意思是 30 轮验证指标不提升就早停避免无效训练。lr00.001是初始学习率小数据集用默认的 0.01 容易震荡降到 0.001 更稳。lrf0.01是最终学习率因子配合余弦退火让学习率从 0.001 平滑降到 0.00001。增强参数是这套数据集能不能出效果的核心。mosaic1.0开启马赛克增强把四张图拼成一张等效于增加样本多样性对小数据集几乎是必开项。mixup0.1和copy_paste0.1用较低概率因为鸡的行为对背景敏感过度混合可能让模型学到错误关联。degrees10限制旋转角度鸡舍摄像头一般是固定角度旋转太大会产生不真实的姿态。fliplr0.5水平翻转是安全的鸡的左右对称行为不受影响。3.3 训练过程监控与指标解读训练启动后重点看几个指标。box_loss和cls_loss应该稳步下降如果cls_loss震荡剧烈多半是类别不平衡导致的。mAP50在验证集上的表现是最终判断依据但这套数据集上别指望能到 0.9能稳定在 0.75 以上就算可用。我一般会在训练时另开一个终端跑 TensorBoardtensorboard --logdir runs/detect/chicken_behavior_v11重点观察验证集的混淆矩阵。如果「睡觉」和「死亡」互相误判严重说明这两个类别的视觉特征在静态图上确实难分需要考虑引入时序信息或者增加这两个类别的样本。如果「吃食」和「喝水」混淆那基本是正常的因为鸡低头动作在单帧上几乎一样只能靠头部位置和地面区域来区分。4. 避坑与排查484 张图训练时最容易翻车的五个地方4.1 视频抽帧导致的训练集泄漏现象验证集 mAP 高得离谱部署到新视频上效果断崖式下跌。原因文件名里的mp4-0000、mp4-0001说明图片是从视频连续抽帧来的。如果同一段视频的相邻帧被随机分到了训练集和验证集那验证集里的鸡和训练集里的鸡几乎是同一只、同一姿态、同一背景模型相当于在「背答案」。解决按视频源划分数据集而不是按图片随机划分。把Farm_indoor3的所有帧放训练集Farm_indoor4放验证集这样验证集才是真正没见过的场景。如果视频源不够至少保证同一段视频的帧不跨集。4.2 类别极度不平衡导致死亡类漏检现象模型对「死亡」几乎不预测召回率极低。原因死亡样本在 484 张里可能只有几十个框而吃食和睡觉各有几百个。YOLO 的损失函数对多数类天然友好少数类被淹没。解决三个方向同时做。一是用copy_paste增强把死亡样本复制粘贴到不同背景上扩充少数类二是在data.yaml里给少数类加权或者用cls_pw参数调整类别权重三是降低置信度阈值部署时把conf从 0.25 降到 0.15宁可误报不可漏报死亡漏检的代价比误报高得多。4.3 异常行为类别定义模糊现象标注里「异常行为」的框位置和大小差异极大模型学不明白。原因异常行为本身是个筐可能包含扎堆、瘫倒、抽搐等多种表现如果标注时没有统一标准同一只鸡不同帧可能被标成不同类别。解决先抽样看 50 张异常行为的标注确认框的是整只鸡还是局部。如果定义太杂建议把异常行为拆成更具体的子类或者干脆合并到死亡类里做二分类。标注一致性比类别数量重要。4.4 图片分辨率与训练尺寸不匹配现象训练时 loss 正常下降但推理时小目标鸡检测不到。原因原始图片可能是 1920×1080训练时缩到 640×640远处的小鸡缩成了十几个像素特征几乎消失。解决如果鸡舍摄像头固定先统计鸡在画面中的典型像素尺寸。如果小于 32×32把imgsz提到 960 或 1280同时batch相应降到 8 或 4。代价是训练变慢但小目标召回会明显改善。4.5 验证集指标好看但实际部署翻车现象mAP50 有 0.8但接到实时视频流上误报频繁。原因验证集和实际部署场景的光照、角度、鸡的品种不一致。数据集里的 Farm_indoor 场景可能和你的鸡舍差别很大。解决从你自己的鸡舍截 20 到 30 张图手工标注后作为测试集不参与训练只用来评估。如果测试集指标远低于验证集说明域偏移严重需要采集自己场景的数据做微调或者用更强的增强模拟你的光照条件。5. 进阶技巧用半监督和时序投票把 484 张图榨干数据量小的时候单靠监督学习很难把指标推到生产可用。我一般会加两层后处理成本低但效果立竿见影。第一层是时序投票。鸡舍视频是连续的单帧误判可以通过多帧投票平滑掉。具体做法是缓存最近 15 帧的检测结果对同一位置的鸡取类别众数。如果 15 帧里 10 帧判为睡觉、3 帧判为死亡、2 帧判为异常最终输出睡觉。这个逻辑用 Python 写起来很简单from collections import deque, Counter class TemporalVoter: def __init__(self, window15, min_votes8): self.window window self.min_votes min_votes self.buffer deque(maxlenwindow) def update(self, detections): # detections: [(track_id, class_id), ...] self.buffer.append(dict(detections)) def vote(self, track_id): votes Counter() for frame_dets in self.buffer: if track_id in frame_dets: votes[frame_dets[track_id]] 1 if not votes: return None cls_id, count votes.most_common(1)[0] return cls_id if count self.min_votes else Nonewindow15对应大约 0.5 秒的视频按 30fps 算min_votes8保证多数帧一致才输出避免单帧噪声。这个后处理对「睡觉 vs 死亡」这种静态难分类别特别有效因为死亡是持续状态睡觉也是持续状态但误判往往是偶发的。第二层是用未标注数据做半监督。你手头肯定有大量没标注的鸡舍视频可以用训练好的模型先跑一遍伪标签挑置信度高于 0.9 的框加入训练集再跑一轮微调。YOLO v11 本身不直接支持半监督但可以手动构造伪标签文件格式和正常标注一样。注意伪标签的类别要过滤只保留高置信度的否则错误会累积。还有一个容易被忽略的点验证时不要只看 mAP要单独统计每个类别的召回率。死亡类的召回率比整体 mAP 重要得多因为漏掉一只死鸡可能导致整栋鸡舍的疫病传播。我现在的习惯是每次训练完先跑一遍验证集把死亡类的召回率单独打出来低于 0.7 就回去调权重和增强不达标不部署。从那以后我每次拿到新的行为数据集都强制先做类别分布统计和视频源划分检查这两步花不了十分钟但能省掉后面几天的排查。希望帮到你。本文还有配套的精品资源点击获取
返回列表