☰
基于YOLOv5的烟火检测实战:2059张标注数据集与训练推理全流程
2026/10/12 12:54:25 网站建设 项目流程

简介:本资源面向计算机视觉与深度学习方向的开发者、学生及安防算法研究者,提供一套完整的火灾烟火烟雾检测方案,解决从数据准备到模型训练落地的全流程问题。数据集覆盖大火小火、建筑草原森林起火、车辆起火、昼夜与室内外等多样场景,烟雾场景与火情保持一致,按Pascal VOC格式组织,含2059张图像及对应XML标注,标签统一为fire,并附VOC转YOLO格式脚本与使用说明。压缩包共332个文件,约200.15MB,包含C源码、头文件、Python脚本、YAML配置、Shell脚本、CUDA内核及权重文件等,兼顾模型训练与推理部署。资源内提供YOLOv5烟雾火灾检测模型及配套说明,读者可据此完成数据格式转换、模型训练、推理验证与效果评估,快速搭建可复用的烟火检测基线。目前已有840人学习下载,适合需要实战数据集与可运行模型的中高级读者参考。

1. 从一次误报说起:这套烟火检测资源到底能干什么

凌晨两点,某园区的监控室里,值班人员被一阵急促的告警吵醒,屏幕上跳出一团“疑似火焰”的红框,结果跑过去一看,是夕阳反射在玻璃幕墙上的光斑。这种玄学误报,做视觉检测的人几乎都遇到过。真正能落地的烟火检测,拼的不是模型有多深,而是数据够不够“脏”、够不够全。我这次拆的这套资源,核心就是一份 2059 张图像、带标注的火灾烟火烟雾检测数据集,外加一套基于 YOLOv5 的训练与推理代码,还有一份使用说明。它解决的不是“从零发明算法”的问题,而是让一个从业者能在半天内把训练环境跑通、把模型训出来、把推理脚本接到自己的视频流上。适合谁?做安防监控、园区消防、工业巡检的算法工程师,以及想拿一个完整视觉项目练手的学生。你不需要自己爬几千张图、一张张画框,这套东西把最耗时的数据准备环节直接跳过了。

2. 数据集拆解:2059 张图里到底有什么门道

2.1 类别定义与标注格式

这套数据集最值得先看的是它的类别划分。从使用说明和标注文件来看,它把目标分成了三类:火焰(fire)、烟雾(smoke)、以及部分场景下的“疑似烟火”区域。标注格式是 YOLO 系列通用的 txt 文件,每张图对应一个同名 txt,每行五个值:类别索引、归一化中心点 x、归一化中心点 y、归一化宽度、归一化高度。这种格式的好处是直接能被 YOLOv5 的 dataloader 读取,不需要再做 VOC 到 YOLO 的转换。但要注意,归一化坐标是相对于原图宽高的,如果你在训练前做了 resize 或 padding,必须保证标注同步变换,否则框会漂移。我一般会先写个脚本统计一下每类的框数量和分布,看看有没有某一类特别少。

import os from collections import Counter label_dir = "datasets/labels/train" counter = Counter() for txt in os.listdir(label_dir): if not txt.endswith(".txt"): continue with open(os.path.join(label_dir, txt), "r") as f: for line in f: cls = int(line.strip().split()[0]) counter[cls] += 1 print("类别分布:", counter) # 输出示例:Counter({0: 3120, 1: 2870, 2: 410})

这段代码遍历训练集标签目录,统计每个类别出现的次数。参数label_dir要换成你实际解压后的路径。如果发现某一类只有几百个框,而另一类有几千个,训练时就要考虑用--weights做类别加权,或者在数据增强里对少样本类做过采样。常见做法是先把类别分布打出来,再决定要不要动hyp里的cls参数。

2.2 图像分辨率与场景覆盖

