抽烟检测数据集实战:从YOLO标注到训练全流程拆解

发布时间:2026/10/20 7:23:35
抽烟检测数据集实战:从YOLO标注到训练全流程拆解 简介这份抽烟检测数据集面向从事深度学习与计算机视觉的开发者、算法工程师及高校学生适用于目标检测模型的训练、微调与验证可支撑公共场所吸烟行为识别、安防监控等场景。资源包共约2000个文件以4650张jpg图像、3235个xml标注文件为主另含少量txt划分列表、Python脚本与说明文档压缩包约298MB。其中JPEGImages目录收录3000余张抽烟场景图片Annotations目录提供对应的labelImg标注xml可直接用于VOC格式目标检测训练并附有voc2yolo4.py等脚本便于格式转换与数据划分。目前已有7530人学习下载适合需要快速搭建抽烟检测基线、验证模型效果或进行数据增强实验的读者参考使用。1. 抽烟检测数据集从标注到训练一份能直接跑通的资源拆解做视觉检测项目的朋友多半有过这种经历模型结构调了半天loss 曲线看着也还行一到实际场景就翻车回头一查问题根本不在网络而在数据。抽烟检测这个方向尤其典型——目标小、遮挡多、姿态杂还夹着手部与嘴部的重叠区域标注质量差一点mAP 直接掉一截。这次拆的这份抽烟检测数据集包含标注文件和对应图片属于那种拿到手就能直接进训练流程的资源。它适合两类人一类是想快速验证检测方案、不想从零爬数据标数据的算法工程师另一类是拿它做课程设计或原型 Demo 的学生和开发者。下面按「这是什么 → 怎么用 → 坑在哪」的顺序把这份资源从头到尾过一遍。2. 数据集结构与标注格式先看清手里有什么2.1 目录组织与文件构成拿到一份检测数据集第一件事不是急着写训练脚本而是把目录结构摸清楚。常见的组织方式有两种一种是图片和标注分开放images/放图labels/放同名 txt另一种是图片和标注混在同一目录靠扩展名区分。这份资源属于前者结构大致如下smoke_dataset/ ├── images/ │ ├── 000001.jpg │ ├── 000002.jpg │ └── ... ├── labels/ │ ├── 000001.txt │ ├── 000002.txt │ └── ... └── classes.txtclasses.txt里通常只有一行smoke或者smoking代表单类别。如果你的任务需要区分「正在抽」和「手持烟」两种状态那这份单类别标注就不够用得自己补标。这一点在选型阶段就要想清楚别等训练完了才发现类别定义和业务对不上。图片格式以 jpg 为主分辨率不统一是常态有的来自监控截图有的来自手机拍摄长宽比差异大。标注文件是 YOLO 格式的 txt每行五个值class_id x_center y_center width height后四个都是归一化到 0~1 的相对坐标。这个格式的好处是跟图片分辨率解耦换尺寸不用重标。2.2 YOLO 标注格式的字段含义把一行标注拆开看0 0.512 0.634 0.087 0.156第一个0是类别索引对应classes.txt里的第 0 类0.512是目标框中心点的 x 坐标除以图片宽度得到0.634是中心点 y 坐标除以图片高度0.087是框宽除以图片宽度0.156是框高除以图片高度。这里有个容易忽略的点归一化用的是各自轴向的尺寸x 和宽除以图宽y 和高除以图高。如果标注工具导出时搞混了框会整体偏移训练时表现为 loss 降不下去或者框乱飞。验证方法很简单写个脚本把标注框画回原图肉眼扫一遍就知道对不对。import cv2 import os img_path smoke_dataset/images/000001.jpg label_path smoke_dataset/labels/000001.txt img cv2.imread(img_path) h, w img.shape[:2] with open(label_path) as f: for line in f: cls, xc, yc, bw, bh map(float, line.split()) # 反归一化还原到像素坐标 x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check_000001.jpg, img)这段脚本的作用是把归一化坐标还原成像素坐标并画框。xc - bw/2是左上角 xxc bw/2是右下角 xy 方向同理。跑完打开check_000001.jpg框应该正好套在抽烟的手部或嘴部区域。如果框偏到画面外或者缩成一点基本可以判定标注有问题。2.3 数据清洗三行脚本筛掉脏样本真实数据集里总有几张图是坏的——文件损坏、尺寸为 0、标注为空。这些样本混进去训练时要么报错中断要么让模型学到噪声。我一般会在训练前跑一遍清洗import os from PIL import Image img_dir smoke_dataset/images lbl_dir smoke_dataset/labels bad [] for name in os.listdir(img_dir): img_path os.path.join(img_dir, name) lbl_path os.path.join(lbl_dir, name.replace(.jpg, .txt)) try: img Image.open(img_path) img.verify() # 校验图片完整性 except Exception: bad.append(name) continue if not os.path.exists(lbl_path) or os.path.getsize(lbl_path) 0: bad.append(name) # 标注缺失或为空 print(问题样本, bad)img.verify()会检查文件头是否完整损坏的图会抛异常。标注为空的情况在抽烟检测里不少见有些图里其实没人抽烟标了反而误导模型这种直接剔除或者归到负样本集。清洗完记得把bad列表里的文件从 images 和 labels 里同步删掉别只删一边。3. 从标注到训练YOLO 训练配置与参数调优3.1 数据集配置文件怎么写YOLO 系列训练前需要一个 yaml 描述文件告诉框架去哪找图、有几类、类名是什么。以常见的 YOLOv5/v8 结构为例# smoke.yaml path: ./smoke_dataset train: images/train val: images/val nc: 1 names: [smoke]path是数据集根目录train和val是相对路径。这里有个前提你得先把数据按比例切成 train 和 val 两个子集。切分脚本不复杂但要注意别让同一段视频的连续帧同时进训练和验证否则验证指标虚高实际部署就翻车。import os import random import shutil random.seed(42) img_dir smoke_dataset/images names [n for n in os.listdir(img_dir) if n.endswith(.jpg)] random.shuffle(names) split int(len(names) * 0.8) for subset, files in [(train, names[:split]), (val, names[split:])]: os.makedirs(fsmoke_dataset/images/{subset}, exist_okTrue) os.makedirs(fsmoke_dataset/labels/{subset}, exist_okTrue) for n in files: shutil.move(os.path.join(img_dir, n), fsmoke_dataset/images/{subset}/{n}) shutil.move(os.path.join(smoke_dataset/labels, n.replace(.jpg, .txt)), fsmoke_dataset/labels/{subset}/{n.replace(.jpg, .txt)})random.seed(42)保证每次切分结果一致方便复现。8:2 是常见比例数据量少的时候可以调到 9:1但验证集别少于几十张否则指标波动大得没法看。3.2 训练命令与关键参数配置写好就能起训。以 YOLOv8 为例yolo detect train \ datasmoke.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/smoke逐个说参数。modelyolov8n.pt用的是 nano 版本参数量小、推理快适合先跑通流程如果精度不够再换 s 或 m。imgsz640是输入尺寸抽烟目标通常偏小640 是底线再低小目标就糊了。batch16看显存8G 显存跑 640 大概能到 16不够就往下调。lr00.01是初始学习率YOLO 默认值一般够用数据量特别小的时候可以降到 0.001 防止过拟合。patience20是早停20 轮验证指标不涨就停省时间。训练过程中重点盯两个指标mAP0.5和mAP0.5:0.95。前者宽松后者严格。抽烟检测里如果 mAP0.5 能到 0.8 以上基本可用mAP0.5:0.95 通常低不少0.5 左右算正常。如果两者差距特别大说明框的位置不够准可能是标注框偏大或偏小。3.3 小目标检测的增强策略抽烟检测的难点在于目标小。手部夹烟这个区域在 640 的图里可能就几十个像素。默认增强策略对小目标不够友好可以针对性调几个参数# 在训练配置里覆盖增强参数 mosaic: 1.0 # 马赛克增强四图拼接提升小目标占比 scale: 0.5 # 随机缩放幅度 copy_paste: 0.1 # 复制粘贴增强把目标贴到其他图上mosaic是 YOLO 的招牌增强把四张图拼成一张小目标相对变大效果明显。但注意训练末期最好关掉 mosaic让模型在真实分布上收敛很多框架有close_mosaic参数控制最后几轮关闭。copy_paste对稀有类别有用但抽烟检测如果正样本够多开太高反而引入不自然的拼接痕迹。提示增强参数不是越多越好。数据量本来就少的时候过度增强会让模型学不到真实特征表现为训练集指标高、验证集指标低。4. 避坑与排查标注和训练里最容易翻车的几件事4.1 类别索引对不上模型全预测成背景现象训练 loss 一直很高推理时一个框都不出。原因classes.txt里类别顺序和标注文件里的 class_id 不一致。比如标注里抽烟是 0但配置文件 names 写成了[background, smoke]模型学的是 1 类推理时阈值一卡就全滤掉了。解决打开classes.txt和 yaml 里的names逐行比对确保索引和名称一一对应。单类别的话names 里只写[smoke]不要加 backgroundYOLO 会自动处理背景。4.2 标注框归一化用错基准框整体偏移现象画框验证时框的位置系统性偏左或偏上。原因标注工具导出时把 x 除以了图高、y 除以了图宽或者用了绝对坐标没归一化。解决写脚本抽查一批标注统计 x_center 和 y_center 的分布。正常情况下两者都应该在 0.3~0.7 之间集中如果某一轴明显偏小或偏大基本就是基准用错了。重新导出或者写脚本转换。4.3 训练集验证集泄漏指标虚高现象验证集 mAP 很高部署到新视频上效果断崖式下跌。原因切分时没打乱或者同一段视频的相邻帧被分到了两边。相邻帧几乎一样模型等于在验证集上见了训练集。解决切分前先按视频来源分组同一来源的帧只进一个子集。没有来源信息的话至少用随机打乱别按文件名顺序切。4.4 图片和标注不同步训练中途报错现象训练跑着跑着报FileNotFoundError或者标注解析失败。原因清洗时删了图片没删标注或者移动文件时只移了一边。解决写个一致性检查脚本遍历 images 里的每张图确认 labels 里有同名 txt反之亦然。不一致的直接列出来处理。import os img_names {n.replace(.jpg, ) for n in os.listdir(smoke_dataset/images/train)} lbl_names {n.replace(.txt, ) for n in os.listdir(smoke_dataset/labels/train)} print(有图无标, img_names - lbl_names) print(有标无图, lbl_names - img_names)4.5 显存爆了batch 调小还是 OOM现象batch16报 CUDA out of memory调到 8 还是报。原因图片分辨率不统一框架按最大尺寸对齐实际占用比预期高。或者开了 mosaic 增强四图拼接后等效 batch 翻倍。解决先把imgsz降到 512 试再逐步往上加。同时确认没有其他进程占着显存。如果还是不行用梯度累积模拟大 batchbatch8配合accumulate2效果接近batch16。5. 推理验证与进阶技巧把模型跑成能用的东西训练完拿到best.pt别急着庆祝先做推理验证。最直接的方式是用命令行跑一批测试图yolo detect predict \ modelruns/smoke/weights/best.pt \ sourcetest_images/ \ conf0.25 \ iou0.45 \ saveTrueconf0.25是置信度阈值低于这个值的框不输出。抽烟检测里这个值可以适当调低到 0.2宁可多报别漏报后处理再筛。iou0.45是 NMS 的 IoU 阈值重叠框超过这个比例就合并。如果发现同一个目标出了好几个框把 iou 调低如果相邻两个目标被合并成一个把 iou 调高。验证的时候重点看几类难样本远距离的小目标、手部遮挡嘴部的情况、逆光或暗光下的画面。这几类如果漏检严重说明训练数据里这类样本太少得补数据而不是调模型。进阶一点的做法是导出 ONNX 做部署验证。PyTorch 模型在服务器上跑得好不代表转成 ONNX 或 TensorRT 之后还一样。导出命令yolo export modelruns/smoke/weights/best.pt formatonnx opset12opset12是算子集版本太低有些算子不支持太高某些推理引擎不认12 是比较稳的选择。导出后用 onnxruntime 跑一遍同样的测试图对比 PyTorch 和 ONNX 的输出框偏差应该在几个像素以内。如果偏差大多半是预处理没对齐——比如 PyTorch 用的是 letterbox 填充ONNX 推理时忘了同样的填充逻辑。最后说个我自己的习惯。每次拿到新数据集不管标注看起来多规整我都会先抽 20 张画框验证再跑一遍一致性检查然后才起训。这个流程多花不了十分钟但能省掉后面几个小时的无效训练。抽烟检测这个方向数据质量对结果的影响远大于模型选型把标注这关把住后面的事就顺了。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询