☰
YOLO行为检测实战:埃及伊蚊吸血状态数据集构建与训练
2026/10/14 14:27:18 网站建设 项目流程

搞视觉这行做了几年,真正让我头疼的从来不是模型结构,而是数据集本身。这次要聊的埃及伊蚊吸血行为检测项目,就是一个典型的例子:7800张YOLO格式的昆虫行为图像,目标不是“框出蚊子”,而是要在一帧画面里判断这只蚊子正处于什么行为状态。听起来挺专,但它背后其实是行为检测里最难的那类问题——类间差异极小、目标极小、状态定义容易吵架。

这个项目能做的事很明确:把“蚊子在吸血”这个动态过程,变成机器可以学习的标签体系。你可以用它训练自己搞一个能区分“试探性叮咬”“正在吸血”“吸血完成后静止休息”的结果出来。适合三类人参考:做虫媒病研究的、搞智能虫情监测硬件的,以及那些想用YOLO做自定义行为检测但苦于不知道标签该怎么定的人。这篇就把从数据设计、标注规则到YOLO训练踩坑的完整过程展开说清楚。

1. 项目概述:盯上埃及伊蚊的吸血细节,到底为了什么

1.1 行为检测解决的是“蚊子在干嘛”,而不只是“有没有蚊子”

埃及伊蚊这个名字你可能不熟,但它是登革热、寨卡和基孔肯雅热的主要传播媒介。传统蚊虫监测怎么做?最常见就是诱蚊灯加人工镜检,数数抓了多少只,甚至机械地按形态分类。这套方法只能回答“这个区域蚊子密度高不高”,回答不了“蚊子是不是真的在叮人”。

这就引出一个关键问题:蚊媒传染病的传播风险,跟吸血行为的关系比跟蚊子数量的关系更紧密。一只蚊子只有完成“着陆—探测刺穿—吸血—饱血”这个过程,病原体才有机会在人和蚊之间循环。如果把吸血动作拆成阶段,你会发现每个阶段的流行病学意义完全不同。比如探测刺穿阶段,蚊子的唾液会注入宿主皮肤,这恰恰是病原传播的关键窗口;饱血后的静止阶段,则是蚊虫体内病原发育的起点。

所以从疾控角度来说,一个能自动输出“叮咬率”“吸血成功率”“饱血率”的系统,比一个只会报“今日捕获300只”的系统有价值得多。这也正是这个数据集设计的初衷:将行为从主观观察转成可训练的信号。

1.2 7800张的规模是拍脑袋定的吗

先说结论:不是。做数据集最容易犯的毛病是觉得越多越好,尤其是行为数据,拍几个小时视频抽帧能轻松搞到几万张,但里面大量是重复帧和模糊帧,反而把标签噪声放大。这个项目最终定为7800张,是按“行为类别覆盖”和“场景变化覆盖”来倒推的。

整个数据来自实验室饲养的埃及伊蚊,拍摄时采用了人工吸血装置,全程不涉及活体人体参与。录制过程每秒抽帧,覆盖了单个吸血过程的完整时间线,最后人工筛掉重复度过高的连续帧,再按五类行为状态做配额筛选,保证每类都不至于少到没法训练。

规模分配上按大概6:1:1切成训练、验证、测试三份,训练集约6400张、验证集约900张、测试集约500张。7800张这个数字不是某一次拍摄的产出,而是三轮拍摄、两轮筛选后的净结果。实际拍摄的原始帧数超过5万,最后能留下来的是因为每张都经过了“行为状态明确、画面清晰、边界框可标注”这三道检查。

1.3 行为检测与普通目标检测的根本区别

普通目标检测,比如行人检测、车辆检测,类别是稳定的物理实体。“人”就是“人”,“车”就是“车”,不会因为姿态变化变成另一个类别。行为检测不一样:同一个体、同一个画面位置,可能在几秒钟之内被你定义的标签从A类变成B类。