2059 张图不是随便凑数的。从文件名和部分预览图看,它覆盖了室内明火、室外烟雾、夜间火光、远距离小目标等场景。分辨率不统一,有 640×480 的,也有 1920×1080 的。YOLOv5 默认会把输入统一 resize 到 640×640,但如果你直接 resize,长宽比会变,小目标烟雾可能被压得更小。我一般会先用--img-size 640跑一版,再对比--img-size 960的效果。注意,img-size 必须是 32 的倍数,否则 YOLOv5 的 backbone 下采样会报错。另外,夜间火光和白天烟雾的对比度差异很大,如果训练集里夜间样本偏少,模型在夜间的召回率会明显掉。建议在划分训练集和验证集时,手动检查一下夜间样本是否被均匀分到两边。

2.3 标签质量与清洗建议

带标签的数据集最怕的是漏标和错标。我抽了 50 张图做人工核对,发现大部分框是准的,但有少数烟雾区域只框了浓烟部分,边缘的薄烟没框进去。这种“部分标注”会让模型学到“只有浓烟才是烟雾”的偏见。处理办法有两个:一是把薄烟区域补框,二是把这类图从训练集里剔除。我一般会先跑一遍推理,把置信度在 0.1 到 0.3 之间的预测框可视化出来,人工看一眼是漏标还是误报。如果是漏标,就补;如果是误报,就保留,让模型学会区分。这个清洗过程大概花半小时,但能明显减少上线后的玄学误报。

3. YOLOv5 训练实战:从环境到权重文件

3.1 环境搭建与依赖版本

YOLOv5 对 PyTorch 和 CUDA 版本比较敏感。我这次用的是 PyTorch 1.12 + CUDA 11.3,在 30 系显卡上跑得比较稳。如果你用 40 系显卡,建议上 PyTorch 2.0 以上,否则可能遇到算力不匹配的报错。安装步骤不复杂,但血泪经验是:不要混用 conda 和 pip 装 torch,容易出现 lib 冲突。我一般会新建一个 conda 环境,然后按官方 requirements.txt 装。

conda create -n fire_detect python=3.8 -y conda activate fire_detect pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt

这里--extra-index-url指定了 PyTorch 的官方轮子源,避免从默认源拉到 CPU 版本。装完后用python -c "import torch; print(torch.cuda.is_available())"验证,返回 True 才算成功。如果返回 False,先检查显卡驱动,再检查 CUDA 版本是否匹配。常见坑是驱动太旧,跑nvidia-smi看右上角的 CUDA Version,必须大于等于你装的 CUDA 运行时版本。

3.2 数据配置文件与训练命令

YOLOv5 需要一个 yaml 文件来描述数据集路径和类别名。我一般会在data目录下新建fire_smoke.yaml,内容如下:

path: ../datasets/fire_smoke # 数据集根目录 train: images/train # 训练集图像相对路径 val: images/val # 验证集图像相对路径 nc: 3 # 类别数 names: ['fire', 'smoke', 'suspicious'] # 类别名,按你的标注索引顺序

注意path可以用相对路径,但建议用绝对路径,避免从不同目录启动训练时找不到文件。nc必须和标注里的最大类别索引加一一致,否则会报 index out of range。训练命令我常用这一套:

python train.py --img 640 --batch 16 --epochs 100 --data data/fire_smoke.yaml --weights yolov5s.pt --cache --project runs/fire

参数说明:--img 640是输入分辨率,--batch 16是批次大小,显存不够就降到 8;--epochs 100对 2000 张图来说够用,但要看验证集 mAP 是否还在涨;--weights yolov5s.pt是预训练权重,用 s 版是因为它快,适合先跑通流程;--cache把图像缓存到内存,加快训练速度,但内存小于 16G 就别开。训练过程中会输出每轮的 box_loss、obj_loss、cls_loss 和 mAP@0.5。如果 obj_loss 一直不降,多半是标注里有空 txt 或者框的宽高为 0。

3.3 训练过程监控与早停策略

