简介:本资源为面向目标检测任务的吸烟人群检测数据集,适用于计算机视觉方向的学生、算法工程师及科研人员,可用于训练和验证抽烟行为识别模型,覆盖自然生活场景与影视剧画面中的吸烟人物。数据集共包含2000个文件,全部为xml格式的标注文件,对应2000余张图片,压缩包整体约198.63MB,标注内容为边界框左上角与右下角的坐标信息,可直接用于目标检测训练,无需额外清洗或格式转换。目前已有685人学习下载,具备一定的使用参考价值。读者可获得一套开箱即用的吸烟行为检测数据,省去自行采集与标注的成本,便于快速搭建基线模型、验证算法效果,也可用于数据增强、模型对比实验或迁移学习等研究场景,适合作为目标检测入门与进阶的实战素材。
1. 吸烟人群检测数据集:从标注到 YOLO 训练,一条能跑通的链路
吸烟人群检测数据集,本质是一个面向目标检测任务的图像数据集,标注对象是「人」和「烟」两类目标,输出格式通常兼容 YOLO 系列。它的价值不在于数据量有多大,而在于场景聚焦——室内监控、公共场所摄像头、工地安全巡检这些场景里,通用 COCO 模型对「手持香烟」这个小目标的召回率经常掉到及格线以下。我最早接触这类需求是在一个园区安防项目里,客户要求对吸烟行为做实时告警,拿 COCO 预训练模型直接推理,烟头几乎全漏。后来自己整理了一份约 3000 张的吸烟场景数据集,用 YOLOv8 微调,mAP@0.5 从 0.41 拉到 0.78,才算能交付。这篇文章就把这条链路拆开讲:数据集长什么样、怎么标注、怎么转格式、怎么训练、坑在哪。适合手上有吸烟检测需求、准备自己训模型的工程师,也适合想拿这个数据集练手目标检测的新手。
2. 吸烟人群检测数据集的结构与标注规范
2.1 两类目标怎么定义:person 与 cigarette
吸烟检测的核心难点在于类别定义。很多人第一反应是只标「烟」,但实际落地时只标烟会出大问题:模型会把白色笔、细长反光物、手指间夹的杂物全判成烟。我的做法是固定两类——person和cigarette,其中cigarette只标注正在被手持或叼在嘴边的烟,桌上放着的烟盒、烟灰缸里的烟头一律不标。这样模型学到的是「人与烟的交互关系」,而不是单纯的细长物体检测。
标注框的粒度也要统一。person标全身或可见上半身,cigarette标烟的可见部分,哪怕只有几个像素也要标,因为小目标检测恰恰是这类数据集的训练重点。如果烟被手指遮挡超过一半,我一般会放弃这个框,避免引入噪声。
2.2 目录结构与标注文件格式
一份可直接用于 YOLO 训练的吸烟人群检测数据集,目录通常长这样:
smoking_dataset/ ├── images/ │ ├── train/ # 训练集图片,约 2400 张 │ ├── val/ # 验证集图片,约 400 张 │ └── test/ # 测试集图片,约 200 张 ├── labels/ │ ├── train/ # 与图片同名的 .txt 标注 │ ├── val/ │ └── test/ └── data.yaml # 数据集配置文件图片格式统一为.jpg,标注为 YOLO 格式的.txt,每行五个值:class_id x_center y_center width height,全部归一化到 0~1。class_id为 0 表示person,1 表示cigarette。这里有个血泪经验:标注文件名必须和图片名严格一致,差一个字符 YOLO 就找不到标签,训练时 loss 直接不降,排查半天才发现是命名问题。
2.3 data.yaml 的写法与路径陷阱
data.yaml是 YOLO 训练的入口配置,写法如下:
# 吸烟人群检测数据集配置 path: /home/user/smoking_dataset # 数据集根目录,建议写绝对路径 train: images/train # 相对 path 的训练图片目录 val: images/val test: images/test nc: 2 # 类别数 names: 0: person 1: cigarette参数说明:path用绝对路径最稳,相对路径在不同工作目录下启动训练时经常翻车;nc必须和names的条目数一致,写错会报索引越界;names的顺序要和标注里的class_id对应,0 和 1 写反了模型会把人和烟搞混。这个文件看着简单,但新手至少有一半的报错出在这里。
3. 从原始图片到 YOLO 格式:标注工具与转换脚本
3.1 标注工具选型:LabelImg 与 Roboflow 的取舍
标注工具我主要用两个。本地标注用 LabelImg,开源、离线、支持 YOLO 格式直接导出,缺点是界面老旧、多人协作麻烦。团队协作或需要在线审核时用 Roboflow,支持自动标注预填充、多人分工、版本管理,导出时直接选 YOLOv8 格式。如果数据涉及隐私不能上云,就老老实实用 LabelImg 或 Label Studio 本地部署。
标注时的操作要点:先标person再标cigarette,保证类别顺序一致;每张图标注完立刻保存,LabelImg 偶尔会丢未保存的框;遇到模糊图片直接跳过,不要硬标,模糊样本对训练只有负作用。
3.2 用 Python 脚本做格式转换与校验
如果你手上有的是 VOC 格式(.xml)或 COCO 格式(.json)的标注,需要转成 YOLO 格式。下面这个脚本处理 VOC 转 YOLO,并顺带做一次校验:
import os import xml.etree.ElementTree as ET from PIL import Image # VOC 转 YOLO,并校验标注合法性 def voc_to_yolo(xml_dir, img_dir, out_dir, class_map): os.makedirs(out_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if not xml_file.endswith('.xml'): continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() img_name = root.find('filename').text img_path = os.path.join(img_dir, img_name) if not os.path.exists(img_path): print(f'图片缺失,跳过: {img_name}') continue w, h = Image.open(img_path).size lines = [] for obj in root.findall('object'): cls_name = obj.find('name').text if cls_name not in class_map: continue cls_id = class_map[cls_name] bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) # 越界裁剪,防止归一化后超出 0~1 xmin, ymin = max(0, xmin), max(0, ymin) xmax, ymax = min(w, xmax), min(h, ymax) if xmax <= xmin or ymax <= ymin: print(f'非法框,跳过: {img_name}') continue xc = (xmin + xmax) / 2 / w yc = (ymin + ymax) / 2 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f'{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}') out_path = os.path.join(out_dir, xml_file.replace('.xml', '.txt')) with open(out_path, 'w') as f: f.write('\n'.join(lines)) # 类别映射:person 为 0,cigarette 为 1 voc_to_yolo('annotations_xml', 'images', 'labels', {'person': 0, 'cigarette': 1})逻辑说明:脚本遍历 XML 文件,读取图片真实宽高做归一化,这是 YOLO 格式的核心要求。越界裁剪那几行很关键,标注时手抖画出图片边界的框,不裁剪会导致归一化值大于 1,训练时直接报错。参数说明:class_map决定类别顺序,必须和data.yaml的names一致;out_dir输出的 txt 文件名和 XML 同名,后续要确保和图片名对齐。
3.3 数据集划分与防泄漏检查
划分训练/验证/测试集时,最大的坑是同一段视频的连续帧被分到不同集合,导致验证集精度虚高。正确做法是按视频源或拍摄场景划分,同一场景的图片只进一个集合。我一般按 8:1:1 划分,划分完跑一遍检查脚本,确认没有同名图片跨集合出现。如果数据集里有人物重复出现,还要检查同一人的图片是否被拆散,否则模型会记住人脸而不是学吸烟特征。
4. 用 YOLOv8 训练吸烟检测模型:参数配置与显存调优
4.1 环境搭建与最小训练命令
环境用 Python 3.10 + PyTorch 2.x + ultralytics 包。安装命令:
pip install ultralytics最小训练命令如下:
yolo detect train \ data=smoking_dataset/data.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ device=0参数说明:model选yolov8n.pt是轻量版,适合先跑通链路;imgsz=640是标准输入尺寸,吸烟检测里烟目标小,可以尝试imgsz=960提升小目标召回,但显存占用会翻倍;batch=16在 8G 显存上比较稳,显存不够就降到 8 或 4;device=0指定第一块 GPU,CPU 训练会慢到无法接受。第一次训练建议先用 10 个 epoch 跑通,确认 loss 正常下降再拉满。
4.2 针对小目标的三个必调参数
吸烟检测的核心矛盾是烟太小。除了imgsz,还有三个参数值得调:
| 参数 | 默认值 | 建议值 | 作用 |
|---|---|---|---|
| imgsz | 640 | 960 | 提升小目标分辨率 |
| mosaic | 1.0 | 0.5 | 降低马赛克增强,避免烟被拼没 |
| copy_paste | 0.0 | 0.3 | 复制粘贴小目标,增加烟的样本量 |
mosaic增强会把四张图拼成一张,烟这种小目标拼完可能只剩几个像素,适当降低比例有好处。copy_paste是 YOLOv8 支持的小目标增强手段,把烟抠出来贴到其他图上,能显著提升召回。我实测在 3000 张数据集上,这三个参数调完 mAP@0.5 能涨 5 到 8 个点。
4.3 训练过程监控与早停策略
训练启动后重点看三个指标:box_loss是否稳定下降、mAP@0.5是否上升、cls_loss是否震荡。如果box_loss降到 0.5 以下但 mAP 不涨,大概率是过拟合,加数据或加增强。早停用patience=20,20 个 epoch 没提升就停,省时间。训练日志和权重默认存在runs/detect/train/下,best.pt是验证集最优权重,部署时用这个而不是last.pt。
5. 吸烟检测落地的避坑与排查清单
5.1 标注类别不均衡导致烟类召回低
现象:训练完person的 AP 有 0.9,cigarette只有 0.4。原因:烟的目标框数量远少于人,模型偏向多数类。解决:用copy_paste增强烟样本,或在 loss 里给烟类更高权重,也可以在数据层面补充更多吸烟图片。我一般先看标注统计,烟框少于总框数 10% 就要警惕。
5.2 验证集精度高但实际推理漏检
现象:验证集 mAP 0.8,部署到摄像头画面里烟几乎检不到。原因:验证集和训练集同源,场景太相似,模型没学到泛化特征。解决:按场景划分数据集,验证集里放不同光照、不同角度的图片;部署前用真实摄像头截图做一次测试,别只看验证集数字。
5.3 图片和标签文件名不匹配
现象:训练启动后 loss 一直是 nan 或不下降。原因:labels目录里的 txt 文件名和images里的图片名对不上,YOLO 找不到标签,全当背景训练。解决:写个脚本比对两个目录的文件名集合,差集打印出来逐个修。这个坑我踩过两次,每次都是命名带空格或大小写不一致。
5.4 显存溢出导致训练中断
现象:训练到一半报 CUDA out of memory。原因:batch或imgsz设太大,或者workers开太多导致内存泄漏。解决:先把batch减半,再降imgsz,workers设成 4 或 8 别拉满。如果还不行,用yolov8n而不是yolov8m,轻量模型显存占用小很多。
5.5 推理时置信度阈值设错
现象:模型能检出烟但框太多,误报严重。原因:默认conf=0.25对吸烟场景偏低,很多细长物体被误判。解决:部署时把conf提到 0.4 到 0.5,同时开iou=0.5做 NMS。如果还是误报,检查训练数据里有没有把笔、数据线误标成烟,这种脏标注必须清掉。
6. 把吸烟检测模型压到边缘设备:量化与推理加速的一个具体技巧
训练完的best.pt在服务器上跑没问题,但园区项目往往要部署到 Jetson 或 RK3588 这类边缘盒子,这时候模型大小和推理速度就是硬指标。我常用的做法是导出 ONNX 再转 TensorRT,或者直接用 ultralytics 的导出命令做半精度量化。
先导出 ONNX:
yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=640 half=Truehalf=True表示 FP16 半精度,模型体积直接减半,推理速度提升 30% 左右,精度损失通常在 1 个点以内,对吸烟检测这种二分类任务完全可接受。导出后在边缘设备上用 ONNX Runtime 或 TensorRT 加载,推理代码里注意预处理要和训练时一致:letterbox 缩放、BGR 转 RGB、归一化到 0~1,任何一步不一致都会导致精度暴跌。
如果边缘设备算力实在紧张,还可以做 INT8 量化,但需要准备校准集。校准集从验证集里抽 200 张有代表性的图片,覆盖不同光照和场景,量化后用测试集验证精度,掉超过 3 个点就说明校准集不够代表性,得补样本。我一般会保留 FP16 和 INT8 两个版本,线上先跑 FP16,算力不够再切 INT8。
验证量化模型是否可用,别只看 mAP,要在真实视频流上跑一遍,统计每秒检出帧数和误报次数。我习惯用一段 5 分钟的吸烟场景视频做回归测试,人工数出真实吸烟次数,和模型告警次数对比,召回率低于 85% 就回去查预处理和阈值。这套流程跑熟之后,从训练到边缘部署大概两天能完成一轮迭代。
最后一个习惯:每次训完模型,把data.yaml、训练命令、关键参数和 mAP 结果记到一个文本文件里,和权重放一起。下次换数据集或调参时,翻记录比翻聊天记录靠谱得多。吸烟检测这个方向数据质量比模型结构重要,标注干净、场景覆盖全,比换更大的模型管用。希望帮到你。
本文还有配套的精品资源,点击获取