简介面向计算机相关专业毕业设计与课程设计需求这套基于YOLOv5的口罩佩戴检测项目打包了完整可复用的系统方案涵盖数据集、源码、训练好的模型以及标注数据适合正在做毕设或需要实战练习的初学者与进阶者。压缩包共149个文件内含40个Python脚本、44个YAML配置、3个预训练模型权重文件以及多张标注图像另有Dockerfile与教程文档便于环境复现和上手整体约139.76MB目录结构清晰经调试后可直接运行。目前已有238人学习下载项目经过严格调试并获导师指导认可可直接作为毕业设计或期末大作业使用。读者能一次性获得数据标注、模型训练、推理检测的完整链路并可根据自带配置与脚本快速二次开发省去收集数据和搭建环境的繁琐过程无需从零开始。1. 为什么口罩检测这类任务YOLOv5依然是最稳的起点戴口罩识别这件事看上去是“人脸检测加一个分类”的组合问题但真要在监控画面、闸机通道、园区出入口这些场景里跑起来难点不在“能不能检测到”而在“检测准不准、漏检多不多、推理够不够快”。YOLOv5在口罩佩戴检测数据集上的表现所以会成为多数人的首选方案是因为它在精度和速度之间给了最划算的平衡点一个中等算力的GPU就能跑出接近实时的帧率而mAP又能压到90%以上。标题里把代码、训练好的模型、标注好的数据打成一个压缩包分发意味着拿到手不需要从零开始做数据集标注先直接跑推理验证效果再根据自己的场景做二次训练或迁移学习。这个方案适合两类人一类是刚接触目标检测的学生或转行者想用最短路径把从数据到训练到部署的全流程走通另一类是有生产项目但工期紧的工程师需要一个已经调好的baseline直接替换成自己的业务目标比如安全帽、工服、反光衣来复用整个流程。这套东西的本质是一个“可复用的目标检测工作流”口罩只是一个载体流程本身才是值钱的部分。接下来我会按实际动手的顺序把我的复现过程、参数设置思路、踩过的坑和绕过的弯完整讲清楚。如果你手头拿到的是类似结构的目标检测项目压缩包操作步骤几乎可以照搬。2. 为什么要用YOLOv5做口罩佩戴检测选型判断与工作流拆解2.1 从任务需求倒推模型选型口罩佩戴检测在计算机视觉里属于单阶段目标检测任务判断逻辑是“先定位人脸区域再给人脸打上“佩戴”或“未佩戴”的类别标签”。主流的选型路线有那么几条两阶段代表是早期R-CNN系列精度高但推理速度拉胯不适合视频流单阶段代表是YOLO系列和SSD速度快精度做得也不错还有基于Transformer的检测头精度上限高但训练成本和部署门槛都更高。在这几条路线里YOLOv5之所以成为事实上的工业级默认选项原因具体来说是三个第一模型结构设计成熟CSPDarknet骨干加PANet颈部加耦合检测头在小目标和中目标上的特征提取能力足够应对人脸的尺度分布第二训练生态完善从数据增强到损失函数都内置好了不需要自己调一堆辅助模块第三部署链路完整导出ONNX、TensorRT、OpenVINO都有官方支持工程化成本低。相比YOLOv8或YOLOv9YOLOv5在精度上确实不是最新的但它的社区资料、踩坑记录和预训练权重数量是最大的对于想“先跑通再优化”的开发者来说这只黑匣子更容易被打开。如果你自己的场景是复杂遮挡、密集人群、极小目标可以考虑后续换YOLOv8或v9但第一步用YOLOv5把流程跑通是效率最高的方式。2.2 拿到项目包后先搞懂目录结构再动手一个标准的YOLOv5口罩检测项目压缩包解压后目录结构通常是这样的mydata/ # 数据总目录 ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 训练标注.txt │ └── val/ # 验证标注.txt ├── data.yaml # 数据集配置文件 ├── classes.txt # 类别列表 yolov5/ # 模型工程目录 ├── train.py # 训练入口 ├── detect.py # 推理入口 ├── weights/ │ └── best.pt # 训练好的模型权重 ├── runs/ │ ├── train/ # 训练日志与曲线 │ └── detect/ # 推理结果这里要特别留意的是一处常见误解images目录里存放的是原始图片不假但labels目录里存的并不是图片而是与每张图片同名的txt标注文件格式是class_id x_center y_center width height五个值都用归一化后的0到1之间的浮点数表示。这个格式来自YOLO系模型的标准标注规范写错一位坐标就拉低整批数据的训练效果。如果压缩包里的标注不是YOLO格式而是VOC的XML或COCO的JSON那就得先做格式转换再训练。常见做法是写一个解析脚本遍历XML或JSON提取边界框坐标归一化后写入txt。我一般会先随机挑三张图可视化标注框确认坐标没问题再批量转换这一步花五分钟能省后面训练返工的两小时。2.3 核心文件data.yaml的作用data.yaml是数据集和模型之间的桥梁YOLOv5训练时会先读这个文件来确定类别数和数据路径。train: mydata/images/train val: mydata/images/val nc: 2 names: [with_mask, without_mask]nc表示类别数量口罩检测通常是两类如果要加入“口罩佩戴不规范”比如露出鼻子就是三类。names列表的顺序必须与标注文件中class_id的数字一一对应顺序错位会出现“模型收敛了但预测结果全错”的玄学现象。路径建议用相对路径这样整个项目目录挪到别的机器上不用改配置。这个文件的修改频率其实很低但对于要复用这套流程检测其他目标的人来说它是最先需要改的地方——把names换成你自己的类别名nc改成对应的类别数。3. 用训练好的模型跑推理参数设置与效果验证3.1 第一条命令让模型先“动起来”拿到项目包后做的第一件事不是重新训练而是用自带的权重文件跑一次推理确认整套环境没有问题。这一步能验证三件事环境依赖有没有装齐、权重文件有没有损坏、推理链路是否通畅。python detect.py --weights weights/best.pt \ --source data/images/test.jpg \ --conf-thres 0.5 \ --iou-thres 0.45 \ --device 0--weights指定权重路径--source可以填单张图片、一个文件夹、视频文件或摄像头设备号--conf-thres是置信度阈值高于这个值才输出检测框--iou-thres是NMS去重时的IOU阈值--device 0表示用第一张GPU改成cpu就是纯CPU推理。第一次跑推理输出结果会保存在runs/detect/exp/目录下建议直接把原图和检测结果图并排放一起看。重点观察三件事口罩戴得标准的人脸能不能被稳定检测出来口罩拉到下巴、露出鼻子的情况是判成哪个类别侧脸、低头、逆光这些“刁钻角度”有没有漏检。如果这三类情况的表现都不差说明这个baseline权重是可靠的可以进入后面的迁移训练阶段。3.2 置信度阈值和NMS阈值的调节逻辑--conf-thres和--iou-thres这两个参数是推理阶段最需要反复试的旋钮它们的取值直接决定你看到的检测效果。conf-thres调低比如0.25模型会更“激进”漏检变少但误检变多调高比如0.7误检变少但漏检风险上升。实际场景里闸机通道这种“宁可多拦一次也不放错一次”的安防场景阈值适合偏低而考勤打卡这种“不能让系统频繁乱框”的场景阈值适合偏高。iou-thres控制的是NMS去重强度同一张人脸附近出现多个重叠框时IOU大于这个值的框会被合并。这个值不建议低于0.4否则同一个目标可能出现双框也不建议高于0.7两个紧挨着的人脸容易被误判成同一个目标。我一般会用一组测试图片在不同阈值下各跑一遍把检测结果保存成表格对比再根据业务侧的漏检误检接受度选参数而不是拍脑袋定一个数用到底。python detect.py --weights weights/best.pt --source data/images/val --conf-thres 0.3 --iou-thres 0.5 python detect.py --weights weights/best.pt --source data/images/val --conf-thres 0.6 --iou-thres 0.5 python detect.py --weights weights/best.pt --source data/images/val --conf-thres 0.3 --iou-thres 0.6这三组跑完在结果目录里对比几次检测框的数量和位置变化你就能直观感受到这两个参数对结果的影响量级。3.3 视频流推理时要注意的隐藏开销口罩检测的真实使用场景大多是视频流不是单张图片。使用视频作为--source输入时YOLOv5会自动逐帧推理并合成标注视频但这里有一个常被忽略的点模型推理本身只是耗时的一部分视频解码和编码在CPU较弱的环境下可能占掉40%以上的时间看起来帧率很低其实是编解码瓶颈不是模型跑不动。遇到这种情况用--nosave只做推理不做结果落盘测试这个操作下视频处理的耗时就能把模型推理耗时和编解码耗时分开。如果确实是编解码瓶颈可以先把视频抽帧成图片批量推理再用FFmpeg把带标注的帧合成新视频算是一种绕过瓶颈的土办法但非常管用。ffmpeg -i input.mp4 -qscale:v 1 frames/%06d.jpg python detect.py --weights weights/best.pt --source frames/ --conf-thres 0.5 ffmpeg -r 30 -i runs/detect/exp/frames/%06d.jpg -c:v libx264 output.mp4三条命令把“视频→图片→推理→视频”串起来每次出错都能定位到具体是哪一步有问题比直接在视频上跑好排查得多。4. 把标注数据吃透格式转换、数据检查与增强策略4.1 YOLO标注格式的逐字段说明YOLO格式的txt标注每一行代表一个目标五个字段的顺序和含义这里看清楚一遍后面能省很多排查功夫0 0.5312 0.4825 0.2914 0.3597 1 0.7831 0.2153 0.1781 0.1893第一个数字是类别ID0通常对应with_mask1对应without_mask第二个数字是边界框中心点的x坐标相对图片宽度归一化第三个数字是中心点的y坐标相对图片高度归一化第四个是框宽度相对图片宽度第五个是框高度相对图片高度。全部是0到1之间的小数。假设一张图片宽1920像素、高1080像素某个口罩框的左上角坐标是(480, 270)宽高是(384, 216)那么中心点x就是(480384/2)/1920 0.35中心点y就是(270216/2)/1080 0.35宽是384/1920 0.2高是216/1080 0.2最终这行标注就是0 0.35 0.35 0.2 0.2。最容易出错的是后两个字段很多人会想当然地把右下角坐标直接除以图片宽高得到一个0到1之间的小数然后发现训练时loss能降但预测框位置全偏。坐标转换这一步建议写个小的校验脚本随机抽几张图把标注框画出来人工确认。4.2 可视化检查发现标注坐标错位的最快方法标注数据质量直接决定模型上限而可视化检查是发现标注问题最直观的手段比翻txt文件高效得多。用OpenCV把每张图的标注框画出来批量生成预览图五分钟就能扫完几百张图。import cv2 image_path data/images/train/000001.jpg label_path data/labels/train/000001.txt img cv2.imread(image_path) h, w img.shape[:2] with open(label_path, r) as f: for line in f.readlines(): cls_id, x_center, y_center, bw, bh map(float, line.split()) x1 int((x_center - bw / 2) * w) y1 int((y_center - bh / 2) * h) x2 int((x_center bw / 2) * w) y2 int((y_center bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cls_id)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(check_000001.jpg, img)这段代码把归一化坐标乘以图片实际宽高还原成像素坐标并画框。跑完看一眼预览图框是紧贴人脸还是偏到背景上、框的大小是贴合还是过大过小、有没有整张图只有一个框但图里明显有多个人脸的情况——这些问题在预览图里都是一眼能看出来的。标注文件里最常见的三种问题就是坐标轴搞反、中心点算错、类别ID错位。4.3 数据增强参数让模型见过更多“刁钻角度”数据集里“口罩佩戴规范”的样本往往占多数“没戴”“不规范”的样本占比少模型对少数类的学习天然吃亏。YOLOv5内置的数据增强能缓解这个问题关键参数在训练配置里可以看到hsv_h色调、hsv_s饱和度、hsv_v明度、degrees旋转角度、translate平移、scale缩放、flipud上下翻转、fliplr左右翻转。对口罩检测这个任务我比较常用的配置是degrees设到10左右人脸旋转超过这个范围就不像自然状态了、fliplr保持开启左右翻转不改变口罩的语义、hsv_v设0.1左右模拟不同光照条件。flipud不建议开现实中倒着的人脸几乎不存在加了反而让模型学到不存在的特征。另一个有效策略是把训练集里少数类不戴口罩的图片做一次副本增强比如把图片亮度调暗、加高斯噪声后复制一份加入训练集。这种做法会轻微改变样本分布但对拉升少数类别的recall很有效果。# data/hyps/hyp.scratch-low.yaml 中调整 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4 degrees: 10.0 translate: 0.1 scale: 0.5 flipud: 0.0 fliplr: 0.5hsv_h不建议调高人脸肤色对色调敏感改太多会让模型学到错误的颜色特征scale调到0.5能模拟远近不同的拍摄距离。5. 从头训练与微调命令、超参数与阈值判断5.1 迁移学习是默认选择从预训练权重起步拿到这批标注数据后直接train.py开训是最简单的但不是最优的。推荐的路线是加载YOLOv5在COCO上的预训练权重再在你的口罩数据集上微调这叫迁移学习。理由很直接预训练权重已经学会了通用特征边缘、纹理、形状、颜色分布你的数据集只需要教会它“哪些特征组合代表人脸口罩”收敛速度快、精度上限高、对小样本数据集极度友好。python train.py --data mydata/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch-size 16 \ --epochs 100 \ --device 0 \ --workers 4--weights yolov5s.pt加载的是COCO预训练权重传--weights 加--cfg yolov5s.yaml才是从零训练两种模式差距极大小数据集从零训练基本是浪费算力。--img 640是输入分辨率人脸目标相对小分辨率太低会丢细节调720会影响训练速度640是最稳的平衡点。--batch-size要根据显存调整显存不够就减半。5.2 在训练过程中判断模型状态不止看loss曲线训练开始后不能丢给服务器就不管了。需要盯几个关键信号来判断训练是否正常。runs/train/exp/目录下会有results.png包含训练loss、验证loss、精度、召回率、mAP曲线。如果训练loss持续下降而验证loss先降后升这就是过拟合信号解决办法是提前停止早停或加正则化。更实用的判断方法是看val曲线正常训练时mAP稳步上升然后趋于平缓如果在训练后期mAP不但不升反而回落说明模型开始“死记硬背”训练集了。与之相对如果训练了二三十个epoch验证loss纹丝不动问题大概率在数据层面——检查标注是否有大量错位、路径是否正确、类别ID是否与data.yaml对齐。YOLOv5有个内置机制会在每个epoch结束后保存best.pt和last.pt前者是验证集mAP最高的那一轮权重后者是最后一轮权重。默认建议用best.pt做后续推理和导出除非你需要的是更多训练轮数产生的模型。5.3 常见超参数的调整方向和推荐范围--batch-size是影响训练稳定性最直接的参数。batch太小4以下梯度噪声大loss曲线会剧烈震荡batch太大单卡显存放不下模型收敛效果也不一定更好。16到32之间是YOLOv5训练效果比较好的区间12GB显存跑yolov5s配batch 16一般没问题。--epochs的取值要在数据和算力之间权衡数据集几百张图的话50到100轮就能看到明显收敛再多反而有过拟合风险。数据量几千张图可以放到150到200轮。这里有一个习惯值得培养每次训练都搭配--patience参数比如--patience 20表示20个epoch内验证mAP无提升就自动停止既能节省算力也避免训练跑偏。--workers是数据加载线程数Linux下可以设4到8Windows下建议不要超过4否则容易报数据加载错误。线程数并不是越大越好超过CPU核数反而有调度开销。模型尺寸的选择逻辑也很清晰yolov5s是速度和精度的平衡点绝大多数口罩检测项目够用追求更高精度上yolov5m或yolov5l代价是显存占用和推理速度翻倍追求极致速度或部署到边缘设备用yolov5n。6. 生产环境下的五个典型坑从现象到解决6.1 训练loss正常但检测框全偏现象是训练曲线很漂亮loss稳定下降但用训练好的模型跑推理检测框位置明显不对比如框飞到背景上或框大小离谱。原因是标注数据格式出了问题最常见的是标注框的坐标单位没归一化或者中心点坐标误写成了左上角坐标。训练本身不会报错因为模型只是把输入映射到输出它不知道标注对不对照样能把错误标注学进权重里。解决方法是立刻做可视化检查随机抽50张训练图用前面提过的OpenCV脚本把标注框画出来肉眼对照。不要信任任何标注工具导出的数据转换过程一定有手滑的可能可视化是唯一可靠的校验手段。6.2 戴口罩的人能检测到不戴口罩的人检测不出现象是指标好看但实际场景检测失衡戴罩的recall高不戴罩的漏检多。原因是样本不均衡。数据集中“戴口罩”的样本远多于“不戴口罩”模型对多数类学到丰富的特征对少数类的特征学习不充分。训练时模型倾向于把不确定的目标判成多数类这是单阶段检测器里的普遍现象。解决思路是两条线同时走一是用数据增强和副本策略给少数类加密让它的出现频率接近多数类二是用--cls参数调节类别损失权重让模型对少数类的分类错误付出更大的代价。我在类似项目里用过组合拳后不戴口罩类别的recall从78%升到93%左右效果非常明显。6.3 验证集mAP很高放到现场全是漏检观察到的现象是训练时验证集mAP有92%以上信心满满地部署到现场摄像头结果日常的逆光、远距离、半遮挡场景漏检一大堆。原因是训练集和现场数据分布不一致术语叫数据分布漂移。现场摄像头角度、光照、分辨率、人群密度和训练数据集根本不是同一个分布验证集是从训练数据里分出来的它代表不了现场的真实分布。解决思路是收集现场的截图帧用已有的best.pt做推理把误检和漏检的图挑出来人工修正标注后加入训练集再微调一轮。这个“错误收集—标注—补充训练”的迭代闭环是模型效果提升最有效的一条路径比反复调参有用得多。视觉模型在垂直场景落地的真正门槛就是这一步。6.4 推理速度达标但CPU占用奇高现象是视频流推理帧率看着正常但整个机器负载很高其他服务被拖垮。原因大部分时候不是模型推理本身而是视频解码在吃资源。OpenCV默认的VideoCapture硬件加速不一定生效CPU软解4K视频流的代价比一张640x640的推理还高。解决方法是优化输入链路视频流先降分辨率再喂给模型或者尝试启用OpenCV的CAP_PROP_FOURCC设置更进一步的做法是用专门的解码模块做硬件解码把解码后的帧直接送到推理接口这一层优化空间往往比模型优化大得多。6.5 导出ONNX后精度“掉点”现象是在PyTorch环境下测试精度很高导出ONNX或TensorRT后再推理检测结果变差。原因是导出时没有固定模型输入尺寸或者导出精度设置不正确。ONNX默认支持动态输入尺寸但实际推理引擎往往对固定尺寸有额外优化动态尺寸会导致精度和性能都受影响。解决方法是导出时明确指定尺寸--img-size 640 640同时确认--dynamic参数按需开关。这里的经验法则是如果不是必须处理多分辨率输入就不要开dynamic固定尺寸的稳定性远好过动态尺寸。做完导出后拿同一批测试图片在PyTorch和ONNX上各跑一遍逐张对比检测框差异不一致就检查导出参数和预处理是否对齐Normalization方式是最常见的差异来源。7. 一个隐形但关键的动作验证集与测试集的划分比例怎么定YOLOv5的训练入口默认只读train和val两个路径没有强制要求测试集但严肃的项目里测试集一定不能省。划分比例我常用的是7:2:1训练集70%验证集20%测试集10%。验证集用来做训练过程中的模型选型和早停判断它参与了你的调参决策所以不能拿它当最终效果度量测试集从头到尾不参与训练和调参只在全部流程跑完后压一次报告里写的“模型精度”应该以测试集的结果为准否则顶多算自嗨。同时要做到的还有验证集和测试集图片在采集时间或场景上应该有差异如果全部来自同一批拍摄数据再小的模型都能拿到虚高的精度。如果条件允许用不同时间段或不同场景的设备采集测试集图片这是性价比最高的模型体检方式。这个划分动作看似基础却是整个项目交付时最容易被挑战的一点。做甲方项目时如果我把验证集精度当最终精度写进报告基本离返工不远了。8. 最后的进阶习惯把模型压到能上线的体积和速度推理速度和模型体积决定了这个方案能不能真正部署到现场设备。一个完整的YOLOv5训练流程走完后我通常会再花半天做三件事模型剪枝、量化、导出TensorRT。剪枝是把权重中接近零的通道剪掉模型体积能缩小30%左右精度损失控制在一个点以内。量化是把FP32权重转成FP16甚至INT8推理速度在支持INT8的硬件上可以翻倍代价是精度可能掉一到三个点。这两步做完一个能在边缘设备上跑起来的模型才算是真正“落地”了。# 导出FP16 TensorRT引擎 python export.py --weights weights/best.pt \ --include engine \ --device 0 \ --half导出后要做的不是直接上线而是跑一遍全部测试集把INT8模型的检测结果和FP32版本逐张对比确认精度下降在业务可接受范围内。这个验证步骤很多人跳过之后在现场出了精度问题再回来查浪费的时间远比按流程走一遍多得多。我的习惯是每次训练完固定做三件事用测试集出一次客观精度报告、可视化十几张典型的检测效果图、导出ONNX和TensorRT两种格式的模型归档。这套组合拳打下来项目交付时手里有数据、有可视化案例、有多格式产物任何环节出问题都能快速定位到是哪一步掉了链子。如果你按这套流程把一个YOLOv5口罩检测数据集从推理跑通到训练调优到部署导出都走过一遍那再碰到安全帽检测、反光衣检测、施工区域人员闯入检测这类目标检测任务你就知道该改哪里、要防什么坑、哪些环节不能省了。目标检测的落地能力就是这么一步步练出来的。希望帮到你。本文还有配套的精品资源点击获取