YOLOv5 默认每轮跑完验证集,并保存 best.pt 和 last.pt。我一般会盯着runs/fire/exp/results.csv看 mAP@0.5 曲线。如果连续 10 轮 mAP 不涨,就可以停了,再跑下去容易过拟合。早停可以用--patience 10参数,但注意这个 patience 是针对 fitness 指标的,不是直接看 mAP。另外,如果验证集 loss 开始上升而训练集 loss 还在降,说明模型在背训练集,这时候要么加数据增强,要么减模型复杂度。我一般会在hyp.scratch-low.yaml基础上把mosaic调到 0.5,把mixup关掉,因为烟火检测对纹理比较敏感,mixup 容易把火和烟混在一起。

4. 推理与部署:把模型接到视频流上

4.1 单张图像与视频推理

训练完拿到 best.pt 后,先用detect.py跑一张图看看效果:

python detect.py --weights runs/fire/exp/weights/best.pt --source test.jpg --img 640 --conf 0.25 --save-txt

--conf 0.25是置信度阈值,低于这个值的框不显示。烟火检测里,烟雾的置信度通常比火焰低,因为烟雾边缘模糊。如果发现烟雾漏检多,可以把 conf 降到 0.15,但误报会增加。--save-txt会把预测框保存成 YOLO 格式的 txt,方便后续做二次过滤。视频推理把--source换成 mp4 路径就行,但要注意视频帧率,如果原始视频是 25fps,而推理速度只有 10fps,输出视频会变慢。我一般会用--nosave先测速度,再决定要不要抽帧。

4.2 置信度阈值与 NMS 调参

YOLOv5 默认的 NMS IoU 是 0.45,意思是两个框重叠超过 45% 就只保留置信度高的那个。烟火检测里,火焰和烟雾经常挨在一起,如果 IoU 设太低,烟雾框会被火焰框抑制掉。我一般会把--iou-thres调到 0.5 到 0.6 之间,让两者都能保留。另外,如果同一区域出现多个烟雾框,说明模型对烟雾的定位不稳定,这时候可以加一个后处理:对同一类别的框做一次聚类,把中心点距离小于 20 像素的框合并。这个逻辑不复杂,但能明显减少画面上的框数量。

import numpy as np def merge_boxes(boxes, labels, scores, dist_thres=20): # boxes: [x1, y1, x2, y2], labels: 类别索引, scores: 置信度 keep = [] used = np.zeros(len(boxes), dtype=bool) for i in range(len(boxes)): if used[i]: continue cx_i = (boxes[i][0] + boxes[i][2]) / 2 cy_i = (boxes[i][1] + boxes[i][3]) / 2 group = [i] for j in range(i + 1, len(boxes)): if used[j] or labels[j] != labels[i]: continue cx_j = (boxes[j][0] + boxes[j][2]) / 2 cy_j = (boxes[j][1] + boxes[j][3]) / 2 if np.hypot(cx_i - cx_j, cy_i - cy_j) < dist_thres: group.append(j) used[j] = True # 取组内置信度最高的框作为代表 best = max(group, key=lambda k: scores[k]) keep.append(best) used[i] = True return keep

这段代码把中心点距离小于dist_thres的同类框合并,只保留置信度最高的那个。参数dist_thres要根据你的图像分辨率调,640 图上 20 像素大概对应画面里的一小团烟雾。如果调太大,会把相邻但独立的火点合并;调太小,又起不到去重效果。我一般会在验证集上试 15、20、25 三个值,看哪个框数最接近人工标注。

4.3 部署到边缘设备的注意事项

如果要把模型部署到 Jetson 或树莓派上,别直接跑 PyTorch 权重,先转 ONNX 或 TensorRT。YOLOv5 自带export.py,转 ONNX 用--include onnx,转 TensorRT 用--include engine。注意,转 TensorRT 时--img-size要和训练时一致,否则精度会掉。另外,边缘设备的显存小,batch 只能设 1,推理速度大概在 10 到 30fps 之间,取决于模型大小。如果速度不够,可以把yolov5s换成yolov5n,但 mAP 会降几个点。我一般会先在 PC 上测好精度,再在边缘设备上测速度,取一个平衡点。

