尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

吸烟检测数据集实战:YOLOv8训练与避坑指南

吸烟检测数据集实战:YOLOv8训练与避坑指南 简介这是一份面向目标检测学习者与YOLO使用者的“是否吸烟检测”专用数据集针对公共场所吸烟行为识别与禁烟区域监控场景共覆盖no_smoking、no_smoking_area、smoking三个类别可帮助用户快速上手吸烟检测模型的训练与验证。资源共412个文件包含204张jpg图片、204个txt标注文件和4个yaml配置文件压缩包整体约11.48MB目录已按照train、val、test划分完毕data.yaml中已配置好各集合路径yolov5、yolov7、yolov8等主流算法可直接读取数据开始训练。已有658人学习下载适合数据科学初学者、算法工程师及智慧安防项目开发人员使用。借助这份数据集读者无需自行整理标注与目录结构即可验证目标检测流程也可结合检测结果参考对照模型效果快速建立自己的吸烟检测基线。这份资源整体轻量紧凑适合用于教学演示、相关课题实验或快速跑通吸烟检测流程。1. 吸烟检测数据集为什么值得专门找现成的YOLO格式打包监控画面里有人抬手放到嘴边两三秒后又放下要不要报警提示这类“是否吸烟检测”和常规行人检测最大的不同在于目标是烟头而非整个人——烟头在1080p画面里经常只有十几个像素又细又小对标注和训练都不友好。很多人第一反应是自己收集图片、用labelimg打标完YOLO格式的标注再折腾环境训练但仅打标几百张图就要大半天烟头这种目标还特别容易漏标。smoking-dataset-yolo-1.zip 这类打包好的YOLO吸烟检测数据集解决的就是这部分重复劳动解压后就是图片加同名txtYOLOv5、YOLOv8 等主流训练流程直接能读取。它适合刚接触目标检测、想快速跑通吸烟识别验证方案的从业者也适合做监控边缘设备预研的同学。不过拿到压缩包先别急着训练标签质量决定了训练上限下面这套处理流程才是真正省时间的部分。2. 拆开 smoking-dataset-yolo-1.zip先盘数据和标签再谈训练数据集不是越大越好而是“标签对得上、格式合法、目标画得准”才算能用。我拿到任何 YOLO 格式数据集第一步永远是解压、配对、检查 txt最后再抽图人工看。这三步做完基本能判断这个压缩包是“直接能喂给 yolo 模型训练”还是“需要动手清理一遍”。2.1 解压与目录结构识别images 和 labels 如何一一对应先解压再看目录长什么样。常见做法是把压缩包解压到独立目录避免和项目代码混在一起unzip smoking-dataset-yolo-1.zip -d smoking_data find smoking_data -type f | head -50 find smoking_data -name *.txt | wc -l find smoking_data \( -name *.jpg -o -name *.png \) | wc -l第一行把压缩包解压到 smoking_data 目录避免当前目录被文件铺满第二行看整个目录结构确认是 images/labels 两级目录还是 train/val 下的二级结构第三四行分别数 txt 和图片数量初看图片与标签是否配平。如果解压后发现里面还嵌套一层 zip说明原数据集分了卷或做了二次打包需要再解一次。目录确认后写个小脚本逐对检查每个子集。YOLO 数据集要求每张图片存在同名 txt缺失标签等于这张图被当作纯背景参与训练会影响负样本比例from pathlib import Path root Path(smoking_data) for split in [train, val, test]: img_dir root / split / images lab_dir root / split / labels if not img_dir.exists(): continue imgs {p.stem for p in img_dir.iterdir() if p.suffix in (.jpg, .jpeg, .png)} labs {p.stem for p in lab_dir.iterdir() if p.suffix .txt} print(split, 图片数:, len(imgs), 标签数:, len(labs)) print(缺标签的图片:, len(imgs - labs), 无图片的标签:, len(labs - imgs))这段代码把每个子集里“有图无标”和“有标无图”都数出来。图片和标签文件名不一致是压缩包最常见的翻车点比如某张图叫 img_001.jpg标签却叫 0001.txt训练时 yolo 会静默跳过这张图你甚至注意不到。发现配不平也别急先看差异集中在哪是全目录统一改名还是只有零星几张。2.2 把 txt 标签读出来验证归一化框与类别 ID 是否在预期范围YOLO 格式的每一行固定是“class_id x_center y_center width height”坐标全部归一化到 0~1。很多人只检查了文件存在没看内容结果训练时 loss 直接起飞。我一般会全局扫一遍所有 txt 的类 ID 分布和坐标范围from collections import Counter from pathlib import Path lab_dir Path(smoking_data) / train / labels cls_counter Counter() bad_count 0 for txt in lab_dir.glob(*.txt): for line in open(txt): parts line.split() if len(parts) ! 5: print(行格式异常:, txt, line.strip()) bad_count 1 continue cls int(float(parts[0])) coords [float(v) for v in parts[1:]] if not all(0 v 1 for v in coords): print(坐标越界:, txt, line.strip()) bad_count 1 cls_counter[cls] 1 print(类别分布:, cls_counter) print(异常行数:, bad_count)这段脚本做的事很朴素行数必须是5列class_id 转成整数后进计数器四个坐标必须落在0到1区间。坐标大于1说明原标注不是归一化坐标常见原因是标注工具导出的不是 YOLO 格式被人手动改了扩展名坐标全部是0或1也有问题说明框退化成了点或整张图对训练没有正向帮助。类别分布同样关键——如果 class_id 最大值是0说明这是单类数据集后面的 yaml 只写一个类别如果出现0和1两个 ID而你的业务只需要“是否吸烟”二分类就要确认这两个类分别代表什么别把“不吸烟的人”当正样本喂进去。2.3 数据可视化抽检用 OpenCV 把标签画回图片肉眼查漏标与错标脚本能查出格式错误查不出语义错误。最可靠的验证方式是随机抽几十张图把标注框原样画回去用眼睛看。这一步能发现“标注框框住了整只手而不是烟头”“烟头漏标了大半”“该标烟的位置标了嘴唇”这些让模型越学越乱的坏标签import cv2 from pathlib import Path img_dir Path(smoking_data) / train / images lab_dir Path(smoking_data) / train / labels for img_path in sorted(img_dir.glob(*.jpg))[:30]: img cv2.imread(str(img_path)) h, w img.shape[:2] txt lab_dir / (img_path.stem .txt) if not txt.exists(): continue for line in open(txt): cls, xc, yc, bw, bh map(float, line.split()) x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check_ img_path.name, img)代码本身是逐行解析 txt、把归一化坐标乘回图像宽高、画绿色框、另存为新文件不覆盖原图。抽检重点看三类内容小目标是否多数被框住且框贴合是否存在大量“难分样本”比如棒棒糖、手指、烟盒被框进来图片是否全部来自同一个场景或同一个角度的截图。如果抽30张图里有超过5张明显漏标这个数据集就需要先清洗再训练否则后期补标成本会远高于重新标注一批。3. 基于该数据集训练 YOLOv8数据集 yaml 与最小可跑命令数据和标签盘清楚后就可以进入训练。模型选型上我默认用 YOLOv8 起步原因不是它一定比 v5 或 v11 准而是它对小目标的数据增强组合和命令行参数都写成了默认可用几乎不用调适合作为基线。同样是处理吸烟检测数据集YOLOv8 会在训练过程中自动做 mosaic、翻转、色彩扰动对烟头这种小目标多、背景杂的数据集有天然的容错。选型理由先放这儿下面直接走到能跑的步骤。3.1 数据集 yaml 怎么写路径、类别名、train/val 拆分规范YOLO 训练前要准备一个 yaml告诉框架“数据在哪、类别叫什么”。这是新手最常写错的一步路径写挂会导致训练直接找不到标签。以解压目录 smoking_data 为例标准写法如下path: ./smoking_data train: train/images val: val/images names: 0: smoking如果前面检查类别分布时看到两个 class_id说明数据集里已分好“吸烟”和“非吸烟”两个类别那么 names 改成names: 0: smoking 1: normal这段配置里path 是相对训练命令执行目录的路径也可以换成绝对路径train 和 val 的取值是 images 目录的相对路径框架会自动把路径中的 images 替换成 labels 来定位标注文件names 必须与 txt 里的 class_id 顺序一致顺序错位是“模型训练完但输出类别张冠李戴”的头号原因。注意 train 和 val 都必须有 labels 目录val 只有图片没有标签训练能启动但验证阶段会报错。如果压缩包没有划分 train/val我一般按 9:1 或 8:2 随机分并保证同一场景的图片不被拆到两边。3.2 训练命令与关键参数从默认值到针对小目标调优环境装好 ultralytics 包后训练命令极短yolo detect train \ modelyolov8s.pt \ datasmoking.yaml \ epochs100 \ imgsz640 \ batch16 \ workers8 \ seed42 \ patience20模型选择 yolov8s 是速度和精度的折中监控场景图片量大s 比 n 的误检少比 m 快不少适合第一次跑通epochs100 对几百张图的数据集够用配合 patience20验证集指标连续20轮不涨就提前停imgsz640 是默认推理尺寸这里有个针对烟头小目标的调整点——显存够用就把 imgsz 提到 896 或 1024能显著改善小目标召回代价是单卡训练时间变长。batch16 是8GB显存附近的安全值如果训练时 OOM优先把 batch 降到8而不是换模型。针对吸烟检测这类小目标数据集我通常额外加上两个参数yolo detect train \ modelyolov8s.pt \ datasmoking.yaml \ epochs100 \ imgsz896 \ batch8 \ mosaic1.0 \ mixup0.0 \ close_mosaic10mosaic1.0 表示前90轮启用四图拼接增强能让模型在小目标上见多识广close_mosaic10 表示最后10轮关掉 mosaic让模型在接近真实分布的画面里收尾避免验证时对拼接图产生依赖。mixup0.0 是针对烟头这种小目标关掉的选项mixup 会融合两张图导致小目标变得更模糊我在小目标数据集上默认关掉。这些参数不是玄学mosaic 和 close_mosaic 的组合在公开目标检测里已是标准操作值得作为固定配置写进自己的训练模板。3.3 训练结果判断与第一次推理看指标不如看错图训练结束后runs/detect/train 目录下会生成 weights/best.pt 和 weights/last.pt。best.pt 按验证集 mAP 挑选是部署首选。先别急着看 loss 曲线先跑一次测试图推理直观感受模型输出yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourcetest_samples \ conf0.3 \ iou0.7 \ saveTrue把 test_samples 换成你准备的带吸烟场景的测试图片目录conf0.3 是置信度门限只保留得分高于0.3的框iou0.7 是 NMS 的 IoU 阈值两个框重叠超过这个值就合并成一个。运行结束后打开 save 目录下的标注图重点看三件事真正的烟头有没有框出来、人手或嘴唇有没有被误框、方框是紧贴目标还是偏了一半。指标再好看错图检查这一关过不了部署上线也迟早翻车。把验证集的 val_batch 图和混淆矩阵也打开看漏检的是漏了大多数还是只漏了小目标这决定下一步是补数据还是调门限。4. YOLO训练吸烟检测避坑小目标、坏标注和误检的5条翻车记录数据集类项目的血泪经验往往不在训练代码里而在标签和场景分布里。下面这几条是我在这个方向上反复踩过的坑按“现象 → 原因 → 解决”记录每条都值得你在跑之前先对照一遍。4.1 漏标严重连自己数得清的框模型一个都学不会现象训练完 mAP 看起来不低但推理时同一个场景里总有烟头漏检。回到训练集检查发现不少图片里明明有人拿着烟标签文件里却没有这个框。原因吸烟检测数据集的标注对象是“烟头或烟支”目标太小标注员很容易漏。人脸的框可以看到脸就标烟头必须放大到像素级才看得清漏标率天然比行人检测高几个百分点。训练时这些漏标区域会被当作背景模型在相同位置学习到“这里是背景”推理时自然不敢输出框。解决训练前必须做可视化抽检漏标率超过一定比例就把图挑出来重标。重标时建议统一标注策略是标“烟支整体”还是“烟头燃烧点”两种策略对应不同业务需求全数据集必须保持一致。采用我自己固定下来的规则标注燃烧的烟头端并在烟支清晰可辨认时把整根烟框住宁可框略大不要框一半。4.2 烟头只有十几个像素640 输入下特征不够框在嘴和手之间漂现象模型能“感知”到嘴巴附近有东西但输出的框一会儿落在手上一会儿落在嘴上置信度在0.2到0.4之间摇摆死活稳定不下来。原因1080p 监控画面里烟头经常只占十几个像素。yolo 下采样到 640 尺寸后这个目标只剩几个像素宽特征图上的语义信息几乎为零模型只能靠“手在嘴边”这个上下文猜所以框的位置随上下文偏移。解决实测最有效的一招是提高输入分辨率imgsz 从 640 提到 960小目标召回能明显上涨。显存受限时改用 yolov8n 加高分辨率比用 s 但低分辨率效果更好。另外把小目标区域切图训练——离线把图片按滑动窗口切片、对应标签裁切后单独训练是监控场景的常见做法代价是切图会产生大量无目标子图需要在数据处理时过滤。4.3 负样本缺失背景被当成“不吸烟”推理时到处是误报现象在测试视频里模型把棒棒糖、手指、甚至衣服上的花纹都框成吸烟目标误检多到没法用。原因很多现成吸烟检测数据集只标注“烟”的正样本所有不吸烟的画面全靠背景图撑。如果压缩包里全是人拿着烟的近景模型看到的负样本就只有“手没拿东西”没看过“手拿棒棒糖”“手拿笔”“手指弯曲”这些近似场景推理时就会把一切棒状物当烟。解决在训练集里补负样本不要求负样本是空场景关键是包含容易混淆的物体。挑几十张手拿笔、棒棒糖、吸管、火柴的近景图不标注任何框作为纯背景加入训练。模型只有见过“手拿棒棒糖不是烟”上线后才不会被这类目标骗到。另外训练时 data yaml 里不用给负样本单开类别保持单类正样本、背景为负即可。4.4 class_id 顺序错位损失正常下降预测输出却驴唇不对马嘴现象训练过程 loss 曲线正常mAP50 也不低但推理时模型把所有目标都标成“吸烟”另一类目标一个都出不来。原因yaml 里的 names 顺序和 txt 里的 class_id 对应关系错了。比如标注数据里 class_id1 代表“正常”yaml 里却把索引1写成了“smoking”模型在训练时不会报错只会默默把这两个语义学反。这是 labelimg 打标完 YOLO 格式的数据最常见的一类问题标注工具自定义类别顺序时许多人没看 txt 就把 yaml 按自己想象的顺序写了。解决训练前把 2.2 里统计出的类别分布打印出来按 class_id 数值从0开始核对每类语义。如果你用 labelimg 重新打标注意 classes.txt 文件里的顺序就是 class_id 顺序别在导出后手动调整名字。4.5 数据划分泄漏连续帧同时进训练和验证精度虚高到不敢信现象训练时验证集 mAP 很高一到真实监控视频立刻打折漏检和误检都成倍增加。原因不少数据集从视频里抽帧连续几帧几乎一样。随机按 8:2 划分时同一段视频的相邻帧会被同时分进训练集和验证集验证集约等于“开卷考试”模型见过的画面再考一遍自然拿高分。这个现象在吸烟检测数据集里尤其普遍因为烟头小、背景单一模型背场景比学目标容易得多。解决划分数据必须按“视频片段”或“场景”划分而不是按图片编号随机切。切分前先看一眼数据文件名如果文件名带时间戳或视频ID就按这个名字的粒度分组再划分。没有分组信息时可以按图片相似度做去重把高度相似帧从验证集移除宁可验证集小一点也要保证模型没见过这些画面。5. 部署前最后一关用测试图和置信度门限把模型调到能上线训练完成不等于能上线。吸烟检测在真实场景里的误报代价很高——频繁报警会让管理人员直接关掉系统。所以部署前我会专门跑一批“难测试图”把置信度门限和 NMS 参数实打实地调一轮。先写个批量预测脚本统计每张图的检测数量并保存画框结果from ultralytics import YOLO from pathlib import Path model YOLO(runs/detect/train/weights/best.pt) out Path(result) out.mkdir(exist_okTrue) for img_path in sorted(Path(test_samples).glob(*.jpg)): results model.predict(str(img_path), conf0.30, iou0.7) for r in results: print(img_path.name, 目标数:, len(r.boxes)) r.save(filenameout / img_path.name)这段脚本把 test_samples 目录下所有图片过一遍模型逐个输出检测数量并保存框画图。跑完先做第一轮人工判断哪些图是漏检哪些是误检分别属于哪一类。然后针对置信度门限做一张小表把门限从 0.15 到 0.60 各跑一遍conf效果观察适用场景0.15小目标多召回误报明显变多报警后可人工复核漏报代价高的场景0.30常规默认值误报与漏报相对均衡通用场景起步值0.45误报少只认高置信特征无人值守、自动处罚类场景0.60只输出非常明确的吸烟动作需要绝对低误报的展示场景这里没有唯一正确答案取决于业务更受不了漏报还是误报。我的习惯是先固定在漏检率可接受的最低门限然后用负样本集把误报压下去。之前在类似场景里吃过亏一开始为了少漏检把门限压到 0.05结果系统一天弹出几百条假报警最后不得不重新设计门限和逻辑。后来我总结出一条规则监控报警场景优先保证“误报低于每日1条”再在阈值范围内追求召回。每调整一次门限就把当天采集的测试视频整段跑一遍统计真实触发率。最后提一句部署时把模型导出 ONNX 或用 TensorRT 加速能在保持相同门限效果下把推理耗时降下来。希望这些流程和踩坑记录帮到你少走几步弯路。本文还有配套的精品资源点击获取
返回列表