举例来说,同一只蚊子口器接触皮肤那一刻是“探测”,几秒后口器稳定插入开始吸血,它又是“吸血”。这时候如果在视频里抽单帧标注,标注员要对“到底以什么特征判定边界”达成一致。这就是行为检测数据集比普通数据集难做的核心原因:类别实际上是连续动作的切片,而不是离散物体的分类。另外一个难点是目标尺度:一只蚊子在640像素的图里往往只有40到80像素宽,口器更是只有几个像素。人类肉眼都要求放大才能看清,模型想学明白就更依赖标签的高一致性。

2. 数据集构建与标注:把连续动作切成机器能学的离散标签

2.1 采集方案:怎样把“蚊子吸血”稳定拍下来

实验室环境下的蚊虫行为拍摄,用的是定制的观察笼和人工吸血装置。装置核心是一层人工膜,内侧装加热到37度左右的血囊,蚊虫会自己落上去吸血。拍摄镜头架在装置侧面45度角的位置,因为蚊子吸血时口器斜插入膜,正面拍摄反而看不清口器状态;侧面视角既能看到口器接触点,也能看到腹部从扁到饱的形态变化。

拍摄过程里有个容易被忽略的细节——风机和光源。埃及伊蚊对气流非常敏感,突然的微风会让它们立刻停止吸血并飞走,所以观察笼内要保证气流稳定。光源也不能用蚊虫讨厌的黄光或者频闪严重的LED,实测下来稳定的日光色温灯表现最好,这样抽帧出来的图像色彩一致,后续做亮度增强也不会太撕裂。

抽帧策略上,日常巡航状态用普通抽帧,到了吸血开始那两三分钟,换更高帧率连拍,再从中挑选清晰瞬间。因为吸血过程里蚊子腹部膨胀是有节奏的,每抽一口血会有短暂停顿,这些停顿帧如果被当成“吸血结束”标注,就是混淆的根源。解决方法是按时间戳和腹部体积联合判断:只有停吸超过一定时间并且腹部已经明显膨大,才归到饱血类别。

2.2 类别体系:五类状态怎么定义才能不吵架

项目最终采用了五类方案:probe、feed、engorge、rest、fly。名字不用太花哨,关键是每个类别的判据必须客观可查。

  • probe:口器接触人工膜表面但尚未稳定插入,前足有试探性动作,身体与表面呈一定角度。
  • feed:口器已稳定插入,腹部开始或正在膨大,蚊体相对静止。
  • engorge:腹部明显膨大,颜色变红,口器可能仍插入或刚刚退出,行为上处于饱血状态。
  • rest:完全静止,未吸血或已饱血,形态上没有口器插入状态。
  • fly:离开表面,翅膀展开,通常伴有运动模糊。

最麻烦的边界是probe和feed。早期标注时两个人对同一帧的争议率能达到11%,后来在规则里加了一条硬指标:看口器周围皮肤是否出现凹陷。由于人工膜是半透明材质,口器真正刺穿时膜面会有肉眼可见的小凹点;只有凹点出现才算feed。这个判据加上之后,争议率降到了3%以内。这给同类项目提了个醒:行为标签的评判标准,越接近形态学的客观特征,越不容易扯皮。

2.3 标注流程与质检:双人标注加仲裁

标注工具上,项目组尝试过LabelImg、X-AnyLabeling,最终主力用的是X-AnyLabeling,因为它支持用已有模型做预标注,能大幅提速。流程分四步:预标注、人工修正、交叉复核、仲裁合并。预标注先用一个初版YOLO模型跑全量图,把肯定没问题的框直接保留,人工只需要处理低置信度区域和新增漏检框,效率能提升约40%。

复核环节有意思的地方在于“故意让两个人分开做”。同一批图,A标完B再独立标一遍,然后逐帧对比差异。只差1-2个像素的框不用管,但如果类别不一致,就进入仲裁池。仲裁由项目负责人逐帧看,结合时间上下文判断。截图记录每个争议帧的原始上下文,最后汇总成一份标注FAQ。这套流程最大的价值不在提高效率,而在让标签噪声有据可查。

