
简介本资源为基于Yolov7的口罩检测模型面向计算机视觉学习者、防疫监控开发者及目标检测项目实践者可识别戴口罩、未戴口罩和未戴好口罩三类情况适用于公共场所防疫、企业园区安全与智能硬件集成等场景。压缩包共150个文件约669.41MB包含24个py训练与推理脚本、26个yaml模型配置、4个pt权重文件以及jpg、png图像样本、xml标注、sh运行脚本和md说明文档覆盖数据准备、模型训练到部署推理的完整流程。模型精度约93%支持实时检测项目内提供详细使用教程与多模型选择便于快速加载推理。已有3045人学习下载适合希望掌握Yolov7目标检测实战、复用预训练权重并落地口罩佩戴检测的读者参考。1. 基于 YOLOv7 的口罩检测模型从数据集到部署一条能跑通的路口罩检测这件事说大不大说小也不小。2020 年那会儿我接过一个园区入口的活要求对进出人员是否佩戴口罩做实时判断误报率还得压得住。当时试过两阶段检测器速度上不去也试过分类模型滑动窗口框位置飘得厉害。最后落到 YOLOv7 上才算把精度和帧率同时按住。基于 YOLOv7 的口罩检测模型本质就是把「人脸 口罩」这个二分类或三分类目标检测任务交给一个单阶段、Anchor-free 风格的检测头去跑输入一张图直接输出每个人脸框以及框内是否戴口罩。它适合谁适合手里有几百到几千张标注图、想在一周内跑出一个能演示甚至能上边缘设备的从业者。这篇文章不讲论文只讲我踩过的路数据怎么标、YOLOv7 的配置文件怎么改、训练参数怎么调、部署时哪些坑会让你前功尽弃。2. 数据集准备与 YOLOv7 格式转换别让标注毁掉训练2.1 口罩检测的数据从哪来、怎么标口罩检测的数据集公开的不少但直接拿来用往往翻车。常见做法是一部分用公开数据比如 RMFD 这类口罩人脸数据集一部分自己补拍。补拍时注意三个点第一场景要覆盖你实际部署的环境室内白光、室外逆光、夜间补光各来几百张第二口罩类型要杂医用蓝、N95、黑色布口罩、甚至下巴兜着没戴好的都要有否则模型会把「蓝色」当成口罩特征第三负样本不能少也就是没戴口罩的人脸比例大概占 20% 到 30%不然模型见谁都框成口罩。标注用 LabelImg 或 CVAT 都行类别我一般设三类face_mask规范佩戴、face_no_mask未佩戴、face_mask_incorrect佩戴不规范比如露鼻子。如果只做二分类就把后两类合并成no_mask。标的时候框要贴着脸部轮廓别把整个头框进去YOLOv7 对框的宽高比敏感框太松会让回归分支学得吃力。2.2 从 VOC/COCO 转成 YOLO 格式的脚本与四个边界坑YOLOv7 吃的是 YOLO 格式的 txt每行class_id x_center y_center width height全部归一化到 0 到 1。如果你手里是 VOC 的 XML用下面这个脚本转我用了三年稳。import os import xml.etree.ElementTree as ET # 类别映射顺序必须和 data.yaml 里的 names 一致 CLASS_MAP {face_mask: 0, face_no_mask: 1, face_mask_incorrect: 2} def convert_voc_to_yolo(xml_dir, out_dir, img_w, img_h): os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() # 有些数据集 size 字段缺失必须兜底否则归一化全错 size root.find(size) w int(size.find(width).text) if size is not None else img_w h int(size.find(height).text) if size is not None else img_h 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) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 边界裁剪防止标注越界导致归一化后出现负数 x1, y1 max(0, x1), max(0, y1) x2, y2 min(w, x2), min(h, y2) if x2 x1 or y2 y1: continue # 宽高为 0 的脏框直接丢 xc (x1 x2) / 2.0 / w yc (y1 y2) / 2.0 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) with open(os.path.join(out_dir, xml_file.replace(.xml, .txt)), w) as f: f.write(\n.join(lines)) convert_voc_to_yolo(./annotations, ./labels, 640, 640)逻辑说明脚本先读 XML 的 size 字段拿真实宽高拿不到就用传入的默认值兜底这是第一个坑——很多公开数据集 size 是错的不兜底归一化全废。第二个坑是边界裁剪标注框超出图像范围时不裁剪会算出负坐标训练时 loss 直接 NaN。第三个坑是宽高为 0 的脏框必须跳过。第四个坑是类别映射顺序必须和后面data.yaml里的names严格一致差一位模型就学反。参数上img_w和img_h只在 size 缺失时生效建议填你实际训练分辨率比如 640。转换完抽查几个 txt用wc -l看行数是否和标注框数量对得上。2.3 data.yaml 与目录结构YOLOv7 认死的路径YOLOv7 官方仓库对目录结构有约定不按它来训练脚本会报「No labels found」。我一般这样组织dataset/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml内容train: ./dataset/images/train val: ./dataset/images/val nc: 3 names: [face_mask, face_no_mask, face_mask_incorrect]注意train和val写的是图片目录YOLOv7 会自动把images替换成labels去找标签。所以图片和标签的文件名必须一一对应只差扩展名。我见过有人把标签放同级目录结果训练 loss 一直不降查了半天是标签根本没加载。划分比例上train:val 我一般 8:2如果数据少于 500 张用 9:1val 只做监控不做调参。3. YOLOv7 口罩检测的训练配置参数怎么设、显存怎么省3.1 选哪个配置文件yolov7.yaml 还是 yolov7-tiny.yamlYOLOv7 官方提供好几个配置yolov7.yaml、yolov7x.yaml、yolov7-tiny.yaml、yolov7-w6.yaml等。口罩检测这个任务目标单一、类别少我的血泪经验是别一上来就上 yolov7x。yolov7x 参数量大在 1080Ti 上 batch size 只能开到 4训练慢还容易过拟合。常规选择配置文件参数量级适用场景显存建议yolov7-tiny.yaml最小边缘设备、Jetson、树莓派4G 够yolov7.yaml中等服务器训练、精度优先8G 起yolov7x.yaml大数据量 1 万张12G 起我一般先用yolov7-tiny.yaml跑一版 baseline看 mAP 能不能到 0.85不够再换yolov7.yaml。改类别数只改一处配置文件里的nc从 80 改成 3。别去动 anchorYOLOv7 是 anchor-free 的改了反而乱。3.2 训练命令与关键参数逐条拆解训练入口是train.py我常用的命令python train.py \ --weights yolov7.pt \ --cfg cfg/training/yolov7.yaml \ --data data/mask_data.yaml \ --hyp data/hyp.scratch.p5.yaml \ --epochs 100 \ --batch-size 16 \ --img-size 640 640 \ --device 0 \ --workers 8 \ --name mask_yolov7逐条说--weights yolov7.pt是加载 COCO 预训练权重口罩检测数据少不加载预训练基本训不动这是最重要的一条。--cfg指向你改过nc的配置文件。--hyp是超参文件口罩检测我建议把hyp.scratch.p5.yaml里的mosaic从 1.0 降到 0.5因为 mosaic 四图拼接会让小脸口罩样本变形严重降一点更稳。--img-size640 是甜点值再大显存吃不消再小人脸糊。--batch-size根据显存调8G 卡用 1612G 用 32。--workers是数据加载线程设成 CPU 核数的 0.8 倍设太高反而抢资源。训练过程中盯三个指标box_loss、obj_loss、mAP0.5。正常情况 box_loss 从 0.1 降到 0.02 左右obj_loss 从 0.05 降到 0.01。如果 obj_loss 不降反升八成是标签路径错了或者类别数不对。3.3 显存不够时的三个降级手段显存爆了别急着换卡按顺序试这三招。第一降--batch-size从 16 降到 8梯度累积用--accumulate补回来比如 batch 8 加 accumulate 2 等效 batch 16。第二开混合精度加--amp能省 30% 显存精度损失可忽略。第三降--img-size到 512但注意512 训练完推理也用 512别训练 512 推理 640尺度不匹配 mAP 掉得厉害。这三招我一般组合用1080Ti 上跑 yolov7.yaml 加 amp 加 batch 8能稳住。4. 推理、评估与部署从 mAP 到实际帧率4.1 用 detect.py 跑通第一张图训练完权重在runs/train/mask_yolov7/weights/best.pt。先别急着部署用detect.py验证python detect.py \ --weights runs/train/mask_yolov7/weights/best.pt \ --source ./test_images \ --img-size 640 \ --conf-thres 0.4 \ --iou-thres 0.45 \ --device 0--conf-thres是置信度阈值口罩检测我设 0.4比默认 0.25 高因为误检一个「没戴口罩」比漏检更麻烦。--iou-thres是 NMS 的 IoU 阈值0.45 是常规值如果发现同一个人脸出两个框降到 0.4。--source可以是单张图、文件夹也可以是0摄像头。跑完看runs/detect/下的结果图重点看逆光和侧脸有没有漏。4.2 评估指标怎么看mAP0.5 不是唯一test.py会输出每个类别的 P、R、mAP0.5、mAP0.5:0.95。口罩检测里face_no_mask的召回率比精确率重要因为漏掉一个没戴口罩的人防控就形同虚设。我一般要求face_no_mask的 R 不低于 0.9P 可以放宽到 0.8。如果 R 低调低--conf-thres到 0.3 再测如果 P 低说明误检多回去查负样本够不够。mAP0.5:0.95 这个指标在口罩检测里参考价值有限因为口罩框的 IoU 本来就难做高别死磕。4.3 部署到边缘设备的两个现实问题部署到 Jetson 或 RK3588 这类设备第一件事是转模型。YOLOv7 转 ONNX 再转 TensorRT或者用 ncnn。转 ONNX 时注意--grid参数YOLOv7 的输出层有 grid 操作不处理会导致输出维度对不上。第二件事是预处理对齐训练时用的是 letterbox 填充部署时也必须 letterbox否则长宽比一变框全飘。我见过有人部署时直接 resize结果 mAP 从 0.88 掉到 0.6查了两天才发现是预处理不一致。帧率上yolov7-tiny 在 Jetson Xavier NX 上 TensorRT FP16 能到 30 FPS 左右yolov7 大概 12 FPS够用不够用看你场景。5. 避坑与排查五个让我熬夜的口罩检测问题5.1 现象训练 loss 正常但 mAP 一直是 0原因最常见的是data.yaml里names顺序和标注时的类别映射不一致模型学的是反的。其次是 val 集图片和标签没对上评估时找不到标签mAP 自然为 0。解决先跑detect.py看输出框的类别名对不对再检查labels/val下 txt 数量是否和images/val一致用ls | wc -l对比。5.2 现象模型把「没戴口罩」识别成「戴口罩」原因负样本太少或者负样本场景太单一。模型没学到「口罩」这个特征而是学到了「人脸」这个特征见谁都判戴口罩。解决补负样本尤其是不同光照、不同角度的未佩戴口罩人脸比例提到 30%。另外检查标注有没有把「露鼻子」错标成face_mask。5.3 现象推理时同一张脸出好几个框原因NMS 的iou-thres设太高或者模型对同一目标输出了多个高置信度框。解决把--iou-thres从 0.45 降到 0.4 甚至 0.35。如果还不行说明训练时hyp里的obj损失权重太低模型没学会抑制重复框可以适当调高obj系数。5.4 现象换到新场景 mAP 断崖下跌原因过拟合到训练场景的光照和背景。口罩检测模型很容易学到「背景是白色墙壁 戴口罩」这种伪特征。解决训练时开--mosaic和--mixup增强hyp里hsv_h、hsv_s、hsv_v调大一点让模型对颜色不敏感。另外新场景如果有条件补拍 100 张微调最后一层效果立竿见影。5.5 现象转 ONNX 后输出和 PyTorch 对不上原因YOLOv7 的导出脚本对--grid和--end2end参数敏感不处理 grid 会导致输出是原始特征图而不是解码后的框。解决导出时加--grid并且用官方export.py别自己写。导出后用onnxruntime跑一张图和 PyTorch 的输出逐元素对比误差超过 1e-3 就说明转换有问题。6. 把口罩检测模型压到 10MB 以内一个实用技巧模型训好了部署时发现权重 70 多 MB边缘设备存不下这是常事。我一般用「剪枝 量化」两步走但剪枝调参麻烦实际项目里我更常用的是INT8 量化 层融合简单且收益直接。以 TensorRT 为例先转 ONNX再用trtexec做 INT8 量化trtexec --onnxmask_yolov7.onnx \ --saveEnginemask_yolov7_int8.engine \ --int8 \ --calibcalibration_data.npz \ --workspace2048 \ --verbose--calib是校准数据从训练集里抽 200 到 500 张图覆盖各种光照校准表的质量直接决定量化后的精度。--workspace是显存工作区2048MB 够用。量化完yolov7-tiny 的权重能从 24MB 压到 7MB 左右yolov7 从 70MB 压到 20MB 以内推理速度还能提 1.5 到 2 倍。量化后必须做精度回归别信「无损」这种话。我一般跑一遍 val 集对比 FP32 和 INT8 的 mAP掉 2 个点以内可接受掉 5 个点以上说明校准数据没选好补一些逆光和暗光样本重新校准。另外INT8 对face_mask_incorrect这种细分类别影响最大如果这个类别重要考虑只对 backbone 做 INT8检测头保持 FP16。最后说个习惯每次训完模型我都会把hyp、data.yaml、cfg三个文件连同权重一起打包存档命名带日期。口罩检测这活需求方今天要加「露鼻子」类别明天要换场景没有存档复现就是玄学。希望帮到你。本文还有配套的精品资源点击获取