
简介本资源面向安全监控、火灾预警方向的开发者与深度学习学习者提供一套基于YOLOv5的烟雾检测完整方案包含训练好的模型权重与配套数据集可直接用于实时视频流烟雾识别与预警系统搭建。压缩包共约2000个文件整体360.52MB以3688张jpg烟雾图像、3688个txt标注、3687个xml标注为主另含yaml配置、py脚本、pt权重及Docker部署文件覆盖数据、训练、推理与容器化部署全流程。已有2356人学习下载说明该方案在目标检测实践中具备较高参考价值。读者可借助现成模型快速验证烟雾检测效果结合标注数据理解数据组织方式并参考脚本与配置文件完成微调、迁移学习或集成到监控、无人机巡检等场景减少从零搭建的时间成本。1. 烟雾检测项目落地从数据集到训好的模型一次讲透前阵子有个做安防方向的朋友找我说他们想在园区里加一路烟雾识别不想依赖传统烟感问我有没有能直接跑起来的方案。我翻了一圈最后给他推的就是这个基于 YOLOv5 的烟雾检测项目——它最大的好处是数据集和训好的权重都打包好了不用自己从零标注、从零训练clone 下来改改路径就能出检测结果。这个项目适合两类人一类是想快速验证烟雾检测可行性的开发者另一类是拿它当模板做二次开发的学生或工程师。它本质上是一个目标检测任务把烟雾当成一个类别来框技术栈就是 PyTorch YOLOv5 OpenCV训练和推理流程都是 YOLOv5 官方那套改动量很小。下面我按「能干什么 → 怎么跑 → 怎么改」的顺序把这份资源拆开讲。2. 项目结构与技术选型为什么是 YOLOv5 而不是别的2.1 目录结构长什么样拿到这份资源解压后你会看到一个典型的 YOLOv5 工程目录外加两个关键文件夹datasets/和weights/。我先把整体结构列一下方便你对照自己的解压结果smoke-detection-yolov5/ ├── data/ │ ├── smoke.yaml # 数据集配置文件 │ └── hyps/ # 超参数配置 ├── datasets/ │ ├── images/ │ │ ├── train/ # 训练集图片 │ │ └── val/ # 验证集图片 │ └── labels/ │ ├── train/ # 训练集标签YOLO格式txt │ └── val/ ├── models/ │ ├── yolov5s.yaml # 模型结构定义 │ └── hub/ # 可选hub配置 ├── weights/ │ └── best.pt # 训好的烟雾检测权重 ├── utils/ # 通用工具NMS、绘图、指标 ├── train.py # 训练入口 ├── detect.py # 推理入口 ├── val.py # 验证入口 └── requirements.txt # 依赖清单这个结构不是随便摆的。data/smoke.yaml是数据集的总开关里面写清楚训练集、验证集路径和类别名datasets/下按 YOLO 标准格式组织图片和标签同名不同后缀weights/best.pt是已经训好的权重直接拿来做推理。你如果只想跑通其实只需要关心smoke.yaml、best.pt和detect.py这三个文件。2.2 为什么选 YOLOv5 做烟雾检测烟雾检测这个任务有几个特点目标边界模糊、形态变化大、背景干扰多。传统方法用颜色阈值或者纹理特征稍微换个光照就翻车。YOLOv5 作为单阶段检测器在速度和精度之间平衡得比较好而且它的 anchor 机制对不规则形状的目标容忍度更高。更关键的是YOLOv5 的工程化做得好数据加载、增强、训练、推理、导出全链路都有现成脚本你不需要自己写 DataLoader 和 NMS。常见做法是选 YOLOv5s 作为基线因为烟雾检测通常部署在边缘设备上s 版本参数量小、推理快。如果你对精度要求更高可以换成 YOLOv5m 或 l但推理速度会下降。这个项目默认用的是 s 版本权重文件大概十几兆在普通显卡上跑实时检测没问题。2.3 数据集的组织方式数据集是这份资源的核心价值之一。烟雾检测的公开数据不多自己标注又费时所以拿到一份整理好的数据集能省很多事。YOLO 格式的标签是每行一个目标格式为class_id x_center y_center width height坐标都归一化到 0~1 之间。我建议你先打开datasets/labels/train/下的一个 txt 看看确认类别 id 和smoke.yaml里的names对得上。smoke.yaml的内容一般长这样# data/smoke.yaml train: ../datasets/images/train val: ../datasets/images/val nc: 1 names: [smoke]这里nc是类别数烟雾检测通常就一类所以是 1。names里写类别名顺序要和标签里的 class_id 一致。如果你后面要加别的类别比如同时检测火焰就把nc改成 2names里加一个fire然后重新训练。注意路径写的是相对路径实际运行时是相对于train.py所在目录解析的。如果你把数据集挪到别的地方记得同步改这里否则会报「No labels found」之类的错。3. 环境搭建与推理跑通先看到框再谈训练3.1 依赖安装与版本选择YOLOv5 对 PyTorch 版本有一定要求太新或太旧都可能出问题。我一般会先建一个干净的 conda 环境然后按requirements.txt装。常见做法是# 创建环境Python 用 3.8 或 3.9 比较稳 conda create -n smoke python3.9 -y conda activate smoke # 安装 PyTorch根据你的 CUDA 版本选对应命令 # 这里以 CUDA 11.3 为例 pip install torch1.12.1cu113 torchvision0.13.1cu113 \ --extra-index-url https://download.pytorch.org/whl/cu113 # 安装项目依赖 pip install -r requirements.txt如果你没有 GPU把 torch 换成 CPU 版本也能跑推理只是慢一些。requirements.txt里通常包含opencv-python、numpy、tqdm、matplotlib、pyyaml这些都是推理和训练的基础库。提示装完 torch 后进 Python 执行import torch; print(torch.cuda.is_available())返回 True 才说明 GPU 可用。如果返回 False先检查 CUDA 和驱动版本别急着往下跑。3.2 用训好的权重做推理推理是最快能看到效果的一步。项目里已经给了weights/best.pt你只需要准备一张带烟雾的图片或者一段视频然后执行# 对单张图片推理 python detect.py \ --weights weights/best.pt \ --source datasets/images/val/ \ --img-size 640 \ --conf-thres 0.25 \ --project runs/detect \ --name smoke_test参数说明一下--weights指定权重路径--source可以是单张图、文件夹、视频文件甚至摄像头编号比如0表示默认摄像头--img-size是推理分辨率640 是 YOLOv5 的默认值--conf-thres是置信度阈值低于这个值的框会被过滤掉--project和--name决定结果保存位置跑完会在runs/detect/smoke_test/下看到带框的图片。跑完之后打开输出目录你应该能看到烟雾区域被框出来框上方有类别名和置信度。如果一张框都没有先别怀疑模型把--conf-thres降到 0.1 试试或者换一张烟雾更明显的图。3.3 推理代码里发生了什么detect.py的主流程其实不复杂我把它拆成几个关键步骤# detect.py 核心流程简化版 import torch from models.experimental import attempt_load from utils.datasets import LoadImages from utils.general import non_max_suppression, scale_coords # 1. 加载模型 device torch.device(cuda if torch.cuda.is_available() else cpu) model attempt_load(weights/best.pt, map_locationdevice) model.eval() # 2. 加载图片 dataset LoadImages(datasets/images/val/, img_size640) # 3. 逐张推理 for path, img, im0s, vid_cap in dataset: img torch.from_numpy(img).to(device).float() / 255.0 img img.unsqueeze(0) # 增加 batch 维度 # 前向传播 pred model(img)[0] # NMS 去重 pred non_max_suppression(pred, conf_thres0.25, iou_thres0.45) # 坐标还原到原图尺寸 for det in pred: if det is not None and len(det): det[:, :4] scale_coords(img.shape[2:], det[:, :4], im0s.shape).round() # 绘图并保存...这里有几个点值得注意attempt_load会同时加载模型结构和权重non_max_suppression负责把重叠的框去掉iou_thres控制去重力度scale_coords把 640 分辨率下的框映射回原图尺寸否则你看到的框位置会偏。如果你要改推理逻辑比如只保留置信度最高的一个框就在 NMS 之后加一层筛选。4. 训练自己的数据从 smoke.yaml 到 best.pt4.1 训练命令与参数解读如果你手头有新的烟雾数据或者想微调模型训练流程也是现成的。假设你已经把图片和标签按前面的结构放好了执行python train.py \ --data data/smoke.yaml \ --cfg models/yolov5s.yaml \ --weights weights/best.pt \ --epochs 100 \ --batch-size 16 \ --img-size 640 \ --project runs/train \ --name smoke_finetune--data指向数据集配置--cfg是模型结构如果你想换更大的模型就改这里--weights可以填预训练权重也可以填从零开始--epochs是训练轮数微调一般 50~100 够用--batch-size根据显存调整16 是 8G 显存比较稳的值--img-size要和推理时保持一致。训练过程中终端会打印每一轮的 loss、precision、recall、mAP 等指标。重点关注mAP0.5它反映模型在 IoU 阈值 0.5 下的平均精度。如果训练几轮后 mAP 一直不涨可能是学习率太大或者数据有问题。4.2 数据增强与超参数YOLOv5 默认开启了 Mosaic、HSV 增强、随机翻转等。烟雾检测里HSV 增强对光照变化很有帮助Mosaic 能提升小目标检测能力。这些配置在data/hyps/hyp.scratch-low.yaml里你可以按需调整。比如烟雾颜色偏灰白可以把hsv_v调大一点让模型对亮度变化更鲁棒。常见做法是先用默认超参跑一遍看指标曲线再针对性调。如果验证集 loss 比训练集高很多说明过拟合了可以加大weight_decay或者减少模型复杂度。4.3 训练结果怎么看训练结束后runs/train/smoke_finetune/下会有weights/best.pt和weights/last.pt还有results.csv和混淆矩阵图。best.pt是验证集上表现最好的权重通常拿它做推理。results.csv里记录了每轮的指标你可以用 pandas 画个曲线看看收敛情况。如果 mAP 在 0.6 以上对于烟雾检测来说已经能用了。要是低于 0.4先检查标签有没有标错再看数据集是不是太少。烟雾检测的标注一致性很重要不同人标的框松紧不一样模型会学懵。5. 避坑与常见问题那些我踩过的雷5.1 报错「No labels found」怎么办现象训练一开始就报这个错然后退出。原因通常是smoke.yaml里的路径不对或者标签文件夹名字不是labels。YOLOv5 要求图片和标签目录结构对称比如images/train对应labels/train。解决方法是检查路径确保标签文件和图片文件同名只是后缀从.jpg变成.txt。5.2 推理结果框位置偏移现象框画出来了但位置明显不对偏上或偏左。原因多半是scale_coords用的原图尺寸不对或者图片在加载时被 resize 过但没记录原始尺寸。解决方法是确认LoadImages返回的im0s是原始图像不要在里面做额外裁剪。如果自己改了数据加载逻辑记得同步改坐标还原。5.3 显存不够导致训练中断现象训练到一半报 CUDA out of memory。原因是batch-size太大或者img-size太高。解决方法是把--batch-size降到 8 或 4或者把--img-size降到 416。YOLOv5 支持梯度累积你可以用小 batch 配合--accumulate来模拟大 batch。5.4 模型把白云当成烟雾现象推理时天空的白云被框成 smoke。原因是训练集里缺少负样本模型没学会区分白色不规则物体和烟雾。解决方法是在数据集里加一些不含烟雾但含白云的图片标签为空文件让模型学习背景。或者提高--conf-thres把低置信度的误检过滤掉。5.5 训练 loss 不下降现象loss 一直震荡或者不降。原因可能是学习率太大、数据标签有问题、或者预训练权重和模型结构不匹配。解决方法是先用小学习率跑几轮确认 loss 有下降趋势再检查标签格式确保没有越界坐标最后确认--weights和--cfg是配套的别拿 yolov5m 的权重去加载 yolov5s 的结构。6. 二次开发与改造思路把烟雾检测嵌进你的系统6.1 导出 ONNX 做跨平台部署如果你要把模型部署到 C 或者边缘设备上PyTorch 权重不够方便常见做法是导出 ONNXpython export.py \ --weights weights/best.pt \ --include onnx \ --img-size 640 \ --batch-size 1导出后会生成best.onnx你可以用 ONNX Runtime 或者 TensorRT 加载。注意导出时的img-size要和推理时一致否则输入维度对不上。ONNX 模型不包含 NMS需要自己在后处理里实现或者用 ONNX Runtime 的扩展算子。6.2 改成视频流实时检测detect.py默认支持视频和摄像头把--source改成0就是调用本地摄像头。但如果你想嵌入自己的视频处理管线可以把推理部分抽成一个函数def detect_frame(model, frame, conf_thres0.25, iou_thres0.45): 输入一帧 BGR 图像返回带框的图像和检测结果 img letterbox(frame, 640, stride32)[0] img img[:, :, ::-1].transpose(2, 0, 1) # BGR - RGB img np.ascontiguousarray(img) img torch.from_numpy(img).float() / 255.0 img img.unsqueeze(0) pred model(img)[0] pred non_max_suppression(pred, conf_thres, iou_thres) results [] for det in pred: if det is not None and len(det): det[:, :4] scale_coords(img.shape[2:], det[:, :4], frame.shape).round() for *xyxy, conf, cls in det: results.append((xyxy, conf.item(), int(cls))) # 画框... return frame, results这样你就可以在自己的循环里逐帧调用配合多线程或异步推理提升吞吐。注意letterbox的填充要和训练时一致否则精度会掉。6.3 增加类别或替换骨干网络如果你想同时检测烟雾和火焰改smoke.yaml的nc和names然后重新训练。标签里火焰的 class_id 设为 1。如果想换更轻量的骨干可以把models/yolov5s.yaml里的backbone换成 MobileNet 或 ShuffleNet但需要自己写适配层改动量较大。我一般建议先在 s 版本上调通再考虑换骨干。6.4 一个我常犯的错早期我改完smoke.yaml直接跑训练忘了把--weights换成结果模型加载了旧权重的类别数训练时直接报维度不匹配。从那以后我每次改类别数都强制走一遍「检查 yaml → 确认权重 → 小批量试跑」的流程确认没问题再开完整训练。希望这个习惯能帮到你少走点弯路。本文还有配套的精品资源点击获取