ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLOv5口罩检测实战:数据集标注、模型训练与部署全流程

YOLOv5口罩检测实战:数据集标注、模型训练与部署全流程 简介面向计算机相关专业毕业设计与项目实战的YOLOv5口罩佩戴检测完整项目包涵盖数据集、源码、训练好的模型与标注数据经导师指导并调试通过可直接用作毕业设计、课程设计或期末大作业也可作为学习目标检测的入门实战案例。压缩包共包含149个文件整体大小约139.76MB文件类型覆盖Python源码、模型配置、预训练权重、标注数据、示例图片以及Dockerfile环境配置与Jupyter教程等各类文件分工明确便于按需取用。目前已有238人学习下载适合正在准备毕设或希望系统掌握目标检测完整流程的学生。资源中还提供了训练好的模型和相应标注数据可直接运行进行推理也能基于自己的图片重新训练与验证配套脚本和文档对数据预处理、模型训练、性能评估等环节均有说明能帮助读者快速复现口罩佩戴检测流程并在此基础上进行改进与拓展。1. 先别急着跑代码这套口罩检测方案到底在解决什么问题很多找“基于YOLOV5口罩佩戴检测数据集系统代码训练好的模型标注好的数据.zip”的人其实已经见过类似的压缩包了。拆开一看里面有模型权重、训练脚本、标注文件但真正决定你能不能快速落地的不是那份训练好的best.pt而是那批标注好的数据。口罩检测本身不算一个特别难的目标检测任务绝大多数项目翻车都翻在数据格式对不上、标签顺序错位、训练集和实际场景分布不一致这些地方。这篇文章把这套资源拆成四个部分来讲数据集目录长什么样、标注文件里的数字怎么读、怎么用YOLOv5把模型训练出来、以及拿到best.pt之后怎么推理和验证。适合手里已经有这套资源但不知道怎么下手的初学者也适合想拿它当基线、再训练自己业务数据的工程师。整条链路走通之后你会发现真正的工作量并不在训练而在数据验收和模型验证上。2. 把数据集拆开看“标注好的数据”到底长什么样2.1 一个能直接用的口罩数据目录是什么结构你从压缩包里解压出来的数据大概率遵循YOLOv5训练时默认的目录习惯。不要小看这个目录结构很多人在第一步就把train和val路径写错导致训练脚本直接报“找不到图片”。mask-dataset/ ├── images/ │ ├── train/ │ │ ├── 000001.jpg │ │ ├── 000002.jpg │ │ └── ... │ ├── val/ │ │ ├── 010001.jpg │ │ └── ... │ └── test/ ├── labels/ │ ├── train/ │ │ ├── 000001.txt │ │ ├── 000002.txt │ │ └── ... │ ├── val/ │ │ ├── 010001.txt │ │ └── ... │ └── test/ ├── data.yaml └── classes.txt这里的核心规则是images/train里的每张jpg都要在labels/train里有一个同名同前缀的txt文件后缀从.jpg换成.txt。YOLOv5训练时不会去读classes.txt它只认data.yaml里写的类别名classes.txt一般是给你自己看的。train和val的划分比例常见的做法是8:2或者9:1test目录不是必须的很多人直接把val当测试用。还要注意一个老生常谈的坑整个项目的绝对路径里不要出现中文和空格。Windows用户尤其容易踩路径带中文时OpenCV读图可能正常但YOLOv5内部用Path处理路径时会出现莫名其妙的问题排查起来特别费时间。2.2 标注文件里每一行数字是怎么来的口罩检测的标注文件是YOLO格式的txt每张图片对应一个txt每一行代表一个目标框。打开任意一个文件你能看到类似这样的内容0 0.482031 0.354688 0.273438 0.418750 1 0.726562 0.681250 0.230469 0.356250这行5个数字分别代表类别id、框中心点的x坐标、框中心点的y坐标、框的宽度、框的高度。注意这里的坐标不是像素值而是归一化到0到1之间的比例值也就是用像素坐标除以图片的宽或高得到的。归一化的好处是同一份标注可以适配任意分辨率的图片模型训练时不管输入是640还是1280都不需要因为图片尺寸去改标注。看一段简单的解析代码你就能把这些数字翻译回像素坐标with open(labels/train/000001.txt, r) as f: for line in f: parts line.strip().split() cls_id int(parts[0]) x_c, y_c, w, h map(float, parts[1:]) print(f类别{cls_id}, 中心点({x_c:.3f}, {y_c:.3f}), 宽{w:.3f}, 高{h:.3f})# 转回像素坐标 img_w, img_h 1920, 1080 x1 (x_c - w / 2) * img_w y1 (y_c - h / 2) * img_h x2 (x_c w / 2) * img_w y2 (y_c h / 2) * img_h这段代码里的x_c和y_c是中心点比例所以换算到左上角坐标时要做减半操作。如果你发现某个框画出来明显偏到图片外面去了十有八九是标注人员把中心点坐标写成左上角坐标了这种错误只看txt里的数字很难发现必须可视化检查。2.3 训练之前先画一批框最值得做的验收动作标注数据最容易出现三类问题框贴得不紧、漏标、类别错标。这些在训练前检查一遍能省下后面好几个小时的排查时间。我一般会写一个批量可视化脚本随机抽200到300张图把框画出来直接看。import cv2 img_path images/train/000001.jpg label_path labels/train/000001.txt img cv2.imread(img_path) h, w img.shape[:2] with open(label_path, r) as f: for line in f: c, x, y, bw, bh map(float, line.split()) x1 int((x - bw / 2) * w) y1 int((y - bh / 2) * h) x2 int((x bw / 2) * w) y2 int((y bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(c)), (x1, y1 - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.imwrite(check_000001.jpg, img)这里有一个很典型的误区很多人以为标注质量可以用训练后的mAP来间接验证。如果模型最后mAP不低就觉得标注没问题。但目标检测模型对标注噪声有一定容忍度少量错框和漏框可能只会让mAP下降零点几个点而这些噪声直接导致预测框在实际使用时偏大偏小。把标注当黑匣子直接丢进训练出了问题是很难定位的。抽检画框是给自己留一颗后悔药尤其是当你打算把别人的数据集和自己新增的数据合并时原始标注风格是否统一直接决定要不要重标。如果抽检后发现类别顺序有问题比如0代表戴了口罩但data.yaml里把0写成了without_mask训练出的模型就会把结果完全颠倒。这种错误比标注框不贴还致命因为loss一样收敛模型一样能出框但业务上完全不可用。3. 用YOLOv5训练自己的口罩数据集配置、命令与超参数3.1 data.yaml三个路径最容易把新手卡住训练前要准备的核心配置文件就是data.yaml。这个文件决定了模型学什么也决定了数据从哪里读。一个最简版本的data.yaml长这样train: data/images/train val: data/images/val nc: 2 names: [without_mask, with_mask]很多人都以为train和val指向的是放图片的目录就够了其实YOLOv5会根据这个路径去推断labels目录的位置它会把路径里的images替换成labels所以如果你的图片在data/images/train标注文件就必须在data/labels/train一个字母都不能差。如果不想依赖这个隐式规则也可以用绝对路径比如/home/user/mask-dataset/images/train写绝对路径时图片和标注目录之间没有再替换规则只要能读就行。nc表示类别数量口罩检测通常是2对应names里两个名字。names列表的下标顺序必须和标注txt里第一列的整数完全一致。常见的做法是把不带口罩的类别放前面。如果数据里还有一类叫mask_weared_incorrect表示口罩戴得不规范那nc就是3names里也得对应三个名字。3.2 一条命令把训练跑起来先求跑通再求指标准备就绪后在YOLOv5代码目录下执行训练命令。第一次跑通建议所有参数都走默认不要一上来就调超参数。python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0weights参数填的是预训练权重文件yolov5s.pt这个文件在YOLOv5官方仓库的release页面里可以下载它的价值在于已经在COCO数据集上预训练过可以显著加快收敛速度。口罩检测的数据量一般不大几千张图的话100个epoch的耗时在单张RTX 3060上通常是1到3小时。训练产物会保存在runs/train/exp目录下里面weights子目录里的best.pt就是整个训练过程中在验证集上mAP最高的模型。这里有一个最常见的翻车点batch size设得太大显存直接爆掉。如果显存是8Gimg 640搭配batch 16很容易OOM这时候把batch降到8或者4或者把img降到416。img尺寸不一定是越大约好口罩目标在监控画面里往往占比较大416到640都能得到可用结果反而小输入能显著提升推理速度。如果训练中途log里出现警告说图片里没有标注目标优先检查数据路径而不是急着改参数。3.3 模型规模怎么选yolov5s不一定适合你的场景YOLOv5有n、s、m、l、x几个版本权重文件体积和推理速度差别很大。很多初学者默认选yolov5s但它不一定是最优解。模型体积和显存占用推理速度适合的场景yolov5n最小最快边缘设备、嵌入式板卡如RK3568、树莓派yolov5s适中性价比高快普通显卡训练CPU推理可接受yolov5m较大较慢对精度要求高且硬件不紧张的服务端yolov5l/x最大慢离线分析、小目标密集场景如果你只做闸机抓拍的口罩检测多数情况下yolov5s已经够了。但如果摄像头离人远人脸占比小就需要用yolov5m甚至更大因为小目标对特征分辨率更敏感。这里顺带说一句网上很多人喜欢对着YOLOv5网络结构图逐层背C3模块和SPP结构实际落地时这些不是最关键的。你需要知道的是Backbone负责提特征PANet负责融合不同尺度的特征Head负责在三个尺度上输出预测结果。真正需要关心的是结构图末尾的这些输出层和后面的NMS后处理它们决定了模型输出什么格式影响你后续写推理逻辑。3.4 超参数默认起步小步试错YOLOv5的训练超参数集中在data/hyps目录下的yaml文件里比如hyp.scratch-low.yaml。里面有lr0、lrf、mosaic、hsv_h这些名字。很多人一上来就按照网上搜到的“最佳学习率”去改结果模型反而训飞了。我的建议是第一次训练完全用默认超参数把注意力放在数据质量和epoch数上。如果确认数据干净、loss收敛但mAP一直上不去再去动超参数也不迟。比较值得试的两个改动是把mosaic从1.0降到0.5减少物体被裁断的概率或者把lr0从0.01调到0.02加速前几个epoch的收敛。超参数这事情很看重数据集分布本质上是带着玄学成分的调优每次只改一个变量改完就跑一组对比实验别同时动好几个参数。训练过程中盯住train/box_loss持续下降、val/box_loss在后期趋于平稳这两点比每次都看训练端mAP数字更实在。4. 从best.pt到实际检测推理与部署的最小闭环4.1 用detect.py先把单张图跑通训练结束后别急着部署先用官方自带的detect.py验证一遍best.pt是否正常工作。这里输入一张验证集图片指定权重路径和置信度阈值。python detect.py \ --weights runs/train/exp/weights/best.pt \ --source data/images/val/000001.jpg \ --conf-thres 0.4结果会输出到runs/detect/exp/目录保存的是画好框的结果图。conf-thres是置信度阈值低于这个值的检测结果会被丢弃。推荐先用0.4跑统计测试集再用0.25跑实际场景因为验证集的分布通常比线上场景要简单在验证集上0.5效果很好的阈值放到现场可能漏检。detect.py里的逻辑可以看作是标准预测管线的参考实现完整的预测流程包括图片缩放、归一化、模型前向传播、三个尺度解码、NMS非极大值抑制、坐标回映到原图。你后续写自己的推理脚本时最难写的是NMS和坐标回映很多人的推理结果框偏了就是忘了把缩放前的坐标换算回来。4.2 通过Python API把模型接进业务系统如果要做成实时检测服务把torch.hub加载和推理封装成一个函数会更方便。import torch model torch.hub.load( ultralytics/yolov5, custom, pathruns/train/exp/weights/best.pt, force_reloadTrue, ) results model(test.jpg, size640) df results.pandas().xyxy[0] print(df[[name, confidence, xmin, ymin, xmax, ymax]])torch.hub.load的第一个参数是仓库名第二个传custom表示加载自定义权重第三个path指定你的pt文件路径。返回的results对象里封装了原始tensor和边界框数据pandas()方法能直接把检测结果导出成DataFrame方便和业务逻辑对接。如果模型要跑在CPU上可以在加载后执行model.model.to(cpu)不过在CPU上做实时视频流检测会比较吃力yolov5s推理一帧640x640的图大约要100到200毫秒取决于CPU型号。4.3 边缘设备上的部署导出ONNX再量化如果你的目标是RK3568这类边缘板卡不能直接跑pt文件常见的做法是先导出ONNX再转RKNN。export.py是YOLOv5自带的转换脚本一条命令就能完成python export.py \ --weights runs/train/exp/weights/best.pt \ --include onnx \ --opset 12导出后的模型是yolov5s.onnx可以用ONNX Runtime加载也可以输入到RKNN-Toolkit2做量化转换。导出ONNX后一定要做一次精度对比测试因为部分算子在转换过程中会被替换或融合结果可能与PyTorch原始输出有差异。常见的做法是用同一张图分别跑pt和onnx对比框的坐标和置信度误差控制在很小的范围内才算通过。这里还有个容易忽略的细节export时默认会把NMS后处理排除在ONNX图之外也就是说onnx模型输出的是原始的预测张量后处理要自己在推理代码里写否则框会叠加非常多重复值。4.4 视频流和批量图片的推理参数差异detect.py的source参数支持文件夹、视频文件和视频流地址。处理视频时有个实用参数是--vid-stride表示每隔几帧抽一帧检测用来控制计算量。实时视频流场景需要关注推理耗时如果每帧推理超过50毫秒画面就会明显卡顿此时优先考虑降低输入尺寸而不是换更大的模型。需要处理大量历史录像时我一般把视频抽帧保存成jpg文件夹再走批量检测这样能并行加速也好排查中间哪一步出了问题。5. YOLOv5口罩检测常见问题5个高频翻车点与修复方法5.1 标签类别错乱模型输出的名字和实际框相反现象训练正常收敛但推理时明明框住了戴口罩的人打印出来却是without_mask。原因标注txt里的类别id和data.yaml里names列表的顺序不一致。比如txt里0代表不戴口罩但data.yaml里names写的是[with_mask, without_mask]模型学到的语义就被整体对调了。这类错误在合并多个来源的数据时特别容易发生不同批次的标注习惯可能不一样。解决训练前用2.3节的可视化脚本在框上同时打印出类别id和类别名抽查几十张确认对应关系。如果发现已经训练完了最简单的修复办法是重新标注一个小的子集做验证或者直接交换data.yaml里names的顺序再重训一次不用去改txt文件。5.2 训练报错No labels found或者图片路径一直找不到现象运行train.py后日志里出现大量图片加载失败的警告或者直接提示找不到标签文件loss一直是0。原因最多的情况是data.yaml里的train路径写错了。很多人只写了data/images但YOLOv5需要的是images/train这一层因为它是通过图片目录去推导标签目录的。其次是图片本身损坏jpg头文件缺失OpenCV读不出来但资源管理器能正常预览这种情况在网上下载的数据集里偶尔会出现。解决先去images/train目录下数一数图片数量再数labels/train下的txt数量确保一致。然后在train.py前加一行代码打印图片路径确认能被正确加载。如果怀疑图片损坏可以用Python把images目录遍历一遍逐张用cv2.imread读取失败的单独记录删除。5.3 检测不到目标置信度阈值只调小没用要看分数分布现象同一个模型验证集上mAP有0.9现场图片却一个框都出不来。原因第一种是conf-thres设得过高在detect.py里直接调低可能有用。第二种是模型过拟合了验证集训练时早停选出的best.pt是基于val指标的如果val分布和现场差异大现场图输出的置信度普遍偏低。口罩佩戴检测的数据集一般来自网络图片而实际现场的摄像头角度偏俯视光线也差分布偏移会直接拉低置信度。解决把detect.py的conf-thres降到0.1保存所有低置信度的框统计分数分布。如果大量正确目标卡在0.2到0.4之间说明模型对现场数据泛化不够优先补充现场角度的图片重新训练。靠调阈值只能临时放大recall代价是大量误检治标不治本。5.4 CUDA Out of Memory显存不足但不想降batch现象训练或推理时直接报CUDA OOM程序退出。原因显卡显存不足以容纳当前batch size下的计算图。很多人为了保持batch size不降硬改梯度累积结果调试半天代码效果还不一定好。解决最直接的做法是按显存减半batch。8G显存跑yolov5simg 640时batch降到8通常比较稳再不够就把img降到512或416。生产环境里推理时OOM常见原因是同时加载了多个模型实例或者tensor没有及时释放排查时先在推理循环里加一行del results和torch.cuda.empty_cache()观察显存占用曲线。5.5 mAP不算低但业务方反馈框不准现象Val mAP在0.85以上可是产品验收时发现框比人脸大一圈有时两个口罩框重叠在一起。原因边界框回归的精度不够或者NMS的IOU阈值设置过高导致重复框被保留。口罩检测场景对框的贴合度要求比较高如果框大一圈下游的口罩佩戴判断逻辑很容易碰到相邻的人脸。解决先在val.py上跑一遍看置信度阈值0.5时的mAP和框误差。如果框普遍偏大检查标注本身是否本身就画得宽松。其次把detect.py里的--iou-thres从默认值调低到0.3能有效抑制重复框。这两个参数一个控制框的可信度一个控制框的重复度调参逻辑完全不同新手容易混在一起改导致本来正常的检测结果越改越乱。6. 用PR曲线和混淆矩阵做验收一个值得养成的收尾习惯6.1 一条命令生成全套验证结果训练完成后不要只盯着训练日志里的mAP数字结束我习惯跑一次官方val.py把PR曲线和混淆矩阵图保留下来作为这个模型是否真正可用的判断依据。python val.py \ --data data.yaml \ --weights runs/train/exp/weights/best.pt \ --conf-thres 0.3 \ --iou-thres 0.5验证完成后runs/val/exp目录下会生成PR_curve.png和confusion_matrix.png。PR曲线是Precision和Recall在不同置信度阈值下的trade-off曲线曲线下面积就是每个类别的APmAP是所有类别AP的平均值。很多团队只看最后的mAP数字但mAP只能告诉你整体水平分辨不出哪一类最容易漏检、哪一类最容易误检。6.2 两个读图习惯先看曲线形态再看混淆矩阵我会先看PR曲线的右半段是否快速掉下来。如果Recall到0.4之后Precision还一直维持在高位说明模型的置信度排序比较健康反过来如果曲线在中段出现明显凹陷说明存在一批困难样本模型对它们的预测置信度普遍摇摆。这种场景下上线后调的置信度阈值应该选在曲线拐点附近而不是机械地取默认0.25。再看混淆矩阵重点看无口罩类被预测成有口罩的比例。在口罩检测业务里漏检和误检的代价完全不一样把没戴口罩的人漏掉是安全问题把戴了口罩的人误判成没戴是业务投诉。如果混淆矩阵显示误检偏高优先补充戴了口罩但背景复杂的人脸样本比盲目增加总样本量更有效。我有一个已经坚持很久的习惯每次训练完都把PR曲线和混淆矩阵截图放进项目文档下一个版本的模型迭代时翻出来对比。这样就能清楚知道模型是用在哪一步改进上而不是靠感觉说“又变准了”。这条验证流程算是整个口罩检测项目里性价比最高的收尾操作希望帮到你。本文还有配套的精品资源点击获取
返回列表