YOLOv7口罩检测实战:从数据标注到TensorRT部署全链路

发布时间:2026/10/10 12:07:09

YOLOv7口罩检测实战:从数据标注到TensorRT部署全链路 简介本资源提供一套基于Yolov7的口罩检测模型面向计算机视觉学习者、防疫监控开发者及需要目标检测落地的工程人员可识别戴口罩、未戴口罩和未戴好口罩三类情况适用于公共场所防疫、企业园区安全与智能硬件集成等场景。压缩包共150个文件约669.41MB包含24个py脚本、26个yaml配置、4个pt权重文件以及jpg、png图像样本、xml标注、sh运行脚本、Dockerfile和pdf说明文档覆盖训练、推理与部署所需的主要材料。目前已有3047人学习下载。模型精度约93%保存在runs文件夹中附带详细使用教程与多模型选择读者可据此快速加载权重完成推理并理解Yolov7的单阶段检测原理、多任务损失函数与实时检测流程适合作为课程设计、项目原型或二次开发的基础方案。1. 基于 YOLOv7 的口罩检测模型从标注到部署一条能跑通的链路口罩检测这件事说简单也简单无非是「有人脸、有口罩、判断戴没戴」说难也难难在真实场景里人脸尺度差异大、遮挡多、光照乱模型很容易在「露鼻子」和「没戴」之间反复横跳。基于 YOLOv7 的口罩检测模型本质是把 YOLOv7 这个单阶段检测器拿来做二分类或三分类任务戴口罩、未戴口罩有时再加一类「佩戴不规范」。它适合谁适合手头有几百到几千张现场图、想快速搭一套能落地的检测服务的人也适合已经用过 YOLOv5、想看看 YOLOv7 在密集小目标上到底强在哪的人。这一篇不讲空泛原理只讲我实际做下来能复现的路径数据怎么标、配置怎么改、训练怎么盯、部署怎么不翻车。2. YOLOv7 做口罩检测选型理由和最小数据闭环2.1 为什么是 YOLOv7而不是 v5 或 v8YOLOv7 在 5 FPS 到 160 FPS 范围内精度和速度的平衡做得比较激进。口罩检测的典型场景是出入口闸机、公交站台、工厂车间这些地方往往需要同时处理多路视频流单帧推理时间直接决定你能开几路。YOLOv7 的 E-ELAN 结构让模型在不增加太多计算量的前提下增强了特征提取能力对小目标口罩区域更友好。另一个现实原因是YOLOv7 的 anchor 机制和损失函数设计对「戴口罩」和「未戴口罩」这种类间差异小、类内差异大的任务收敛比 v5 稳一些。当然如果你手里只有几百张图v5 可能更快出结果但如果你打算把模型推到边缘设备上跑YOLOv7 的 tiny 版本和裁剪空间更值得折腾。2.2 数据标注三类标签的边界怎么定口罩检测的数据标注最容易翻车的地方不是画框而是类别定义。我一般会分成三类mask规范佩戴口罩、no_mask口鼻完全暴露、incorrect口罩拉到下巴、露鼻子、只挂耳朵。如果业务只关心「戴没戴」可以合并成两类但合并后模型对「不规范佩戴」的误判率会上升因为这类样本的特征介于两者之间。标注时框要贴紧口罩区域不要把人脸整个框进去否则模型会学到人脸特征而不是口罩特征。每类建议至少 800 到 1000 个实例且要覆盖侧脸、低头、逆光、多人重叠这些情况。数据量不够时优先补incorrect和no_mask因为这两类在真实场景里更少但更关键。2.3 从原始图片到 YOLO 格式转换脚本与目录结构YOLOv7 沿用 YOLO 系列的标注格式每张图对应一个.txt每行class_id x_center y_center width height全部归一化到 0 到 1。如果你用 LabelImg 或 CVAT 标的是 VOC 的 XML需要转一道。下面这个脚本是我常用的支持 VOC 转 YOLO并自动划分训练集和验证集。import os import random import xml.etree.ElementTree as ET from pathlib import Path # 类别映射顺序要和 data.yaml 里的 names 一致 CLASS_MAP {mask: 0, no_mask: 1, incorrect: 2} def voc_to_yolo(xml_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASS_MAP: continue cls_id CLASS_MAP[name] 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_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return lines def split_dataset(img_dir, xml_dir, out_dir, val_ratio0.2): img_dir Path(img_dir) xml_dir Path(xml_dir) out_dir Path(out_dir) for sub in [images/train, images/val, labels/train, labels/val]: (out_dir / sub).mkdir(parentsTrue, exist_okTrue) # 假设图片是 jpgXML 和图片同名 all_imgs list(img_dir.glob(*.jpg)) random.shuffle(all_imgs) val_count int(len(all_imgs) * val_ratio) for idx, img_path in enumerate(all_imgs): xml_path xml_dir / (img_path.stem .xml) if not xml_path.exists(): continue # 这里需要读取图片真实宽高示例用 PIL from PIL import Image with Image.open(img_path) as im: w, h im.size lines voc_to_yolo(xml_path, w, h) if not lines: continue split val if idx val_count else train # 复制图片 import shutil shutil.copy(img_path, out_dir / fimages/{split} / img_path.name) # 写标签 with open(out_dir / flabels/{split} / (img_path.stem .txt), w) as f: f.write(\n.join(lines)) if __name__ __main__: split_dataset(./raw_images, ./raw_xml, ./dataset, val_ratio0.2)这段脚本做了三件事解析 XML、归一化坐标、按比例划分。参数val_ratio控制验证集比例小数据集建议 0.15 到 0.2大数据集可以降到 0.1。注意CLASS_MAP的顺序必须和后面data.yaml里的names完全一致否则训练时类别会错位模型会把「戴口罩」学成「未戴口罩」这种错误在推理阶段很难发现属于血泪经验。2.4 data.yaml 和超参文件的最小改动YOLOv7 官方仓库里data目录下有一堆 yaml自己建一个mask.yaml就行。内容如下train: ./dataset/images/train val: ./dataset/images/val nc: 3 names: [mask, no_mask, incorrect]nc是类别数names顺序和脚本里的CLASS_MAP对应。超参文件hyp.scratch.p5.yaml里我一般只动三个地方lr0从 0.01 降到 0.005因为口罩数据集通常不大学习率太大会震荡mosaic保持 1.0但如果你发现小目标漏检多可以降到 0.5让模型多看原图scale从 0.5 调到 0.3避免过度缩放导致口罩纹理丢失。这些改动不是绝对的但能帮你少走几轮弯路。3. 训练 YOLOv7 口罩检测模型命令、参数和盯盘技巧3.1 环境准备和权重下载训练前先把环境搭好。我习惯用 conda 建一个 Python 3.8 或 3.9 的环境PyTorch 选 1.12 以上CUDA 版本跟显卡驱动匹配。YOLOv7 官方依赖里requirements.txt直接装就行但注意torch和torchvision最好按官网命令单独装避免版本冲突。权重方面从官方仓库下载yolov7.pt或yolov7-tiny.pt放在项目根目录。如果你打算在边缘设备上跑直接选 tiny 版本精度掉得不多速度提升明显。# 创建环境 conda create -n yolov7_mask python3.9 -y conda activate yolov7_mask # 安装 PyTorch以 CUDA 11.3 为例 pip install torch1.12.1cu113 torchvision0.13.1cu113 --extra-index-url https://download.pytorch.org/whl/cu113 # 安装 YOLOv7 依赖 pip install -r requirements.txt3.2 训练命令拆解每个参数都影响收敛单卡训练的命令如下我逐段解释python train.py \ --weights yolov7.pt \ --cfg cfg/training/yolov7.yaml \ --data data/mask.yaml \ --hyp data/hyp.scratch.p5.yaml \ --epochs 150 \ --batch-size 16 \ --img-size 640 640 \ --device 0 \ --workers 8 \ --name mask_exp \ --project runs/train--weights指定预训练权重从 COCO 上迁移过来比从头训快很多。--cfg是模型结构文件如果你用 tiny 版本换成yolov7-tiny.yaml。--batch-size根据显存调8G 显存跑 640 尺寸大概能到 1612G 可以到 32。--img-size建议保持 640除非你的口罩目标特别小可以试 1280但显存和速度会成倍变化。--workers是数据加载线程Linux 下可以设 8Windows 下设 0 或 2不然容易卡死。--name是实验名训练日志和权重会存到runs/train/mask_exp下。3.3 训练过程盯什么loss 曲线和 mAP 的异常信号训练启动后终端会打印每个 epoch 的 box loss、obj loss、cls loss 和 mAP0.5。我一般重点看三个信号第一box loss 在前 10 个 epoch 应该明显下降如果几乎不动检查学习率是不是太小或者数据标注有问题第二cls loss 如果一直很高说明类别不平衡incorrect类样本太少需要补数据或者用类别权重第三mAP0.5 在 50 epoch 后如果还在 0.5 以下大概率是 anchor 不匹配可以用kmeans重新聚类 anchor。另外验证集 loss 如果连续 20 个 epoch 不降就可以考虑早停别硬跑满 150 轮浪费时间还容易过拟合。3.4 推理验证用 detect.py 看单张图效果训练完先别急着导出用detect.py跑几张验证图看看python detect.py \ --weights runs/train/mask_exp/weights/best.pt \ --source ./test_images \ --img-size 640 \ --conf-thres 0.4 \ --iou-thres 0.45 \ --device 0 \ --save-txt--conf-thres是置信度阈值口罩检测建议从 0.4 起步太低会出很多误检太高会漏掉侧脸。--iou-thres控制 NMS 的合并程度0.45 是比较稳的值。--save-txt会把检测框存成 txt方便你后续做统计。如果发现「未戴口罩」被大量误判成「戴口罩」先别改阈值回去看训练集的no_mask样本是不是太少或者标注框是不是把口罩区域也框进去了。4. 口罩检测模型部署从 PyTorch 到 ONNX 再到 TensorRT4.1 导出 ONNX 的坑动态轴和 opset 版本YOLOv7 官方提供了export.py但直接跑可能会遇到两个问题一是 opset 版本太低导致某些算子不支持二是动态 batch 没开部署时只能跑固定 batch。我一般用 opset 12并显式指定动态轴python export.py \ --weights runs/train/mask_exp/weights/best.pt \ --grid \ --img-size 640 640 \ --batch-size 1 \ --dynamic \ --simplify \ --opset 12 \ --include onnx--dynamic让 batch 和尺寸可变--simplify会调用 onnx-simplifier 去掉冗余节点。导出后用onnxruntime跑一遍确认输出和 PyTorch 一致。如果遇到Unsupported operator多半是 opset 太低升到 12 或 13 再试。4.2 TensorRT 加速FP16 和 INT8 怎么选如果你在 NVIDIA 边缘设备上部署TensorRT 是绕不开的。FP16 基本无损速度比 FP32 快一倍左右INT8 需要校准集精度会掉 1 到 3 个点但速度再翻一倍。口罩检测这种任务FP16 通常够用除非你跑在 Jetson Nano 这种算力很紧的设备上才考虑 INT8。转换命令如下trtexec \ --onnxbest.onnx \ --saveEnginebest_fp16.engine \ --fp16 \ --workspace2048 \ --minShapesimages:1x3x640x640 \ --optShapesimages:4x3x640x640 \ --maxShapesimages:8x3x640x640--workspace是显存工作空间2048MB 一般够用。--minShapes、--optShapes、--maxShapes定义了动态尺寸范围根据你实际并发路数调整。转换完成后用trtexec --loadEnginebest_fp16.engine --shapesimages:4x3x640x640跑一下 benchmark看单帧延迟和吞吐。4.3 后处理对齐别让 NMS 拖垮精度ONNX 和 TensorRT 导出的模型输出通常是三个尺度的特征图需要自己做解码和 NMS。很多人直接抄 YOLOv5 的后处理但 YOLOv7 的 anchor 和输出排列不一样抄错了会导致框全部偏移。我一般会拿同一张图分别用 PyTorch 和部署端跑把框画出来叠在一起看如果偏移超过 2 个像素就是解码公式错了。另外NMS 的iou_thres在部署端要和训练时保持一致否则会出现「训练时好好的部署后框全没了」的玄学问题。5. 口罩检测避坑5 个我踩过的真实翻车点5.1 现象模型把「未戴口罩」全判成「戴口罩」原因训练集里no_mask样本太少且很多是远距离小目标模型学到了「人脸戴口罩」的捷径。解决补 300 张以上近距离no_mask图并在hyp里把cls损失权重调高或者用 focal loss 替换默认的 BCE。5.2 现象训练 loss 正常下降但 mAP 一直卡在 0.3原因anchor 尺寸和实际口罩框不匹配YOLOv7 默认 anchor 是基于 COCO 的口罩框通常更扁更小。解决用kmeans对自己的标注框重新聚类生成 9 个 anchor替换yolov7.yaml里的anchors。5.3 现象部署后推理速度只有训练时的三分之一原因后处理用了 Python 循环或者 NMS 在 CPU 上跑没放到 GPU。解决把解码和 NMS 写成 CUDA kernel 或使用 TensorRT 插件至少也要用 NumPy 向量化别用 for 循环遍历每个框。5.4 现象同一张图PyTorch 和 ONNX 结果差很多原因预处理没对齐PyTorch 用的是 letterbox 填充ONNX 导出时没把 letterbox 参数带进去导致缩放比例不一致。解决在导出时把 letterbox 的缩放和填充参数固定下来部署端严格按同样逻辑处理或者直接用--grid让模型输出原图坐标。5.5 现象模型在白天很准晚上全瞎原因训练集几乎全是白天图模型没学过低照度下的口罩纹理。解决补夜间样本或者在前处理加自适应直方图均衡化但注意均衡化后的图要和训练时预处理一致否则又是新的坑。6. 把 mAP 再提 3 个点一个我常用的验证技巧训练完模型别只看 mAP0.5那个指标在口罩检测里容易虚高。我习惯做一个「分场景验证」把验证集按光照、遮挡、人脸尺寸分成几组分别算每组的召回率和误检率。具体做法是在test.py里加一段按文件名前缀分组的逻辑比如day_、night_、crowd_然后输出每组的指标。这样你能清楚看到模型到底在哪类场景下拉胯而不是被一个平均分骗过去。# 在 test.py 的验证循环后加一段分组统计 groups {day: [], night: [], crowd: []} for path, pred in zip(img_paths, predictions): for key in groups: if key in path: groups[key].append(pred) # 然后对每个 group 单独算 mAP这个技巧帮我省了很多「盲目调参」的时间。有一次白天 mAP 0.89晚上只有 0.52我直接补了 200 张夜间图晚上 mAP 拉到 0.78比改任何超参都管用。另外如果你打算长期维护这个模型建议把验证集固定下来每次训练完都跑一遍分组指标形成趋势记录。我自己的习惯是每换一次数据集或改一次 anchor就重新跑一次分组验证把结果记在表格里时间长了就能看出哪些改动是真有效哪些只是随机波动。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/10 12:07:09