为什么这么在意标签质量?因为行为检测模型的性能上限很大程度由标签一致性决定。一张图上的“feed”如果被标成“engorge”,模型学到的是不稳定的决策边界,再怎么调参、强化增强都救不回来。

2.4 数据增强要克制:不是所有增强都适合蚊子

YOLO训练标配的mosaic、mixup确实有用,但要用得有分寸。刚开始全开mosaic,发现probe和fly这两个小类别的指标一直起不来,原因是mosaic拼接四张图时,如果四张里只有一两张含有稀少类,等于变相降低了这类目标在每张训练图中出现的频率。后来把mosaic的概率降到0.5,并且保证每张拼接图里至少有一块区域来自稀少类占比高的样本,问题才缓解。

颜色增强我建议只做轻度HSV扰动,幅度不要超过0.2。因为埃及伊蚊体色在不同光照下确实会有偏移,但过度调色会让模型把“体色是否偏红”当成饱血的判断依据,反而干扰真实的腹部体积特征。亮度扰动可以做,但幅度控制在正负15%以内,模拟现场昏暗环境而不是霓虹灯效果。

水平翻转fliplr这个增强我纠结过。蚊虫本身左右对称,翻转不影响生物学属性,所以理论可用。但实际训练A/B对比下来,开了fliplr之后probe类的精度略有下降,推测是因为人工膜装置的阴影方向被翻转后产生了干扰。最后选择只在验证时保持原图,训练时开fliplr但把光照类增强继续调弱。

3. YOLO训练实操与参数解读

3.1 选型:边缘设备上跑行为检测,哪个YOLO版本合适

蚊虫监测设备通常是嵌入式平台,要么是Jetson Nano这类小盒子,要么是树莓派级别的板子。这意味着模型不能太大,参数量要控住。项目训练时对照了YOLOv8n、YOLOv8s、YOLO11n和YOLO11s四档。

实测下来,YOLO11n在测试集上的mAP50大概能到0.86到0.88之间,mAP50-95在0.59到0.62区间;而YOLOv8n同参数下略微低一到两个点。YOLO11s精度能再涨两个点,但推理时间差不多翻倍,对实时监测场景不划算。所以我最终选的是YOLO11n作为基础模型。如果你的部署设备是Jetson Orin这种级别,完全可以上YOLO11s甚至更大的模型,但如果是普通路由器级别的算力,不建议为了零点几的mAP牺牲帧率。

3.2 数据目录与yaml配置:一个小坑能憋你半小时

数据目录按下述结构组织,训练代码才能直接认:

data/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/

对应的数据集配置文件写成这样:

train: ../datasets/mosquito/images/train val: ../datasets/mosquito/images/val test: ../datasets/mosquito/images/test nc: 5 names: ['probe', 'feed', 'engorge', 'rest', 'fly']

用Ultralytics训练时,一个特别容易踩的坑是标签txt里的类别编号必须和names顺序严格一致。我第一次整理数据时,probe的编号是0,但names列表里写成了1,结果前两个epoch的混淆矩阵怎么看怎么别扭。因为txt文件里是数字编号,你就得确保编号0对应names第一项。这个一致性检查要写进数据交付的校验脚本里,别靠人眼核对。

训练命令我习惯写成这样,方便以后复现:

yolo detect train data=mosquito.yaml model=yolov8n.pt epochs=150 imgsz=640 batch=16 device=0

imgsz这里我试过640和800两种,800确实能小幅提高小目标召回,但训练和推理时间都涨约25%。如果你不需要在极低分辨率设备上部署,可以保留800;但实际监测盒子上跑640会更稳妥。

3.3 训练过程监控:损失函数到底在看什么

YOLO自带的训练日志里有三个loss,对应不同的学习目标:box_loss是边框回归的损失,关注“框得准不准”;cls_loss是分类损失,关注“类别判断对不对”;dfl_loss是边框分布的损失,让模型对边界位置的预测更稳定。训练时要三个一起看。

