
简介本资源面向计算机视觉学习者与行为识别方向开发者提供基于YOLOv5-6.0框架训练完成的吸烟行为检测模型可直接用于图像或视频中的吸烟动作识别适合课程设计、安防场景验证与算法二次开发。压缩包共373个文件约128.03MB包含5个pt权重文件含YOLOv5m与YOLOv5s两个训练好的吸烟检测模型、31个py源码、44个yaml配置、54个txt标注与说明、174张jpg样本图以及png曲线图、csv训练日志、sh脚本与Dockerfile等覆盖训练、验证与部署所需环节。目标类别为smoke准确率在90%以上并附有PR曲线、loss曲线等评估结果便于直观判断模型收敛情况与检测性能。目前已有2392人学习下载读者可据此快速复现训练流程、对比不同规模模型效果并在此基础上迁移到其他行为检测任务。1. 吸烟检测为什么值得用 YOLOv5 单独做一遍在工地、加油站、化工厂、林区这类场景里吸烟检测几乎是刚需。传统做法靠人盯监控一个安全员盯十几路画面漏检是迟早的事。用 YOLOv5 做吸烟检测本质是把「烟」和「人」两个目标绑在一起识别——只检测烟容易误报只检测人又没意义所以主流方案是定义两个类别smoke香烟/烟雾和person吸烟者或者干脆只标香烟本体加一个「正在吸烟」的行为标签。yolov5-6.0-smoking_detect.zip这个标题指向的是一套基于 YOLOv5 6.0 版本的吸烟检测工程包里面通常包含数据集配置、模型权重、训练脚本和推理代码。它解决的核心问题是让你不用从零搭环境直接跑通「数据准备 → 训练 → 推理 → 部署」这条链路。适合两类人一是想快速验证吸烟检测可行性的算法工程师二是需要把模型落到边缘设备比如 RK3568、树莓派上的嵌入式开发者。这一章先把「为什么是 YOLOv5、为什么是 6.0、为什么单独做吸烟检测」讲清楚后面再动手。YOLOv5 6.0 这个版本在工程圈口碑比较稳原因是它的导出链路成熟——ONNX、TensorRT、RKNN 都有现成脚本后处理逻辑也相对固定。吸烟检测的目标尺寸偏小香烟在画面里可能只有几十像素YOLOv5s 的 P3 特征层对小目标还算友好这也是很多人选它而不是 YOLOv8 的原因之一6.0 的生态工具链更全量化到 RK3568 的踩坑记录也更多遇到问题容易搜到答案。2. 从 zip 到能跑环境、数据与训练配置2.1 解压后先看目录结构别急着 pip install拿到yolov5-6.0-smoking_detect.zip后第一件事是解压并确认目录。典型的 YOLOv5 6.0 工程结构长这样yolov5-6.0-smoking_detect/ ├── data/ │ ├── smoking.yaml │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ ├── models/ │ ├── yolov5s.yaml │ └── hub/ ├── weights/ │ └── yolov5s.pt ├── utils/ ├── train.py ├── detect.py ├── export.py └── requirements.txt先看data/smoking.yaml这是数据集配置文件决定了类别数和路径。一个典型的吸烟检测配置如下# data/smoking.yaml path: ../data # 数据集根目录 train: images/train # 训练集图片路径 val: images/val # 验证集图片路径 nc: 2 # 类别数smoke 和 person names: [smoke, person]这里有个容易翻车的点nc必须和names长度一致且names的顺序要和标注文件里 class id 对应。如果你标注时smoke是 0、person是 1那这里就不能写反。改完配置后用下面这条命令检查数据集是否被正确加载python -c from utils.datasets import LoadImagesAndLabels; d LoadImagesAndLabels(data/smoking.yaml, img_size640); print(len(d), d.names)逻辑说明这段代码直接调用 YOLOv5 的数据集加载类打印样本数量和类别名。如果报FileNotFoundError说明path或train路径写错了如果names打印出来是默认的 COCO 80 类说明 yaml 没被正确读取。参数上img_size640要和训练时的--img保持一致否则后续 anchor 匹配会出问题。2.2 训练命令与超参数别用默认 lr 硬跑YOLOv5 6.0 的训练入口是train.py吸烟检测这种小数据集通常几千张不建议从头训而是基于预训练权重做迁移学习。我一般用这条命令python train.py \ --weights weights/yolov5s.pt \ --cfg models/yolov5s.yaml \ --data data/smoking.yaml \ --epochs 100 \ --batch-size 16 \ --img 640 \ --hyp data/hyps/hyp.scratch-low.yaml \ --name smoking_v1逐参数说明--weights指定预训练权重没有它收敛会慢很多--cfg是网络结构吸烟检测用 s 版本就够m/l 版本在边缘设备上跑不动--epochs 100对小数据集通常够用但要看mAP0.5是否还在涨--batch-size 16是 8G 显存下的稳妥值显存不够就降到 8--hyp选hyp.scratch-low.yaml是因为吸烟检测的标注框普遍偏小低学习率增强策略更稳。训练过程中重点看三个指标box_loss、obj_loss和mAP0.5。如果obj_loss震荡不降大概率是标注里有空框或类别错乱如果mAP卡在 0.3 上不去先检查验证集里有没有训练集没出现的场景比如夜间、逆光。2.3 推理验证先跑通单张图再谈部署训练完权重在runs/train/smoking_v1/weights/best.pt用detect.py做推理python detect.py \ --weights runs/train/smoking_v1/weights/best.pt \ --source data/images/val \ --img 640 \ --conf-thres 0.4 \ --iou-thres 0.45 \ --save-txt--conf-thres 0.4是吸烟检测的经验值太低会把烟头、红色物体误检成 smoke太高会漏掉小目标。--iou-thres 0.45控制 NMS 合并如果一个人嘴里叼烟同时被检成 smoke 和 person这两个框 IoU 通常不高不会互相抑制这是正常的。--save-txt会输出每个框的坐标和类别方便你核对误检。提示推理时如果发现大量「人嘴附近有框但类别是 smoke」的情况说明模型学到了位置先验这是好事但如果框出现在手指、烟囱、红色广告牌上就要回去补负样本。3. 吸烟检测的避坑与排查5 个血泪教训3.1 现象训练 loss 正常但 mAP 极低验证集几乎全漏原因标注格式不是 YOLO 格式。YOLO 要求class x_center y_center width height且全部归一化到 0~1。很多人用 LabelImg 导出的是 VOC 的xmin ymin xmax ymax直接塞进去训练模型学到的全是错位框。解决用脚本批量转换转换后随机抽 10 张图用utils.plots可视化核对# voc2yolo.py import os from xml.etree import ElementTree as ET def convert(xml_path, img_w, img_h, save_path): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): cls obj.find(name).text cls_id 0 if cls smoke else 1 bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化并转为中心点宽高 x (xmin xmax) / 2.0 / img_w y (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x:.6f} {y:.6f} {w:.6f} {h:.6f}) with open(save_path, w) as f: f.write(\n.join(lines))参数说明img_w和img_h必须从对应图片读取不能写死 640否则非正方形图会错位。转换后建议用python -c import cv2; ...画框抽查。3.2 现象模型把红色打火机、烟盒也检成 smoke原因训练集里 smoke 类样本几乎全是「香烟 红色包装」的组合模型学到了颜色和形状的伪相关。解决补负样本。把不含香烟但含红色物体的图片加入训练集标注为空不写任何框让模型学会区分。负样本比例控制在正样本的 10%~20% 比较合适太多会导致漏检上升。3.3 现象夜间或逆光场景下漏检严重原因吸烟检测数据集大多来自白天监控夜间样本少模型对低照度下的烟雾纹理不敏感。解决两个方向。一是数据层面用亮度增强--hsv_v 0.6和随机伽马变换扩充夜间样本二是后处理层面夜间适当降低conf-thres到 0.25但要在验证集上确认误报没有暴涨。3.4 现象导出 ONNX 后推理结果和 PyTorch 不一致原因YOLOv5 6.0 的export.py默认把后处理NMS也导出但不同推理引擎对NonMaxSuppression算子支持不一致导致框的数量和位置有偏差。解决导出时加--include onnx --grid或者干脆只导出 backbonehead后处理自己在 C/Python 里写。RK3568 量化时尤其要注意建议用--include rknn并核对量化前后 mAP 下降是否在 2 个点以内。3.5 现象树莓派上跑 YOLOv5s 只有 2~3 FPS原因树莓派 4B 的 CPU 推理 ONNX 模型没有针对 ARM 优化且输入分辨率 640 对它是负担。解决换树莓派 5 或用 RK3568 的 NPU。如果必须用树莓派 4B把--img降到 320并用 NCNN 推理框架实测能到 8~10 FPS。量化到 INT8 还能再快但吸烟检测的小目标对量化敏感建议只量化 backbonehead 保持 FP16。4. 把吸烟检测落到 RK3568 与树莓派上的关键参数4.1 RK3568 量化先对齐后处理再谈精度RK3568 的 NPU 对 YOLOv5 支持已经比较成熟但吸烟检测的小目标在量化时容易掉点。我一般按这个流程走# 1. 导出 ONNX python export.py --weights best.pt --include onnx --img 640 --batch 1 # 2. ONNX 转 RKNN需要 rknn-toolkit2 python -c from rknn.api import RKNN rknn RKNN() rknn.config(mean_values[[0,0,0]], std_values[[255,255,255]], target_platformrk3568) rknn.load_onnx(modelbest.onnx) rknn.build(do_quantizationTrue, datasetquant_dataset.txt) rknn.export_rknn(best.rknn) 参数说明mean_values和std_values要和训练时的归一化一致YOLOv5 默认是 0~1 归一化所以 std 写 255。dataset是量化校准集至少准备 200 张覆盖白天/夜间/逆光的图片否则量化误差会集中在某些场景。do_quantizationTrue开启 INT8如果 mAP 掉超过 3 个点改成False用 FP16。4.2 树莓派 5 部署用 NCNN 比 ONNX Runtime 快一倍树莓派 5 的 CPU 比 4B 强不少但推理框架选择依然关键。实测同一模型NCNN 比 ONNX Runtime 快 80%~100%。转换命令# ONNX 转 NCNN python export.py --weights best.pt --include ncnn --img 320 # 编译 NCNN 后用 benchncnn 测试 ./benchncnn 4 1 0 0 0--img 320是树莓派上的折中值640 太慢320 对小目标又不够。如果吸烟检测的场景里香烟占比很小建议 416 起步。benchncnn后面的参数分别是线程数、GPU 开关、功耗模式等树莓派 5 用 4 线程比较稳。4.3 后处理阈值不同场景下的 conf 和 iou 怎么调场景conf-thresiou-thres说明室内固定摄像头0.450.5光照稳定误报少可以调高室外白天0.350.45背景复杂适当放宽夜间/逆光0.250.4漏检优先接受一定误报边缘设备实时0.40.45平衡速度和准确率这张表是我在几个项目里试出来的经验值不是绝对标准。核心原则是先保证漏检率可接受再压误报。吸烟检测漏检的代价通常比误报高。5. 一个提升小目标召回率的技巧切片推理与 anchor 重聚类吸烟检测最难的不是「有没有烟」而是「烟太小」。640 输入下一根香烟可能只占 20×10 像素YOLOv5 的 P3 层 stride 是 8理论上能覆盖但实际召回率经常卡在 0.6 左右。我常用的两个技巧一个是切片推理SAHI一个是 anchor 重聚类。切片推理的思路是把大图切成重叠的小图分别推理再合并结果。对 1080P 监控画面切成 4 块 640×640 的图小目标像素占比直接翻倍。代价是推理时间变成 4 倍所以只适合离线分析或对实时性要求不高的场景。如果必须实时可以只对画面中心区域切片边缘用全图推理。Anchor 重聚类更轻量。YOLOv5 默认 anchor 是基于 COCO 的吸烟检测的框分布完全不同。用utils/autoanchor.py跑一遍python utils/autoanchor.py --data data/smoking.yaml --weights weights/yolov5s.pt --img 640它会输出建议的 anchor 尺寸替换models/yolov5s.yaml里的anchors字段。我做过对比重聚类后小目标召回率能涨 5~8 个点而且不增加推理耗时。注意重聚类要在训练前做训练后改 anchor 需要重新训。还有一个容易被忽略的点是--rect参数。默认训练时图片会 letterbox 到正方形如果监控画面是 16:9上下会有大量灰边浪费计算。加--rect可以按长边缩放减少无效像素对小目标检测有轻微帮助。最后说一个验证技巧不要只看 mAP。吸烟检测要单独统计smoke类的召回率和误报率因为person类通常很好检会把整体 mAP 拉高掩盖 smoke 的问题。用val.py的--verbose输出每类指标或者自己写脚本按类别统计。我自己踩过最深的坑是在一个工地项目里模型在验证集上 mAP 0.85上线后安全员反馈「烟没检出来几根」。回去查发现验证集全是白天正脸叼烟而现场摄像头是俯视角度烟被人脸挡住。后来补了 500 张俯视样本重训才解决。所以数据集的场景覆盖比模型选型重要得多别在调参上花太多时间先把数据搞扎实。希望帮到你。本文还有配套的精品资源点击获取