
简介基于YOLOV5的口罩检测项目资料包面向计算机相关专业毕业设计、课程设计与期末大作业场景提供从数据集、标注文件到训练模型与完整代码的一站式方案。项目经导师指导并以98分评审通过适合需要快速搭建检测系统、完成论文实验或进行项目实战学习的学生。压缩包共149个文件包含44个yaml配置、40个Python脚本、3个pt权重文件及已标注数据集并附有notebook演示、Dockerfile部署配置、shell训练脚本等内容整体约922.84MB结构清晰便于二次开发。已有193人学习下载。除核心检测代码外还涵盖预处理、训练、评估各环节工具读者可直接加载模型运行推理也可基于标注数据重新训练或迁移学习并能借助配置与脚本复现完整流程为项目报告和答辩提供扎实支撑。1. 基于YOLOv5口罩检测方案毕业设计与大作业都在用的目标检测全流程目标检测是计算机视觉里少有的、用一次毕业设计就能把“数据→训练→评估→部署”整个链路走通的子方向而口罩检测又是这个方向上最经典的落地点。所谓“基于YOLOv5口罩检测”的完整方案通常包含三块内容一份标注好的口罩图片数据集、一套可运行的YOLOv5训练代码、以及训练好的权重模型。拿到这些资源你要做的不是从零写网络结构而是理解数据格式、跑通训练链路、把参数调到合理范围并产出可视化证据。这个方向适合有Python基础、想在3到6周内独立完成一个可演示项目的学生也适合期末大作业里需要快速出结果的同学。前提是你愿意把每一步都亲手过一遍。2. 制作可训练的数据集口罩标注格式、目录结构与类别设计标注数据的组织方式是YOLO系列训练里最容易翻车的地方。很多项目做不下去不是模型结构的问题而是目录结构、标注格式和YOLOv5的读取约定不一致导致训练时读不到标签或者读到的框全是错的。花半小时把数据规整好远好过训练完再回头查。2.1 从原始图片到可训练数据集目录结构就是第一个约定YOLOv5的train.py读取数据集的方式非常固定它要求数据集目录长成下面这样dataset/ ├── images/ │ ├── train/ │ │ ├── mask_0001.jpg │ │ └── ... │ └── val/ │ ├── mask_0001.jpg │ └── ... └── labels/ ├── train/ │ ├── mask_0001.txt │ └── ... └── val/ ├── mask_0001.txt └── ...图片和标签必须一一对应同名文件后缀分别是.jpg和.txt。如果你下载到的数据集是VOC格式的XML标注或者COCO格式的JSON标注第一件事就是写个转换脚本统一转成这种目录结构。现在网上能搜到很多现成的格式转换工具但直接拿来用之前要想清楚一个致命点不同数据集对类别顺序的定义不一样。口罩检测最常见的两个类别是with_mask和without_mask顺序一旦颠倒训练出来的模型在推理时框是对的但类别标签永远是反的。关于文件命名我建议在转换阶段就把所有图片统一重命名为纯序号格式比如00001.jpg、00002.jpg不要保留原始下载文件名。原始文件名里经常带空格、括号或中文在Windows上跑训练时可能读不到文件报错还很隐蔽。2.2 YOLO格式标注从XML/JSON到TXT的转换细节YOLO标注格式的每一行代表一个目标对象五个数字含义依次是类别ID、框中心点X坐标、框中心点Y坐标、框宽度、框高度。注意这里存的是归一化坐标范围在0到1之间不是像素坐标。换算公式为假设图片宽W、高H某个目标的边框记为(x_min,y_min,x_max,y_max)中心点X (x_min x_max) / 2 / W中心点Y (y_min y_max) / 2 / H宽度 (x_max - x_min) / W高度 (y_max - y_min) / H绝大多数从VOC XML转换出错的场景都出在边界情况某个目标非常贴近图片边缘时转换后的坐标可能出现负数或者大于1的值YOLO训练时遇到这种越界标注会直接丢弃导致模型少学一类目标。所以转换脚本里必须加一层数值裁剪。下面这个Python脚本可以把VOC格式的XML标注转成YOLO需要的TXT标注import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, out_dir, class_names): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_names: continue class_id class_names.index(name) box obj.find(bndbox) x_min float(box.find(xmin).text) y_min float(box.find(ymin).text) x_max float(box.find(xmax).text) y_max float(box.find(ymax).text) # 归一化坐标 x_center ((x_min x_max) / 2) / img_w y_center ((y_min y_max) / 2) / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h # 越界裁剪防止训练时标签被丢弃 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w min(max(w, 0.0), 1.0) h min(max(h, 0.0), 1.0) lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) if not lines: return xml_name os.path.splitext(os.path.basename(xml_path))[0] out_path os.path.join(out_dir, xml_name .txt) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines))这段脚本的逻辑很直接解析XML拿图片尺寸遍历每个目标框计算归一化中心点、宽和高。两个容易被忽略的点一是class_names列表的顺序必须和训练时的data.yaml完全一致二是裁剪放在归一化之后而不是之前否则你先裁了像素坐标再做归一化时比值还是可能越界。2.3 数据集划分与类别平衡怎么切才合理口罩检测的数据集切分常见做法是固定比例划分我一般用90%训练、10%验证小数据集上用更保守的85%/15%也行。YOLOv5读取的是目录结构所以划分本质上是把图片文件和对应的TXT标签文件一起搬进不同目录。下面这段脚本演示了带有固定随机种子的划分方式import os import random import shutil random.seed(42) src_img_dir raw_images src_label_dir raw_labels train_img_dir dataset/images/train val_img_dir dataset/images/val train_label_dir dataset/labels/train val_label_dir dataset/labels/val all_imgs [f for f in os.listdir(src_img_dir) if f.endswith(.jpg)] random.shuffle(all_imgs) val_count int(len(all_imgs) * 0.1) val_imgs all_imgs[:val_count] train_imgs all_imgs[val_count:] for img in train_imgs: shutil.copy(os.path.join(src_img_dir, img), train_img_dir) label img.replace(.jpg, .txt) shutil.copy(os.path.join(src_label_dir, label), train_label_dir) for img in val_imgs: shutil.copy(os.path.join(src_img_dir, img), val_img_dir) label img.replace(.jpg, .txt) shutil.copy(os.path.join(src_label_dir, label), val_label_dir)先用random.seed(42)固定随机数生成器再指定训练集和验证集的目标目录。脚本执行完以后一定要核对图片和标签是否一一对应检查是否有图片存在而标签缺失或者反过来。最简单的方式是遍历两个目录比对文件名集合的差集。我见过有人切完数据后训练集里混入了两张无标注图片训练时loss曲线出现周期性抖动排错排了一整天。类别平衡方面口罩检测的两类目标with_mask和without_mask在多数开源数据集里比例并不均衡通常是戴口罩的样本多。如果两类标注框比例差距超过7比3就要考虑在训练时对少数类做额外增强或者直接往训练集里多补充少数类的图片。单纯调loss权重在这个任务上的收益不明显不如从数据本身下手。关于数据集最后提醒一个习惯无论数据是下载的还是别人分享的训练前一定要自己抽查标注。挑20张图片把标签可视化画出来对照原图看看框的位置和类别是否合理。这一步花十分钟能省掉后面好几天调参的时间。3. 环境与配置依赖安装到初次推理验证环境配置在很多人印象里充满玄学其实YOLOv5的运行环境已经非常成熟。真正容易出问题的点是Python版本、PyTorch版本、CUDA版本这三者的匹配关系。毕业设计场景下照着稳妥的路径走一小时内就能把环境跑通。3.1 conda虚拟环境与PyTorch安装我强烈建议用conda单独开一个虚拟环境不要用系统自带的Python去装深度学习依赖。深度学习依赖的包版本冲突非常常见隔离环境是最省心的方案conda create -n yolov5 python3.9 -y conda activate yolov5PyTorch的安装命令取决于硬件条件。有NVIDIA显卡且驱动正常的机器安装GPU版本纯CPU环境则安装CPU版本。安装完以后一定要在当前环境里验证PyTorch能否正确调用设备import torch print(torch.__version__) print(torch.cuda.is_available())cuda.is_available()返回False通常有两种可能装的是CPU版PyTorch或者CUDA版本与PyTorch要求的版本对不上。最常见的现场是电脑明明有显卡但安装命令里带的是cpu字样或者是PyTorch要求的CUDA版本高于本机驱动的支持版本。对毕业设计来说没有GPU也不是做不了只是训练时间会明显拉长几千张图、几十个epoch的任务在CPU上可能要跑三四个小时以上。3.2 修改data.yaml训练入口的类别定义YOLOv5仓库的训练入口是train.py它不直接读数据集而是读取一个data.yaml配置文件。这个文件极其重要训练前必须改对。一个标准的口罩检测配置长这样# dataset.yaml train: dataset/images/train val: dataset/images/val nc: 2 names: [with_mask, without_mask]train和val字段是相对于YOLOv5仓库根目录的相对路径。写绝对路径也能跑但相对路径在迁移项目时更省心。nc是类别数量names是类别名称列表。这两者必须严格对应——nc写2但names写了3个类名训练会直接报错names顺序和标注文件里的类别ID对不上模型会学到错误的映射。模型结构方面YOLOv5提供了yolov5s.yaml、yolov5m.yaml、yolov5l.yaml等配置对应从小到大不同规模的网络。口罩检测是两类目标、场景简单的小任务s规模完全够用。除非你的数据集里大量包含远距离、小尺寸的人脸目标才需要换m甚至l。3.3 用预训练权重做一次推理验证正式训练之前先用官方预训练权重跑一次检测验证环境链路是通的。首次运行detect.py时YOLOv5会自动下载yolov5s.pt权重文件。如果在离线环境下跑提前下载好放到仓库根目录就行python detect.py --weights yolov5s.pt --source dataset/images/val --conf-thres 0.5这条命令会把验证集所有图片跑一遍推理结果默认保存到runs/detect/exp/目录。如果这一步能正常输出结果说明环境、权重、数据读取链路全部通畅。如果这一步就报错大概率是依赖包版本问题而不是你的数据有问题。此时把报错堆栈复制到搜索引擎查一查绝大多数都能找到解决办法不建议自己硬读源码调试环境兼容性。环境配置阶段还有一个小坑YOLOv5的requirements.txt列出的依赖版本在历史版本中一直在变化。如果你是克隆的老版本代码用pip install -r requirements.txt安装时如果报冲突优先考虑降低PyTorch版本而不是去改YOLOv5的源码。4. 训练口罩检测模型超参数、数据增强与权重管理数据就绪、环境跑通之后进入正式训练环节。这一步的价值在于理解YOLOv5如何在自定义数据集上收敛以及如何控制过拟合。实训阶段会遇到一个矛盾训练指标很好看但验证集表现差或者训练过程在某个节点突然失控。4.1 训练入口与核心参数batch-size、imgsz和epochs怎么选模型训练的命令是完整闭环的最小启动形式常规做法是先用迁移学习把收敛速度拉起来python train.py \ --data dataset.yaml \ --cfg models/yolov5s.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --imgsz 640 \ --device 0各参数的实际影响参考下表参数作用建议值--epochs训练总轮数口罩检测100轮够用小数据集50轮即可观察趋势--batch-size每批图片量显存允许时尽量大低于8可能导致BN统计不稳定--imgsz输入图片统一尺寸640是速度与精度的平衡点--device训练设备0表示第一张显卡CPU环境填cpubatch-size是一个经常被误解的参数它不只影响显存占用还直接影响BatchNorm层的统计量。batch-size过小比如设成4BN层在每批数据上估计的均值方差会波动剧烈模型训练过程来回震荡。如果你显存紧张优先把imgsz从640降到512而不是大幅度压缩batch-size。把输入图片调小显存占用的下降是平方级的比压缩batch-size划算得多。训练过程中命令行会实时打印每轮的loss、precision、recall、mAP50、mAP50-95。前30个epoch如果mAP一直是0不用急着下结论YOLOv5的mAP在前期可能完全不起色但只要loss在持续下降说明模型在正常学习。真正要警惕的是loss曲线反复震荡或者突然冲高这个问题放到避坑章节展开。4.2 数据增强的取舍mosaic在口罩数据上的影响YOLOv5内置了多种数据增强手段最核心的是mosaic增强把4张训练图片拼成一张再喂给网络变相增加了每张图里的目标数量对小目标检测的提升很明显。但口罩检测场景里很多人发现mosaic带来的收益有限。原因是来自街道、教室或办公室的照片里口罩目标通常占画面比例不小拼图之后目标被裁剪的概率变大反而破坏了样本的完整性。YOLOv5的超参数文件允许你调整各项增强的启用概率。默认的hyp.scratch-low.yaml里mosaic: 0.5表示mosaic有50%的概率被触发。如果你发现训练到后期mAP提不上去可以专门为迁移学习场景建立一个微调超参文件# hyp.mask_finetune.yaml mosaic: 0.0 fliplr: 0.0把训练拆成两个阶段是这个方向常见的实践前70个epoch开启全部增强让模型学习泛化特征后30个epoch关掉mosaic和水平翻转让模型在更小的增强扰动下精调边框回归精度。这个操作在口罩检测上尤其有效因为口罩的左右不对称特性使得水平翻转会带来错误的监督信号——口罩带子翻转后会出现在另一侧模型学到的是混乱的朝向特征。4.3 训练产物怎么用best.pt、last.pt与指标存档训练结束后runs/train/exp/目录下会生成整套产物。最关键的两个权重文件是best.pt和last.pt。best.pt是验证集上mAP最高的权重部署时用它last.pt是最后一个epoch的权重如果你想换一组超参数继续训练或者中途中断后恢复训练就要用它作为起点。训练产出的results.png记录了十多个指标随epoch的演化曲线答辩时展示这张图比口头说“效果还不错”有说服力得多。如果你想管理多次实验用--project和--name参数指定输出目录python train.py ... --project runs/mask_train --name exp01这样每次训练的结果独立存放不会被默认的exp、exp2这种命名搞混。训练完成之后怎么评价模型性能行业里最核心的两个指标是mAP50和mAP50-95。mAP50是IOU阈值为0.5时的平均精度比较宽容框的位置有些偏移也能算对mAP50-95把IOU阈值从0.5到0.95按0.05间隔取十个值分别计算再平均对边框回归精度的要求苛刻得多。口罩检测这个任务mAP50做到90以上已经很好mAP50-95通常比mAP50低10到20个百分点这是正常的数值差异不代表模型性能差。5. 避坑专项口罩检测项目里5类高频故障的排查记录做了一批学生的课题和自己的工作我把口罩检测训练里最容易踩的坑按“现象→原因→解决”整理在下面。每一条都是实际训练中反复出现过的问题希望能帮你少走弯路。5.1 训练loss在下降但mAP完全不上涨现象训练日志里loss从1.5稳定降到0.3但mAP50一直停留在0.3以下验证集上的检测结果基本全错。原因这是典型的标签错位问题。一方面是数据集划分时train和val混入了同一批图片模型对训练集过拟合后验证集指标失真另一方面是标注类别顺序在TXT文件中与data.yaml不一致模型学到的类别映射是错误的评估时按错误的映射去匹配GTmAP自然上不去。解决第一步拆分数据之前先对图片做去重确保train和val没有相同内容的图片混入。第二步从验证集随机挑5张图片做标签可视化对照原图检查框的位置和类别ID。如果可视化正常再检查data.yaml里的names顺序是否与之前转换脚本里的class_names列表一致。5.2 训练中途loss变成nan模型直接报废现象训练跑到某个epochloss突然变成nan之后所有指标跟着变nan继续训练没有任何意义。原因学习率过高导致的梯度爆炸或者数据里存在异常的标注框比如宽度或高度为零归一化公式里出现除数为0的情况。解决降低初始学习率在训练命令中加--lr0 0.005或者改用余弦退火调度器--cos-lr。同时写一个扫描脚本遍历所有标签文件把其中宽度或高度为0的行删除或修正。扫描脚本很简单十几行for循环加条件判断重点是不能只修TXT文件对应的图片也要检查是否损坏比如全黑的图片或分辨率异常的图片。5.3 推理时检测框整体偏移目标框不贴合物体现象训练时指标一切正常但拿到真实图片上推理哪怕是在训练集里的图片上推理框都会偏在目标上方或下方框住的位置和实际物体对不上。原因标注数据坐标系出现偏移。最典型的原因是转换脚本搞错了Y坐标的方向——VOC格式的y_min原点在图片左上角从上方开始向下增长如果转换时把它当成从下方开始的坐标系Y坐标就会整体翻转模型学到的边框回归方向全部出错分类准确但定位失败。解决重新检查转换脚本中Y坐标的计算方式用OpenCV画框的方式对照原始XML标注做视觉校验。挑一张图把原始XML像素坐标画成红框把转换后的YOLO坐标画成蓝框两者应该完全重合。不重合就按这个对比定位转换公式的问题修正后重新转换并重新训练。5.4 batch-size降到4还是显存溢出现象运行train.py阶段直接报CUDA out of memorybatch-size从16降到4依旧报错显卡明明还能跑别的程序。本科毕设用的笔记本显卡多半是4GB或6GB显存64是普遍瓶颈。原因默认输入分辨率640加上mosaic增强显存占用比想象中大得多。xue微注意mosaic会在一个批次里同时保留4张图片的特征图实际显存占用接近单图的4倍。batch-size4在数值上虽然小但叠加mosaic的放大效应后仍然吃紧。解决把--imgsz降到480或416显存占用会显著下降。再不够把--workers降到0避免数据加载线程和训练进程抢内存。最后一步是把--device cpu作为兜底方案用CPU把完整流程跑通证明算法路线可行有条件再换GPU跑正式训练。5.5 同参数跑了两次mAP差距悬殊现象同一个数据集、同一套训练参数连续跑两次一次mAP50是85另一次只有72差异大到无法判断模型真实水平。原因随机性来源有三个数据加载顺序、随机增强、以及权重初始化。YOLOv5默认的随机种子不固定两次训练的实际输入序列和数据扰动完全不同结果自然出现明显波动。解决在命令行加--seed 42固定随机数种子训练脚本内部也要用环境变量限制各库的随机性。如果你要对比不同参数的效果固定种子是最基本的实验控制手段。不固定种子你无法判断mAP差异是参数改进带来的还是随机波动带来的。固定种子后同参数两次训练的mAP差异应该被压缩到1到2个百分点以内这个区间是正常浮动的范围。6. 部署与答辩素材整理训练收敛之后项目进入部署和验证阶段这一步直接决定最终交付效果。建立一个常规的推理流程并通过参数调整适配不同的输入源。6.1 一套推理命令覆盖图片、视频和摄像头YOLOv5自带的detect.py脚本可以承担绝大多数部署需求。实际执行python detect.py \ --weights runs/train/exp/weights/best.pt \ --source test_video.mp4 \ --conf-thres 0.5 \ --iou-thres 0.45 \ --save-txt \ --save-conf--source参数可以接单张图片、目录、视频文件路径也可以接0直接调用默认摄像头。--save-txt会把每个检测框的坐标、类别、置信度写入TXT文件--save-conf额外附加置信度数值。需要把结果合成在图片上查看时YOLOv5默认输出的标注图就自带框和标签。做演示时有个容易被问到的点你的模型处理速度是多少。用--benchmark参数实测FPS或者自己在Python里写个循环记录每帧推理耗时。把这个数字记下来答辩时现场演示会从容很多。6.2 答辩需要的可视化证据训练日志、PR曲线、案例图毕业设计的验收环节除了能跑通代码更重要的是证据完整。一个可信的模型工作证据链至少包含三个部分训练日志体现收敛过程PR曲线或mAP曲线体现性能检测结果图片或视频截图体现真实场景效果。这三样东西在训练结束后自动存在于runs/目录下你需要做的只是挑几张代表性图片并整理到报告里。对mAP的解读用实际数字为例模型mAP500.95、mAP50-950.78说明边框定位已经相当精准在场景简洁的口罩数据集上完全可以达到。如果换到户外人多的复杂场景FPS下降、mAP也可能掉几个点这不是模型坏了而是训练数据的分布无法覆盖所有真实场景。答辩时把这个现象讲清楚反而能证明你理解泛化能力这个核心概念。6.3 一个保存记录的习惯固定版本、存档配置、跑通即备份我现在的做法是任何一次正式训练开始之前先复制一份dataset.yaml和超参数文件到训练输出目录里。训练结束后把detect.py推理时用的命令也记录到一个README.md里。这样两个星期后回来或者导师问到某个实验数字是怎么来的你可以立刻还原现场不需要靠记忆去拼凑参数。这个习惯在答辩前救过我一次导师指着我提交的mAP数据追问实验设置我直接打开实验目录下的配置文件解释清楚一场追问变成一次验收。另外一个实践细节训练过程中的中间权重也有用。训练到一半就用last.pt去跑一段过场视频提前发现问题不要等训练全部结束才去测。epoch中期就能看出模型有没有学崩避免最后一刻才看到完全不可用的结果。希望这一整套流程能帮你在口罩检测项目上少走些弯路更希望你能理解每个命令和参数背后的逻辑而不是照着指令盲打一遍。基于YOLOv5目标检测的能力边界数据、算力和耐心三者缺一不可祝实验顺利。本文还有配套的精品资源点击获取