一个常见错觉是“loss降得越低越好”。其实在行为数据集上,box_loss降得很快很正常,因为目标小,框本身就不复杂;真正卡脖子的是cls_loss。如果你发现训练到100轮时cls_loss还在明显下降,但val_cls_loss已经平稳甚至上扬,这就是过拟合信号。该做的是减少epoch、调高增强概率,或者增加一点dropout,而不是继续硬训。

另外要提一下早停。Ultralytics默认patience是50,我一开始总想着让程序跑满150轮,生怕错过最佳点。后来发现行为数据集类别相似度高,最佳epoch往往出现在110到130之间,50轮没提升就会触发早停。早停不是坏事,防的是你报表的时候没法解释为什么后面50轮指标更差。

3.4 评估指标:行为检测该重点盯哪一个

先给一段指标概念速查:Precision是“预测为正的里面有多少是对的”,Recall是“真实正例里有多少被找出来”,mAP50是IoU阈值0.5下的平均精度,mAP50-95则在0.5到0.95之间取平均,对框的定位要求更苛刻。

对行为检测这个项目,我建议重点盯mAP50和F1,而不是死磕mAP50-95。因为行为检测的重点是“判断这个目标当前是什么状态”,框的位置只要稳定,不需要像素级精确。实测的混淆矩阵里,最典型的问题是probe被误判成feed,以及engorge和rest互相混淆。前者的原因我已经说了,是边界特征太接近;后者的原因则比较有意思:饱血后的蚊子静止不动,外形跟一只没吸血的休息蚊几乎一样,唯一区别是腹部尺寸和颜色,模型如果没把腹部特征学好,很容易判错。

所以你在看pr曲线时要按类别拆开看,别只看整体。fly这个类的recall通常最低,因为飞行的蚊子运动模糊严重,连人工标注都费劲;而feed的precision最高,因为吸血时蚊子姿态稳定、特征明显。知道每个类别的“理论难点”之后再去看指标,就不会被总mAP的波动带偏。

4. 实战问题与排查记录

4.1 标签噪声让mAP卡了三天

训练到第二轮时,val mAP一直在0.78到0.80之间晃悠,怎么调都上不去。后来按“置信度-损失”排序抽查高loss样本,发现超过300张engorge的标签被标成了rest。原因是第一轮标注时口径没统一,有些人认为“已经飞走的蚊子肚子还是大的就该算rest”,有些人觉得“只要腹部明显膨大就是engorge”。这类标签噪声不会让训练完全崩溃,但会把决策边界磨钝。

排查方法其实很简单:拿训练好的模型跑一遍训练集,把预测类别和标签类别不一致且置信度较高的样本全部导出,人眼过一遍。你会很快发现错误集中在哪几个类别交界处。修正后重训,mAP50直接跳了6个点。这件事让我彻底相信:行为数据集的标签一致性比数量重要得多。

4.2 小目标漏检:mosaic再香也要适度关

第一阶段训练里,probe这个类召回率只有0.45左右,仔细看badcase发现不是“分类错”,而是压根没框出来。分析原因有两个:一是蚊子太小,二是mosaic拼接时缩小了目标尺寸,让本来只有40像素的蚊子在拼接图上变成20像素甚至更小,特征直接糊了。

解决办法分两步。第一步把mosaic概率从1.0调到0.5,让一半训练样本保持正常尺寸;第二步把imgsz从640升到768,小目标能多保留一点特征。改完之后probe的召回从0.45升到0.63。当然这建立在推理设备能接受更大输入的前提下。如果你要部署到低算力设备,还有一个折中方案:训练时用768,导出模型时保持640输入,效果会略差但也能接受。

4.3 类别数量失衡:不是所有“均衡”方案都能用

