尧图精选

YOLOv8吸烟检测实战:991张数据集训练与88.3%识别率复现

🕒 发布时间:2026/10/1 3:40:50 📁 来源:尧图网络
简介这份吸烟行为检测数据集面向计算机视觉开发者与目标检测学习者适用于公共场所吸烟识别、行为分析等场景的模型训练与验证。资源共包含991张原始图片全部采用YOLOv8格式标注每张图片配有对应的txt标签文件另附1个yaml配置文件用于类别与路径定义压缩包整体约44.7MB文件总数1983个以jpg图像与txt标注为主结构规整、开箱即用。据描述该数据集在训练后平均识别率可达88.3%可作为基线参考帮助读者快速搭建吸烟检测模型、验证算法效果或进行迁移学习。目前已有110人学习关注适合需要现成标注数据、希望省去采集与标注成本的中初级视觉开发者也便于在此基础上扩充样本、调优模型。1. 吸烟检测数据集落地991 张原始图片与 88.3% 识别率的真实边界吸烟行为检测在智慧工地、加油站、化工厂、公共交通等场景里是刚需但真正动手做的时候第一个卡住大多数人的不是模型结构而是数据。公开的吸烟数据集本来就少能直接拿来训练 YOLOv8 的更少标注格式对不上、类别定义模糊、负样本缺失随便一个坑都能让 mAP 掉十几个点。这份资源给的是 991 张原始图片已经按 YOLOv8 格式标注好官方给出的平均识别率在 88.3%。它解决的是「从零标注到能跑通训练」这一段最耗人力的环节适合两类人一类是想快速验证吸烟检测方案可行性的算法工程师另一类是手上有部署需求、但没精力从零攒数据集的嵌入式或边缘计算开发者。991 张不算大但作为基线数据集它足够让你把训练、验证、导出、部署这条链路完整走一遍先跑通再谈优化。2. 数据集结构与 YOLOv8 标注格式拆解991 张图到底怎么组织2.1 文件命名规律与图片规格从项目正文列出的文件名能看出图片命名是「数字编号 _jpg.rf. 一串哈希」的形式比如1277_jpg.rf.9c8828412f0497d36739ffc3e4553b84.jpg、1023_jpg.rf.2a12f93b37d6f0cb5bcb568dd60b4b65.jpg。这种命名是典型的标注平台导出风格rf.后面那串是导出时生成的唯一标识用来防止重名覆盖。编号本身不连续说明原始素材经过了一轮筛选和清洗不是简单按顺序截帧。图片格式统一是 JPG这对训练是好事——YOLOv8 的 dataloader 对 JPG 解码支持最成熟不会像 PNG 透明通道那样在某些版本上出玄学问题。实际拿到手之后建议先做一次文件完整性检查确认 991 张图都能正常解码避免训练到一半报Corrupt JPEG data。常见做法是用 PIL 批量过一遍from PIL import Image import os img_dir datasets/smoking/images/train bad [] for name in os.listdir(img_dir): path os.path.join(img_dir, name) try: img Image.open(path) img.verify() # 校验文件完整性不真正解码像素 except Exception as e: bad.append((name, str(e))) print(f总检查 {len(os.listdir(img_dir))} 张异常 {len(bad)} 张) for n, e in bad: print(n, e)这段代码的逻辑是Image.open只读文件头verify()检查文件是否被截断或损坏比直接load()快很多。参数上img_dir换成你实际的训练集图片目录即可。如果异常数量超过个位数说明下载或解压过程出了问题别急着训练先重新获取。2.2 YOLOv8 标注格式与类别定义YOLOv8 的检测标注是每张图对应一个同名.txt文件每行格式为class_id x_center y_center width height后四个值都是归一化到 0~1 的相对坐标x_center、y_center是框中心点width、height是框宽高。这一点和 YOLOv5 完全一致所以如果你之前有 v5 的数据集格式上可以直接复用。吸烟检测通常是单类别class_id就是 0对应smoke或smoking。但这里有个容易翻车的地方有些标注平台导出时会把「吸烟」和「香烟」分成两类或者把「手持香烟」单独标一类。拿到数据集后第一件事就是看data.yaml里的names列表确认类别数和你的业务定义一致。# data.yaml 典型结构 path: ./datasets/smoking train: images/train val: images/val nc: 1 names: 0: smokingnc是类别数names是索引到类名的映射。如果你的场景需要区分「正在吸烟」和「手持未点燃」那这个单类别数据集就不够用得自己补标。991 张图按常见 8:2 划分训练集约 793 张验证集约 198 张。这个量级下验证集只有不到 200 张评估指标的波动会比较大88.3% 这个数字要结合置信度阈值和 IoU 阈值一起看不能只看一个孤立的百分比。2.3 目录组织与训练前自检YOLOv8 对目录结构有约定推荐按下面这样组织smoking_dataset/ ├── data.yaml ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/图片和标签必须同名只是扩展名不同。常见错误是标签文件多了一层目录或者图片是.JPG大写而标签是.txt小写导致匹配不上。训练前跑一段自检脚本确认每张图都有对应标签、每个标签坐标都在 0~1 之间import os img_dir smoking_dataset/images/train lbl_dir smoking_dataset/labels/train missing, out_of_range [], [] for name in os.listdir(img_dir): stem os.path.splitext(name)[0] lbl_path os.path.join(lbl_dir, stem .txt) if not os.path.exists(lbl_path): missing.append(name) continue with open(lbl_path) as f: for line in f: parts line.strip().split() if len(parts) ! 5: out_of_range.append((stem, 字段数不对)) continue vals list(map(float, parts[1:])) if any(v 0 or v 1 for v in vals): out_of_range.append((stem, 坐标越界)) print(缺标签:, len(missing)) print(异常标签:, len(out_of_range))这段脚本解决的是训练前最隐蔽的一类问题标签坐标越界不会让训练直接报错但会让模型学到一个偏移的框最终表现为「框总是偏一点」。参数上img_dir和lbl_dir按实际路径改len(parts) ! 5能抓出多空格、少字段的情况。自检通过再开训能省掉后面调参时怀疑人生的时间。3. 从零跑通 YOLOv8 训练环境、命令与参数怎么设3.1 环境搭建与依赖版本YOLOv8 通过ultralytics包分发安装本身不复杂但版本兼容性是血泪经验重灾区。截至我写这篇时的稳定组合是 Python 3.10 PyTorch 2.x ultralytics 8.x。如果你在 Ubuntu 20.04 上跑 CPU 版本先确认 glibc 版本够用再装依赖conda create -n smoke python3.10 -y conda activate smoke pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralytics第一行建虚拟环境第二行激活第三行装 CPU 版 PyTorch——注意--index-url指向的是 CPU 专用源如果你有 NVIDIA 显卡换成对应的 CUDA 源。第四行装 ultralytics它会自动拉取 opencv、numpy 等依赖。CPU 训练 991 张图按 100 epoch 算大概要几个小时到十几个小时取决于机器性能。如果只是验证流程先把epochs设成 10 跑通再说。3.2 训练命令与关键参数含义YOLOv8 的训练入口是命令行yolo detect train也可以用 Python API。命令行方式更适合快速实验yolo detect train \ datasmoking_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/smoke \ nameexp1逐项说明data指向你的data.yamlmodel选yolov8n.pt是最小的 nano 版本991 张图用 nano 足够用 large 反而容易过拟合epochs100是上限配合patience20做早停——20 轮验证指标不提升就停imgsz640是输入分辨率如果你的图片原始尺寸远大于 640YOLOv8 会自动缩放batch16在 CPU 上可能偏大显存或内存不够就降到 8 或 4lr00.01是初始学习率小数据集上这个值偏大时容易震荡可以降到 0.005。project和name决定输出目录权重、曲线图、混淆矩阵都会存在runs/smoke/exp1/下。3.3 训练过程监控与指标解读训练启动后控制台会逐 epoch 打印 box_loss、cls_loss、mAP50、mAP50-95。这里要区分两个指标mAP50 是 IoU 阈值 0.5 时的平均精度mAP50-95 是 0.5 到 0.95 每隔 0.05 取一次再平均后者更严格。88.3% 这个识别率大概率指的是 mAP50 或者某个置信度下的准确率具体要看评估口径。如果 mAP50 到 88% 但 mAP50-95 只有 50% 出头说明框的位置还不够准属于正常现象小数据集上很难把高 IoU 阈值下的指标做高。训练结束后runs/smoke/exp1/下会有results.csv可以用 pandas 画损失曲线import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/smoke/exp1/results.csv) df.columns df.columns.str.strip() # 列名可能带空格 plt.plot(df[epoch], df[train/box_loss], labelbox_loss) plt.plot(df[epoch], df[val/box_loss], labelval_box_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.savefig(loss_curve.png)df.columns.str.strip()这行别省ultralytics 导出的 CSV 列名有时带前导空格不处理会 KeyError。看曲线时重点看验证损失有没有在训练损失还在降的时候先抬头那就是过拟合的信号早停参数就是干这个的。4. 推理验证与 88.3% 识别率的复现口径4.1 用验证集跑一遍指标训练完不能只看训练日志要用val模式在验证集上重新评估yolo detect val \ modelruns/smoke/exp1/weights/best.pt \ datasmoking_dataset/data.yaml \ imgsz640 \ conf0.25 \ iou0.5conf0.25是置信度阈值低于这个值的检测框会被丢弃iou0.5是 NMS 的 IoU 阈值控制重叠框的合并。这两个参数直接决定你看到的精度和召回。把conf调高精度上升但召回下降调低则相反。88.3% 这个数字一定要问清楚是在什么conf和iou下测的否则没有可比性。我一般会跑三组conf0.25 / 0.4 / 0.5看指标变化心里有个区间。4.2 单张图片推理与结果可视化验证指标是一回事实际看图是另一回事。用predict模式跑几张图肉眼确认框的位置yolo detect predict \ modelruns/smoke/exp1/weights/best.pt \ sourcesmoking_dataset/images/val \ conf0.25 \ saveTrue \ projectruns/predict \ nameval_vissource可以是单张图、目录或视频流。saveTrue会把带框的结果图存到runs/predict/val_vis/。重点看两类错误漏检有人吸烟但没框出来和误检把类似吸烟的动作框成吸烟。吸烟检测的误检重灾区是「打电话」「托腮」「手持笔」这些手部靠近脸部的动作如果验证集里这类负样本少误检率会偏高。991 张图里如果负样本占比低建议自己补一些负样本进去哪怕不标注作为背景图也能降低误检。4.3 导出与部署格式选择训练完的.pt权重是 PyTorch 格式部署到不同平台要转格式。常见的有 ONNX、TensorRT、OpenVINO。如果目标是 RK3588 这类边缘芯片通常走 ONNX 再转 RKNN如果是 x86 服务器ONNX Runtime 或 OpenVINO 都行。导出 ONNX 的命令yolo export \ modelruns/smoke/exp1/weights/best.pt \ formatonnx \ imgsz640 \ opset12 \ simplifyTrueopset12是 ONNX 算子集版本太低会缺算子太高某些推理引擎不支持12 是比较稳的选择。simplifyTrue会调用 onnx-simplifier 做图优化去掉冗余节点。导出后建议用 onnxruntime 跑一张图和 PyTorch 的输出对比确认数值误差在可接受范围内别等到部署到板子上才发现对不上。5. 避坑与常见问题排查那些让 mAP 掉点的细节5.1 现象训练 loss 正常下降但 mAP 一直上不去原因通常有两类。一是标签里有大量空文件或坐标越界模型在学噪声二是类别定义和评估时的类别对不上比如data.yaml里nc1但标签里出现了class_id1。解决方法是回到 2.3 节的自检脚本把标签全过一遍同时确认names列表和标签里的class_id范围一致。如果标签里有class_id超出nc-1ultralytics 会在训练时警告但不报错很容易被忽略。5.2 现象验证集精度远高于实际场景表现这是小数据集的典型问题。991 张图如果来源单一比如都是同一个监控角度、同一批人验证集和训练集分布几乎一样指标会虚高。到了实际场景光照、角度、人物衣着一变精度就崩。解决办法是划分验证集时按场景或按人划分而不是随机划分。如果原始数据没有场景标签至少保证验证集里有一些和训练集明显不同的图片。另外88.3% 这个数字要放在「同分布验证集」的语境下理解跨场景部署时预期要打折扣。5.3 现象CPU 训练极慢或内存溢出CPU 训练 YOLOv8 时batch设太大直接 OOM设太小又跑得慢。常见做法是先把imgsz降到 416 或 320 跑通流程确认代码没问题后再升到 640。另外workers参数在 Windows 上设大于 0 容易出多进程问题Linux 上可以设 4 或 8 加速数据加载。如果内存实在紧张用yolov8n.pt而不是更大的模型nano 版本在 CPU 上的推理速度也更能接受。5.4 现象推理时框重叠严重或同一目标多个框这是 NMS 参数没调好。iou阈值设太高比如 0.9重叠框不会被合并设太低比如 0.3相邻目标会被误合并。吸烟检测里如果一个人手和脸离得近框容易重叠iou建议在 0.5~0.7 之间试。另外agnostic_nms参数在多类别时有用单类别可以不管。如果同一目标出现多个框且置信度都差不多检查是不是标注时同一个目标被标了多次这种脏数据在 991 张里如果有几十张就够让 NMS 表现异常。5.5 现象导出的 ONNX 推理结果和 PyTorch 不一致先确认导出时的imgsz和推理时的输入尺寸一致不一致会导致坐标缩放错误。其次检查预处理PyTorch 推理时 ultralytics 内部做了 letterbox 填充如果你自己写 ONNX 推理代码要复现同样的 letterbox 逻辑否则框会偏移。最后确认opset版本和推理引擎兼容ONNX Runtime 对高版本 opset 的支持有滞后。建议导出后先用 onnxruntime 的 Python API 跑一张图和 PyTorch 结果做数值对比误差在 1e-3 以内算正常。6. 小数据集提点技巧从 88.3% 再往上走的几个实操方向991 张图、88.3% 的基线如果直接上生产还差一口气有几个方向可以试。第一是数据增强YOLOv8 默认开了 mosaic、HSV 抖动、随机翻转但吸烟检测里「手部靠近脸部」这个动作对水平翻转敏感——翻转后左右手互换可能引入不真实样本。我一般会把flipud和fliplr的概率调低或者关掉fliplr用degrees做小角度旋转代替。第二是补负样本前面提过误检主要来自相似动作找 100~200 张「打电话」「托腮」「吃东西」的图不标注直接作为背景图放进训练集能明显压误检。第三是调整损失权重。YOLOv8 的box、cls、dfl三项损失有权重参数小数据集上分类损失容易过拟合可以适当降低cls权重让模型更关注框的位置。具体在训练命令里加box7.5 cls0.5 dfl1.5这是 ultralytics 默认值附近微调别一次改太多。第四是尝试更大的输入分辨率如果原始图片里吸烟目标占画面比例很小imgsz640下目标可能只有几十个像素升到 960 或 1280 能提升小目标召回代价是训练和推理都变慢。第五是用预训练权重做冻结训练先冻结 backbone 训 20 轮再解冻全量微调小数据集上这招比直接全量训练稳。验证方法上别只看 mAP。我会额外统计「漏检率」和「误检率」两个业务指标漏检率 漏检数 / 实际正样本数误检率 误检数 / 检测总数。这两个数字比 mAP 更贴近实际体验。跑完验证集后把 FP 和 FN 的图单独挑出来看比盯着曲线有用。从那以后我每次拿到新数据集都强制先跑一遍完整性自检和标签范围检查再开训。这个习惯帮我省掉了至少三次「训练三天发现标签是坏的」的后悔药。希望这份 991 张的吸烟数据集能帮你把吸烟检测的基线快速立起来剩下的就是在这个基础上补数据、调参数、做部署。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →