基于YOLO的抽烟检测数据集制作与模型训练全攻略
简介面向目标检测算法训练与落地验证该数据集提供了一套开箱即用的抽烟检测样本库适用于YOLOv5、YOLOv8等主流模型的迁移学习与微调可服务安防监控、工地安全、餐饮厨房等禁烟场景的智能识别需求。包内共594个文件包含297张JPG原图与297个同名XML标注文件压缩包整体约59.11MB。XML文件采用VOC格式标注每个目标的边界框与类别只需少量脚本即可转换为YOLO训练所需的txt标签图片与标注一一对应目录结构清晰便于自行划分训练集、验证集与测试集。数据场景覆盖室内外不同光照条件包含多角度、多姿态以及部分遮挡情况有助于提升模型的泛化能力。目前已有366人参与学习下载。借助这份数据集初学者可以跳过数据采集与手工标注环节直接体验从数据准备、模型训练到性能评估的完整流程有经验的开发者也能以此为基础快速构建业务原型节省大量前期时间尤其适合毕业设计、竞赛课题以及企业预研项目。 做抽烟检测这个方向我得先给你提个醒别看这任务听起来简单真落地的时候坑多得很。我最早接这个需求是在一个加油站项目里对方要求对卸油区和便利店出入口做实时告警结果我拿着公开数据集训练出来的模型一上现场误报率直接让人崩溃——穿深色衣服的路人被当成烟头、消防栓上的红色反光贴也被框出来。后来我痛定思痛自己整理了一套专门的抽烟目标检测数据集配合YOLO系列重新训练才算把误报压下去。这篇文章我就把这份数据集的完整结构、标注细节、训练流程和踩坑记录都摊开讲清楚给同样在做这个方向的你一个可以直接抄作业的参考。先明确一个概念抽烟检测本质上是目标检测(Object Detection)里的一个细分场景核心任务是在图像或视频帧中定位到“人手夹烟”或“嘴部含烟”的区域并框出来。它和通用的行人检测、车辆检测最大的区别在于目标物体尺寸小、形态多变、遮挡严重——烟头可能只有一个像素点大手部动作千奇百怪再加上光照变化、背景干扰模型很容易学偏。这也是为什么我不能直接拿来一个通用COCO预训练模型就上线必须在自有数据集上做针对性训练。1. 数据集整体设计与标注规范拆解1.1 场景定义与目标定位做数据集之前一定要想清楚一个核心问题你到底要检测什么是检测“烟”本身还是检测“抽烟这个动作”这两个目标对应的标注策略完全不同。我的建议是检测“手部区域与烟的交互”也就是把目标类别统一归为“smoking”标注框覆盖人的手部及烟体所在区域。为什么这么定因为如果你单独去标烟头小目标检测会让模型训练难度直线上升如果你去标整个人框太大又缺乏区分度。折中方案是标注“手持烟区域”既保留了烟的特征又让框的尺寸不至于过小。我第一版数据集就是按这个思路来的实测在YOLOv8m模型上的效果比直接标烟头高了接近12个点的mAP。数据集整体包含图片文件和标定数据两部分标定数据统一采用YOLO格式的txt文件每张图片对应一个同名txt。txt里每一行表示一个目标格式为类别id 中心点x坐标 中心点y坐标 框宽度 框高度。注意这里的坐标值全部做了归一化处理范围在0到1之间而不是像素坐标。这一设计直接对接YOLO系列的训练管线省去了中间转换的麻烦。类别id我固定为0即只有一个类别smoking。1.2 数据来源与场景覆盖这份数据集的图片来源主要涵盖三类场景室内办公环境、室外公共区域、以及特殊管控区域加油站、生产车间。每个场景下都刻意拍摄了不同光照条件强光、逆光、夜间补光和不同距离近景特写、中景半身、远景全身的样本。为什么要这么刻意因为目标检测模型的泛化能力严重依赖训练数据的多样性如果你只在同一个办公室拍200张图模型学到的可能只是“那个特定办公室的抽烟姿势”换个环境立刻失效。我在这套数据集里刻意加入了逆光环境下烟头高亮、夜间红外补光下的人手轮廓、远距离小目标的密集分布等难点样本就是为了逼模型学到“烟手”的本质特征而不是背景特征。不过有一点必须说明完全自采数据的成本很高我在初期也混入了一部分公开的抽烟检测样本和网上爬取并清洗过的图片。混入外部数据时要特别注意标注风格的统一网上很多数据集的框非常随意有的框住了整条手臂有的只框住烟头这种标注风格不一致会严重干扰模型训练需要全部重新标注一遍。2. 标定数据的生成、校验与易错点2.1 标注工具与标注流程标注工具我用的是LabelImg和X-AnyLabeling两套。LabelImg是老牌工具胜在稳定适合批量处理X-AnyLabeling自带SAM分割模型可以半自动生成候选框效率会高不少。流程上是先用X-AnyLabeling的自动标注功能跑一遍初稿然后人工逐张修正边界框的位置和大小。这里有个小技巧自动标注跑出来的框普遍偏大因为SAM分割倾向于把整个语义区域切出来但检测任务需要的是紧贴目标的框所以人工修正的重点通常是把框往内收确保烟体和手部主体都在框内但背景区域越少越好。标注我建议两个人交叉复核一个人标完另一个人抽检20%的图片重点看边界框是否贴合、有无漏标目标、有无错误类别。为什么非要这么做因为抽烟检测的标注主观性很强同样的图片不同人标的框可能差出10个像素以上这10个像素就足以影响小目标的定位精度。我第一次做的时候偷懒没做交叉复核结果训练出来的模型在验证集上precision很高但recall特别低检查发现不少样本的框只标了烟头没标手模型学到的特征是“烟头”而非“人手夹烟”稍微换个角度就漏检。2.2 数据清洗与异常样本处理数据集构建最花时间的其实不是标注而是清洗。我拿到的原始图片素材里大概有15%左右是不能直接用的主要包括严重模糊的图片运动中拍摄导致拖影、目标占比过小的图片烟体小于15x15像素、重复图片同一场景连拍、以及标注信息与图片内容不匹配的脏数据。这些脏数据如果直接进训练集轻则拉低精度重则让loss根本无法收敛。我写了一个简单的Python脚本来辅助清洗先遍历所有标注文件筛出宽度或高度小于5像素归一化后的框并标记对应图片再人工确认这批图片是删除还是重新标注。这个脚本不复杂但在数据集较大时能省下不少时间。标签一致性问题是另一个容易忽视的坑。早期标注时有部分框的类别名称写的是cigarette另一部分写的是smoking还有一部分写的是smoke训练前如果不统一模型会把它当成三个类别来学导致检测结果混乱。我在交付前会用脚本检查所有txt文件中的类别id是否都在允许范围内不在范围内的直接报错并进入修复流程。2.3 常见标注错误速查错误类型表现后果解决方案框过大框住了半边身体模型定位不准IOU低紧贴烟体和手部重新标框过小只框住烟头特征不足小目标漏检扩大到手部区域漏标目标图片中有多个目标只标了一个召回率下降两人交叉复核类别混乱smoking/cigarette混用类别数错乱训练异常脚本统一替换坐标越界归一化坐标大于1训练直接报错清洗脚本修复3. 用这份数据集训练YOLO模型的完整实操流程3.1 环境配置与依赖版本训练环境我建议直接用YOLOv8官方仓库或者是Ultralytics的pip包。我的环境配置供参考Ubuntu 20.04系统Python 3.9PyTorch 1.13.1CUDA 11.7显卡是单张RTX 3080 10G。如果你用的是AMD显卡也不用慌YOLOv8推理是可以用CPU的只是速度慢一些训练阶段如果显存不够就调小batch size。这里多说一句很多新手卡在环境配置上其实你只需要在conda里建一个干净环境执行pip install ultralytics就能跑起来不需要手动装一堆依赖。实测下来Python版本3.9到3.11都能正常工作PyTorch 2.0以上版本会有小幅速度提升。数据集目录结构我建议固定成官方推荐的样子smoking-dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── README.mdimages和labels两个目录必须严格一一对应训练时YOLO会去labels目录里找和图片同名的txt文件找不到会直接跳过这张图片又找不对就会导致训练集图片数少于实际数量。3.2 数据集划分与配置文件编写数据划分比例我习惯按8:1:1来切80%训练、10%验证、10%测试。这里有个容易踩的坑——划分之前一定要先对图片做去重特别是你从网上爬的数据很可能存在同一张图被压缩成不同尺寸后重复出现的情况。我的去重方法是先计算每张图片的MD5值然后在8:1:1划分前再按感知哈希pHash做一次相似度去重否则验证集里混入训练集的近似重复图片训练时的验证指标会虚高上真实场景就露馅。这个pHash去重的逻辑不复杂先要用Python的PIL库把图片缩放成固定尺寸再灰度化然后计算哈希值比较汉明距离。距离小于5的视为重复图片直接剔除。我第一版数据集里就靠这个方法筛掉了二十多张重复图。data.yaml文件是YOLO训练的关键配置内容如下path: /path/to/smoking-dataset train: images/train val: images/val test: images/test nc: 1 names: 0: smokingpath建议填绝对路径避免相对路径在不同机器上报错。nc是类别数量这里只有smoking一个类别所以填1。names是一个字典或列表0号索引对应smoking。3.3 训练参数选择与心得训练命令我用的是yolo detect train \ data/path/to/smoking-dataset/data.yaml \ modelyolov8m.pt \ epochs150 \ imgsz640 \ batch16 \ patience30 \ projectsmoking_project \ nameexp1模型选yolov8m而不是yolov8s是因为抽烟小目标检测对特征提取能力要求较高m尺寸的模型在精度和速度之间更平衡。epochs设150但配合patience30做早停如果连续30个epoch在验证集上没有提升就自动结束训练。batch size设16如果你的显卡显存低于8G建议降到8否则OOM报错会让人非常头疼。imgsz设640是在精度和速度之间的妥协。我之前试过用imgsz1280训练mAP50确实能提升3到4个点但推理速度几乎翻倍在边缘设备上跑不动。如果你最终要部署到Jetson Nano这类设备上建议从最开始就用640训练不要做无谓的算力浪费。4. 训练过程评价标准与指标解读4.1 mAP、精确率、召回率到底怎么看目标检测训练过程中评价标准这件事我见过的初学者踩坑率最高。YOLO训练结束后会输出各类指标其中最核心的是mAP50和mAP50-95。因为我们的任务是单类别检测mAP和APAverage Precision等价数值高就代表模型检测效果好。mAP50指的是在IOU阈值为0.5时的平均精度mAP50-95则是在0.5到0.95之间每间隔0.05取一个阈值求平均后者要求更严格反映的是模型的定位精度。精确率Precision衡量的是“模型检测出来的目标有多少是真正的目标”召回率Recall衡量的是“真正的目标有多少被模型检测出来”。抽烟检测这种安全告警场景我一般更看重召回率宁可误报也不能漏报漏一次可能出大事。但recall也不是越高越好如果recall拉满precision掉到60%以下现场值班人员会被海量误报折磨疯掉最后选择关闭告警系统那就更危险了。通常我会在训练时通过调整conf_thres来平衡这两个指标默认conf_thres0.25实际部署时我会拉到0.3到0.4来压低误报因为安全场景宁可略降recall也要保证告警可信度。4.2 训练曲线识读技巧训练过程中生成的results.png文件很有参考价值重点看两条曲线train_loss和val_loss。理想的曲线是两者持续下降并最终趋于平稳如果train_loss持续下降但val_loss先降后升说明模型过拟合了此时应该减小模型复杂度、增加数据增强或提高正则化系数。如果两个loss都在早期就跌不下去先不要急着调参检查一下学习率——YOLOv8默认学习率是0.01配合AdamW优化器一般情况下不需要手动调整。但如果你的数据集比较小少于2000张图片建议把学习率降到0.005否则前期loss容易波动过大训练不稳定。一条有效的经验是训练期间除了看loss每10个epoch保存一次验证集上的预测可视化结果人工扫一眼预测框的位置和置信度。你可能会发现loss明明在降但预测框全偏到了图片角落——这类问题只有肉眼看图才能发现指标本身无法暴露。5. 常见问题与排查技巧实录5.1 数据集加载报错这类报错的根源基本都是路径问题或标签文件格式问题。先检查data.yaml里的path路径是否存在再把images和labels目录下的文件名逐一对比特别是后缀名是否一致——图片是.jpg标签名也必须是.jpg对应的.txt而不是.png对应的.txt。一个取巧的排查方式是打开训练日志看Loaded的图片数量是否等于你train目录下图片的实际数量如果数据量对不上直接说明有图片没被加载成功。标签文件中如果是全角冒号、中文字符或前后多出来的空格训练时也会报Conversion error。我提供一个小脚本帮你快速清洗所有txt文件import os label_dir labels for root, _, files in os.walk(label_dir): for f in files: if not f.endswith(.txt): continue path os.path.join(root, f) with open(path, r) as fp: lines fp.readlines() cleaned [] for line in lines: parts line.strip().split() if len(parts) ! 5: continue try: cls int(parts[0]) coords [float(x) for x in parts[1:]] if all(0 x 1 for x in coords): cleaned.append(f{cls} { .join(map(str, coords))}) except ValueError: continue with open(path, w) as fp: fp.write(\n.join(cleaned) \n)5.2 训练loss不下降排查优先级从上到下数据问题、学习率问题、模型问题。数据问题最常见的是标注框有大量错误或标注坐标未归一化YOLO默认会认为你在标注时用的是绝对像素坐标导致loss直接起飞。解决方案是把所有坐标值除上图片宽度和高度确保在0-1范围内。学习率问题很好判断把初始学习率调到0.001再训50个epoch试一下如果loss有下降趋势说明之前的学习率设置偏大。模型问题一般是batch size过小导致BatchNorm统计不稳定把batch size调到16以上如果显存允许往往能缓解。5.3 小目标漏检的优化策略很多抽烟检测场景下人是离镜头很远的烟体在640x640分辨率下可能只占10x10像素甚至更小。YOLOv8模型针对这个问题提供了两个关键设计方案一是Feature Pyramid Network结构将不同尺度的特征融合让浅层特征保留下来的边缘纹理信息能与深层语义特征结合二是检测头增加P2层小目标专用特征层专门用于处理小物体。但在数据层面更直接的办法是把原图切块也就是把一张1920x1080的大图切成四块960x540的小图分别送入模型推理这样小目标在模型输入里的占比提高了4倍。代价是推理时间相应增加到约原来的4倍。我实测后建议不要用1280的imgsz硬扛小目标——准确率提升有限但显存占用和推理耗时会大幅增加很不划算。5.4 数据增强策略调整训练YOLO模型时默认会用马赛克增强mosaic它把4张图拼成一张在丰富样本多样性的同时也容易让上下文信息失效不利于小目标检测。所以我训练小目标场景时通常会调低mosaic概率从默认的1.0降到0.5同时开启hsv_h和hsv_s这两个颜色抖动参数增强模型对光照变化的鲁棒性。因为这些训练阶段的增强不会影响推理速度所以可以放心加大强度。但要记得关闭一些与目标形状相关的增强比如旋转角度调成0——烟和手的朝向很关键旋转增强容易破坏其结构特征导致模型学歪。6. 部署落地的补充建议模型训练完我建议用以下命令做一次测试集上的批量验证指定conf_thres和iou_thres输出最终指标yolo detect predict \ modelbest.pt \ source/path/to/smoking-dataset/images/test/ \ conf0.3 \ iou0.45 \ save_txtTrue \ save_confTrue验证通过后如果准备做边缘设备的实时部署建议做一次模型轻量化——用TensorRT或ONNX Runtime做量化推理FP16精度下YOLOv8m在Jetson Xavier NX上能跑到30到40FPS完全满足实时监控需求。再分享一个部署阶段的小细节抽烟检测属于禁止类行为识别视频流里的画面通常是连续帧而目标检测模型是单帧处理的。如果对每一帧都做独立判断很容易因为单帧检测失败导致漏报。我的做法是做时间维度的滑窗投票每5帧为一组只要连续3帧检测到目标就判定为有效告警否则直接丢弃。这个简单的策略可以把漏报率降低30%以上同时基本不增加计算量——你只在前3帧需要跑完整模型后2帧可以用同样的模型但降低输入分辨率来快速验证实测下来效果很好。基于我个人的经验如果你正准备用YOLO做抽烟检测最好把精力集中到数据清洗和标注规范上而不是一开始就纠结模型选型。同样的YOLOv8m骨架在一份干净的数据集和一份脏乱的数据集上训练出来的效果差距远大于不同YOLO版本之间的差距。先把数据搞干净后面的一切都会顺很多。本文还有配套的精品资源点击获取