
简介目标检测是计算机视觉的核心任务之一YOLOv5作为单阶段检测器的代表凭借速度与精度的平衡成为工程落地和课程项目的热门选择。从数据准备到模型部署完整的工程链路是深度学习实践的关键。本文围绕口罩检测这一典型应用基于2000张标注数据详细梳理了从数据集构建、环境配置、模型训练到推理部署的完整流程并总结了常见踩坑与优化建议适合目标检测入门者、课程设计者和算法工程师参考。 最近帮人复盘了一份课程大作业标题就是“YOLOv5口罩检测数据集代码模型2000张标注好的数据”。做过目标检测项目的人都懂这种题目在高校里出现频率极高——既不算太难又覆盖了从数据准备、模型训练到实际部署的完整链路作为大作业选题确实聪明。如果你正被同样的题目卡住或者准备做类似的目标检测项目这篇内容应该能帮你省掉不少试错时间。我会从项目选型、数据整理、训练参数、代码解析到踩坑记录把整个流程掰开揉碎讲清楚。1. 项目整体设计与技术选型思路1.1 为什么口罩检测项目适合作为课程大作业口罩检测本质上是一个二分类目标检测问题在图片或视频中定位人脸区域并判断该人脸是否佩戴了口罩。相比通用物体检测它有几个明显优势非常适合课程项目。第一数据集获取难度低。口罩数据不像工业缺陷、遥感影像那样稀缺公开数据集和现成标注资源都很丰富自己补充采集也方便。你拿到手的2000张标注图片规模适中能比较快地完成训练不至于像大规模数据集那样跑一次要等很久。第二模型效果易于可视化。目标检测的结果可以直观画框展示准确率和召回率也有清晰指标。答辩的时候现场跑一段摄像头检测效果一目了然比讲一堆理论更能打动老师。第三技术栈成熟。YOLOv5社区活跃文档完善预训练权重容易获取遇到问题基本都能搜到解决方案。对课程项目来说稳定可靠比花哨更重要。1.2 技术选型为什么选YOLOv5而不是其他检测框架目前主流的目标检测框架不少两阶段的有Faster R-CNN单阶段的有YOLO系列、SSD还有Transformer系的DETR等。选YOLOv5我是基于这几个考虑。首先是训练和推理速度的均衡。单阶段检测器直接回归边界框和类别不需要像Faster R-CNN那样先生成候选区域再二次分类速度天然快。口罩检测通常有实时性需求YOLOv5在GPU上能跑到几十到上百FPS完全够用。其次是工程化程度。YOLOv5的官方仓库把数据准备、训练、验证、导出、推理全都封装成了命令行工具detect.py、train.py、val.py 各司其职对新手非常友好。你不需要从零搭训练循环改改配置就能跑通。再者是预训练模型迁移带来的收益。mask检测和人脸检测都属于通用目标检测的下游任务从COCO上预训练的权重出发做微调收敛速度比随机初始化快得多需要的样本量也小。这个在你只用2000张图片的情况下特别关键。如果换成Faster R-CNN精度可能不错但工程代码量更大训练也更慢对课程作业来说投入产出比不高。如果换成最新的YOLOv8或者YOLOv9某些模块改进确实带来精度提升但对作业而言没有本质差异而且如果你的机器配置一般大模型反而增加负担。YOLOv5作为“够用且好用”的中间选择是我推荐的理由。1.3 数据集和项目文件的整体规划拿到手的项目文件一般包含这几块数据集JPEGImages图片 labels标注、YOLOv5代码仓库、训练好的权重best.pt、以及推理脚本。先搞清楚每块内容是什么再做训练和修改会顺手很多。数据集层面2000张图是一个比较合理的课程项目规模比单纯调库演示有工作量又不至于训练时间过长。一般会划分为训练集和验证集比例可以按9:1或8:2来。图片中的人脸可能包含戴医用口罩、戴布口罩、不戴口罩、戴歪口罩等情况标注越规范训练出的模型越可靠。代码层面建议单独把代码仓库放在项目根目录数据集放在外部目录用软链接或路径配置关联避免数据集太大拖慢Git管理也防止误改代码文件导致版本混乱。2. 环境搭建与数据集预处理2.1 环境版本匹配Python、PyTorch与CUDAYOLOv5对环境的依赖不算苛刻但版本匹配问题足以浪费新手半天时间。我建议按以下组合配置Python 3.8或3.9PyTorch 1.10以上2.x也可以CUDA对应你的显卡驱动版本。如果没有NVIDIA显卡CPU也能跑只是训练速度慢很多建议学习用正式训练还是找台有GPU的机器。安装依赖的方式是进入项目目录后执行pip install -r requirements.txt这里有个细节requirements.txt里的torch版本可能与你的CUDA不匹配。如果你已经单独装好了适配自己显卡的PyTorch就不要直接装requirements里指定的torch可以先打开文件把torch和torchvision两行注释掉再安装其余依赖。验证环境是否可用最直接的方法是运行一个最简单的推理python detect.py --source data/images/bus.jpg --weights yolov5s.pt如果能看到一张画了检测框的输出图说明环境基本没问题。这一步建议在训练前就确认不要等到训练中途才发现某个依赖缺失。2.2 数据集目录结构与YOLO标注格式YOLOv5对数据集目录有约定训练前需要把图片和标注按固定结构放好。推荐使用这样的目录结构datasets/mask/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── mask.yamlimages里放jpg或png图片labels里放同名的txt文件。关键点图片和标注文件的名称必须一一对应否则训练时找不到标注会直接跳过该图。YOLO标注格式非常简洁每个txt文件里每一行代表一个目标框格式是class_id x_center y_center width height注意这里的四个坐标值都是归一化后的相对值范围在0到1之间。x_center和y_center是目标框中心点相对于图片宽度和高度的比例width和height是框的宽高相对于图片宽高的比例。如果直接用像素坐标或者用左上角右下角的格式训练时损失函数会直接乱套。我见过不少同学从网上爬数据时拿到的标注是VOC格式的XML里面是xmin、ymin、xmax、ymax的绝对像素坐标。如果遇到这种情况需要先转成YOLO格式。转换公式很简单x_center (xmin xmax) / 2 / img_width y_center (ymin ymax) / 2 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height标签文件里class_id从0开始比如0代表“佩戴口罩”1代表“未佩戴口罩”这个映射关系要和yaml配置文件里一致。2.3 数据划分与类别平衡数据准备好后需要将2000张图片划分为训练集和验证集。我习惯按9:1划分也就是1800张训练、200张验证。如果你的数据集包含戴口罩和不戴口罩两类建议检查一下两类的数量比例不要一边有1500张、另一边只有500张差距过大会导致模型对少数类别学习不充分。处理这种情况的方法有两个一是收集更多少数类别的样本二是在训练时设置类别权重。在作业场景下更推荐前者因为如果原始数据里就严重不平衡即使调整损失函数权重模型对少数类别的泛化能力依然有限。划分数据时还要注意同一个人或者同一个场景的图片尽量只出现在训练集或验证集中不要让一张场景的图片既参与训练又被拿去验证否则验证指标会虚高到了新场景上效果打折扣答辩现场演示时容易被问住。3. 训练前的关键配置模型选择与超参数3.1 配置文件里需要改哪些内容YOLOv5训练时需要准备两个配置文件数据集配置文件mask.yaml和模型结构配置文件yolov5s.yaml。模型结构配置文件一般不用大改主要改数据集配置文件格式如下train: datasets/mask/images/train val: datasets/mask/images/val nc: 2 names: [with_mask, without_mask]train和val分别指向训练集和验证集图片目录nc表示类别数量这里口罩检测就是2类names列表与标注文件里的class_id一一对应。有个很容易踩的坑是路径写法。YOLOv5会自动将相对路径拼接在当前工作目录下如果数据集明明放在datasets/mask下却报“image not found”多半是路径写错。建议直接用绝对路径简单直接省得排查。3.2 预训练权重与模型规模的选择YOLOv5提供了n、s、m、l、x五种不同规模的模型复杂度依次递增。课程项目的数据量是2000张我推荐使用yolov5s或者yolov5m。yolov5s参数约700万训练和推理都快显存占用低yolov5m参数约2100万精度略高但训练时间相应增加。用yolov5l或更大模型跑2000张数据不仅慢而且容易过拟合对作业来说没有必要。使用预训练权重的方式python train.py --weights yolov5s.pt --data mask.yaml --img 640 --epochs 100 --batch-size 16yolov5s.pt是在COCO数据集上预训练好的权重。初始训练时模型会冻结主干网络的前几层因为预训练特征已经足够通用只需要微调后几层来适应口罩检测这个任务。如果你自己有训练好的模型也可以在此基础上继续训练比如用之前某次训练的权重作为初始权重接着跑这在数据有更新时很有用。3.3 超参数选择epochs、batch size与学习率超参数是容易被忽略、但影响很大的地方。先说epochs。2000张图片的数据量一般训练100到200个epoch就足够。如果设置过少模型欠拟合mAP偏低设置过多后段loss基本不再下降纯属浪费时间。可以用一个简单的办法判断观察训练日志里val精度是否还在持续上升如果连续20个epoch没有提升就停止训练。batch size主要受显存限制。在8GB显存的GPU上yolov5s 640分辨率batch size设16是安全范围。如果显存不够优先减小batch size同时可以考虑把分辨率从640降到512但会损失对小目标的检测精度。如果显存充足适当增大batch size有助于稳定训练。学习率方面YOLOv5默认是0.01配合余弦退火调度器大多数情况下不需要手动修改。如果训练开始后loss出现明显震荡可以考虑降到0.005如果loss下降特别慢可以稍微调到0.02。不过课程项目场景下保持默认参数往往是最稳妥的。3.4 数据增强逻辑与注意事项YOLOv5默认开启Mosaic增强也就是把4张图拼成一张输入。这个设计的目的在于增加小目标样本的数量同时让模型对遮挡、不同尺度更鲁棒。在口罩检测中Mosaic增强特别实用因为很多脸部区域占比不大通过拼接可以模拟更多样的场景组合。但Mosaic增强有个副作用训练样本与真实场景差异变大如果验证时不开Mosaic训练和验证指标可能不完全一致。这是正常的不用慌。另一个增强策略是HSV色域扰动它会让模型对光线变化更鲁棒。口罩检测场景中不同光照条件下人脸颜色差异客观存在这个增强对提高泛化能力有帮助。如果你想减少增强强度可以在data/hyps/hyp.scratch-low.yaml里调整比如把mosaic参数从1.0降到0.5。不过我的建议是保持默认让模型多接触一些变化对应对实际场景中的复杂情况更有帮助。4. 模型训练全流程与效果评估4.1 训练命令逐项说明训练命令大致是这样的python train.py \ --weights yolov5s.pt \ --data mask.yaml \ --epochs 100 \ --batch-size 16 \ --img 640 \ --device 0 \ --name mask_exp逐项说下这些参数的作用weights指定初始权重data指定数据集配置文件epochs是训练轮数batch-size每批样本量img输入图片尺寸device指定GPU编号CPU就写cpuname是实验名称训练结果会保存在runs/train/mask_exp目录下。还有一个容易被忽略的参数是--workers控制数据加载的线程数。默认是8如果你的电脑CPU核数较少或内存不大建议降到4或2否则可能因为数据加载瓶颈拖慢训练甚至在Windows下报DataLoader worker相关的错误。我自己的经验是Windows环境下workers设成0或2最稳Linux下可以放心用8。训练开始后终端会实时输出每个epoch的loss、精度和召回率。你不需要盯着每个数字看重点关注两类一类是box_loss和obj_loss是否持续下降另一类是验证集的mAP是否在提高。4.2 训练结果目录里有什么训练结束后runs/train/mask_exp目录下会生成很多文件常见的有weights/best.pt验证集mAP最高的权重、weights/last.pt最后一个epoch的权重、results.png训练曲线汇总图、混淆矩阵、验证集预测结果图等。这里有个实际经验best.pt和last.pt不一定是同一个。如果训练后期过拟合last.pt在验证集上可能不如best.pt所以作业演示时一定用best.pt不要随意拿last.pt做推理。results.png非常直观包含训练和验证的box_loss、obj_loss、cls_loss曲线以及precision、recall、mAP0.5和mAP0.5:0.95曲线。答辩时给老师展示这个图比展示一堆终端日志更有说服力。4.3 评估指标怎么解读YOLOv5训练日志里最核心的指标是mAP0.5和mAP0.5:0.95。mAP0.5的含义是当预测框与真实框的IoU大于0.5时算检测正确计算所有类别的平均精度。如果你看到mAP0.5在0.9以上说明模型在这个数据集上表现已经很不错了。mAP0.5:0.95则是一个更严格的指标计算IoU从0.5到0.95步长0.05共10个阈值下的平均mAP。因为口罩检测对边界框的精确性要求不算特别高mAP0.5:0.95在0.6到0.7之间已经是不错的水平。Precision精确率的含义是在所有预测为某类别的框中正确框的比例Recall召回率的含义是所有真实目标中被检出的比例。这两个指标往往存在权衡如果检测框绝大多数是对的但不全精确率高、召回率低如果什么框都画出来召回率高、精确率低。理想状态是在P和R都高的情况下达到平衡也就是PR曲线下面积大对应mAP更高。4.4 实际训练时的观察记录我自己在类似数据集上跑YOLOv5s的经验是前10个epoch损失下降明显大概从0.1级快速降低到0.05以下到30个epoch左右mAP0.5能到0.8以上50个epoch后提升速度变缓80到100个epoch时基本稳定在0.9以上。如果你的数据质量好、标注干净这个曲线应该大体一致。如果前几个epoch损失不降要看几件事一是学习率是不是设得过高二是数据集路径是否配错有没有可能模型一直在空数据上训练三是标注文件有没有和图片对应上。这些排查方法我会在第6章展开说。5. 核心代码解析与二次开发5.1 用训练好的模型做图片推理训练完成后用detect.py做推理是最基础的用法python detect.py --weights runs/train/mask_exp/weights/best.pt --source test.jpg --conf-thres 0.5--source可以是图片路径、视频路径、图片目录也可以是摄像头设备编号0表示默认摄像头。--conf-thres是置信度阈值只有超过这个值的检测框才会被保留。口罩检测场景我建议设在0.4到0.5之间。设太高会漏检尤其是远处人脸或戴着花色口罩的人脸设太低会误检出现各种奇怪的框。推理结果会自动保存到runs/detect/exp目录下包含原图叠加检测框和类别标签后的效果图。这里建议你在答辩前自己多测几张不同场景的图片比如室内灯光、户外逆光、多人场景提前知道模型在哪些场景下表现好在哪些场景下可能误检。5.2 摄像头实时检测的演示技巧作业演示时摄像头实时检测是最容易拉满印象分的环节。命令本身就很简单python detect.py --weights runs/train/mask_exp/weights/best.pt --source 0 --conf-thres 0.45打开摄像头后窗口会实时显示检测结果。这里有几个实战细节大家最好提前处理。一是摄像头权限问题。在Windows下如果提示摄像头被占用或找不到设备检查是不是有别的软件正在用摄像头。在远程服务器或虚拟机环境下摄像头可能根本没有被正确映射这时建议改用视频文件演示。二是实时性。如果你在低配电脑上跑发现画面掉帧严重可以把输入尺寸从640降到480或者把--view-img改为保存视频而不实时显示。显卡够好的话一般没问题但提前测试总是好的。三是演示翻车预案。摄像头现场出意外的情况我见过不少电源管理把摄像头禁用了、驱动掉了、光线太暗导致完全检测不到人脸。建议提前录制一个短视频万一现场摄像头故障直接播放视频检测结果依然能展示检测效果。5.3 批量推理与结果导出如果需要对一批图片或视频批量检测同样用detect.py--source直接指向目录或视频文件即可。检测结果中有一个labels字段记录了每个检测框的类别、置信度和归一化坐标你可以把这些结果导出成CSV方便做统计分析。有些同学会在大作业里加一些数据统计功能比如统计一段视频里出现未戴口罩的帧数、统计某个时间段的人流量。这个思路不错但要提前想好数据口径否则容易被老师追问。一个常见做法是每隔N帧记录一次检测结果用这个采样结果近似估计整体比例并把抽样方式和近似误差说明清楚。5.4 将检测封装成函数方便复用如果后续要做图形界面或者更复杂的业务逻辑建议不要直接在detect.py上改而是把检测过程封装成一个独立函数。YOLOv5提供了可调用的API大致逻辑如下import torch model torch.hub.load(ultralytics/yolov5, custom, pathruns/train/mask_exp/weights/best.pt, force_reloadTrue) model.conf 0.45 model.iou 0.45 results model(test.jpg) results.print() results.show() results.save()torch.hub.load会自动加载模型结构和权重模型返回的结果对象里包含pandas格式的DataFrame可以直接读取每个框的坐标、置信度和类别。用这种方式的好处是灵活你可以方便地接入Flask写一个Web接口或者用Tkinter写一个桌面程序。对大作业来说这算是一个加分项。那么接口怎么设计我建议做两个参数conf置信度阈值和imgsz输入尺寸其余参数直接写默认值。接口返回时明确给出检测框的像素坐标、类别名和置信度方便上层做展示和统计。6. 实操中的常见问题与避坑指南6.1 CUDA out of memory显存不足最经典的问题训练中途报“CUDA out of memory”。处理思路从低风险到高风险排列先把batch size减半比如从16降到8如果还不行把--img从640降到512如果还不行换yolov5n模型。尽量不要在一开始就换小模型因为yolov5s的精度更适合作为课程项目展示。还有一个容易被忽略的点同时跑多个训练任务会互相占显存。训练前用nvidia-smi检查一下当前显存占用情况看到别人遗留的进程能清就清一下不能清就换GPU编号。6.2 loss不下降或过早平稳loss不下降或者下降速度极慢优先怀疑数据问题。检查labels目录下是否有空txt文件检查图片和txt名称是否完全一致yaml文件里的nc和names是否和标注匹配。如果数据没问题再考虑学习率。loss一开始在0.1层级波动然后很久不降有可能是标注框质量太差比如很多框位置偏移或者包含大量背景。这种情况需要用可视化工具检查几张训练图片把标注画出来看看是否贴合目标。YOLOv5官方没有直接提供画标注的工具但可以用OpenCV写几行代码把txt转成矩形框画在图片上检查前20张图片基本就能发现问题。6.3 检测结果中类别混淆训练结束后测试发现“未戴口罩”经常被检成“戴口罩”或者反过来这多半是数据问题不是模型问题。排查思路检查数据集中两类图片的特征是否足够区分比如戴布口罩、手捂嘴、口罩戴在下巴上这些情况是否都被标注成了正确的类别。如果标注时把“口罩没戴好”也统一标成“戴口罩”模型就会学出错误规律。处理方式有两种一是把不清楚的样本从数据集中剔除宁缺毋滥二是把“口罩没戴好”单独作为第三类这样模型不用勉强把中间状态归到两边检测效果反而更稳。但会增加标注工作量最后会不会高仁者见仁需要你自己权衡。6.4 验证集mAP高、实际场景检测差这就是过拟合的典型表现。模型把训练集的背景和特殊场景记住了而不是真正学会人脸和口罩的特征。缓解办法增加数据增强的强度、降低模型规模、增加训练样本多样性。采集一些不同光线、不同角度、不同表情的数据往往比调参更有用。还有一种情况是实际场景中的人脸与你训练集里的人脸差异过大比如训练集都是正脸、实际检测时都是侧脸。这种情况即使加大增强强度也未必有用最直接的方法是补充侧脸和低头数据。6.5 推理速度慢怎么办课程项目通常不需要极致的推理速度但如果演示时卡顿明显可以按顺序优化把输入尺寸从640降到416或320这是立竿见影的换用TensorRT或ONNX Runtime做推理速度能显著提升但配置复杂度也上升使用yolov5s或yolov5n模型比大模型快很多。对作业来说建议做到第一步就够了后面的优化可以写进“后续改进方向”里表明你思考过这个问题。6.6 几个小坑速查根据我的经验还有几个细节容易让人头疼torch.hub.load下载权重时网络超时手动把权重文件放到指定目录即可解决中文路径会导致读图失败项目路径和文件名尽量不要出现中文detect.py保存结果的目录会按exp、exp2、exp3递增命名找不到文件时可以回去看看这个规律如果用了GPU训练而CPU加载模型要加map_location参数否则会报权重复制错误。我建议把这些坑直接写进实验报告“问题与解决”一节老师看到这些真实调试记录比空泛的“解决了技术难点”更有说服力也更像一个自主完成的“高分项目”。7. 答辩演示与项目扩展建议到了答辩环节重点是讲清楚“我做了什么”“为什么这样做”“效果如何”而不是念PPT。演示顺序可以参考先展示一张未戴口罩和戴口罩的检测效果对比图再现场摄像头实时检测最后展示训练曲线和指标。如果时间充裕再补充说明你踩过哪些坑这会让老师觉得你是真正在做项目而不是在应付作业。关于项目后续扩展你可以提出几个方向比如把模型导出为ONNX并部署到手机或嵌入式设备、添加人脸身份识别功能、统计某区域口罩佩戴率并做可视化报表、用KAIST等类似数据集验证模型的泛化能力。这些方向都不需要你现在就实现但能证明你对目标检测的工程链路有整体认知。最后再分享一个我个人的经验这类项目最大的价值不在于把mAP从0.95提到0.96而在于完整走通“数据标注-模型训练-评估-部署”这条链路。2000张图片、一个预训练模型、一次微调看起来简单但其中每一环都可能出问题。真正把这些细节经历一遍你对深度学习落地的理解会扎实很多。做项目时不光盯着准确率几个数字多留意那些让你卡住半小时的小问题它们才是你答辩时最宝贵的素材。本文还有配套的精品资源点击获取