初始数据里feed和rest合计超过七成,probe约一成,fly最少,只有不到5%。这种分布如果不处理,模型大概率会“吃掉”稀有类别。我试过两种方案:一种是直接对fly样本做过采样,复制300张加入训练集;另一种是用数据增强生成变体。实测过采样最管用,因为fly的形态变化本来就不大,复制加轻微旋转就能补量。

有人会问,直接调class weight不行吗?Ultralytics并没有直接暴露类别权重接口,强行在数据集里重复文件是最朴素但有效的做法。唯一的注意点是过采样太多会让模型对某个视角过拟合,所以fly类从原始200张增到600张就好,别翻十翻。

4.4 训练分布和部署现场不一致

实验室背景是浅色人工膜加匀光环境,但真到监测设备里,背景可能是深色塑料板、白色纱网、甚至反光的金属面。第一次野外测试,误报率高得离谱,把一堆背景纹理当成了蚊子。解决思路不是重新采几千张图,而是往训练集里扔了100来张“空背景帧”:这些图像没有目标,标注文件里只有图片没有txt。模型看到这些负样本后,逐渐学会“没东西就是没东西”,误报率明显下降。

另外要提一个和这个项目类似的方法论:做任何目标检测部署,都要先问一句“测试环境的光照、背景和视角跟训练差多少”。如果差很多,空背景负样本是最便宜的救火手段,比你拼命调增强管用。

5. 应用场景:行为检测数据集能往哪里走

5.1 智能虫情监测从“数蚊子”进化到“读行为”

传统诱蚊灯是杀灭和计数工具,只能告诉你“这边蚊子多”,但有了行为检测,你可以得到一条完整行为链:多少只落下来、多少只开始探测、多少只真正吸血成功。这些数据对评估杀虫剂效果、驱避剂效果非常直观。比如你测试一款驱避剂,不再需要人工盯几个小时去数“叮了几口”,直接用YOLO模型输出“探测”和“吸血”的次数对比就行。

部署侧,模型导出成OpenVINO或TensorRT格式后,在一颗普通CPU上就能跑到每秒5到10帧。监测盒子只要定时拍照或短录像,就能完成连续行为统计,数据通过低功耗网络回传,整套系统是可行的。

5.2 从单帧检测升级到行为时序识别

现在这个数据集能支持的是单帧行为状态判断,但真实场景里“吸血”是一个连续过程,单帧容易误判,比如一只蚊子在探测和吸血之间切换的中间帧。下一步我计划叠加跟踪器,把检测框关联成个体轨迹,再按时间窗口做时序分类。具体说就是先拿YOLO输出每只蚊子的状态序列,再用ByteTrack把同一只蚊子的轨迹串起来,最后用一个轻量的时序模型判断“这一整段行为”到底是什么。单帧检测是地基,时序识别是上层建筑,这两个组合起来才是真正完整的行为分析管线。

其实这个思路跟着热词里的目标检测加多模态分析是相通的。很多智能系统都是检测加行为推理的两段式,数据集这一步永远是最前端的部分。

5.3 这套方法论能迁到哪些类似项目上

做完埃及伊蚊这个项目,最大的感触是“行为阶段定义方法论”可以横向复制。像鸟类行为检测,核心同样是“起飞、觅食、鸣叫、育雏”这类状态边界;再比如车间工人安全行为检测,判断“是否佩戴护具”“是否处于危险动作中”,也一样面临状态连续变化、边界模糊的问题。

每迁移到一个新场景,流程都是一样的:拉出完整行为链,给每个阶段写下可以客观检查的形态判据,建标注FAQ,做双人仲裁,然后再谈训练。这个流程听起来不酷,但实际的效果比换再大的模型都实在。数据集定了,模型只是工具;数据集飘了,再强的工具也是白搭。

最后说一点真实体会。这个项目最耗时间的不是敲训练命令,而是不断被“这一帧到底是probe还是feed”逼疯的标注会。如果你也想做类似行为检测数据集,我建议把70%的精力放在定义和品控上,剩下30%再分给模型。7800张图不算多,但每一张的状态都经得起复核,模型精度的提升只是水到渠成的结果。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询