简介:面向目标检测与YOLOv5算法学习者,提供一套可直接用于训练的烟雾检测数据集及标注文件。压缩包大小约110.38MB,共2000个文件,以1864张JPG图像和对应的1864个TXT标签为主体,同时包含YOLO格式的yaml配置与缓存文件,每个txt文件内含类别编号与归一化边界框坐标,数据划分清晰,标注格式可直接接入YOLOv5训练流程,无需额外转换,整体标注质量可靠。资源特别适用于计算机、电子信息、数学等专业学生的课程设计、期末大作业或毕业设计,也适合刚接触YOLO系列的开发者作为入门参考。包内文件组织规范,图像与标签一一对应,配有参数可调的工程代码思路,能帮助使用者省去手动标注环节,专注模型调试与效果优化。目前已有237人学习下载,兼具实用性与参考价值。
1. 拿到YOLOv5烟雾数据集后,先想清楚这几件事
烟雾检测在工业消防、森林防火、工厂安监这些场景里的需求一直很硬,但真正动手做的时候,大部分人卡住的不是模型,而是数据。YOLOv5本身已经是非常成熟的目标检测框架,训练流程网上一抓一大把,真正稀缺的是带标注的烟雾数据。所以当看到“1500张图像+已标注文件”这种资源时,第一反应应该是:这能不能直接用来跑训练?答案是可以,但前提是你得先搞清楚三件事——标注文件是什么格式、能不能被YOLOv5直接读取、训练出来的模型在你的场景下有多少可信度。这篇文章就围绕这三个问题展开,从数据集的组织结构、标注文件的解析方法、训练流程的完整复现,到雾场景下的调参技巧和模型导出,一步步讲清楚怎么做,以及每一步有哪些坑。
2. 数据集的结构和标注文件格式,动手前必须搞清楚的事
2.1 解压后看到的目录结构,先认清YOLOv5的底线
常见的烟雾检测数据集在解压后会有images和labels两个目录,images下面存放的是JPG或PNG格式的图像,labels下面存放的是同名的txt文件。YOLOv5训练时要求每张图像对应的标注文件必须和图像同名,扩展名不同,比如smoke_001.jpg对应smoke_001.txt。如果你拿到的压缩包是这种结构,那基本可以直接用。如果不是,比如标注文件是XML或者JSON格式,就需要先做一次格式转换。
看一下典型结构:
smoke_dataset/ ├── images/ │ ├── smoke_001.jpg │ ├── smoke_002.jpg │ └── ... ├── labels/ │ ├── smoke_001.txt │ ├── smoke_002.txt │ └── ...YOLOv5的label.txt格式是每一行一个目标对象,共5个数值:class_id center_x center_y width height。注意这四个坐标值都是归一化到0~1之间的比例值,center_x和center_y是目标中心点相对图像宽高的比例,width和height是目标框相对图像宽高的比例。这里最容易出问题的是坐标标准化,有些数据集从LabelImg生成的XML转过来后,忘记除以图像宽高,训练时会出现大量警告,mAP直接崩到0.2以下。拿到数据集后,建议先随机抽几个样本,写一小段脚本验证坐标值是否都在0~1范围内。
2.2 用两行Python代码快速校验标注文件
在开始训练之前,批量解析几个标注文件能帮你提前排除九成的问题。常见做法是读取标注文件的内容,检查数值范围和目标数量:
import os label_dir = "smoke_dataset/labels" invalid_files = [] counts = [] for fname in os.listdir(label_dir): if not fname.endswith(".txt"): continue with open(os.path.join(label_dir, fname), "r") as f: lines = [line.strip() for line in f.readlines() if line.strip()] for line in lines: parts = line.split() if len(parts) != 5: invalid_files.append(fname) continue vals = list(map(float, parts[1:])) if any(v < 0 or v > 1 for v in vals): invalid_files.append(fname) counts.append(len(lines)) print("异常文件数:", len(set(invalid_files))) print("平均每张图目标数:", sum(counts) / len(counts))这段代码做了两件关键的事:检查每个标注行是否恰好5个字段,以及所有坐标是否在0~1的标准化区间内。如果异常文件过多,说明数据集的标注格式需要清洗。还有一个需要注意的点是类别ID。YOLOv5的类别ID从0开始计数,如果你的数据集中还有其他类别,比如smoke是第5类,对应的ID就是4。训练前要确认data.yaml中的类别顺序和标注文件里的数字能对上。
提示:如果压缩包内的标注文件是XML格式,我一般会直接用ultralytics仓库里的
xml_to_yolo.py脚本做转换,然后手动抽查几个文件,不要盲目相信自动转换的结果。
2.3 可视化检查标注效果,比看数值更直观
数值校验没问题之后,还有一个必要步骤是把标注框画回图像上看一眼。这一步能帮你发现标注偏移、漏标、错标等问题。用OpenCV写一个简单的可视化脚本:
import cv2 import os img_dir = "smoke_dataset/images" label_dir = "smoke_dataset/labels" sample_names = ["smoke_001", "smoke_002", "smoke_003"] for name in sample_names: img_path = os.path.join(img_dir, name + ".jpg") label_path = os.path.join(label_dir, name + ".txt") img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path, "r") as f: for line in f: cls_id, cx, cy, bw, bh = map(float, line.split()) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, f"smoke_{int(cls_id)}", (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imshow(name, cv2.resize(img, (800, 600))) cv2.waitKey(0) cv2.destroyAllWindows()在可视化检查时,重点关注三类问题:一类是标注框明显大于或小于烟雾实际边缘的;一类是同一片烟雾被切成多个框的;还有一类是远处的烟雾完全漏标的。前两类在后续训练中还可以靠调整loss权重来缓解,漏标的样本则可能在训练时被当作背景,产生假正样本。这步检查做完了,数据集本身的质量心里就有底了。
3. 用YOLOv5在本地跑通烟雾检测训练的最小命令集
3.1 环境配置和项目准备
要把数据集跑起来,先得有YOLOv5的基础环境。常见做法是拉取ultralytics官方仓库并安装依赖,然后在数据集同级目录下操作。建议在虚拟环境中执行:
git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt python -c "import torch; print(torch.__version__, torch.cuda.is_available())"如果这条命令能正常打印出CUDA可用的信息,说明环境没问题。接下来把数据集放到datasets/目录下:
mkdir datasets cp -r ../smoke_dataset datasets/然后把数据集目录调整为YOLOv5期望的结构。如果解压的时候原始结构不是train和val分开的,需要先划分一下。这里有一个常规做法:用train_test_split或直接按索引分,保证验证集的比例在20%左右。划分时可以手动写一个小脚本,把images和labels文件按比例移动到train和val目录中。
3.2 创建data.yaml并修改模型配置
YOLOv5训练的核心配置是一个YAML文件,它告诉训练脚本三样东西:训练集路径、验证集路径、类别名。在yolov5/data/下新建smoke.yaml:
train: ../datasets/smoke_dataset/images/train val: ../datasets/smoke_dataset/images/val nc: 1 names: ['smoke']这段配置的含义很直白。train和val指向的是图像目录,YOLOv5会沿路径自动寻找同名的txt文件。如果你的压实包里有单独的train和val划分,那就直接用现成的路径填进去。nc表示类别数量,这里是单类别检测,填1。names列表里的顺序决定了训练时类别ID的映射关系,必须与标注文件中的数字一一对应。
如果是单类别的烟雾检测,一般不需要改动模型结构。直接用yolov5s.yaml,它的网络深度和宽度居中,在速度和精度之间取得了一个平衡点。如果是边缘设备部署,可以考虑yolov5n.yaml,但训练时间差不多的前提下,先从s开始跑。
3.3 启动训练并理解输出日志
训练命令长这样:
python train.py --data data/smoke.yaml --weights yolov5s.pt --img 640 --epochs 100 --batch-size 16 --name smoke_run参数不复杂但也别写错。--weights yolov5s.pt表示加载官方在COCO上的预训练权重,用迁移学习的方式微调。--img 640是输入分辨率,烟雾在图像中的尺寸如果比较小,可以试试896或1024。--batch-size取决于显存大小,16G显存跑16基本没问题。--name是本次实验的标识,产物会保存在runs/train/smoke_run/。
训练过程中终端会持续输出日志,重点关注三列:box_loss、obj_loss、mAP@0.5。box_loss是回归框的loss,逐渐下降说明定位在变好;mAP@0.5从0.2涨到0.7以上才算正常。如果loss降不下来,大概率是标注质量有问题或学习率偏大。
3.4 用验证集评估模型性能
训练结束后,用val.py对模型做一次完整评估:
python val.py --data data/smoke.yaml --weights runs/train/smoke_run/weights/best.pt --img 640输出中会有一列Precision和Recall,分别表示精确率和召回率。烟雾检测场景里,我通常看重Recall多于Precision,因为在森林防火这种安全场景中,漏报的代价远高于误报。如果Recall低,问题可能出在数据分布上——比如训练集里远处的稀疏烟雾太少。评估结果还会生成一个confusion_matrix.png,可以直观地看到哪些类别互相混淆。
4. 烟雾检测特有难点与超参数调整
烟雾和普通目标不一样,它没有清晰的边缘,形态高度变化,颜色从白到灰黑都有,而且经常是半透明的。直接套用YOLOv5默认的COCO训练参数,效果一般不会太好。需要针对烟雾的特性做几处重点调整。
4.1 数据增强参数要不要关,取决于你的烟雾形态
YOLOv5的默认数据增强里有一些对烟雾来说不太友好的策略。比如hsv_h和hsv_s会把色相和饱和度做随机扰动,虽然能增强模型的颜色鲁棒性,但烟雾本身颜色范围已经很大,再做扰动容易让模型学偏。另外,flipud(上下翻转)在森林防火场景里没有物理意义,火焰不会出现在天空中,可以关掉。
修改data/hyps/hyp.scratch-low.yaml中的相关字段:
hsv_h: 0.01 hsv_s: 0.2 hsv_v: 0.2 flipud: 0.0 mosaic: 1.0 mixup: 0.2有人会问mosaic要不要关。新增训练中mosaic能显著增强模型的鲁棒性,但最后十几轮建议关掉mosaic,因为拼接图片和真实场景差异较大,会影响最终收敛精度。常见做法是把mosaic设为一个调度参数,在最后10个epoch设置为0。YOLOv5中可以通过设置--mosaic 0在训练中后期关闭。
4.2 锚框尺寸对烟雾检测的影响
YOLOv5默认的anchor是在COCO数据集上聚类得到的,适配的是大尺寸目标。烟雾检测中小目标占比往往很高,尤其是森林场景中远处的小片烟雾。训练时不需要手动重新聚类anchor,YOLOv5在训练开始时会自动用k-means重新计算anchor,但有一个开关:--noautoanchor。如果不想让模型自动聚类,就保持默认让自动anchor开启,一般效果比手动指定的好。
如果训练时发现autoanchor的报告中显示最好的k-means结果和默认anchor差距大,可以手动指定一个改动后的anchor。但大多数人不太需要走到这一步。
4.3 小目标烟雾的处理策略
小目标检测是烟雾检测里绕不开的另一个痛点。YOLOv5在70x70的特征图上检测小目标,但对于远距离烟雾来说仍然不够。常用技巧是--img 1024,把输入分辨率提高。分辨率提高之后训练显存占用会显著上升,batch-size需要相应减小。另一个技巧是使用--multi-scale参数,让输入分辨率在训练过程中动态变化,增强模型对不同尺度目标的适应性。
python train.py --data data/smoke.yaml --weights yolov5s.pt --img 896 --batch-size 8 --epochs 150 --multi-scale提示:小目标很多的场景不要盲目堆数据集数量。要看小目标样本量的分布比例,如果远距离烟样本太少,模型只能学到中近景的烟雾特征,部署到远距离摄像头后mAP会跌得很难看。
4.4 误检问题的处理思路
烟雾检测的误检来源很典型:白色的建筑、雾、云甚至玻璃反光都可能被误报为烟雾。调阈值是最直接的方法,--conf-thres增加到0.4或0.5可以过滤掉低置信度的检测框,但会牺牲召回率。另一个有效的方向是收集误报样本,把它们加入训练集并标注为额外负样本,这种方式代价低效果好,被很多实际项目采用。
5. 模型导出与摄像头实时烟雾检测的落地操作
5.1 导出为TorchScript或ONNX格式
训练好的模型最终要部署到实际环境,常见做法是导出为TorchScript或OpenVINO格式。导出命令很简单:
python export.py --weights runs/train/smoke_run/weights/best.pt --include torchscript onnxTorchScript格式适合在Jetson Nano这类嵌入式设备上运行,ONNX格式适合跨平台部署。导出后可以用下面这段代码验证导出结果是否能正常推理:
import torch model = torch.jit.load("best.torchscript") img = torch.rand(1, 3, 640, 640) pred = model(img) print(pred[0].shape)能正常输出[1, 25200, 6]之类的形状说明导出成功。注意导出时输入的尺寸要和训练时的尺寸保持一致,否则检测结果的位置信息会偏移。
5.2 用摄像头做实时烟雾检测的最小脚本
实际部署中最常见的需求是把模型跑在实时视频流上。下面的脚本把摄像头帧逐帧送入模型进行检测,并只保留置信度高于0.35的结果:
import cv2 import torch model = torch.hub.load("ultralytics/yolov5", "custom", path="best.pt", force_reload=True) model.conf = 0.35 model.iou = 0.5 cap = cv2.VideoCapture(0) while cap.isOpened(): ret, frame = cap.read() if not ret: break results = model(frame) rendered = results.render()[0] cv2.imshow("smoke_detection", rendered) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()这段代码里model.conf控制置信度阈值,model.iou控制NMS的IoU阈值。如果你的检测场景中烟雾重叠度很高,IoU阈值可以稍微调高至0.6。实时推理时如果帧率不达标,优先考虑降低输入分辨率或换轻量化模型。
5.3 增量数据和模型迭代的节奏
拿到一个1500张的数据集只能算起点。一套完整的迭代节奏是:先用现有数据训练一个baseline,部署到实际场景收集误报和漏报样本,每周或每两周手动标注一批增量数据并入训练集,然后重新训练并替换旧模型。这个闭环跑起来之后,模型的精度会稳步提升。收集增量数据时要注意去重,每隔几帧保存一张画面,避免大量相似帧导致过拟合。标注增量数据时沿用已有的标注规范,保持边框画法和类别定义一致。
本文还有配套的精品资源,点击获取