尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

YOLOv5-6.0吸烟检测实战:从训练到部署的避坑指南

发布时间:2026/9/24 19:53:34

资讯中心
01
ARTICLE

YOLOv5-6.0吸烟检测实战:从训练到部署的避坑指南

YOLOv5-6.0吸烟检测实战:从训练到部署的避坑指南
简介这份资源面向计算机视觉方向的学习者与开发者提供基于YOLOv5-6.0训练完成的吸烟行为检测模型可用于公共场所、工地、加油站等场景下的吸烟行为识别与预警。包内包含YOLOv5m与YOLOv5s两个已训练权重目标类别为smoke在数千张吸烟数据上训练准确率超过90%并附有PR曲线、loss曲线等训练过程记录便于评估模型表现与复现实验。资源共373个文件以jpg图像、txt标注、yaml配置、py脚本、pt权重为主另有png曲线图、md说明文档、sh运行脚本及Dockerfile等部署文件压缩包约128.03MB目录结构完整覆盖数据、训练、推理与容器化部署环节。目前已有2392人学习下载适合希望快速上手吸烟检测、参考训练配置或进行二次开发的中高级读者。1. 从一张吸烟检测图说起yolov5-6.0-smoking_detect.zip 到底能跑出什么厂区安全巡检的朋友发来一张监控截图画面里两名工人蹲在角落其中一人手指间夹着烟背景是堆放的纸箱。他问这种场景能不能用 YOLOv5 自动抓答案是可以而且yolov5-6.0-smoking_detect.zip这类工程包已经把「吸烟检测」这个垂类任务从数据标注到推理部署的链路走通了一遍。它解决的不是通用目标检测问题而是把「香烟 人脸/手部」这种小目标、遮挡多、正负样本极不均衡的场景收敛到一个可复现的训练配置里。适合两类人一是手里有厂区、加油站、林区监控想快速验证吸烟行为识别可行性的工程人员二是正在学yolov5训练自己的数据集想找一个真实垂类练手而不是拿 COCO 跑一遍就结束的开发者。这个包的价值不在模型多大而在于它把吸烟检测的类别定义、数据组织、超参和推理阈值这些容易翻车的地方提前踩过一遍。2. 吸烟检测为什么不能直接套用 COCO 预训练模型2.1 香烟在 640 分辨率下只剩十几个像素COCO 里没有「香烟」这个类最接近的是person和handbag之类直接拿yolov5s.pt去推理吸烟画面模型只会框出人不会框烟。更麻烦的是尺度一根香烟在 1080P 监控画面里可能只占 20×8 像素缩放到 YOLOv5 默认的 640×640 输入后特征图上只剩 2~3 个像素点。YOLOv5 的 P3 检测头 stride 是 8理论上能覆盖 8 像素以上的目标但实际感受野和正样本匹配策略会让这种极小目标在训练早期就被判为背景。常见做法是把输入尺寸提到 960 或 1280同时把数据集中「香烟」框的宽高比单独统计一遍。如果宽高比集中在 2:1 到 4:1 之间可以在 anchor 聚类时把--img-size和--anchors一起调而不是用默认的 COCO anchor。我一般会先跑一遍python utils/autoanchor.py --data data/smoking.yaml --img-size 960看聚类出来的 anchor 和默认值差多少差得远就替换。2.2 吸烟检测的类别定义比想象中更关键很多开源吸烟数据集只标一个smoke类把香烟、烟雾、点火动作混在一起。这种标法在训练时会让模型学到「手靠近脸」就等于吸烟误报率极高。更稳的定义是拆成两类cigarette香烟本体和smoking吸烟行为含手部与面部交互。yolov5-6.0-smoking_detect.zip这类工程包通常采用单类smoking但会在数据清洗阶段把只有烟雾没有香烟的图剔除。如果你自己标数据建议先定一个判定规则香烟可见且与人脸/手部有接触才标smoking只有烟雾或只有烟盒不标。规则写进data/smoking.yaml的注释里标注人员按同一把尺子走否则后面调参全是玄学。2.3 负样本里必须混入「类似吸烟」的干扰吸烟检测最大的误报来源不是没人吸烟而是有人在做类似动作喝水、打电话、托腮、戴口罩调整。如果负样本只有纯背景模型会把「手靠近脸」学成强特征。我一般会在训练集里按 1:3 的比例混入这些干扰图且不标任何框。YOLOv5 训练时这些图会贡献背景损失压制误报。具体操作是在data/smoking.yaml里把train指向一个包含正负样本的 txt 列表负样本图路径也写进去对应 label 文件为空。YOLOv5-6.0 对空 label 的处理是整图算背景不会报错但要注意--rect模式下空 label 图如果宽高比极端可能被裁得只剩背景影响不大。3. 用 yolov5-6.0 跑通吸烟检测的最小命令链3.1 环境准备conda 建环境与依赖版本锁定YOLOv5-6.0 对 PyTorch 和 CUDA 的版本比较敏感尤其是torchvision的 NMS 算子。我习惯用 conda 建一个独立环境避免和系统里的其他 torch 版本打架。conda create -n smoking python3.8 -y conda activate smoking # 安装 pytorch 1.8.1 cuda 11.1这是 yolov5-6.0 验证过的组合 pip install torch1.8.1cu111 torchvision0.9.1cu111 -f https://download.pytorch.org/whl/torch_stable.html # 安装 yolov5-6.0 的 requirements pip install -r requirements.txt逻辑说明Python 3.8 是 6.0 版本官方测试过的解释器版本3.9 以上在torch.nn.functional.interpolate的recompute_scale_factor参数上会有警告。CUDA 11.1 对应 torch 1.8.1如果你显卡是 30 系这个组合能正常调用 cuDNN。装完用python -c import torch; print(torch.cuda.is_available())验证返回 True 再往下走。3.2 数据组织images 与 labels 的目录对齐YOLOv5 要求图片和标签分目录存放文件名一一对应。假设你的数据放在smoking_data/下smoking_data/ ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ └── 0002.jpg │ └── val/ │ └── 0003.jpg └── labels/ ├── train/ │ ├── 0001.txt │ └── 0002.txt └── val/ └── 0003.txt每个 txt 里一行一个目标格式是class x_center y_center width height全部归一化到 0~1。如果只有一类smokingclass 就是 0。常见翻车点是有人把labels目录名写成label或者图片是.jpeg而标签是.txt但文件名大小写不一致YOLOv5 会直接跳过这些图训练日志里train: Scanning的数量对不上。3.3 配置文件smoking.yaml 与模型选择在data/下新建smoking.yaml# 吸烟检测数据集配置 path: ../smoking_data # 数据集根目录 train: images/train # 训练集图片相对路径 val: images/val # 验证集图片相对路径 nc: 1 # 类别数只有 smoking 就写 1 names: [smoking] # 类别名顺序要和 label 里的 class 对应模型选择上yolov5s.pt适合边缘部署yolov5m.pt精度更高但推理慢。如果目标是树莓派 5 上部署建议从yolov5s起步输入尺寸 640量化后再看 mAP 掉多少。训练命令python train.py --img 960 --batch 16 --epochs 100 --data data/smoking.yaml --weights yolov5s.pt --cfg models/yolov5s.yaml --name smoking_s参数说明--img 960是为了让香烟这种小目标在特征图上多留几个像素--batch 16在 8G 显存下比较稳显存不够就降到 8--weights yolov5s.pt用 COCO 预训练权重做迁移比从头训收敛快很多--name smoking_s会在runs/train/smoking_s/下存日志和权重。3.4 训练过程看什么loss 曲线与 mAP 的合理区间启动后先看runs/train/smoking_s/下的results.txt或 TensorBoard。前 10 个 epoch 的box_loss和obj_loss应该明显下降如果obj_loss一直不降大概率是 label 格式错了或类别数对不上。mAP0.5 在吸烟检测这种小目标任务上能到 0.6~0.75 就算可用超过 0.8 要警惕验证集泄漏。我一般会在第 50 epoch 和最后 epoch 各跑一次val.py看混淆矩阵里smoking被误判成背景的比例。如果漏检集中在夜间或逆光图说明数据里这类场景太少需要补样本而不是调参。4. 推理部署与阈值调优从 PyTorch 到实际画面4.1 detect.py 的默认阈值为什么不够用YOLOv5-6.0 的detect.py默认--conf-thres 0.25--iou-thres 0.45。在吸烟检测里香烟框的置信度普遍偏低因为目标小、特征弱。如果直接跑很多真香烟会被 0.25 卡掉。我一般会把--conf-thres降到 0.15同时把--iou-thres提到 0.5让重叠框多保留一些再在后处理里按面积过滤。python detect.py --weights runs/train/smoking_s/weights/best.pt --source test_video.mp4 --img 960 --conf-thres 0.15 --iou-thres 0.5 --save-txt逻辑说明--save-txt会把每帧的检测框存成 txt方便后续统计误报。--img 960必须和训练时一致否则模型看到的尺度变了小目标直接消失。如果视频是 4K建议先缩到 1080P 再推理不然显存和耗时都吃不消。4.2 用置信度与面积双阈值压误报单靠置信度阈值很难同时压住漏检和误报。我的做法是在detect.py输出后加一层过滤只保留面积大于整图 0.1% 且置信度大于 0.2 的smoking框。面积太小的框大概率是噪声面积太大的框可能是把整个人误判成吸烟。# 后处理过滤示例读取 detect.py 输出的 txt import os img_area 1920 * 1080 # 假设原图尺寸 min_area_ratio 0.001 conf_thres 0.2 for txt_file in os.listdir(runs/detect/exp/labels): with open(os.path.join(runs/detect/exp/labels, txt_file)) as f: for line in f: cls, x, y, w, h, conf line.strip().split() area float(w) * float(h) * img_area if float(conf) conf_thres or area / img_area min_area_ratio: continue # 保留的框写入新文件或做告警参数说明min_area_ratio根据你的画面分辨率调1080P 下 0.001 对应约 2000 像素差不多是 50×40 的框能滤掉大部分香烟误报。conf_thres设 0.2 比默认 0.25 略低给真香烟留机会。4.3 树莓派 5 上部署的量化与耗时预期树莓派 5 的 CPU 是 Cortex-A76没有 CUDA只能跑 ONNX Runtime 或 NCNN。YOLOv5s 转 ONNX 后在树莓派 5 上单帧 640 输入大约 200~400ms960 输入会到 800ms 以上做不到实时。常见做法是降到 416 或 320 输入mAP 会掉 10~15 个点但帧率能到 5~8 FPS够做低频抓拍。# 导出 ONNX python export.py --weights runs/train/smoking_s/weights/best.pt --include onnx --img 640 --dynamic # 树莓派上安装 onnxruntime pip install onnxruntime注意--dynamic会让 batch 和尺寸动态树莓派上如果固定输入可以去掉推理更快。量化用 ONNX Runtime 的quantize_dynamic做 INT8权重量化后模型小一半但吸烟检测这种小目标对量化敏感建议量化后在验证集上重跑一遍 mAP掉超过 5 个点就放弃量化。5. 吸烟检测训练与部署的避坑排查5.1 训练 loss 正常但 mAP 为 0现象box_loss和obj_loss都在降但val.py跑出来 mAP 接近 0。原因通常是data/smoking.yaml里的nc和 label 里的 class 编号不匹配比如 label 里写了 1 但nc是 1只有 class 0YOLOv5 会把 class 1 当越界忽略。解决用python utils/general.py --check-labels或手动统计所有 txt 里的 class 最大值确保小于nc。5.2 验证集 mAP 很高但实际画面全是误报现象验证集 mAP0.5 到 0.85但拿现场视频跑到处框吸烟。原因是验证集和训练集同分布且负样本太少模型没学过「类似吸烟」的干扰。解决从现场视频里截 200 张误报帧不标任何框加入训练集重新训 20 个 epoch误报会明显下降。这是血泪经验补负样本比调阈值管用。5.3 香烟框在增强后消失现象训练时开了--mosaic和--mixup小目标香烟在拼接后变得更小甚至被裁掉。原因Mosaic 会把 4 张图缩放到 640原本 20 像素的香烟变成 5 像素低于 P3 的有效感受野。解决在data/hyps/hyp.scratch-low.yaml里把mosaic概率从 1.0 降到 0.5或者把--img提到 1280 再开 Mosaic。我一般会在最后 20 个 epoch 关掉 Mosaic让模型在原始尺度上微调。5.4 推理时 GPU 显存溢出现象训练完用detect.py跑视频报 CUDA out of memory。原因--img 960加上默认 batch 推理显存峰值比训练还高。解决加--batch-size 1或者用--device cpu先跑通流程。如果必须 GPU把--img降到 640或者用--half半精度推理显存能省 40% 左右。5.5 树莓派上 ONNX 推理结果和 PyTorch 不一致现象PyTorch 下能检出的香烟转 ONNX 后在树莓派上漏检。原因导出时--img和推理时输入尺寸不一致或者 ONNX Runtime 的 NMS 算子和 torchvision 有差异。解决导出和推理都用同一尺寸NMS 用 ONNX Runtime 自带的NonMaxSuppression不要自己写。另外检查export.py里的--opset版本树莓派上 onnxruntime 1.12 支持 opset 12太高会报错。6. 把吸烟检测推到可用一个后处理技巧与验证习惯如果你已经跑通训练想让吸烟检测从「能检出」变成「敢告警」重点不在换更大的模型而在后处理的时序过滤。单帧检测必然有抖动同一根香烟在连续帧里可能时有时无。我的做法是维护一个长度为 10 帧的滑动窗口只有当smoking框在窗口内出现次数超过 6 次且框的中心点位移小于画面宽度的 5%才触发告警。这个逻辑用 Python 队列就能实现不需要改模型。from collections import deque # 时序过滤10 帧窗口命中 6 次且中心稳定才告警 history deque(maxlen10) STABLE_RATIO 0.05 # 中心位移阈值画面宽度的 5% def update(detections, img_w): # detections: list of (x_center, y_center, w, h, conf) if not detections: history.append(None) return False # 取置信度最高的框 best max(detections, keylambda d: d[4]) history.append(best) valid [d for d in history if d is not None] if len(valid) 6: return False # 检查中心点稳定性 xs [d[0] for d in valid] if max(xs) - min(xs) img_w * STABLE_RATIO: return False return True参数说明maxlen10对应约 0.5 秒20FPS 下窗口太长告警延迟大太短压不住抖动。STABLE_RATIO根据摄像头焦距调广角画面可以放到 0.08长焦放到 0.03。这个逻辑对「有人路过时手靠近脸」的瞬时误报特别有效因为干扰动作通常只持续两三帧进不了 6 次命中。验证习惯上我每次改完阈值或后处理都会拿同一段 5 分钟现场视频跑一遍人工数误报和漏检记在表格里。不要只看 mAPmAP 不反映时序抖动。另外吸烟检测的模型最好每季度用新场景数据微调一次厂区换季、工人换装、摄像头角度调整都会让旧模型掉点。我自己的习惯是保留一个hard_examples/目录平时看到误报就截图丢进去攒够 100 张就重训一轮比一次性标几千张更可持续。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。