构建高质量吸烟检测数据集:从数据采集到YOLO模型训练与Android部署
1. 项目概述:为什么我们需要一个专门的吸烟检测数据集?
在计算机视觉的落地应用里,行为识别一直是个硬骨头,而吸烟检测又是其中兼具社会价值和挑战性的一个细分领域。你可能在不少公共场所见过“禁止吸烟”的标识旁,配着一个不起眼的摄像头,背后很可能就运行着一套基于深度学习的检测系统。但要让这套系统真正“聪明”起来,能准确区分一个人是在抽烟、喝水还是仅仅用手托着下巴,核心中的核心,就是一个高质量、标注精准的数据集。
我接触过不少刚入行的朋友,想用YOLOv5、YOLOv8甚至最新的RT-DETR来做吸烟检测,第一步就卡在了数据上。网上搜到的图片要么质量参差不齐,要么场景单一(基本都是室内正面照),训练出来的模型一到复杂的真实环境——比如光线昏暗的楼梯间、人员密集的餐厅角落,或者只是行人侧身的一个动作——就频频误报或漏报。这就像让一个只见过教科书例题的学生去参加综合考试,结果可想而知。
所以,这个项目聚焦于“吸烟检测数据集”本身。它不只是一个简单的图片打包,而是构建一个可靠检测系统的基石。我们将深入拆解一个合格的数据集应该包含哪些要素,从哪里获取,以及如何正确地使用它,涵盖从数据准备到模型训练(以PyTorch为例)乃至考虑移动端(Android)部署的完整链条。无论你是算法工程师、在校学生,还是对AI应用感兴趣的开发者,理解数据集的内涵,都能让你在后续的模型调优和工程化中事半功倍。
2. 吸烟检测数据集的核心要素与构建逻辑
一个直接可用的、标注好的数据集无疑是宝贵的资源。但在急切地寻找下载链接之前,我们必须先搞清楚,什么样的数据集才算是一个“好”的数据集。这决定了你未来模型的性能上限。
2.1 数据多样性与场景覆盖
吸烟行为并非发生在真空中。一个鲁棒的检测模型必须能应对各种复杂情况。
- 视角多样性:这是最容易被忽视的一点。监控摄像头可能是俯视(安装在屋顶)、平视(安装在墙壁)或斜视。数据集必须包含这多种视角下的吸烟样本。例如,俯视视角下,香烟和手的相对位置与平视视角截然不同。
- 光照条件:涵盖白天、夜晚、室内灯光、逆光、阴影交错等不同光照环境。模型需要学会不依赖于特定的亮度或对比度来识别特征。
- 场景复杂性:吸烟可能发生在办公室、工厂车间、餐厅、楼梯间、户外公园、车内等。背景的复杂程度干扰极大。一个只在干净背景下训练的数据集,在杂乱背景中几乎无法工作。
- 行为状态:包括点烟、持烟、吸烟、弹烟灰、熄灭烟头等完整动作序列的不同瞬间。特别是“持烟”静止状态,容易与手持笔、手机、牙刷等物品混淆。
- 人群与遮挡:吸烟者可能是不同年龄、性别、穿着,且香烟可能被手部分遮挡,或者人在人群中只露出局部。
注意:很多开源数据集往往在“室内办公室白墙前”这种简单场景下表现良好,但一到实战就“掉链子”。评估一个数据集时,务必检查其场景是否单一。
2.2 标注质量与规范
标注是给数据“注入灵魂”的过程。对于吸烟检测,通常采用目标检测的标注格式(如PASCAL VOC的XML或COCO的JSON)。
标注粒度:
- 香烟级别:仅标注香烟本身。优点是目标小,标注快,但模型容易混淆,比如筷子、笔。
- 手部-香烟联合体:标注包含手和香烟的整个区域。这更符合人类认知(“正在吸烟的手”),能提供更多上下文信息,模型更鲁棒,但标注成本高。
- 人-香烟级别:先检测人,再判断人手中是否有烟。这适合需要先进行行人检测的复杂场景。数据集可能需要人体和香烟的两级标注。实操建议:对于通用性要求高的场景,推荐使用“手部-香烟联合体”的标注方式。它平衡了精度和鲁棒性。
标注精确性:边界框(Bounding Box)必须紧密贴合目标物体,既不能过大引入背景噪声,也不能过小裁切目标。对于细长的香烟,框的宽高比会非常极端,需要标注员格外仔细。
难点样本标注:对于模糊、遮挡严重、尺寸极小的吸烟样本,不应直接舍弃,而应尽可能准确地标注。这些“困难样本”对提升模型在边缘情况下的性能至关重要。
2.3 数据格式与划分
一个准备完善的数据集通常包含以下结构:
Smoking_Dataset/ ├── images/ # 存放所有图像文件 │ ├── train/ # 训练集图片 │ ├── val/ # 验证集图片 │ └── test/ # 测试集图片(可选,有时用val代替) ├── annotations/ # 存放所有标注文件 │ ├── train/ # 训练集标注(如 .xml 文件) │ ├── val/ # 验证集标注 │ └── test/ # 测试集标注 └── labels/ # 另一种常见格式,存放YOLO格式的.txt标注文件 ├── train/ ├── val/ └── test/关键点:训练集(Training Set)、验证集(Validation Set)和测试集(Test Set)必须严格分离,确保图像无重复。通常按照7:2:1或类似比例随机划分。验证集用于训练过程中调整超参数、监控过拟合;测试集仅在最终评估时使用一次,以反映模型的真实泛化能力。
3. 吸烟检测数据集的获取与处理实战
了解了标准,接下来就是如何获取和处理数据。这里有开源、自制和合规使用三个方向。
3.1 开源数据集检索与评估
完全从零开始制作数据集成本高昂。首先应积极寻找开源资源。
主流学术数据集平台:
- Kaggle Datasets:搜索关键词“smoking detection”、“cigarette”。Kaggle上的数据集通常附带讨论和基线模型,适合入门。但需注意数据量和质量可能参差不齐。
- Google Dataset Search:这是一个专门搜索数据集的引擎,用英文关键词搜索效果更好,如“smoking cigarette image dataset”。
- Roboflow Universe:一个非常实用的计算机视觉数据集平台。它提供大量预处理(已标注、已划分、已增强)的数据集,并且支持一键导出为YOLO、COCO、TensorFlow等多种格式。在这里搜索“Smoking”很可能有惊喜发现。
评估开源数据集:下载前或下载后,务必进行快速评估:
- 查看数据统计:图片数量、标注实例数量、类别分布(是否只有“smoking”一类?还是有“non-smoking”作为负样本?)。
- 可视化检查:随机打开几十张图片,用标注工具(如LabelImg)加载对应的标注文件,直观感受标注质量、场景多样性和难点样本比例。
- 检查许可协议:明确数据集的使用许可(License),特别是用于商业项目时,需遵守CC BY-SA、MIT等开源协议的要求。
3.2 从零构建:数据采集与标注流程
如果开源数据集无法满足需求,就需要自己动手。这是一个系统性的工程。
数据采集渠道:
- 合规的网络爬取:从遵守Robots协议且允许图片用于研究的网站(如某些公开的监控场景数据集网站)采集。必须严格遵守法律法规和版权要求,禁止爬取个人隐私、商业机密或明确禁止爬取的内容。可使用Scrapy或Selenium框架,但需设置合理的请求间隔,避免对目标服务器造成压力。
- 模拟场景拍摄:在确保安全、合规且不侵犯他人权益的前提下,可以自行组织拍摄。使用不同型号的手机、摄像头,在多种光照和背景下,拍摄模拟吸烟动作(可使用道具代替真烟,避免健康风险并符合规定)。这种方式获取的数据最贴合自身需求。
- 公开视频帧提取:从公开的影视剧、纪录片(需注意版权)或某些行为分析公开视频中截取帧。可以使用OpenCV的
VideoCapture模块轻松实现。
数据标注工具与实操:
- 工具选型:
LabelImg(经典,支持PASCAL VOC格式)、CVAT(功能强大,支持在线协作和视频标注)、Roboflow Annotate(在线工具,体验流畅)。对于新手,LabelImg足矣。 - 标注实操步骤: a.统一规范:在开始前,团队内必须统一标注规范:是标“香烟”还是“手拿香烟”?模糊样本标不标?遮挡超过多少比例则舍弃? b.启动LabelImg:打开工具,设置图片目录和预保存的标注文件目录。 c.创建标签:在标签栏输入“smoking”(或其他你定义的类别名)。 d.绘制边界框:对于每一个吸烟实例,用鼠标框选出目标区域。尽量紧贴目标。 e.保存格式:选择保存为PASCAL VOC格式(.xml)或YOLO格式(.txt)。YOLO格式是归一化后的中心点坐标和宽高,更常用。 f.质量控制:标注一部分后,应由另一人进行复核,纠正错误标注和不一致的地方。
- 工具选型:
数据清洗与增强:
- 清洗:删除完全无效的图片(如全黑、全模糊),检查并修正错误的标注文件。
- 数据增强(Data Augmentation):这是在小数据集上提升模型泛化能力的关键。应在训练时在线(on-the-fly)进行,而不是预先增强存储。常用增强包括:
- 几何变换:随机水平翻转、小角度旋转(如±15度)、缩放、裁剪。
- 颜色变换:随机调整亮度、对比度、饱和度,添加高斯噪声。
- 高级增强:
albumentations或torchvision.transforms库支持更复杂的增强,如CutMix、Mosaic(YOLO系列常用),能极大提升模型性能。
实操心得:对于吸烟检测,随机水平翻转非常有效且安全,因为吸烟行为通常没有固定的左右手倾向。但大角度旋转要谨慎,因为倒立吸烟的样本在现实中几乎不存在,可能引入噪声。
3.3 数据格式转换与准备
不同的训练框架需要不同的数据格式。最常见的是YOLO格式和COCO格式。
YOLO格式详解:每个图像对应一个.txt文件,每行代表一个目标。
<class_id> <x_center> <y_center> <width> <height>class_id:类别索引,从0开始。如果只有吸烟一类,就是0。x_center, y_center:边界框中心点的x、y坐标,已归一化(除以图片宽度和高度),范围0~1。width, height:边界框的宽度和高度,已归一化。- 示例:图片尺寸为640x480,一个目标框的左上角为(100, 120),右下角为(200, 300)。则:
- 中心点 x = (100 + 200)/2 / 640 = 0.234375
- 中心点 y = (120 + 300)/2 / 480 = 0.4375
- 宽度 w = (200 - 100) / 640 = 0.15625
- 高度 h = (300 - 120) / 480 = 0.375
- txt文件内容为:
0 0.234375 0.4375 0.15625 0.375
格式转换脚本:如果你拿到的是VOC格式(.xml),需要转换为YOLO格式。下面是一个简单的Python脚本示例:
import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_file, img_w, img_h, classes): tree = ET.parse(xml_file) root = tree.getroot() yolo_lines = [] for obj in root.findall('object'): cls = obj.find('name').text if cls not in classes: continue cls_id = classes.index(cls) xmlbox = obj.find('bndbox') x1 = float(xmlbox.find('xmin').text) y1 = float(xmlbox.find('ymin').text) x2 = float(xmlbox.find('xmax').text) y2 = float(xmlbox.find('ymax').text) # 计算归一化后的中心点和宽高 x_center = (x1 + x2) / 2.0 / img_w y_center = (y1 + y2) / 2.0 / img_h w = (x2 - x1) / img_w h = (y2 - y1) / img_h yolo_lines.append(f"{cls_id} {x_center} {y_center} {w} {h}") return yolo_lines # 假设 classes = ['smoking'] # 遍历所有xml文件,调用函数并写入对应的txt文件使用这个脚本,你可以批量完成格式转换。
4. 基于PyTorch与YOLO的训练环境搭建与配置
有了高质量的数据集,下一步就是选择模型和搭建训练环境。PyTorch因其灵活性和活跃的社区,成为当前深度学习研究和应用的首选。
4.1 PyTorch与CUDA环境精准配置
这是让训练跑起来的第一步,也是最容易踩坑的一步。
版本匹配矩阵:PyTorch、CUDA、cuDNN、显卡驱动之间必须版本兼容。以目前主流的RTX 40系显卡(如5060)和CUDA 12.x为例:
- 显卡驱动:去NVIDIA官网下载最新版驱动,通常新版驱动向下兼容多个CUDA版本。
- CUDA Toolkit:决定你的PyTorch能调用哪些GPU功能。CUDA 12.1/12.4是当前稳定选择。
- PyTorch:访问PyTorch官网(https://pytorch.org/get-started/locally/),使用其提供的配置命令。例如,对于CUDA 12.1:
# 使用conda安装(推荐,便于环境隔离) conda create -n smoking_det python=3.9 conda activate smoking_det conda install pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia # 或者使用pip安装 pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 - 验证安装:在Python中运行以下代码:
import torch print(torch.__version__) # 输出PyTorch版本 print(torch.cuda.is_available()) # 应输出 True print(torch.cuda.get_device_name(0)) # 输出你的GPU型号
Anaconda环境管理:强烈建议使用Anaconda或Miniconda为每个项目创建独立的虚拟环境。避免不同项目间的包版本冲突。上述安装命令就是在虚拟环境中执行的。
踩坑记录:我曾遇到
CUDA error: no kernel image is available for execution的错误,根本原因是PyTorch版本与CUDA版本不匹配。例如,用pip默认安装的可能是仅支持CUDA 11.8的PyTorch,而我的环境是CUDA 12.4。务必使用官网命令,明确指定CUDA版本。
4.2 YOLOv8训练框架快速部署
Ultralytics YOLOv8因其极简的API和出色的性能,已成为目标检测的新标杆。用它来训练我们的吸烟检测模型非常高效。
安装YOLOv8:在配置好的PyTorch环境中,安装非常简单。
pip install ultralytics这个命令会安装YOLOv8所需的所有依赖。
准备数据集配置文件:YOLOv8需要一个描述数据集的
.yaml文件。这是连接你的数据和模型的桥梁。 创建一个名为smoking_dataset.yaml的文件,内容如下:# 数据集路径(建议使用绝对路径,避免相对路径引发的错误) path: /home/user/Smoking_Dataset # 数据集的根目录 train: images/train # 训练集图片路径,相对于 path val: images/val # 验证集图片路径,相对于 path # test: images/test # 测试集路径(可选) # 类别数量 nc: 1 # 类别名称列表 names: ['smoking'] # 可选:下载地址/说明 # download: ...关键点:确保
path目录下的结构严格符合前文所述,images/train和labels/train等文件夹名称必须对应。模型选择与训练启动:YOLOv8提供了不同尺寸的模型(n, s, m, l, x),在精度和速度之间权衡。
from ultralytics import YOLO # 加载一个预训练模型(推荐,即迁移学习) model = YOLO('yolov8s.pt') # 使用小模型yolov8s,训练快,适合初步尝试 # 开始训练 results = model.train( data='smoking_dataset.yaml', # 数据集配置文件路径 epochs=100, # 训练轮数,根据数据集大小调整 imgsz=640, # 输入图像尺寸 batch=16, # 批次大小,根据GPU内存调整 device='0', # 使用GPU 0,如果是CPU则设为'cpu' workers=4, # 数据加载线程数 name='smoking_det_v1', # 本次训练的实验名称 pretrained=True, # 使用预训练权重 optimizer='AdamW', # 优化器 lr0=0.01, # 初始学习率 ... )训练过程会自动在
runs/detect/smoking_det_v1目录下生成所有结果,包括模型权重、训练曲线、验证结果等。
4.3 训练过程监控与调优核心参数
启动训练后,并非一劳永逸。你需要像教练一样观察模型的“学习状态”。
关键监控指标:
- 损失曲线(loss):
train/box_loss,train/cls_loss,val/box_loss,val/cls_loss。关注训练损失是否平稳下降,验证损失是否同步下降且未明显上升(防止过拟合)。 - 性能指标:
metrics/mAP50-95(mAP@0.5:0.95) 是核心指标,综合衡量模型在不同IoU阈值下的精度。metrics/precision,metrics/recall分别关注查准率和查全率。 - 可视化工具:YOLOv8训练时会启动一个本地Web服务(默认
http://localhost:6006),使用TensorBoard展示所有曲线,非常直观。
- 损失曲线(loss):
核心调优参数解析:
imgsz:输入图像尺寸。增大尺寸(如从640到1280)通常会提升检测小目标(如远处香烟)的能力,但会显著增加显存消耗和训练时间。需要根据你的GPU资源和目标大小权衡。batch:批次大小。在GPU显存允许范围内,尽可能设大。大的batch size能使梯度更新更稳定。如果出现“CUDA out of memory”错误,首先尝试减小batch或imgsz。lr0:初始学习率。这是最重要的超参数之一。太大可能导致训练震荡甚至发散,太小则收敛缓慢。YOLOv8内置了学习率调度器,通常从lr0开始,会先经过一个热身(warmup)阶段,再根据策略下降。对于小数据集,可以从更小的学习率(如0.001)开始尝试。patience:早停(Early Stopping)耐心值。如果验证集指标在连续patience个epochs内没有提升,训练将自动停止,以防止过拟合。默认是50,对于小数据集可以设小一些(如20)。
实操心得:数据决定上限,调参决定逼近上限的速度。如果模型性能始终上不去,首先应该回头检查数据质量(标注是否准确、难点样本是否足够、数据增强是否有效),而不是盲目调整超参数。增加数据多样性往往比调参带来的提升更显著。
5. 模型评估、优化与Android端部署考量
训练完成后,得到一个.pt权重文件,但这只是开始。我们需要评估其真实能力,并考虑如何让它“跑”起来。
5.1 模型性能评估与错误分析
使用训练时预留的测试集(或验证集)进行最终评估。
使用YOLOv8进行验证:
# 在命令行中,使用最佳权重进行验证 yolo task=detect mode=val model=runs/detect/smoking_det_v1/weights/best.pt data=smoking_dataset.yaml这会输出详细的评估表格,包括mAP、精确率、召回率等。
可视化预测结果:
from ultralytics import YOLO model = YOLO('runs/detect/smoking_det_v1/weights/best.pt') results = model('path/to/test_image.jpg', save=True, conf=0.25) # conf为置信度阈值将预测结果(边界框和标签)画在图片上保存。这是错误分析(Error Analysis)的关键步骤。
错误分析实战:仔细查看模型在测试集上的错误预测。
- 误报(False Positive):把不是吸烟的行为(如喝水、打电话)识别为吸烟。这说明模型学到的特征不够鲁棒,可能需要对负样本(非吸烟图片)进行增强,或在数据集中加入更多容易混淆的负样本。
- 漏报(False Negative):漏掉了真实的吸烟行为。重点关注这些漏报的样本:是香烟太小?遮挡太严重?光照太暗?还是视角太奇特?针对性地补充这类困难样本到数据集中,重新训练。
- 定位不准:框的位置偏差大。检查标注是否准确,或者尝试调整损失函数中定位损失的权重(在YOLO中通常是
box_loss_gain参数)。
5.2 模型优化与压缩策略
为了在资源受限的端侧(如Android手机)部署,模型通常需要优化。
- 模型剪枝(Pruning):移除网络中不重要的连接或通道,减少参数量和计算量。YOLOv8本身提供了
model.prune()方法进行尝试性剪枝,但更精细的剪枝需要借助其他工具(如Torch Pruning)。 - 知识蒸馏(Knowledge Distillation):用一个庞大复杂的“教师模型”来指导一个轻量级“学生模型”的训练,让学生模型在保持较小体积的同时获得接近教师模型的性能。这对于从YOLOv8l到YOLOv8n的压缩是一个研究方向。
- 量化(Quantization):将模型权重和激活从高精度(如FP32)转换为低精度(如INT8)。这能大幅减少模型大小和推理延迟,是移动端部署的标配技术。
- 训练后量化(Post-Training Quantization, PTQ):对已训练好的模型进行量化,简单快捷,但可能有精度损失。
- 量化感知训练(Quantization-Aware Training, QAT):在训练过程中模拟量化效应,让模型适应低精度计算,通常能获得更好的精度保持。
5.3 向Android端部署的转换路径
将PyTorch模型部署到Android,主流路径是转换为适用于移动端的推理框架格式。
中间格式:ONNX:ONNX是一个开放的模型表示格式。首先将PyTorch模型导出为ONNX。
from ultralytics import YOLO model = YOLO('best.pt') success = model.export(format='onnx', dynamic=False, simplify=True, opset=12)dynamic=False表示固定输入输出尺寸,有利于部署优化。simplify=True会应用ONNX Simplifier简化计算图。移动端推理引擎选择:
- TensorFlow Lite (TFLite):Google主推,Android原生支持良好,工具链成熟。需要将ONNX模型进一步转换为TFLite格式(可使用
onnx-tf和TFLite Converter工具链)。 - PyTorch Mobile:PyTorch官方移动端解决方案,保持了PyTorch API风格,但社区生态和性能优化目前略逊于TFLite。
- NCNN:腾讯开源的为手机端极致优化的神经网络前向计算框架。特别针对ARM架构做了大量优化,在不少移动设备上性能优于TFLite。通常需要先将模型转到ONNX,再用NCNN的工具链转换。
- MNN:阿里巴巴开源的轻量级深度学习引擎,同样性能优异,支持多种模型格式。
- TensorFlow Lite (TFLite):Google主推,Android原生支持良好,工具链成熟。需要将ONNX模型进一步转换为TFLite格式(可使用
Android集成核心步骤: a.模型转换:根据选择的引擎,将ONNX模型转换为对应的格式(如
.tflite,.ncnn.bin/param)。 b.引入引擎库:在Android项目的build.gradle中添加对应引擎的依赖。 c.编写推理代码:在Java或Kotlin中,加载模型,预处理输入图像(缩放、归一化、转换为ByteBuffer等),运行推理,解析输出(边界框、置信度、类别)。 d.后处理:将模型输出的归一化坐标转换为屏幕坐标,应用非极大值抑制(NMS)去除重叠框,绘制结果。 e.性能优化:利用多线程、GPU委托(如果引擎支持,如TFLite GPU Delegate)来提升推理速度。
部署心得:在Android真机上测试前,务必在PC上用相同的引擎和模型进行推理验证,确保转换过程没有引入错误。预处理和后处理必须与训练时完全一致,任何细微差别(如图像归一化方式、颜色通道顺序)都可能导致结果异常。对于吸烟检测这种实时性要求较高的应用,需要重点关注每帧的处理耗时,确保能达到流畅的检测帧率(如15-30 FPS)。