5. 避坑与排查:那些让我后悔药都来不及吃的瞬间

5.1 现象:训练 loss 正常但 mAP 为 0

原因:标注文件的类别索引和 yaml 里的names顺序不一致。比如标注里 0 是 smoke,1 是 fire,但 yaml 里写反了。模型学到的“fire”其实是 smoke,验证时按名字匹配就全错了。解决:打开一个标注 txt,看第一个数字对应的类别,再和 yaml 里的names列表逐一对齐。我一般会写个脚本统计每个类别索引的框数,再和 yaml 里的名字对照。

5.2 现象:推理时框全挤在图像左上角

原因:标注归一化坐标时用了错误的宽高。比如用 resize 后的尺寸做归一化,但推理时又用原图尺寸。YOLO 格式要求用原图宽高归一化,且 x、y 是中心点坐标。解决:检查标注生成脚本,确保x_center / img_w、y_center / img_h、w / img_w、h / img_h这四个值都在 0 到 1 之间。如果出现大于 1 的值,说明归一化用错了基准。

5.3 现象:烟雾检测召回率极低

原因:训练集里烟雾样本太少,或者烟雾框只标了浓烟部分。模型没见过薄烟和远距离烟雾,自然检不出。解决:先统计烟雾类别的框数,如果少于 1000,考虑用数据增强里的copy-paste把烟雾区域复制到其他图上,或者手动补标一批薄烟。另外,把--img-size从 640 提到 960,小目标烟雾的召回率会明显提升,但速度会降。

5.4 现象:训练到一半显存爆了

原因:--cache把图像缓存到内存,如果数据集图像分辨率高、数量多,内存先爆,然后显存跟着爆。解决:去掉--cache,或者把--batch降到 8。另外,如果用了--img-size 960,显存占用大概是 640 的 2.25 倍,batch 要相应减半。我一般会在训练前用nvidia-smi看显存余量,留 2G 给系统。

5.5 现象:视频推理结果抖动严重

原因:逐帧推理时,模型对同一目标的框位置有微小变化,导致画面上的框跳来跳去。解决:加一个简单的跟踪器,比如用 IoU 匹配前后帧的框,或者用卡尔曼滤波平滑中心点。如果不想加跟踪,可以把连续 3 帧的预测框做平均,再画到画面上。这个后处理不复杂,但能明显提升观感。

6. 进阶技巧:用验证集反推数据短板

训练完不是终点,真正有价值的是从验证结果里看出数据缺什么。我一般会跑一遍val.py,把预测结果和真实标签并排可视化,重点看三类:漏检的、误报的、框不准的。漏检多,说明该类样本少或特征不明显;误报多,说明背景里有类似烟火的干扰物,比如云、灯光、红色物体;框不准,说明标注质量有问题。下面这个表格是我常用的排查对照:

现象可能原因处理动作
火焰漏检多火焰样本少或夜间样本不足补标火焰图,增加夜间增强
烟雾误报多背景有云、雾、蒸汽加入负样本,调高 conf 阈值
框偏大标注时框了过多背景重新收紧标注框
框偏小标注只框了核心区域适当外扩 5 到 10 像素
小目标漏检img-size 太小提到 960 或 1280

另外,我习惯在训练前把验证集单独留出 10% 的夜间样本,不参与训练,只用来测夜间召回率。如果夜间召回率低于 0.6,说明数据集的场景覆盖不够,需要补数据。这个习惯是从一次园区项目里养成的,当时白天 mAP 0.85,晚上直接掉到 0.4,后来补了 300 张夜间图才拉回来。从那以后我每次拿到新数据集,都强制走一遍“分场景验证”的流程,先看夜间、再看远距离、最后看小目标。希望这套资源能帮你少走点弯路,把时间花在调参和业务对接上,而不是从零攒数据。

本文还有配套的精品资源,点击获取

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

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

立即咨询