2026年10月行业调研:跨境电商批量跨境翻译工具哪个好

本人10月行业调研跨境电商批量跨境翻译工具哪个好现在越来越多跨境电商卖家布局多站点运营,覆盖欧美、东南亚、拉美等多个不同语言市场,从商品listing文本到主图详情页文字,再到短视频字幕,都需要批量转换为当地语言。人工翻译不仅…

2026/10/10 16:34:01

羽毛球轨迹预测代码解析:从数据预处理到STGCN建模

简介:本资源是一套基于深度学习的轨迹预测完整实现代码,面向人工智能初学者、高校学生及轨迹分析方向的研究者,解决船舶、车辆等移动对象未来位置预测的实际建模问题。压缩包共11个文件,含7个核心Python脚本(如lstm模型…

2026/10/10 16:34:01

OpenCV车牌识别从定位到模板匹配:Python完整流水线实战

简介:PythonOpenCV车牌自动识别实战项目,面向计算机视觉初学者与智能交通开发者,完整演示了从图像预处理、车牌定位、字符分割到模板匹配识别的全流程。资源包含2000个文件,包括1999张JPG图片和1个Python源码文件,压缩…

2026/10/10 16:34:01

DeepLabv3+图像分割实战:从Pytorch环境搭建到Cityscapes训练避坑

简介:面向图像分割学习者和算法工程师的DeepLabv3实战资源,基于Pytorch在VOC与Cityscapes两个公开数据集上完成训练、验证与推理,覆盖数据加载、数据增强、网络定义、损失函数、学习率策略、评估指标和可视化等关键环节,适合快速上…

2026/10/10 16:34:01

STM32基础1:嵌入式历史与生态

嵌入式历史与生态 目录 嵌入式历史与生态 一、历史生态问题 1.1.计算机发展的底层驱动 1.2.军转民 1.3.摩尔定律 1.4.通用与专用 1.5.嵌入式系统的诞生 1.6.嵌入式命名的由来 二、认识计算机 2.1.个人电脑(PC) 2.2.智能手机、平板电脑 2.3.…

2026/10/10 16:34:01

短剧内容自动化生产:知漫剧工作室落地教程

短剧工作室接单,最愁的不是没活,是活接不动:跨五六个软件做一条片,导文件、对序号、等渲染,产能全耗在搬运上。近期一轮工作室工具横评中被反复提及的知漫剧(zz.jiaxunai.cn),主打站…

2026/10/10 7:31:36

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/9 20:15:56

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/8 6:05:44

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 0:04:53

从逻辑门到计算机:数字电路核心原理与全加器搭建实战

如果你拆过一台旧电脑的主板,盯着那些黑乎乎的小芯片看上一会儿,可能会冒出同一个疑问:这堆引脚密集的元件,到底是怎么“变”出那么复杂的应用的?答案并不在某个神秘的部件里,而是在所有芯片内部都在反复使…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