简介:在计算机视觉领域,目标检测模型训练通常依赖大规模数据集,但真实场景中往往面临样本稀缺的困境。迁移学习为解决这一问题提供了有效路径,通过加载YOLOv8预训练权重,模型已具备通用视觉特征提取能力,只需少量场景数据微调即可适配特定任务。本文以灭火器识别为例,介绍如何利用127张监控画面构建高质量小数据集,涵盖数据采集、筛选、标注格式转换、训练参数调优及ONNX/RKNN部署全流程。重点分析了数据分布、标注口径、验证集划分对模型泛化性能的影响,并给出置信度阈值调整与失败案例回馈的迭代优化方法。实验表明,在固定摄像头场景下,小样本训练可实现99.5%的识别准确率,为消防设备检测等工业视觉应用提供了低成本、高可用的工程实践参考。 消防设备识别这块,我今年踩了个挺有意思的坑。项目要识别厂区里的灭火器,按习惯我第一反应是直接找公开数据集、拉个大模型来微调。但实际测试下来,通用数据集里的灭火器图片和真实监控画面差距太大,漏检率根本压不住。后面我干脆自己建了一套小数据集——127张训练图、640x640分辨率、YOLOv8格式标注框,识别率做到了99.5%。这篇文章就完整记录一遍这套数据集的构建思路、标注细节、训练参数和部署经验,给同样想做专项目标检测、又不想一上来就堆几万张图的朋友一个参考。
1. 为什么我只用127张训练图:小数据集不等于不能实战
先说结论:127张图能跑出99.5%的识别率,前提是你清楚这套模型服务的场景边界。
我一开始也怀疑这个数量。YOLOv8官方Demo都是拿COCO十几万张图说话,127张听起来像过家家。但COCO数据集有个致命问题:它里面的灭火器图像偏“展示性”,经常是手持、室内、背景干净,或者画面里灭火器占很大面积。真实监控场景则是灭火器挂在走廊墙上,旁边有消防栓、杂物、水管,视角固定、距离固定、光照随早晚变化。用COCO预训练权重直接去推理,很容易把灭火器旁边的红色水桶、红色配电箱一起框出来。因为通用数据集里的灭火器语义被摊薄了,模型学到的是一堆“红色圆柱体”的共模特征,而不是“灭火器挂在消防箱旁”这个具体场景。
这时候,迁移学习的价值就体现出来了。YOLOv8的预训练权重(比如yolov8n.pt或yolov8s.pt)已经在海量数据上见过各种纹理、边缘、颜色组合,它不需要你重新教它什么是“红色”和“圆柱体”。你拿着一小批场景数据去微调,本质上是把通用视觉特征往你的专属场景上做一次“精调”。所以127张图承担的任务不是从零学习灭火器,而是把已有的通用知识搬迁到摄像头固定视角下的消防检查场景中。
这也解释了为什么数据集可以小:当检测任务的语境足够封闭——摄像头位置固定、灭火器尺寸和外观相对统一、背景变化不剧烈——模型的输入分布就非常窄,小样本自然够用。反过来说,如果你做的是移动巡检机器人,灭火器可能在画面各个位置、各种角度、各种光照下出现,那127张图绝对不够,至少得加两个数量级。这个边界要在项目一开始就想清楚,不然后面部署时会很痛苦。我的判断标准很简单:训练集能覆盖实际运行时可能出现的主要变化维度,就可以开工。
2. 数据采集与筛选:127张图的构成,决定训练效率的上限
小数据集最忌讳的就是把“数量”当指标,却忽略“质量分布”。我做这套数据集时,先定了一个筛选原则:不追求图像多,而是追求“每张图都带来新的信息量”。
2.1 数据来源和采集方式
采集来源我给三个:监控录像抽帧、手机补拍、开放图库补充。监控录像抽帧是最贴近真实部署的,因为最终推理输入的视频流就来自这些摄像头。我直接从厂区监控导出几个时段的录像,用ffmpeg按固定间隔抽帧,再人工筛选。手机补拍是为了覆盖监控覆盖不到的角度,比如侧面的近距离视角。开放图库则用来补充不同光照和背景下的外观,但数量要克制,因为图库照片和真实监控画面的画质差异会干扰训练。
抽帧时有个细节:同一个摄像头画面在几秒内几乎一样,连续抽帧会出现大量重复图像。我用图像哈希算法做了一次去重,把相似度超过阈值的帧只保留一张。不然127张图里有三四十张是同一视角的微变帧,训练时模型会反复强化那个角度,其他角度的泛化能力就弱。
2.2 筛选标准
从几百张原始素材里筛出127张,我按下面这套标准来操作:
| 筛选项 | 标准 | 说明 |
|---|---|---|
| 图像清晰度 | 无运动模糊、无明显对焦模糊 | 监控画面容易出现拖影,这种图会让标注框边缘不准确 |
| 最低分辨率 | 不小于640x640;不足则上采样到640x640 | 目标太小的话,上采样后纹理已经很糊,不太适合训练 |
| 目标占比 | 灭火器占图像面积不低于3% | 低于这个比例,目标只有几十个像素,检测器很难学 |
| 光照覆盖 | 包含白天、黄昏、夜间 | 夜间红外模式的色调与白天差异很大,必须覆盖 |
| 遮挡程度 | 轻度遮挡保留;超过50%的严重遮挡剔除 | 遮挡太严重的样本标注难度高,也容易给模型带来噪声 |
| 外观多样性 | 红色瓶身灭火器为主,如有其他颜色也保留 | 在真实场景中红色灭火器占绝对主流,但保留下其他颜色能提高鲁棒性 |
这个表是我筛选时的核心参考。实际做下来,最容易被忽略的是夜间图像。很多项目白天测试效果不错,一到夜间红外模式下就崩,就是因为训练集里没放夜间的图。我在筛选时专门保证夜间画面的比例占到15%左右,后面训练出来效果确实稳定很多。
2.3 数据增强的取舍
只有127张原始图,不要急着靠增强来造数据。YOLOv8训练时默认会做mosaic、随机翻转、HSV扰动等增强,这已经够用了。关键的一点是:验证集一定不要做增强。因为验证集的作用是评估真实性能,如果验证集也被随机裁剪、颜色增强过,你看到的指标就会虚高。我习惯把原始图直接拆出验证集,训练时对它不做任何变换,只做resize到640x640,这样测出来的mAP才有参考价值。
3. 标注转化为YOLOv8格式的全过程
拿到127张图后,下一步是把图片变成YOLOv8能读懂的标注文件。这个步骤看着简单,但里面有不少细节,标注口径稍有偏差,训练结果就会飘。
3.1 YOLOv8标注格式的基本规则
YOLOv8的标准标签是每个txt文件对应一张图片,文件名与图片名一致。txt里每行代表一个目标框,格式是:
class_id x_center y_center width height四个数值全部归一化到0~1之间。class_id从0开始编号。比如我这个数据集只有一个类别,那class_id始终是0,names列表里就是['fire_extinguisher']。
这里要注意:x_center、y_center是框中心点的相对坐标,width和height是框的宽度和高度相对整图尺寸的比例。不是左上角坐标,也不是右下角坐标。很多新手在这里换算出错,我就直接贴一个例子。
假设某张图尺寸是1000x800,标注框左上角是(200, 150),右下角是(420, 380)。那么框的中心点:
- x_center = (200 + 420) / 2 / 1000 = 0.31
- y_center = (150 + 380) / 2 / 800 = 0.33125
- width = (420 - 200) / 1000 = 0.22
- height = (380 - 150) / 800 = 0.2875
最终txt里的一行内容就是:
0 0.31 0.33125 0.22 0.2875在标注工具里你看到的是像素坐标,导出到YOLOv8格式时要按上面的公式做换算。如果你用的是LabelImg这类工具,它本身支持YOLO格式导出;如果你用的是CVAT,导出时选YOLO 1.1格式即可,也是同样的结构。
3.2 标注口径的统一
127张图数量不多,最难的不是标注本身,而是保证标注口径一致。灭火器这目标有个特点:瓶身和挂架连在一起,有时候墙壁上还有消防箱,框的范围怎么定,直接决定模型学到的形状。
我的做法是:标注框只包含灭火器主体(瓶身、喷嘴、提压把),不包含外围挂架。如果灭火器被消防箱的玻璃门半遮挡,就框可见部分的瓶身;如果画面里同时出现多个灭火器,每个都要单独标注。口径统一之后,模型学到的就是灭火器这个物体本身的轮廓,而不是被挂架或遮挡物带偏。
3.3 标注结果的检查
标注完不能直接开训,至少要做两轮检查。第一轮是人工抽查,用可视化脚本把标注框画回原图,看看有没有框偏、漏框、多框。第二轮是程序化检查,检查每行标注是否满足0 <= x_center <= 1这类归一化约束,以及框的宽高是否为正值。
这两轮检查在127张图上用不了半小时,但能避免很多训练时的问题。我之前偷懒跳过检查,结果发现某几张图导出的txt里出现了1.02这样的越界值,训练时虽然没报错,但损失曲线死活不下降,排查了半天才发现是标注文件的问题。小数据集的容错能力弱,一个坏标签就会让训练结果失真。
3.4 数据集目录结构
我最终采用的目录结构是这样的:
fire_extinguisher/ ├── data.yaml ├── images/ │ ├── train/ # 100张 │ └── val/ # 27张 └── labels/ ├── train/ # 100个txt └── val/ # 27个txttrain和val的划分比例约80%比20%。127张图本来就不多,验证集只保留了27张。这里的27张是精心挑选出来的,尽量覆盖白天、夜间、侧角度、遮挡等不同情况,而不是随机抽。随机抽可能把少数夜间图全抽进训练集,导致验证集光照单一、指标虚高。
data.yaml文件内容如下:
train: /your_absolute_path/fire_extinguisher/images/train val: /your_absolute_path/fire_extinguisher/images/val nc: 1 names: ['fire_extinguisher']路径建议写绝对路径,避免训练时找不到数据。如果后面要迁移到服务器上跑,把路径改成服务器上的实际路径即可。
4. 训练配置与99.5%识别率的真实含义
数据集准备好之后就是训练环节。这部分是大家最关心的,但也是误解最多的地方。
4.1 训练环境
我用的是一张GTX 1660 Ti 6GB显存的显卡,这也是很多个人开发者和小型团队手里常见的配置。在6GB显存下,imgsz=640、batch_size=8是稳定能跑的配置。
环境版本方面:
- Python 3.10
- PyTorch 2.1.2
- ultralytics 8.1.0
安装ultralytics很简单,一条命令就行:
pip install ultralytics4.2 预训练权重的选择
预训练权重我建议优先考虑yolov8s.pt。yolov8n.pt更小、速度更快,但在小样本迁移场景下,n模型的特征表达能力相对弱,识别率上限可能不如s模型。如果你的部署设备是弱算力的嵌入式板子,再考虑n模型,毕竟它更轻量。我这里选s模型,主要是希望在有限图像数量下给模型更大的容量去拟合场景特征。
训练命令:
yolo detect train data=fire_extinguisher/data.yaml model=yolov8s.pt epochs=150 imgsz=640 batch=8 patience=20 project=./runs name=fire_exp1几个关键参数我解释下:
- epochs设置为150,实际训练时用早停机制,一般在80到120轮之间就会收敛。
- patience=20,表示如果连续20轮验证集指标没有提升,训练就提前停止。小数据集特别适合用早停,因为一旦过拟合,验证集指标会迅速恶化。
- imgsz=640,这是标题里标明的分辨率,也是训练和推理的统一输入尺寸。
4.3 99.5%识别率是怎么算出来的
先亮个底:99.5%这个数字不是我瞎编的,但也不是普适指标。在这个场景下,我用验证集的27张图做推理,按IoU大于等于0.5作为判定标准,统计每个框的置信度,得到漏检框和误检框,最终识别准确率等于正确的检测框数除以总检测框数。27张图里大概包含30多个灭火器实例,一轮跑下来偶尔出现一个目标置信度低于阈值的情况,那准确率就是30/31约等于96.8%;如果全部检测正确且没有误检,就是100%。99.5%相当于在多次重复实验中保持了接近满分的检出表现。
这里需要说明的是,小验证集上的高准确率不等于所有场景下都可靠。27张验证图能覆盖的只是这个固定监控场景中的常见变化。如果你把训练好的模型换个厂房、换一种光照条件,准确率大概率会明显下降。
为了让大家更直观了解评估方式,我用一张表整理常用指标和它们在小数据集上的表现特征:
| 指标 | 说明 | 小数据集上的表现 |
|---|---|---|
| Precision | 预测为正的样本中预测正确的比例 | 容易接近1,因为误检样本很少 |
| Recall | 实际为正的样本中被正确检出的比例 | 容易达到1,因为验证集样本数量少 |
| mAP50 | IoU阈值为0.5时的平均精度 | 小数据集普遍偏高 |
| mAP50-95 | IoU阈值从0.5到0.95取平均 | 这个指标更能反映框的贴合程度 |
所以在小数据集上,我更推荐同时关注mAP50-95,它不会因为几个样本检测正确就给出虚高的结果。我最终得到的mAP50基本在0.99左右,mAP50-95大概在0.85到0.9之间。99.5%的识别率描述的是实际推理效果,而不是论文里刻意刷出来的mAP。
4.4 提高小数据集训练效果的参数细节
如果你也想用少量图训出类似的识别率,除了默认配置,我还调整了这几个地方。
训练前10轮,YOLOv8默认会开mosaic增强。在小数据集上,mosaic能把四张图拼在一起,变相增加样本量,这是个好事情。但在训练后段,mosaic生成的图与真实场景差异越来越大,反而会让模型稳定不下来。我的做法是在最后20轮关闭mosaic,让模型在接近真实分布的图像上做收敛。
在ultralytics中可以通过配置参数实现:
mosaic: 0.0不过一种做法是训练到一半手动修改配置重启,另一种做法是直接用命令行覆盖参数。我更推荐第二种,比如在训练时把mosaic关小:
yolo detect train data=fire_extinguisher/data.yaml model=yolov8s.pt epochs=150 imgsz=640 batch=8 mosaic=0.5 close_mosaic=20其中close_mosaic=20表示最后20轮关闭mosaic,mosaic=0.5表示训练前中期使用50%概率的mosaic增强。这个组合在小数据集上实测挺稳的。
另外,HSV扰动保持默认即可,其中hsv_h=0.015、hsv_s=0.7、hsv_v=0.4。对灭火器这种红色特征明显的目标,过强的色相扰动可能出现“红色瓶身被变成蓝色”这种不合理的训练样本,所以色相扰动不要调得太大。
4.5 损失曲线怎么看
小数据集训练时,损失曲线下降会比较快,通常前30轮就会迅速收敛,后面趋于平缓。如果训练损失持续下降但验证损失上升,说明模型过拟合了。早停机制会帮你在验证损失上升前停下来。我在训练完成后会查看runs/fire_exp1/文件夹下的results.png,这是训练过程的可视化汇总,包含损失曲线、精度、召回率等指标。
一个有效的小技巧是:训练结束后对比best.pt和last.pt的验证结果。best.pt是早停时验证指标最好的权重,last.pt是最后一轮权重。如果两者差距很大,说明训练后期过拟合较重,直接用best.pt即可;如果差距很小,说明模型收敛稳定。
5. 部署到真实场景:边端推理与迭代优化
训练出了高识别率模型,接下来就是部署。市面上很多教程到best.pt这一步就结束了,实际落地时还有不少坑。
5.1 导出ONNX和RKNN
如果部署目标是Windows工控机+USB摄像头,可以直接用PyTorch或者转成ONNX使用。如果目标是嵌入式设备,常见的选择是把模型转成ONNX再转成各家芯片的格式。比如RK3588平台上,需要把ONNX转成RKNN。
先用ultralytics导出ONNX:
yolo export model=runs/fire_exp1/weights/best.pt format=onnx imgsz=640导出后的best.onnx可以先用onnxruntime在PC端做一次一致性验证,确保导出后的推理结果与PyTorch下相差不大。这一步很容易被跳过,但很重要。因为嵌入式部署时,很多问题其实在ONNX导出阶段就埋下了。
在RK3588上转RKNN时,RKNN-Toolkit2会对算子做优化和量化,这个过程中精度会有一定损失。我的经验是,如果检测精度要求高,不要用INT8量化,先用FP16模型。FP16在RK3588上跑起来速度已经可以接受,而且能保留几乎全部精度。等确认INT8量化后精度损失在可接受范围内,再切换成INT8模型换更高帧率。
5.2 置信度阈值的调整
训练时用的置信度阈值是0.25,这个是ultralytics默认值。部署时不能直接照搬。在真实摄像头画面中,由于视角、光照变化,模型输出的置信度会有波动。如果阈值设得太低,会出现大量误检;设得太高,又会漏检。
我的做法是:先收集一段真实运行视频,让模型输出每个检测框的置信度,画出置信度分布,再根据项目需求选择阈值。比如消防场景宁可多报警也不能漏报,那就把阈值调到0.15到0.2;如果是做数量统计,要求精确,那就调到0.4以上。这个阈值只影响推理时的判定,不影响模型本身,所以可以放心调。
5.3 部署后的失败案例收集
模型上线后,一定要设计一套反馈机制,把真实场景里检测失败的图片收集起来。我会在推理程序里加一个逻辑:如果某个目标的置信度在0.2到0.5之间,就把这张图保存到一个单独的文件夹,方便事后人工筛查。
这些低置信度图就是扩充数据集的天然素材。每过一两周,把收集到的失败案例筛选一遍,挑出框架清晰、目标明显、但模型没识别出来的图片,补标后加入训练集重新训练。这个方法我实测很有用,每次加入三五十张失败样本,模型的鲁棒性都会有明显提升。这就是小数据集的正常迭代打法:先小步快跑上线,再靠真实环境数据不断回喂。
5.4 扩展方向:从灭火器到整套消防设备检测
做完灭火器识别后,同一个数据集构建流程可以快速复制到其他消防设备检测上,比如消防软管卷盘、烟雾报警器、安全出口灯。新类别图像数量不需要前期就达到几千张,先按这套方法——场景筛选、标注口径统一、验证集精心划分——收集一两百张训练图,往往就能取得可用的初步效果。
复用YOLOv8的预训练权重时,新数据集的names改成['fire_extinguisher', 'fire_hose', 'smoke_detector'],nc改为3,再把旧数据和新数据放在一起重训即可。这里的经验是,新增类别时一定要把之前的灭火器数据一起加进去,否则灾难性遗忘会让旧类别的识别率明显退化。
最后再分享一条实操体会。数据集数量不是越少越牛,也绝不是127张这个数字本身有什么魔力,关键在于你是否把验证集设计得足够真实、把标注口径控制得足够严格。我踩过最大的坑就是第一版数据集的验证集和训练集分布太像,导致验证指标虚高,部署后掉点严重。后来重新划分验证集、加入夜间图和遮挡图,指标才落回真实水平。如果你也要做类似的小数据集目标检测,建议先把这条记住:数据集的分布和验证方式,比一张训练图的多少更重要。
本文还有配套的精品资源,点击获取