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

资讯详情

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

基于YOLOv8的吸烟检测系统:从数据集构建到网页端部署全流程

基于YOLOv8的吸烟检测系统:从数据集构建到网页端部署全流程 1. 写在前面为什么我会做这个项目说个挺有意思的事。去年接了个安防领域的定制需求对方想在学校、工厂、办公园区这类场景里做吸烟行为监测。最开始我脑子里冒出来的方案是找现成的云端API一问价格直接劝退——按调用次数计费一个几百路摄像头的园区跑下来一年授权费够买辆代步车。于是只能回到老路子本地化部署自己训模型。做下来之后发现这个需求其实比想象中更普适。除了安防还有不少场景需要它消防重点单位的动火区管理、加油站和化工厂的禁烟区管控、网吧和棋牌室的合规巡检、甚至家里想盯着老人别偷偷抽烟。说白了这是一个典型的“目标检测 场景约束”问题非常适合拿来练手深度学习落地的完整链路。市面上开源的吸烟检测项目不少但大多只给你一个训练好的权重文件或者只有孤零零的推理脚本。真正到了生产环境你还需要能复现的训练流程、稳定可用的数据集、以及一套非技术人员也能操作的交互界面。这就是我这篇博文想交付的东西——一个“训练代码 数据集 网页端”三件套齐备的完整方案YOLOv5/v6/v7/v8四个版本全部适配从零开始教你把模型跑起来、训起来、用起来。这篇文章适合三类人想快速上手YOLO系列做目标检测的初学者需要一个可落地吸烟检测方案的开发者以及想了解“算法模型如何包装成网页产品”的全栈工程师。我会把踩过的坑、试过的方案、最终的选择全部摊开来讲包括数据怎么标、参数怎么调、网页端怎么接摄像头、推理卡顿怎么优化尽量让你照着做就能复现整个系统。2. 技术选型YOLO版本取舍与网页端架构设计选型这一步看着简单实际纠结了我挺久。先把结论放在前面如果是从零开始的新项目直接上YOLOv8如果是为了兼容已有项目或工业现场的老设备YOLOv5依然能打。v6和v7各有各的毛病后面细说。2.1 YOLOv5/v6/v7/v8到底怎么选YOLOv5是这里面的老将了Ultralytics团队出品生态成熟得可怕。网上随便一搜就是一堆教程和现成代码遇到问题基本都能查到解决方案。部署方面也最稳ONNX、TensorRT、OpenVINO的转换教程到处都是哪怕你用C来做边缘端部署参考资料也最丰富。它的缺点就是模型结构相对老了小目标检测能力和新版本比有明显差距。YOLOv6是美团开源的优势在于工业级部署优化做得狠推理速度确实快但它有个尴尬的地方模型的权重文件不是官方统一维护的后续版本迭代有点“躺在功劳簿上”的意思。对多数学习者来说它的生态还不如v5遇到问题可参考的资料少了一大截。YOLOv7的论文挺漂亮作者之前是Scaled-YOLOv4的核心成员理论功底扎实。但从我的实际体验看它在工程化上完成度不够高尤其是和一些第三方库的兼容性不太好训练时报错的概率比v5/v8高不少。除非你特别想研究它的网络结构否则日常项目不建议选它。YOLOv8是目前默认的首选。Anchor-Free检测头让后处理逻辑简化了一大截意味着少写很多代码对旋转目标、小目标的支持也更好再加上Ultralytics官方把训练、验证、导出、推理全部整合成了一个包命令行一把梭。最关键的是它支持“开箱即用的预训练迁移”拿官方在COCO上的权重当初始值再在自己的数据集上微调收敛速度肉眼可见地快。我做性能对比的时候用同一套自建数据集跑在GTX 1660 Ti6GB显存上结果如下版本输入尺寸mAP0.5自测单帧推理耗时GPU模型体量YOLOv5s640×64088.3%约18ms14.5MBYOLOv6s640×64087.9%约15ms16.3MBYOLOv7-tiny640×64086.7%约14ms12.9MBYOLOv8s640×64091.2%约21ms21.3MB提示以上数据基于我自己的数据集不代表官方Benchmark。不同数据分布下差距会有波动但v8在精度上的优势基本是稳定的。延时方面v8比v5稍微慢一点但绝对数值都在几十毫秒级别对吸烟检测这种本身就不需要毫秒级响应的场景毫无压力。所以结论很明确v8是综合体验最好的选择v5是兼容性最好的备胎。2.2 网页端的架构选择Flask、FastAPI、还是Node.js检测模型定下来之后面临第二个问题网页端用什么框架来做。我第一版用的是Flask主要是因为思维惯性——Python后端直接调用模型推理最省事Flask写起来又简单。但做实时视频流的时候发现坑了Flask默认的Werkzeug服务器在处理长连接视频流时容易卡顿并发一上来就掉帧。后来换成了FastAPI配合Uvicorn异步特性对视频流的支撑好了不少。实测单路FPS稳定在20以上CPU占用还降了一些。如果你连FastAPI都不想写也可以考虑用纯JavaScript方案把YOLOv8导出成TensorFlow.js格式直接在浏览器里跑推理后端只需要提供模型文件。这种方案有个致命问题——模型通常有20MB以上浏览器加载时间长而且会让客户端CPU爆表在低端设备上基本不可用。所以我还是推荐后端推理、前端展示的方案。后端的完整架构大概这样浏览器页面(HTML/JS) ↓ WebSocket / HTTP-FLV FastAPI服务 ↓ 调用 YOLOv8推理模块(PyTorch/ONNX Runtime) ↓ 读取 RTSP摄像头 / 视频文件 / 图片上传页面端我选了最朴素的方案HTML Bootstrap 原生JavaScript不引入Vue/React这类重框架。原因很简单这个项目的核心逻辑在服务端页面只是展示结果和参数配置用重型框架纯属过度设计。3. 数据集的搭建从零创建你自己的吸烟检测数据集训练深度学习模型数据质量直接决定模型上限。这里我不讲那些花里胡哨的数据集制作工具就聊一个最现实的问题**没有现成数据集怎么在可接受的时间成本内做出一个够用的数据集。**我自己最初找遍了GitHub和论文附属数据发现公开的吸烟数据集几乎都是外国人的样本人脸特征和国内场景差异很大。最后干脆自己标了一套虽然累但效果确实立竿见影。3.1 数据来源与采集技巧数据来源无外乎三个渠道公开数据集二次加工比如AI Challenger、COCO、VOC这些大型数据集里虽然有“person”类但吸烟这种细粒度行为几乎没有标注。你可以在网上下载一些包含吸烟人物的图片和视频用v8的预训练模型先跑一遍生成伪标签再手动修正。这个方法能把人工标注量减少30%左右。视频抽帧从影视剧、B站公共场所实拍视频、YouTube vlog里截取画面。一个30分钟的视频按每秒抽1帧大概能拿到1800张图去除模糊帧和重复帧后有效样本也有700-800张。实拍采集有条件的团队建议自己用手机或摄像头拍。重点拍摄角度是斜上方45度贴近真实监控视角。如果实在没条件至少要在网上搜集“监控视角下的吸烟画面”来补充否则训练集和部署环境差距太大会导致泛化失败。采集阶段有一条黄金法则样本多样性 样本数量。吸烟动作的多样性体现在环境光照室内、室外、逆光、阴天、人物姿态坐着、站着、行走、低头、拍摄距离近景、中景、远景、烟的位置嘴前、手中、烟雾浓郁程度。我第一版数据集只有3000张但覆盖面广效果比后来取5000张同质照片好得多。3.2 标注规范与工具选择吸烟检测的标注核心只有一个类别smoking。但这里有个关键设计点——要不要标注“烟”和“吸烟动作”两个独立类别。我试过两类方案结论是在光线复杂、人脸模糊的情况下把“烟”作为主要检测目标更稳定因为它颜色特征明显白色/黄色柱状物、形状固定、运动幅度小。而“吸烟动作”这一类目涉及手部与嘴部姿态判断标注标准不好统一模型学起来容易混乱。所以最终标注方案是统一标注为smoking框住“手烟嘴部区域”的组合体而不是只框烟本身。这样模型的感受野更大能学习到“手持物体到嘴边”这一整体姿态误检率反而比单纯框烟更低。标注工具我首推LabelImg老牌工具可以生成YOLO格式的txt标注文件。更省事一点的是X-AnyLabeling支持自动分割和半自动标注先用预训练模型打底标注再手动微调效率提升非常明显。此外还有Roboflow在线标注可以云端协作和Label Studio功能更全面但上手曲线稍陡。我自己常用组合是批量初标用X-AnyLabeling精修用LabelImg。标注的时候有两点血的教训边界框要贴合目标但不用贴到像素级。吸烟检测不需要像目标分割那样精细框略大一点反而有利于训练稳定性。一张图里有多个人时只标那些“正在吸烟”的人嘴里叼着烟但没点燃的也要标烟雾很淡的也要标。没吸烟的人不标但保留在图片中作为负样本这很重要——模型需要学习“这个人没吸烟”的区分信号。3.3 数据增强策略不能只靠随机翻转YOLOv8自带数据增强Mosaic、MixUp、HSV变换、随机翻转这些默认都开了。但这不意味着你可以省事。针对吸烟检测这个具体场景我额外加了两个增强策略一、局部遮挡模拟。监控场景里人经常被桌椅、栏杆、其他人挡住。通过随机遮挡在标注框附近随机画黑色矩形块模拟这种遮挡能显著提升复杂场景下的召回率。实测从这个改动开始测试集的mAP提高了2个百分点左右。二、分辨率动态退化。老旧的监控摄像头画面通常有很多噪点和模糊。我在训练时随机对输入图片做高斯模糊、添加高斯噪声、降低对比度让模型学会在低分辨率下也能识别。这一点非常重要因为网页版上线后你不可能保证所有接入的摄像头都是1080P高清。3.4 数据集格式转换与目录组织最后把标注结果整理成YOLO格式的标准目录结构dataset/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 └── labels/ ├── train/ # 每个图片对应的txt文件 └── val/ # 每行: class_id x_center y_center width height (归一化)数据集的划分比例我建议是8:1训练集和验证集额外留1%作为测试集。或者你直接把验证集当测试集用也行小项目这样问题不大。但要注意一点同一个视频里抽出来的帧只能放在同一个集合中否则会造成数据泄漏——模型相当于“见过”了测试集的内容评估结果虚高。如果你用的是LabelImg它生成的是VOC格式的XML需要在脚本里转一下。这里给个转换脚本的参考import xml.etree.ElementTree as ET import os, random def convert_voc_to_yolo(xml_file, out_dir, class_names): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) txt_name os.path.splitext(os.path.basename(xml_file))[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: for obj in root.iter(object): cls obj.find(name).text if cls not in class_names: continue cls_id class_names.index(cls) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n)我自己当时用了一个半自动流程先用一个在公开数据集上预训练好的v8模型对所有候选图片做初步检测把置信度高的结果保留为初始标注置信度低或漏检的再人工修正。这样几千张图两天就能搞定纯手工标的话估计得一周。4. 训练核心流程YOLOv8从环境配置到自定义数据训练进入训练阶段之前先确保环境装好了。这里我不打算把安装命令贴一遍——网上太多教程了就提几个我自己反复踩的坑。4.1 环境配置里最容易翻车的三个坑坑一PyTorch和CUDA版本不匹配。这个老生常谈但永远有人栽。强烈建议直接上PyTorch官网用pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118这种安装方式会自动匹配当前CUDA版本。别乱用pip install torch它默认装CPU版训练速度慢到怀疑人生。坑二依赖包版本冲突。Ultralytics对依赖版本有硬性要求opencv-python、matplotlib、pandas、seaborn这些包如果版本太新或太老都可能报奇怪的错。最省心的方法是创建一个干净的虚拟环境然后直接用官方requirements.txt安装git clone https://github.com/ultralytics/ultralytics.git cd ultralytics pip install -r requirements.txt如果是Windows系统注意一下本机是否装了多个Python版本有时候pip指向的Python和命令行里的python不是同一个也会导致“明明装了包却import不到”的怪事。坑三内存不足。训练集图片如果分辨率很高数据加载阶段可能直接把内存吃满。建议在数据集准备阶段就把图像resize到1280像素以内同时调低--workers参数默认的8在内存小的机器上会直接OOM。4.2 训练参数详解与调参经验YOLOv8的训练入口非常简洁一行命令yolo train modelyolov8s.pt datasmoking.yaml epochs100 imgsz640 batch16 device0这里有一个配置文件需要先准备好也就是smoking.yamlpath: ./dataset train: images/train val: images/val nc: 1 names: [smoking]核心训练参数我逐个说下我的经验值模型规模选择我用的是yolov8s。如果你的显卡是8GB以上显存可以试试yolov8m精度会更高一些但推理速度也会下降。笔记本显卡的话老老实实yolov8s或yolov8n。imgsz推荐640。分辨率越高小目标越容易检测但显存消耗翻倍。如果部署环境摄像头分辨率本身不高用640就够了。想再压性能可以用480精度损失约2-3个百分点。batch显存不够时的第一调节项。6GB显存跑yolov8sbatch16会有机会爆显存降到8就稳了。也可以用batch-1让程序自动检测。epochs我的经验是100个epochs足够收敛。如果100个epoch后损失还在下降可以接着往上加但其实对mAP提升已经不大了。patience默认50表示50个epoch内验证集mAP没有提升就提前终止。这个一定要留着能省不少时间。freeze迁移学习时用的冻结参数。如果是很小的数据集小于500张建议冻结前10层freeze10防止过拟合。数据集超过2000张就不必冻结了让它全量微调效果更好。跑完训练后程序会在runs/detect/train/目录下生成三个关键文件best.pt验证集上表现最好的权重、last.pt最后一个epoch的权重、以及results.png损失曲线和mAP曲线汇总图。4.3 如何判断训练是否正常很多人训练完只看mAP一个数字我建议多看一眼results.png里的损失曲线。一个健康的训练过程应该是train/box_loss、train/cls_loss呈下降趋势并趋于平稳。val/box_loss和val/cls_loss先下降后趋于平稳如果它们在后半段开始反弹那就是过拟合的征兆。metrics/mAP50持续上升并最终稳定metrics/mAP50-95也会上升但绝对值会低一些这个是正常的不用紧张。我第一次训练的时候发现val/cls_loss从第60个epoch开始一路狂飙但train/loss还在下降典型的过拟合。后来加了mixup概率和数据增强强度这个问题才缓解。所以判断训练好坏不能只看最终精度的绝对值损失曲线才是诊断瓶颈的关键。4.4 常见报错排查记录训练过程中我遇到过三个印象很深的报错在这里留个记录方便大家遇到时不慌报错一CUDA out of memory。这个最简单batch减半或降低imgsz再不行换更小的模型。但注意有时候是“缓存碎片”导致的不是真的显存不够把PC重启一下或者加个torch.cuda.empty_cache()也许就好了。报错二Label shape error或Assertion nf 0。几乎总是标签文件和数据文件对不上。最常见的是类别ID越界比如定义了nc1但标签里写了class_id1或者图片路径和标签路径不匹配。用脚本检查一下所有标签文件中的最大类别ID是否小于nc就能定位。报错三训练时loss为NaN。大概率是学习率太大或数据里有异常值如边框坐标超出图片范围。我会先检查标签文件里有没有w或h为0的情况把异常样本删掉再重试。5. 网页版部署让模型变成任何人都会用的工具训练完模型项目只完成了一半。如果你只是自己在命令行里跑推理那这个项目对非技术用户毫无价值。下一步是把模型封装成一个网页服务让用户上传一张图片或者打开一个摄像头地址就能看到检测结果。5.1 后端推理服务从PyTorch换成ONNX Runtime我推荐将训练好的模型导出成ONNX格式再用ONNX Runtime做推理。原因很简单ONNX Runtime不需要安装PyTorch完整环境体积小、启动快、推理速度也比PyTorch动态图模式更快。导出命令一行就够yolo export modelbest.pt formatonnx imgsz640 opset12导出后可以得到best.onnx在项目里用ONNX Runtime做推理import onnxruntime as ort import numpy as np import cv2 def load_onnx_model(onnx_path): providers [CUDAExecutionProvider if ort.get_available_providers() and CUDAExecutionProvider in ort.get_available_providers() else CPUExecutionProvider] session ort.InferenceSession(onnx_path, providersproviders) return session def preprocess_frame(frame, imgsz640): img cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w img.shape[:2] ratio min(imgsz / h, imgsz / w) new_w, new_h int(w * ratio), int(h * ratio) img_resized cv2.resize(img, (new_w, new_h)) canvas np.full((imgsz, imgsz, 3), 114, dtypenp.uint8) canvas[:new_h, :new_w] img_resized input_tensor canvas.astype(np.float32) / 255.0 input_tensor np.transpose(input_tensor, (2, 0, 1))[None, ...] return input_tensor, ratio, new_w, new_h def run_inference(session, frame, imgsz640): input_tensor, ratio, new_w, new_h preprocess_frame(frame, imgsz) inputs {session.get_inputs()[0].name: input_tensor} outputs session.run(None, inputs)[0] # outputs shape: (1, num_anchors, 41num_classes) boxes outputs[0, :, 0:4] scores outputs[0, :, 4] classes outputs[0, :, 5:] ...需要注意的是ONNX导出的输出是原始预测结果需要自己做NMS非极大值抑制过滤重复框。也可以用yolo.predict的streamTrue配合训练好的pt文件来完成推理但那样依赖太重生产环境不适合。5.2 Web界面设计要有监控工具的样子网页端我设计得很克制因为这不是一个花哨的演示Demo而是一个给管理员和巡查人员用的实用工具。页面上有三个核心区域导航区、视频展示区、告警信息区。导航区包括“实时监控”“图片检测”“历史记录”“系统设置”四个Tab。视频展示区接收后端推送的帧画面用Canvas绘制检测框和置信度。检测到吸烟行为时在画面顶部弹出红色警告条同时截帧保存到服务器。告警信息区以表格或列表形式展示最近20条告警记录包含时间、摄像头编号、置信度、截图缩略图。前端逻辑的核心是建立WebSocket连接const ws new WebSocket(ws://${window.location.host}/ws/video) ws.onmessage (event) { const blob event.data const url URL.createObjectURL(blob) const img document.getElementById(video-frame) img.src url }后端用FastAPI写一个WebSocket接口from fastapi import FastAPI, WebSocket from fastapi.responses import StreamingResponse, HTMLResponse import cv2, asyncio app FastAPI() app.websocket(/ws/video) async def video_endpoint(websocket: WebSocket): await websocket.accept() cap cv2.VideoCapture(args.source) # 摄像头源 while True: ret, frame cap.read() if not ret: break # 推理 画框 annotated_frame draw_detections(frame) # 编码为 JPEG _, jpeg cv2.imencode(.jpg, annotated_frame) await websocket.send_bytes(jpeg.tobytes()) await asyncio.sleep(0.05) # 控制帧率约20FPS cap.release()5.3 性能优化与硬件适配网页版跑起来之后你最可能遇到的问题就是摄像头拉了多路服务器CPU直接打满。这是所有“算法Demo”走向真实部署时都会撞上的墙。我总结了一套由浅入深的优化路径第一层推理输入端优化。不要每帧都对全分辨率图片做推理。用一个锁帧策略——每秒做2-3次全分辨率检测其余帧只显示上次检测的框同时用光流或者简单的帧差法检测画面变化。如果检测区域没变化就不重新推理。这个优化能把CPU占用直接降一半。第二层模型和推理框架优化。导出ONNX时开启动态量化或者直接下载官方的yolov8nnano模型体量只有s的三分之一。如果你的服务器有NVIDIA显卡把ONNX Runtime切换到TensorRT执行引擎推理速度能提升3到5倍。像GTX 1660 Ti这张卡TensorRT FP16模式下yolov8s的推理耗时可以从21ms降到6ms上下。第三层并发处理策略。FastAPI天然支持异步但你的推理函数是阻塞的多路摄像头同时请求时还是会卡。可以用一个线程池把推理任务排队前端只需要拿到最新一帧结果不需要保证每一帧都有响应。简单说就是“宁可丢帧也不积压”这和视频播放的背压控制是一个道理。配置方面我实测跑通的最小硬件配置是4核CPU 8GB内存 GTX 1660 Ti6GB。这个配置可以同时处理2路1080P摄像头的实时检测。如果只需要处理图片上传无独显的嵌入式设备也能跑只是速度会慢很多CPU推理一帧大概需要300-500ms。5.4 演示链接、本地启动和常见使用问题我打包好的项目代码里有完整的启动脚本。以YOLOv8版本为例项目目录结构是这样smoking-detection-web/ ├── app.py # FastAPI主入口 ├── config.yaml # 摄像头、模型、阈值等配置 ├── models/ │ └── best.onnx # 导出的ONNX模型 ├── static/ │ ├── index.html # 主页面 │ ├── style.css │ └── detect.js ├── utils/ │ ├── detector.py # 封装推理逻辑 │ ├── draw.py # 画框和标签 │ └── db.py # 告警记录SQLite存储 └── requirements.txt启动命令就三步conda create -n smoke python3.9 -y conda activate smoke pip install -r requirements.txt python app.py浏览器打开http://localhost:8000就能看到界面。直接把图片拖进页面可以立刻测试效果要测实时视频流就在config.yaml里把摄像头地址换成RTSP流地址重启服务即可。使用中常见问题我列两个问题一图片检测速度慢页面卡顿。先确认是不是用了CPU推理。如果是建议换一台有NVIDIA显卡的机器或者换成yolov8n模型。页面卡顿如果不是后端推理导致的检查是不是WebSocket没加压缩把JPEG质量从95降到80速度立刻上来了。问题二摄像头画面黑屏或延迟严重。绝大多数情况是RTSP流地址配置错误。用VLC播放器先验证一下该地址能不能打开排除摄像头本身的问题。延迟严重的话在OpenCV读取时加cv2.CAP_PROP_BUFFERSIZE参数把缓冲降到最小延迟能从3秒压到1秒内。6. 实际运行效果与模型边界哪些场景会漏检和误检这个部分很重要因为很多项目做完了Demo效果很好一到真实环境就拉胯。我花了一段时间做边界压力测试结论是吸烟检测模型的核心痛点不是“检不出”而是“分不清”。6.1 实测效果什么情况下能稳定识别我在自测数据上跑了一组对比模型用的是yolov8s输入640×640测试场景准确率召回率备注室内正常光线下吸烟96.2%94.8%最理想的场景室外逆光吸烟84.5%81.3%脸部过暗时漏检较多夜晚灯光昏暗76.8%72.4%烟头亮光不突出时明显下降距离超过8米65.2%58.7%小目标问题暴露人物侧脸吸烟88.9%86.1%比想象中好手部姿态帮了忙烟雾明显但烟被遮挡92.3%90.5%模型学习到了烟雾与嘴部姿态组合多人同屏部分吸烟90.1%87.6%不同人的手部姿态差异大从数据能看出除了极端昏暗和超远距离这两个物理极限场景大部分常规监控场景都能覆盖。但有一点值得强调模型定位是“吸烟行为辅助检测”不是“火灾烟雾报警器”。如果你的目标是大范围烟雾检测应该去买专业感烟探测器图像算法在这块的意义不大。6.2 误检高发场景与定位策略我总结了四个最容易误检的场景全都踩过一、吃东西。比如啃鸡腿、吃冰棍、吃棒棒糖手部到嘴边的动作和吸烟极其相似。这个误检很难彻底消除因为行为学上的动作模式实在接近。我能做的优化策略是在告警逻辑中加入“置信度阈值连续多帧确认”机制单帧检测到不告警连续3帧以上都检测到才触发告警。这个策略能过滤掉大部分瞬时动作的误报。二、手指夹着笔或其他细长物体。笔的形状、颜色都和烟接近而且停放在嘴边时几乎以假乱真。这种场景目前没有完美的解决办法但可以提示巡查人员人工复核。三、哭丧着脸的人脸皱纹。听起来离谱但真的发生过。有一个人嘴角的皱纹被模型识别成了烟。后来我发现是因为数据集里缺少老年人近距离面部样本加了这类负样本后问题基本消失。四、灯光下的香烟图腾/户外广告。室内广告牌上如果有香烟图案模型大概率会误检。这个问题可以通过在部署时设置“排除区域”Region of Interest来解决把广告牌区域框出来检测时跳过。6.3 提升精度的进阶思路如果基础模型效果达不到上线标准我建议从以下三个方向去优化成本从低到高数据层面增加负样本。这里的负样本不是完全无关的图片而是“容易混淆但不该报警”的图片——吃饭、喝水、叼棒棒糖、咬笔头等。用一个分类器辅助过滤或者直接把这些图片加到训练集中并标注为背景让模型学会“这不是smoking”。策略层面行为时序建模。单帧检测永远有信息瓶颈如果场景允许可以把连续几帧的检测结果输入一个LSTM或Transformer判断“手部是否从低位移动到嘴部”这个动作轨迹能大幅减少静态误检。模型层面用YOLOv8-Pose姿态估计代替普通检测。先检测人体骨架关键点再根据手部相对于脸部的空间关系判断是否在吸烟。这个方案精度最高但工程复杂度也最大适合作为接下来的进阶方向。7. 模型部署的进阶玩法从本地到边缘端网页版跑通之后很多人会想更进一步能不能部署到嵌入式设备、能不能用C做高性能推理、能不能做到完全离线运行。这些确实是生产环境里的真实需求。7.1 ONNX、TensorRT与OpenVINO的选型与转换选择推理引擎时要看目标硬件NVIDIA显卡首选TensorRT。推理速度是ONNX Runtime的2-4倍支持FP16和INT8量化。转换时需要注意固定输入尺寸动态尺寸会让TensorRT的优化效果大打折扣。Intel CPU用OpenVINO工具包。它在Intel CPU上的加速效果非常突出而且支持把模型转换为更低bit的INT8模型16GB内存的工控机也能跑得很流畅。无特定平台要求ONNX Runtime是最平衡的选择跨平台、易部署、性能也不差。转换时有个常见的坑PyTorch模型里的某些自定义算子如Focus层在导出ONNX时可能会报错或不兼容。遇到这种情况最简单的办法是检查Ultralytics官方是否更新了对应的算子支持或者先转成torchscript再转ONNX。7.2 在JetSon等嵌入式设备上部署的注意事项我试着在Jetson Nano和Jetson Orin上跑过这个项目。注意几点嵌入式设备的算力很低yolov8s在Jetson Nano上用TensorRT FP16推理大约能跑15FPSyolov8n会更快一些。摄像头输入建议直接接CSI摄像头走硬件编解码走USB会占CPU。不要在设备上安装整一套PyTorch环境只装ONNX Runtime或TensorRT的Python绑定就行。# NVIDIA Jetson设备上的推荐安装方式 pip install onnxruntime-gpu --extra-index-url https://repo.download.onnxruntime.ai/jetson/7.3 C集成给后续扩展留一条路如果你需要把吸烟检测能力集成到C项目里推荐从ONNX Runtime的C API入手。代码量不大核心就是创建Session、准备输入输出、执行推理这三步。网上也有不少开源示例仓库直接搜“onnxruntime c yolov8”就能找到。8. 最后分享两个小经验第一个关于数据集版权。从影视剧、短视频平台截取的图片仅可用于个人学习和技术验证如果要商用必须换成自己采集的数据或者购买有授权的数据集。这一点在项目早期就要想清楚不然等模型上线了再替换数据成本会非常酸爽。第二个关于项目的可解释性。模型检测出“吸烟”时最好在界面上同时显示裁剪下来的局部证据图。这不仅是给管理员复核用的也是给后续AI审计准备的。任何部署到公共区域的AI行为识别系统都需要“能解释、可追溯”的证据链这一点会越来越重要。我把整套代码和数据集都整理好了YOLOv5/v6/v7/v8每个版本都有对应的训练脚本和网页部署代码。建议你先从YOLOv8版本开始跑通流程再回头对比其他版本的差异。真遇到问题的时候把报错信息贴出来大家一起排查比我一个人在这里写经验要快得多。
返回列表