猪行为识别数据集+YOLOv8:从数据准备到训练避坑全指南
发布时间:2026/9/28 1:16:43来源:尧图网络
简介面向计算机视觉与智慧农业领域从业者的猪只行为识别数据集聚焦猪圈监控场景覆盖喝、吃、睡觉、站立四类常见行为平均识别正确率达92.6%。压缩包共含2000个文件1272个txt为YOLOv8格式的标注文件与727张jpg原始图像一一对应另附1个yaml配置文件整体体积约85.86MB解压即可接入主流目标检测训练流程。图像截取自多个猪圈监控片段涵盖不同姿态、角度与光照条件标注边界框贴合目标适合直接用于模型训练、验证与精度调优也可作为智慧养殖、动物行为分析等课题的基准数据。资源按图像与标注文件成对组织目录结构简洁便于批量读取与数据划分。已有224人学习下载适合从事行为识别算法研发、养殖智能化改造及YOLO系列模型实践的研究者与开发者使用。1. 猪圈里的猪行为识别数据集92.6%还不够先要会正确使用它养猪场做智能化管理第一步往往不是调算法而是先问“有没有能用的数据”。这个猪圈里的猪行为识别数据集把喝、吃、睡觉、站立四类行为做成了目标检测标注1272张图片不算大但够把yolov8从零教会对外公布的平均正确识别率是92.6%。我的判断是它适合用来验证“猪舍行为识别能不能落地”这件事也适合做毕业设计或边缘算法原型。但92.6%这个数字是特定标注规范、特定验证划分下的成绩想在自己的猪舍复现并稳定使用就得先把数据集格式、训练参数和指标口径吃透。下面按这个顺序讲。2. 把行为识别当目标检测做为什么不是分类以及数据格式地基2.1 帧内行为不等于视频行为先搞懂yolov8在这套数据上做的是“框类别”很多刚接触猪行为识别的人第一反应是拿一个图像分类模型给整张监控画面打个“喝”或“吃”的标签。这在圈舍里只有一头猪、机位固定的“理想实验”里勉强能看真实猪圈里往往十几头猪挤在一起猪栏上有水渍、地面有漏粪板一头低头喝水另一头同时站起来蹭痒。分类模型只能输出一个主导标签占比小的行为被直接吃掉结果看起来准确率不低但养殖人员根本没法信。这份数据集走入正轨的地方在于它按yolov8格式给每头猪画了边界框并且把框和“drink/eat/lie/stand”四类绑定。这实际是目标检测任务而不是图像分类。目标检测同时输出“在哪儿”和“干什么”后续如果要统计“某头猪今天总共喝了多久、吃了多久”才能把不同帧里同一头猪关联起来按行为段累加。没有框的纯分类连具体头数都数不清楚更别提个体行为曲线。提示四类行为在标注上是互斥的同一头猪在同一帧只能有一个标签。但猪群遮挡严重时一个框里可能混进两只猪的肢体这种噪声会直接影响模型训练建议在进入训练前人工扫一遍密集场景。这里还要说一个选型问题既然是多目标多行为能不能用Faster R-CNN之类的两阶段检测器能但实际场景很多会选yolov8。原因有三一是猪舍监控推理对帧率有要求yolov8s在中等显卡上能跑几十毫秒一帧方便接视频流二是这个数据集只有1272张迁移学习时yolov8的工程设定最顺手数据增强、多尺度训练开箱即用三是目标类别只有4类不需要复杂的稀疏关系建模yolov8这种anchor-free设计足够。如果是一个超大猪场每天千万帧级别数据再考虑换更强backbone。2.2 目录结构与data.yaml把1272张图按yolov8的规矩摆好yolov8训练不强制要求某个绝对路径但它默认读取“images”和“labels”同级目录并且train和val分开放。我拿到一个新数据集的第一件事就是把它整理成标准结构。mkdir -p dataset/images/{train,val} mkdir -p dataset/labels/{train,val}假设原始图片都在raw_imgs/对应标注txt在raw_labels/下面会用python按9:1划分并做分层采样确保四类行为在训练集和验证集里都有代表性。import random from pathlib import Path from collections import defaultdict random.seed(42) img_dir Path(raw_imgs) label_dir Path(raw_labels) train_img_dir Path(dataset/images/train) train_lab_dir Path(dataset/labels/train) val_img_dir Path(dataset/images/val) val_lab_dir Path(dataset/labels/val) train_img_dir.mkdir(parentsTrue, exist_okTrue) train_lab_dir.mkdir(parentsTrue, exist_okTrue) val_img_dir.mkdir(parentsTrue, exist_okTrue) val_lab_dir.mkdir(parentsTrue, exist_okTrue) items [] for img_path in sorted(img_dir.glob(*.jpg)): label_path label_dir / (img_path.stem .txt) if not label_path.exists(): continue classes set() for line in label_path.read_text().strip().splitlines(): if line: classes.add(int(line.split()[0])) items.append((img_path, label_path, tuple(sorted(classes)))) class_combos defaultdict(list) for img_path, label_path, classes in items: class_combos[classes].append((img_path, label_path)) train_items, val_items [], [] for combo, lst in class_combos.items(): random.shuffle(lst) val_cut max(1, int(len(lst) * 0.1)) val_items.extend(lst[:val_cut]) train_items.extend(lst[val_cut:]) for img_p, lab_p in train_items: img_p.rename(train_img_dir / img_p.name) lab_p.rename(train_lab_dir / lab_p.name) for img_p, lab_p in val_items: img_p.rename(val_img_dir / img_p.name) lab_p.rename(val_lab_dir / lab_p.name) print(train:, len(train_items), val:, len(val_items))这段脚本的关键是分层采样class_combos按“图中出现的类别组合”分组每组抽10%。如果只是全局随机抽样某一类行为只出现在50张图里抽到验证集不一定覆盖得到分层后至少保证验证集里每一类都有样本。比例9:1对1272张图而言大约是1145张训练、127张验证。如果你的显卡很紧张8:2也可以只是一部分样本从训练里拿走了模型少学一点点验证估计会更乐观一点点权衡看个人。目录就位后写data.yaml内容是给yolov8指明路径和类别名。path: dataset train: images/train val: images/val nc: 4 names: 0: drink 1: eat 2: lie 3: stand这里names的顺序必须和标注txt里的class id完全一致。如果之前标签文件里写的是1、2、3、4而非0、1、2、3不改yaml、直接训练模型会把“吃”当成“喝”来学训练日志上mAP照样很高到最后推理结果全是错位。我见过最典型的错位是model输出class 3names列表只有3项推理直接索引越界报错。写yaml前先扫一眼任意一个标签文件的开头一行确认类别编号从0开始还是从1开始。2.3 校验标注文件yolov8训练前先扫一遍“坏标签”yolov8对标注格式的要求很死每行是class x_center y_center width height坐标归一化到0~1。很多转格式来的标签常见问题包括坐标还是像素值未归一化、类别id从1开始、box超出图像边界、宽度或高度写成负数。训练中途才报错白烧GPU时间。我习惯在训练前先跑一个快速校验脚本。from pathlib import Path for split in [train, val]: for label_path in sorted(Path(fdataset/labels/{split}).glob(*.txt)): bad_lines [] text label_path.read_text().strip() if not text: bad_lines.append(空标注文件) for line_no, line in enumerate(text.splitlines(), 1): parts line.split() if len(parts) ! 5: bad_lines.append(f{line_no}: 字段数不是5) continue try: cls int(parts[0]) cx, cy, w, h map(float, parts[1:]) except ValueError: bad_lines.append(f{line_no}: 坐标不是数字) continue if cls not in (0, 1, 2, 3): bad_lines.append(f{line_no}: 类别id {cls} 越界) if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): bad_lines.append(f{line_no}: 坐标或尺寸未归一化) if w * 1280 5 or h * 720 5: bad_lines.append(f{line_no}: 框过小5px) if bad_lines: print(label_path, bad_lines)脚本里用的是1280x720作为近似原图尺寸具体图片尺寸可用PIL读一下再替换。框过小这条规则值得展开猪圈监控里远处的猪可能只有十几个像素标注虽然正确但训练时这类小目标贡献的梯度极不稳定有时还会反向干扰。我不会直接删除它们而是等第一轮训练后看混淆矩阵里小目标分类的错误率确实影响严重再考虑过滤。校验脚本的价值在于把问题一次性暴露出来而不是等训练到第100个epoch才告诉你“某个标签第3行parse error”。除了数字格式还要检查类别名映射。数据集比较简单四类行为名称明确但如果你后面自己补充了“can”或“其他”训练时别忘记在names里同步。我常遇到的事实是这种行为数据集最大的坏标签来源不是框画歪而是“喝”和“吃”在嘴部细节上确实很像标注员不一致就会让模型学到一个“混合体”体现为空框和重复框。遇到这样的情况只能回到标注阶段做二次核查模型再聪明也补不了标签的账。3. 训练yolov8行为识别模型跑通命令与哪些参数值得动3.1 用预训练权重起步迁移学习对小数据集几乎是必须的1272张图对深度学习来说是标准小样本。随机初始化从头训练yolov8很容易在三十几个epoch内把训练集“背”下来验证集的precision和recall却上不去最后只能靠早停捡回一个勉强能用的模型。常见做法是加载在COCO上预训练好的yolov8s.pt把最后的检测头换成4类再训练。Ultralytics框架允许直接指定modelyolov8s.pt它会自动适配新的nc4。pip install ultralytics环境上CPU也能训练但1272张图乘以150个epoch在CPU上可能要跑一夜到两天若有NVIDIA显卡会更省心。安装后执行训练命令yolo detect train \ modelyolov8s.pt \ datadataset/data.yaml \ epochs150 \ imgsz640 \ batch16 \ patience20 \ lr00.01 \ device0用yolov8s而不是更小的n模型是考虑到“喝”和“吃”的区别往往在头部和嘴部细节模型容量太小会丢失这些线索更大尺寸的m/l在这种规模数据集上容易过拟合训练速度也慢。s是性价比首选。imgsz640是默认值但猪圈原图如果是1080p监控缩到640后小猪可能只有10像素这时建议根据数据里最小有效标注框来定后面专门讲。patience20是早停机制验证集指标连续20个epoch不提升就终止。对小数据集非常实用否则完整跑完150个epoch很可能在最后30轮里反复震荡。device0表示用第一块GPU笔记本只有CPU的话改成devicecpu但要有耐心。这种场景下我宁可用官方提供的yolov8n.pt在CPU上先跑通流程再换s上GPU。3.2 三个最值得手动调的参数epochs、imgsz、batchyolov8的训练参数很多但对这个规模的数据集大多数保持默认就好真正影响结果的是下面三个我按实际项目经验整理成表。参数默认值行为识别建议理由epochs100120~200数据量少需要更多轮次达到稳定的验证指标曲线imgsz640640~960监控中小目标多提升分辨率能显著改善小框召回batch168~32根据显存调batch太小训练震荡明显batch直接控制每次梯度更新用的图片数。行为数据集里“喝”和“吃”相似度极高batch如果只有4一个batch里可能全是“站立”下一batch又全是“睡觉”梯度方向来回甩训练曲线锯齿严重。我一般先看显存12GB显存跑yolov8s、imgsz640时batch设16没压力如果改imgsz960batch降到8。不要为了凑batch把imgsz砍得很低那样小目标检测损失更大。imgsz的选择依据我会先读一下所有标注里宽度和高度的像素第5百分位取一个约数。如果最小框不到15像素建议imgsz960。注意yolov8会把输入缩放到该尺寸不是原图直接花更多像素而是相当于把远处的小猪放大模型有机会看到嘴部结构。代价是显存占用和训练时间成倍增加但对猪群密集样本往往是值得的。还有一个容易忽略的lr0。加载预训练权重后模型已经具备通用特征学习率太大容易把COCO里的特征全部洗掉小数据集反而学歪。0.01是我常用的起点如果看到训练集loss掉得很快、验证集mAP纹丝不动改到0.005再来一轮。调参时一次只动一个变量不然出了问题也不知道是哪一步造成的。3.3 数据增强参数别让增强扭曲了猪的姿态yolov8默认开了mosaic、hsv、flip等增强对小数据集帮助很大但具体幅度要按场景限制否则等于主动给模型加噪声。我在行为识别上最在意四个方面mosaic1.0默认开启把4张图拼成1张。这对密集猪群有奇效能让模型学会在“画面里到处是猪”的环境下分辨个体。但如果标注框本来就歪mosaic会把多个错误叠加建议先跑一轮校验再启用。hsv_h/hsv_s/hsv_v饱和度微调可以增加对圈舍灯光波动的鲁棒性但hsv_v太大会把夜间红外图的黑暗部分提亮成白天反而让模型困惑。我一般把hsv_v从默认的0.4降到0.2。degrees默认0不加旋转。猪的躯干大多水平加一点旋转小于5度可以模拟监控安装角度差但不要拉到30度那会把“睡觉”的肚皮朝上变成“站立”的视觉特征。flipud垂直翻转最好关掉。猪舍监控一般不会倒装垂直翻转后“站”和“睡”的姿态语义就被颠倒了训练收益微乎其微。这些参数可以写进超参数文件或直接在训练命令里传yolo detect train \ modelyolov8s.pt \ datadataset/data.yaml \ epochs150 \ imgsz640 \ batch16 \ mosaic1.0 \ degrees3.0 \ hsv_v0.2 \ flipud0.0数据增强的本质是让模型见过足够多“不大一样”的猪但不能把猪变成不像猪的东西。行为识别里“行为”由姿态和位置定义过度增强会破坏姿态语义这一点和普通物体检测有区别。比如旋转90度猪躺着变成竖着模型就无法区分“趴着”和“站着”了。3.4 看训练结果别只盯最后一行要拆开看曲线和混淆矩阵训练结束后runs/detect/train/下会生成results、混淆矩阵、验证集预测图等文件。新手最容易犯的错是只看最后一个epoch的mAP然后自信地进入部署阶段。正确的顺序是先看results.png里的四条曲线train/loss、val/loss、metrics/mAP50、metrics/mAP50-95。如果val/loss在训练中后段转头向上说明过拟合已经出现这时mAP50可能还在缓慢上涨但那是在吃老本。要回到参数上要么降lr0、要么把patience设到5来早停。小数据集上过拟合和欠拟合之间的窗口很窄多盯着曲线的斜率能少走弯路。再打开confusion_matrix.png。行为识别里最该看的就是它。四类行为在框层面各归各位模型到底把谁认成了谁一看便知。比如“吃”有15%被分到“喝”那说明嘴部和料槽的局部特征被模型当作饮水器的特征了。这个信息比mAP更直接mAP是把所有框的匹配好坏揉成一个数混淆矩阵能告诉你哪对类别是冤家。val_batch_pred.jpg是验证集预测的可视化图。放大后重点看两类问题一是角落里的小猪漏检二是有没有框把两头挨着的猪圈成一个框。这两类在指标上不一定难看但在行为统计的后续流程里会成倍放大误差。因为漏检的那头猪可能一整天都“不存在”影响行为时长统计的分子和分母。注意混淆矩阵里如果background类占比很高通常代表标注框框得比实际猪身紧模型把大量猪尾巴、露出的腿判成背景。这种情况调阈值没用需要回看训练前标注是否有系统性偏紧。4. 92.6%意味着什么用验证指标反推数据集的边界4.1 mAP与正确识别率口径不对数字再高也没用标题里“平均正确识别率92.6%”在工程验收时要先问清楚它精确指哪个指标。可能是整图分类准确率、逐框行为准确率、或per-class准确率的平均。对这套带框的数据集来说更权威的指标是mAP50和mAP50-95但这两个数字往往和“92.6%”对不上原因在于计算方式。mAP50要求预测框和真值框的IoU超过0.5才算匹配成功然后对四类分别算平均精度再取均值。这个数字对“框是否贴近”很敏感。而“正确识别率”如果是按框统计它只问“匹配上的框里类别猜对多少个”完全不看IoU的严格程度。两者评的东西不一样mAP惩罚“框偏”和“类别错”正确识别率只看“类别错”。所以一篇报告说92.6%另一篇说mAP5089.5%可能都不矛盾。我建议在项目文档里明确写清楚避免验收时扯皮。更实用的做法是同时报三个数mAP50、mAP50-95、逐框行为准确率。逐框行为准确率可以自己从混淆矩阵算出来把对角线上的四个数字相加除以所有有效匹配框的个数。这个数字才最接近养殖场用户的直觉——他打开后台看到“这头猪在喝水”这条记录到底有多少概率是对的。4.2 喝、吃为什么最容易互相认错以及怎么统计类间混淆先跑一个统计脚本看看四类框的样本数量差异。from pathlib import Path from collections import Counter counter Counter() name_map {0: drink, 1: eat, 2: lie, 3: stand} for split in [train, val]: for label_path in Path(fdataset/labels/{split}).glob(*.txt): for line in label_path.read_text().strip().splitlines(): if line: cls int(line.split()[0]) counter[name_map[cls]] 1 total sum(counter.values()) for name in [drink, eat, lie, stand]: print(f{name}: {counter[name]} ({counter[name]/total:.1%}))这段脚本输出每一类行为一共有多少个框以及占比。我拿类似猪舍数据集跑过结果常常是“站立”占35%以上“喝水”可能只有12%。这种不均衡意味着模型天然偏向多数的“站立”因为多数样本的梯度都在告诉它“输出站准没错”。所以只看整体准确率是不够的要看每类的recall。“喝”和“吃”的混淆还有一个客观原因猪喝水时头伸向饮水器身体姿态和低头采食几乎一样区别仅在嘴部接触的位置。如果标注规范标注的是“包含整头猪”的框那框内特征大量是相同的猪身行为差异只在很小的一块区域模型很难学。你可以做一个更合理的约定对“喝”额外给一个头部或嘴部关键点或把检测框缩到更贴住头颈位置。不过本数据集既然已经是整猪框我们只能承认边界靠大量数据让模型记住“水嘴位置的相对高度”这些弱线索。4.3 用conf阈值卡出你要的现场识别率推理置信度阈值conf是一个可以现场调节的旋钮。yolov8默认conf0.25偏向于高召回、低精度监控画面里一点影子晃动都可能被当“站立”。对不同的行为监控目的最优阈值不同。yolo detect val \ modelruns/detect/train/weights/best.pt \ datadataset/data.yaml \ conf0.25 \ iou0.45 \ save_jsonTrue执行后得到predictions.json里面每条记录包含image_id、category_id、bbox、confidence。下一步写脚本扫描conf从0.2到0.7每0.05一档计算每一类的precision和recall画成曲线后选择合适的工作点。如果应用是统计喝水和采食时长漏报会让后台把“喝水”算成“没发生”危害更大conf可以设低到0.2如果应用是发给饲养员的异常报警误报太多会被直接关掉conf要提到0.5以上宁可漏报也不能让系统变成“狼来了”。这里给出一个扫描核心片段def compute_pr(json_result, gt, conf): tp fp fn 0 # 先按conf过滤再匹配IoU统计四类的tp/fp/fn return per_class_precision, per_class_recall真正的实现要把预测框和真值框做IoU匹配代码不复杂但有点长关键是不要为了省事把所有框不加区别去算。我习惯按类分开统计因为“喝”和“吃”的最优conf大概率不一样。这也算这个数据集的一个特点四类行为姿态差异大统一的conf很难同时照顾远距离小猪和近距离大猪。生产中可以在模型后处理里给类别设置不同的conf阈值ultralytics的predict支持class过滤但不支持per-class阈值需要自己包一层。4.4 验证集划分泄漏一个让92.6%虚高的隐性原因前面分层采样只保证了类别覆盖还有一个数据泄漏点需要留意如果原始1272张图片是从视频里连续抽帧得到的前后帧内容几乎一样。随机划分train和val时某一头猪的同一行为连续帧可能几张落在训练集、几张落在验证集模型等于“提前见过答案”val指标就会虚高。识别方法很简单看图片文件名是否带时间戳或序号。如果文件名形如frame_00001.jpg到frame_01272.jpg最稳妥的做法是按时间连续段切分先把前90%时间段的帧划给训练后10%划给验证而不是随机打乱。如果文件名没有可解析顺序也可以用图片内容相似度粗排但这属于额外工作了。我在自用脚本里是这样处理的解析文件名中的时间戳按分钟聚合成片段再把片段整体划到train或val。这样做出来的验证集更贴近实际部署时的“没见过的时间段”模型在这个验证集上的mAP会比随机划分低几个点但那才是可信的数字。所以当你在别处看到92.6%时先问一句“是不是随机划分的”这句话能帮你判断它有多少水分。5. 避坑猪行为识别训练的5个高频翻车点5.1 现象训练loss不降甚至反复跳mAP始终在0.6徘徊原因这类问题十有八九不在模型结构而在标注数据。最常见的有三种一类是标注坐标还是像素值没归一化模型输入看到的目标尺寸变成几百倍梯度直接爆掉一类是存在空txt文件被当作纯背景训练背景样本占比无限大还有一类是负数坐标或box宽度为0yolov8读取时静默忽略某些行导致训练样本数和图片数对不上。解决先跑第2.3节里的校验脚本把所有坏文件暴露出来。然后逐张看校验输出不要自动删除因为可能是单位不统一的问题比如某一张图来自另一个标注工具格式不同。统一格式后重新划分再训练。我发现九成“loss乱跳”是标签问题不是调参问题。所以遇到这种情况先停模型去查数据。5.2 现象验证集mAP很高一放到现场监控视频里狂误报原因数据集的训练集和验证集大概率来自同一段监控视频背景光照几乎一致。模型学到的不只是猪还有圈舍地面的纹理、墙上的水渍和饮水器的位置。换到另一间猪舍背景变了模型就会把类似纹理的东西当猪。这是小样本目标检测最典型的过拟合到场景的问题。解决不能只在这个数据集上原地打转。去目标部署的猪舍抽几分钟视频每2~3秒抽一帧人工补标100~300张和原数据集混合训练。补标不需要画得很精细重点是覆盖新背景、新机位和不同的光照。另外把数据增强里的hsv_h和hsv_s开大一些减小模型对颜色纹理的依赖。最立竿见影的还是加入目标场景的真实帧这比任何正则化都管用。5.3 现象猪睡觉识别成站立尤其在红外夜视图上原因红外夜视图是单通道灰度风格yolov8训练时默认用RGB三通道夜间图在三个通道上的数值几乎一样模型的色彩线索失效。睡觉的猪蜷成一团侧影轮廓和站立的猪非常接近。更麻烦的是如果数据集里白天图和夜间图混在一起模型会试图找一个能同时解释两者的特征结果两边都不讨好。解决先把数据集按光照拆成白天和夜间两份分别统计混淆矩阵。如果夜间样本足够比如超过300张单独训一个夜间模型不够就做亮度增强用hsv_v0.3让模型对亮度的敏感度下降。再复查夜间图标签部分“趴着不动但眼睛微睁”的猪被标成了站立这是标注主观性造成的噪声必须人工统一“lie”要求前腿伸直、肚皮着地“stand”要求前腿支撑两个状态在侧视图中区别明显。标注规范统一后模型预测才稳定。5.4 现象一张图十几头猪模型漏掉角落里的几头总数永远对不上原因猪群密集时角落的小猪目标只有二三十像素anchor和NMS很容易把它们合并到邻近的大目标上。yolov8的检测头设计对小目标不友好加上imgsz640压缩后小目标退化成了几个像素模型根本没有足够信息分辨它是猪还是粪便块。解决三管齐下。一是imgsz提到960让小目标占更多像素二是iou从默认0.45提到0.5降低NMS对紧邻小框的抑制三是在数据增强里开启mosaic1.0模拟多猪密集排列。如果还漏检查角落里那些漏检框是不是标注框画得过大把旁边的猪也框了进来导致训练时模型认为“角落不需要多个框”。必要时单独做一轮小目标增强把包含小目标的图复制一份并放大后再喂给模型。5.5 现象换一台电脑推理结果和训练时对不上边框乱飘原因绝大多数是预处理不一致。训练时imgsz640推理时也写640但yolov8默认会把输入图letterbox到指定尺寸如果你部署代码里忘了做letterbox直接resize图像发生了拉伸检测框自然错位。另外训练和推理的half精度设置如果不一致模型权重从FP32转FP16时某些层出现精度损失边界框就会抖动。解决先确认推理脚本用的是Ultralytics官方predict接口内部已处理letterbox。如果是自己用ONNX或TensorRT的engine推理必须自己实现letterbox和坐标反变换。验证方法非常简单取一张训练时的验证图用官方predict跑一次把原图和模型输出框叠起来框若完全重合则流程正确框偏几个像素多半是预处理问题。我还习惯在推理时固定imgsz不要输入端或大或小传输时也保持同样尺寸不然不同输入尺寸会导致模型输出分布变化。以上五个坑没有一个需要换更贵的算法全是数据、预处理和标注规范的事。我踩得最多的是第一个因为每次换数据集都想当然地信任它的格式“yolov8能加载”不等于“yolov8能训好”。6. 进阶从单帧识别到行为占比、异常提醒的最后一步单帧检测只回答“这一帧里每头猪在干什么”生产现场真正需要的是“这头猪今天喝了多久、睡了多久”。把yolov8的输出接一个按跟踪id聚合的状态机是常规做法。我给个简易思路对视频每3秒抽1帧用IoU匹配或bytetrack把同一头猪的id固定下来对同一个id的连续30帧预测标签做多数投票得到一个稳定行为段把每段时长累加进当天统计表。import collections MAX_FRAMES 30 tracker {} # track_id - deque of recent labels behavior_time collections.Counter() def process_frame(detections): for track_id, label in detections: if track_id not in tracker: tracker[track_id] collections.deque(maxlenMAX_FRAMES) tracker[track_id].append(label) if len(tracker[track_id]) MAX_FRAMES: stable tracker[track_id].most_common(1)[0][0] behavior_time[stable] 3 # 每3秒累加这段代码的核心是滑动窗口行为瞬间抖动时窗口多数投票会忽略短时噪声输出稳定状态。maxlen30对应30个抽帧样本如果抽帧频率是1fps就是30秒窗口覆盖猪舍里几分钟级别的行为切换足够。更精细的做法是给每头猪做一个状态转移检测到变化连续5帧才切换防止“喝一下马上抬头看”被记成两次喝水。部署到边缘设备时yolov8s导出为rknn或tensorrt后单帧耗时大多在几十毫秒量级加上硬件的多路视频能力甚至能同时处理多个圈舍。我往往在导出前先在PC上把验证集的metrics跑一遍再导板子跑同一批图对比mAP差异如果板端差太多第一怀疑后处理NMS实现是否一致不要一上来就怪模型量化。现在拿到这种猪行为数据集我的习惯是先做两件事统计四类框的比例看混淆矩阵里“喝”和“吃”的分裂程度再按部署场景抽帧构一个“没见过的时间段”验证集。这两件事做完92.6%这张成绩单还剩多少含金量基本就心里有数了。先把数据和指标管好模型不会差到哪去。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网