
简介YOLOv8吸烟行为检测资源包面向目标检测开发者和安防、控烟场景应用人员提供了一套可直接运行的训练与部署方案。包内含已训练好的模型权重、基于PyTorch框架的Python源代码以及5000多张使用LabelImg标注完成的吸烟行为图片图片统一为jpg格式标签同时提供xml与txt两种形式类别为smoke可直接用于YOLO系列模型的二次训练、验证与推理。各种训练曲线图和检测效果示例也随包收录方便用户评估模型收敛情况。资源共2000个文件主要类型包括txt标注/说明、md文档笔记、py训练与推理脚本、yaml模型配置等压缩包总体约346.15MB目录结构清晰便于按需查阅。当前已有728人学习下载适合需要快速搭建吸烟检测基线、免去繁琐标注工作或希望以此为模板开展类似行为识别任务的研究者与工程师。1. YOLOv8吸烟行为检测训练好的模型和数据集拿到手离“能上岗”还差几步第一次拿到打包好的 YOLOv8 吸烟行为检测项目很多人会以为解压、跑通、交差就完事了。权重有了数据集有了官方推理脚本也给了流程看起来是通的。我第一回也是这么想的结果在一个 640 分辨率的普通摄像头上跑了半天才缓过神demo 能转不等于现场能稳定报警。白色水杯误报、远处小目标漏检、夜间直接“睁眼瞎”这些问题全藏在训练好的模型和数据集背后需要你自己去补。这篇文章想说的就是YOLOv8 吸烟行为检测这个方向从拿到成品到真正落地需要认清原理、跑通推理、重训适配、排查踩坑的完整路径适合正在做智慧安防、工地或园区吸烟监测的开发者也适合刚接触目标检测、想用现成资源做项目的同学。2. 吸烟行为检测为什么用 YOLOv8原理、选型与数据标注2.1 先讲原理YOLOv8 怎么把一个“人在抽烟”变成两件事吸烟行为检测本质上不是一个“识别整段画面在干嘛”的问题而是一个“找目标、算关系”的问题。摄像头要告诉你的是哪个区域有人、手里有没有烟、烟是不是在嘴附近。这个需求天然落在目标检测框架上模型输出类别和边界框之后在业务层做规则判断。如果改成视频行为识别你只能得到“这一秒有人在抽烟”的粗结果无法告诉现场值班人员具体工位这是落地项目不能接受的。YOLOv8 在目标检测领域被选中的原因很直接它是单阶段模型一次前向就能同时输出所有目标的位置和类别推理速度快适合摄像头实时流。相比之前的版本YOLOv8 全面转向了 anchor-free 结构模型不再依赖预设的 anchor 框而是直接从特征图上的点预测目标中心与宽高。这种设计让不同尺度的目标回归更稳定训练时对数据集分布的敏感度也比老版本低一些省去了聚簇算 anchor 的步骤。从工程角度看YOLOv8 的官方库把训练、验证、导出、推理几个环节统一了一个 CLI 命令或者一个 Python 对象就能跑完整流程。这对做落地的开发者很重要因为你不需要在数据加载、模型定义、后处理这些环节自己写胶水代码。框架内部会处理 Mosaic 增强、自动学习率调度、NMS 后处理这些在过去都是需要手写的大头。不过要注意YOLOv8 并不是专门为吸烟检测设计的它是一个通用检测器。训练好的模型里存的是“这个形状像什么”的统计规律而不是“这个动作是不是在抽烟”的语义逻辑。真正决定能否上岗的是数据集覆盖的现场分布和你在业务层叠加的判断规则。所以拿到训练好的模型后首要任务不是直接上线而是搞清楚它是在什么数据分布上训出来的再决定要不要用现场数据做微调。2.2 模型尺寸怎么选同是 YOLOv8n 和 s 的差距能差出几倍算力YOLOv8 官方按网络深度和宽度给出 n、s、m、l、x 五个尺寸参数量和精度依次递增。很多人看到“训练好的模型”就直接用默认版本不去区分尺寸这是第一批容易翻车的地方。选型号的底线是先看部署环境的算力再看场景对帧率的要求最后才看精度。我自己一般这样权衡模型尺寸参数相对量推理速度适合部署环境YOLOv8n最小最快边缘盒子、低功耗 ARM 设备YOLOv8s中较快普通 x86 工控机、多数项目默认起点YOLOv8m中偏大中等服务器或 GPU 设备追求精度YOLOv8l/x大慢离线批量分析、高精度场景如果你拿到的训练好的权重是 v8n 或 v8s但部署目标是多个摄像头并发推理建议先用 CPU 或低端 GPU 做个压力测试。不要只看单帧速度要看并发路数叠加后的实际帧率。举个例子模拟项目X 里我接手过一个现场方案8 路摄像头同时接入单路上跑 YOLOv8s 勉强 12 帧一旦白天光线变化大检测本身就掉到 8 帧最后只能把模型换成 v8n 并降低输入分辨率才保住实时性。输入分辨率也是选型的一部分。YOLOv8 默认 imgsz 是 640这对大多数近距离场景够用。吸烟检测中香烟本身是个很小的目标如果你的摄像头覆盖范围较大可能要直接用 960 或 1280 的输入分辨率来换取小目标召回率。但分辨率翻倍推理耗时大约翻四倍这个账要提前算清楚。我在本章的建议是拿到训练好的模型第一件事确认它对应 n/s/m/l/x 哪个尺寸然后和你自己的算力资源做匹配不要盲目迷信“参数越大越准”。对吸烟检测这种以中近距离小目标为主的场景v8s 往往是最平衡的起点跑不顺再往下切精度不够再往上加。2.3 数据标注形态框人、框烟还是框手决定了数据集能否复用很多打包好的数据集打开之后你会看到两种完全不同的标注风格这对后续工作影响极大必须在一开始就弄清楚。第一种是只标一个类别“smoking”把吸烟的人整体框进去优点是标注简单、模型容易收敛缺点是无法定位烟在哪里业务层很难做精细判断。第二种是把“cigarette”“person”作为独立类别分别标注模型先找出烟和人再由业务逻辑判断烟是否贴近嘴部。从可复用性角度看我推荐倾向第二类或者在第二类基础上加一个“手”类别。因为只框“smoking”类别的模型一旦部署环境里出现类似手持白色异物的动作很容易产生混淆而把烟作为独立目标检测出来后你可以用阈值判断烟的位置与人脸或手部区域的交叠关系误报率明显更低。标注文件本身是 YOLO 格式的 txt每一行对应一个目标类别序号、归一化的中心点 x 和 y、归一化的宽和高。这里有一个隐藏的坑很多打包数据集用 0 代表“smoking”但用跨摄像头测试时模型换了一个环境类别编号没有对应好会导致推理结果全部错位。所以我建议拿到数据集后先打开几个标签文件核对类别序号和 data.yaml 的 names 映射确认顺序一致再开始训练或推理。另外要考虑标注的边界一致性。如果训练集里“cigarette”的框有的只框烟头有的框整根烟模型学到的目标中心点位置就会不稳定。这种细节问题在验证集上不容易暴露一旦换摄像头、换角度mAP 会掉得很明显。建议花时间统一标注规则明确“从烟蒂到烟头全部纳入框内”再做后续训练。3. 用训练好的YOLOv8权重跑通吸烟检测最小命令与参数3.1 环境准备与权重文件放置先让模型能跑起来拿到训练好的模型最常见的形态是一个.pt权重文件比如smoke_best.pt。先不要急着往项目里塞我建议新建一个干净的 Python 环境再装官方依赖避免和已有 torch 版本打架。这里有一个经验.pt文件本质上是一个用 torch 序列化保存的完整模型状态它和你本地的 torch 版本有兼容性要求环境版本差太远会直接读取失败。# 建议使用 Python 3.9 或 3.10 的独立环境 conda create -n yolo python3.10 conda activate yolo # 安装官方推理依赖会自动带上匹配的 torch 版本 pip install ultralytics这段命令的逻辑是先用 conda 隔离环境防止污染其他项目再通过 pip 安装 ultralytics它会根据平台自动拉取配套的 PyTorch。如果你拿到权重时附带说明文件里面提到的依赖版本和你当前环境不一致宁可多花几分钟重建环境也不要强行在旧环境里跑否则后面排查问题会非常被动。接下来把权重文件放在一个固定目录比如weights/smoke_best.pt。推理时全部通过路径引用。这里建议不要在项目根目录直接放权重后续训练会产生新的 best.pt 和 last.pt容易覆盖混淆。目录结构可以参考smoke_project/ ├── weights/ │ └── smoke_best.pt ├── data/ ├── runs/ └── inference.py有的打包项目给的是 ONNX 格式或 TensorRT 引擎文件这类文件不依赖 PyTorch导入方式不同。但大部分“训练好的模型”默认给 .pt因为它还能继续微调灵活性最高。如果拿到的是 .pt用YOLO()加载即可如果拿到的是 .onnx要配合 onnxruntime 或对应推理引擎使用。3.2 一个 predict 函数同时吃图片、视频和摄像头官方推理接口非常简洁用 Python 调用时图片、视频文件、摄像头序号都走同一个source参数。这对落地调试很友好因为你可以先用图片验证模型是否正常再换成视频最后接摄像头不用改任何代码。from ultralytics import YOLO # 加载训练好的权重 model YOLO(weights/smoke_best.pt) # 图片推理source 传图片路径即可 results model.predict( sourcedata/example.jpg, # 也可以是视频 mp4 或摄像头序号 0 conf0.25, # 置信度阈值低于该值的目标被丢弃 iou0.45, # NMS 的 IoU 阈值 imgsz640, # 推理输入分辨率 saveTrue, # 保存标注后的结果图 )这段代码的核心思路是一次加载、多端复用。conf影响漏检和误检的平衡iou影响重叠框的合并力度imgsz影响精度和速度。这三个参数是后续调优的主力先不要动模型和数据把这三个值调整好往往就能解决大部分问题。命令行方式也支持同样的参数适合快速验证yolo predict modelweights/smoke_best.pt source0 conf0.25 iou0.45 saveTrue注意source0表示默认摄像头如果摄像头被占用会报 no device 之类的错误可以先换成图片路径确认环境正常。我第一次跑摄像头推理时摄像头灯亮了但画面全黑排查半天发现是系统权限没给终端摄像头权限不是代码问题。这类环境问题很容易浪费时间遇到异常先看硬件权限和驱动状态。3.3 conf 和 iou 是落地前最先要调的两个参数很多新手拿到模型只看一张效果图就决定上线这是错误做法。训练好的模型在公开测试集上表现好不代表现场光线和角度下同样好。第一个要调的参数就是conf。conf是置信度阈值默认 0.25。它的表现是调高则误报减少但漏检增多调低则漏检减少但误报增多。在吸烟检测场景里我一般先按 0.25 跑一遍视频统计误报数量如果白色物体误报明显就逐步提高到 0.35 或 0.4如果现场远距离检测不到烟则降低到 0.15 左右试一次再结合其他手段控制误报。iou是 NMS 非极大值抑制的 IoU 阈值默认 0.45。它控制的是两个重叠框是否合并。如果吸烟检测中同一个目标出现两个重叠框可以适当调低iou让它们合并得更快如果担心相邻两个人都被漏检则保持默认值即可。这条规则和场景关系不大建议只调confiou保持 0.45 或 0.5除非看到大量重复框否则不必改动。# 快速批量对比分别跑两个阈值看结果目录中的图片差异 yolo predict modelweights/smoke_best.pt sourcedata/street.mp4 conf0.25 saveTrue yolo predict modelweights/smoke_best.pt sourcedata/street.mp4 conf0.40 saveTrue判断阈值是否合适的标准不是单帧视觉效果而是一段连续视频中“误报次数”和“漏检次数”的综合统计。建议取一段 5 到 10 分钟的现场录像人工标注其中有多少个真实吸烟片段再用不同conf跑一遍找出误报和漏检平衡点。这个过程看起来土但非常有效比盯着单张效果图猜阈值靠谱得多。4. 用自己的数据集重新训练YOLOv8吸烟检测模型数据准备与训练流程4.1 数据集目录、标签格式与训练/验证划分让数据长成 YOLO 认识的样子拿到打包的数据集第一步不是开始训练而是检查目录结构是否符合 YOLO 规范。YOLOv8 默认要求数据集根目录下包含images和labels两个子目录再各自划分train和val。少一个子目录训练直接报数据集为空。smoke_dataset/ ├── data.yaml ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ └── 0002.jpg │ └── val/ │ ├── 1001.jpg │ └── 1002.jpg └── labels/ ├── train/ │ ├── 0001.txt │ └── 0002.txt └── val/ ├── 1001.txt └── 1002.txt标签文件内容格式是每一行class_id x_center y_center width height其中坐标全部除以图片宽高做归一化。常见错误是直接保留了原标注工具输出的像素坐标训练后模型输出全乱。我一般写一个小脚本做格式转换并顺便校验坐标范围import os def convert_label(x1, y1, x2, y2, img_w, img_h): # 将像素坐标转为 YOLO 归一化格式 dw 1.0 / img_w dh 1.0 / img_h x_center (x1 x2) / 2.0 * dw y_center (y1 y2) / 2.0 * dh w abs(x2 - x1) * dw h abs(y2 - y1) * dh return f0 {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n这段脚本的作用是把常见的左上右下坐标转成 YOLO 需要的中心点加宽高比例格式。注意img_w和img_h必须是图片真实宽高有的标注工具会输出缩放后的坐标直接转换会让框偏移。转换后建议写一个反向验证脚本把坐标还原到图片上画框人工抽查几十张。数据划分方面我一般按 8:2 或 9:1 划分训练集和验证集并且保证验证集里包含不同光线、不同姿态的样本。如果打包数据集已经划分好了也建议再随机抽样一遍避免训练集全是白天、验证集全是傍晚的情况。4.2 在线增强mosaic 与 close_mosaic 的正确用法YOLOv8 默认开启在线数据增强其中效果最明显的是 Mosaic 增强把四张图随机裁剪拼接成一张相当于用同样的数据量扩充出更多前景和背景的组合。这种增强对吸烟检测特别有价值因为它让模型看到更多“烟在画面不同位置”的分布。但 Mosaic 增强也有副作用。拼接后的目标尺寸被压缩小目标信息丢失。因此在训练后期建议关闭 Mosaic 让模型用真实比例的目标做精调。Ultralytics 提供了close_mosaic参数意思是最后多少个 epoch 关闭 Mosaicyolo detect train \ datasmoke_dataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ device0 \ close_mosaic10这里close_mosaic10表示最后 10 个 epoch 停止 Mosaic 增强。逻辑是前 90 个 epoch 用丰富的拼接数据让模型充分拟合类别特征后 10 个 epoch 用正常图片校准目标框精度。这是一个很实用的调参习惯尤其是目标相对较小的吸烟检测。如果你发现训练时每个 epoch 耗时特别长先别急着怪显卡先看是不是数据读取瓶颈。把workers参数调高一般能缓解但 Windows 下 workers 太高会报内存错误。训练轮次方面100 个 epoch 是常见起点不一定训满官方库默认开了早停验证集 mAP 多轮不涨会自动停止。4.3 训练启动、断点续训与结果文件解读训练启动前还需要确认data.yaml里的 names 和数据集标签中的类别序号一致。比如你的数据集只有一类“smoking”那么 names 写成{0: smoking}即可如果烟和人分开标就要写成两类并保证标签文件里对应。类别序号对不上训练不会报错但 mAP 会永远偏低且难以排查这是最容易踩的隐藏坑。数据配置文件的内容很直观path: smoke_dataset train: images/train val: images/val names: 0: smoking训练完成后输出默认保存在runs/detect/train/目录下重点是weights/best.pt和weights/last.pt。best.pt是验证集指标最好的权重last.pt是最后一个 epoch 的权重。迁移和推理优先用best.pt。训练日志里重点看metrics/mAP50和metrics/mAP50-95前者是重叠度 50% 时算正确的指标后者更严格。吸烟检测这种小目标场景mAP50 不低于 0.7 才比较可靠。如果训练中断不用重头再来用resume参数可以继续yolo detect train resumeTrue它会自动读取runs/detect/train/weights/last.pt继续训练。也可以用resumeruns/detect/train/指定目录。这个功能在长训练任务里很实用我经常在模拟项目X 里跑到一半发现验证集分布有问题修正数据后从 last 权重继续微调而不是全部重训。还有一点值得说明如果你手头只有别人训练好的模型和数据集重新训练时建议以此为起点做“微调”而不是“随机初始化”。因为你的现场数据通常只有几百到几千张数据量远不足以从零收敛。选择一个预训练权重用较小的学习率继续训练是拿到数据集后最快的适配路径。5. YOLOv8吸烟行为检测的高频问题与排查五个容易翻车的现场5.1 现象白色水杯、白色地面被当成香烟这是吸烟检测上线后最常见的误报。模型对白色细长物体的特征响应很强白色水杯边缘、反光地面、甚至一根白色数据线都可能被框成“烟”。原因是训练集中正样本的亮度和形状特征过于单一模型没有学会“烟通常出现在手附近且尺寸较小”这一隐含关系。解决思路分两步。第一步在推理时适当调高conf比如从 0.25 提到 0.35误报会明显下降。第二步在业务层加一条规则检测到烟后确认其边界框是否与人体区域重叠如果烟的位置远离人体区域则丢弃。这种后处理比单纯依赖模型更可靠也不影响真实吸烟样本的召回。5.2 现象摄像头稍远就漏检烟在画面上只有十几个像素小目标检测是 YOLO 系列的短板。当摄像头安装高度超过三米或者人离摄像头超过五六米烟在 640 分辨率画面里通常只剩 10 到 20 像素宽模型很难稳定识别。很多人第一反应是换更大模型但大模型改善有限。正确做法有两种。第一种把推理输入分辨率提高到 960 或 1280代价是速度下降但小目标召回率明显提升。第二种对原始图像做切片推理把画面分成多块分别检测再合并结果这种方式效率更高但代码复杂度也上升。先试前者不够再上切片方案。5.3 现象白天精度正常晚上或逆光环境下“睁眼瞎”夜间的摄像头图像普遍对比度低、噪声大训练集如果以白天正常光线为主模型自然在夜间失效。逆光场景则相反人脸和手部过暗烟的反光被淹没。这类问题的根源是训练数据与现场数据分布不一致。排查时先做数据层面的对比把夜间现场帧导出几百张放进模型里看失败样本确认是亮度问题还是对比度问题。解决手段可以是收集夜间帧扩充训练集也可以先对输入图像做预处理增强。我常用 gamma 校正或直方图均衡化让暗部细节更明显再进模型。但要注意如果现场摄像头自带红外模式图像整体是灰度风格问题这就不能靠调图像能解决得专门收集红外样本做微调。5.4 现象训练 loss 在降但 mAP 卡在 0.3 左右或者 loss 直接变成 nanmAP 卡在较低水平最常见的原因是验证集标注存在大量错标或者类别序号不对称。YOLOv8 不会检验你的标签是否全部正确模型只能学标注里的“标准答案”如果答案本身错误率高mAP 上限就不可能高。先用可视化脚本把验证集标签画到图上人工翻一圈通常能发现不少框明显偏移的问题。loss 变成 nan 则多发生在学习率过高或模型结构不稳定的情况下。解决方法是把初始学习率调低例如从默认 0.01 调到 0.005并适当增大warmup_epochs。还有一个容易忽略的原因数据里出现了损坏的图片文件某个 batch 读入了空 tensor 导致梯度爆炸。排查时看中断时对应的样本路径删除损坏文件即可。5.5 现象加载权重报错KeyError 或 torch 版本不兼容加载现成模型时报 KeyError 或PytorchStreamReader failed通常不是模型文件本身损坏而是模型训练时的 torch 版本和你当前环境的 torch 版本差别太大。Ultralytics 迭代速度快新版本库可能不再兼容老权重结构。遇到这类问题不要急着怀疑打包项目坑人。先看权重文件训练时配套的 ultralytics 版本如果有 requirements 文件严格照装如果没有就回退到几个常见的稳定版本逐个试。更稳妥的方式是优先加载.pt文件后立刻做一次小图推理确认输出正常再做批量推理。模型文件能加载和能正确推理是两回事中间差一个版本兼容性测试。6. 让吸烟检测真正可用的两个进阶技巧连续帧投票与推理加速6.1 连续帧投票用 5 帧结果代替单帧判断把误报率压下来单帧检测本身的误报率再低放到 24 帧每秒的视频流里也会被放大成可观次数。一个稳妥的优化是引入滑动窗口投票机制不因为单帧出现烟就报警而是统计最近的 N 帧中检出帧数超过阈值才触发。吸烟动作通常持续数秒完全来得及等这个确认过程。from collections import deque class FrameVoter: def __init__(self, window5, min_hits3): self.history deque(maxlenwindow) self.min_hits min_hits def update(self, detected: bool) - bool: # 记录当前帧检测结果返回是否应触发告警 self.history.append(detected) return sum(self.history) self.min_hits这段代码的逻辑很直接window控制统计最近多少帧min_hits控制至少检出几帧才告警。摄像头帧率按 10 fps 算5 帧窗口加 3 帧命中意味着误报要连续高频出现才会触发对偶发的白色物体反光非常有效。代价是真实吸烟报警延迟约半秒对监控场景几乎无感。6.2 导出 ONNX 再走推理引擎保住精度的同时换速度.pt 权重适合研究和微调但直接部署到生产环境通常不够快。常见做法是先导出 ONNX 中间格式再进一步转成推理引擎格式。ONNX 导出后模型计算图被固定省掉了动态图的额外开销推理速度在 CPU 或 GPU 上都有提升。yolo export modelweights/smoke_best.pt formatonnx imgsz640导出时要注意imgsz必须和推理时保持一致否则推理性能会下降。ONNX 导出后要顺手做一次精度对比用同一张图片分别跑.pt和.onnx确认检测结果一致。有时模型结构包含训练时才有的模块导出后精度会小幅下降这是正常现象但下降幅度不应超过 1% 到 2% 的 mAP。如果差距过大优先检查导出时是否被简化了关键节点。我习惯把连续帧投票放在推理引擎之后让加速后的检测输出进入投票器再决定是否给值班平台推送告警。这两个技巧加在一起既解决了误报率又解决了算力瓶颈。以前我图省事直接把单帧结果接到告警平台上线第一天误报上百条后来加了时间窗口过滤才消停。这条路其实不复杂关键是先想清楚模型边界在哪里再用工程手段补足它。希望帮到你。本文还有配套的精品资源点击获取