YOLOv5口罩检测完整实战:训练、评估与摄像头识别
前言
上一篇介绍了目标检测和YOLOv5的基本原理,本文进入完整实战。我们将使用一个已经标注好的口罩数据集训练YOLOv5s,实现mask与no-mask两类目标检测,并使用图片和摄像头验证模型。
本文不是基于当前最新版ultralytics Python包,而是基于本地yolov5_2_0旧版工程代码。很多网络教程使用新版参数,例如--img、runs/train或from ultralytics import YOLO,不能直接照搬到这个项目。本文所有命令均按照当前工程实际支持的参数编写。
本项目已经具备现成数据集,因此不会展开标注软件操作,只说明YOLOv5数据集必须包含哪些内容、目录如何对应、标签如何检查。
整篇代码严格遵循工程化规范,所有训练命令按实际支持的参数编写,环境配置清晰可复现,可直接迁移至其他目标检测数据集的训练任务中。
文章目录
-
- 前言
-
- 一、项目目标与最终效果
- 二、项目目录结构
- 三、Python与Conda环境
- 四、数据集必须包含哪些内容
- 五、YOLO标签文件格式
- 六、数据集目录为什么必须对应
- 七、编写data.yaml
- 八、检查类别编号和样本分布
- 九、模型配置与预训练权重
- 十、训练命令逐项解释
- 十一、正式开始训练
- 十二、训练过程中观察什么
- 十三、训练输出文件说明
- 十四、best.pt与last.pt的区别
- 十五、验证模型并查看分类别指标
- 十六、本项目的实际训练结果
- 十七、使用图片测试模型
- 十八、使用摄像头实时识别
- 十九、实时推理代码逐步解释
- 二十、关键推理参数如何调整
- 二十一、为什么全部识别成戴口罩
- 二十二、如何改善no-mask类别
- 二十三、旧版YOLOv5与新环境兼容问题
- 二十四、常见报错与处理方法
- 二十五、一套规范的实验流程
- 二十六、总结
一、项目目标与最终效果
项目需要在图片、视频或摄像头中检测人脸区域,并输出两个类别:
0:mask(戴口罩)
1:no-mask(未戴口罩)
最终效果如下:
- 绿色框显示戴口罩目标;
- 红色框显示未戴口罩目标;
- 画面中出现
no-mask时显示警告文字。

训练完成后,核心产物不是训练脚本本身,而是权重文件:
runs/exp17/weights/best.pt
以后进行图片或摄像头推理时,主要加载这个文件。
二、项目目录结构
当前项目中,数据集和YOLOv5工程是同级目录:
Mask_YOLO/
├─ MaskDataSet/
│ ├─ train/
│ │ ├─ images/
│ │ └─ labels/
│ ├─ valid/
│ │ ├─ images/
│ │ └─ labels/
│ ├─ test/
│ │ ├─ images/
│ │ └─ labels/
│ └─ data.yaml
└─ yolov5_2_0/
├─ models/
├─ utils/
├─ weights/
├─ runs/
├─ train.py
├─ test.py
├─ detect.py
├─ camera_mask.py
└─ hyp.yaml

“同级目录”意味着从yolov5_2_0出发,先使用..返回上一级,再进入MaskDataSet:
../MaskDataSet
Windows命令中的反斜杠和YAML中常用的正斜杠通常都能被Python处理,但配置文件中使用/更容易跨平台。
三、Python与Conda环境
同一台电脑可以同时存在Python 3.9、3.10、3.11和3.13。不同解释器的第三方库默认不互通,因此不能只看电脑上“安装了PyTorch”,还要看它安装在哪个环境中。
本项目已经验证可用的环境是:
Conda环境名:pytorch
Python:3.10.20
PyTorch:2.5.1 CPU版
在CMD中激活环境:
conda activate pytorch
确认解释器:
where python
python --version
python -c "import sys; print(sys.executable)"
python -c "import torch; print(torch.__version__, torch.cuda.is_available())"
正确路径应类似:
D:\Anaconda3\envs\pytorch\python.exe
如果torch.cuda.is_available()返回False,表示当前使用CPU版PyTorch。程序仍然可以运行,只是训练和推理速度较慢。
为了长期管理,可以将环境克隆为项目专属名称:
conda create -n mask-yolo --clone pytorch
conda activate mask-yolo
四、数据集必须包含哪些内容
现成的YOLOv5目标检测数据集至少需要以下内容:
- 训练图片;
- 与训练图片对应的YOLO TXT标签;
- 验证图片;
- 与验证图片对应的YOLO TXT标签;
- 数据配置文件
data.yaml; - 明确且固定的类别编号与类别名称。
测试集不是训练的绝对必需项。训练时必须有训练集,通常也应有验证集;测试集用于最终独立评价。
图片支持的常见格式包括.jpg、.jpeg和.png。标签必须是纯文本.txt文件。
数据质量比单纯数量更重要。图片应尽量覆盖:
- 不同人物;
- 正脸和侧脸;
- 不同距离和人脸大小;
- 室内与室外光线;
- 明亮、背光和低照度情况;
- 不同颜色、形状的口罩;
- 未戴口罩、错误佩戴、遮挡脸部等困难情况;
- 最终实际使用的摄像头画面。
五、YOLO标签文件格式
每张图片对应一个同名标签文件。例如:
images/person_001.jpg
labels/person_001.txt
TXT中每一行表示一个目标:
class_id x_center y_center width height
示例:
0 0.515625 0.462500 0.187500 0.325000
1 0.243750 0.510000 0.162500 0.290000
第一行表示类别0,第二行表示类别1。一张图有多少个目标,就有多少行。
后四个坐标必须归一化到0~1。如果标注工具导出的坐标是像素值,需要转换:
x_center_normalized = x_center_pixel / image_width
y_center_normalized = y_center_pixel / image_height
width_normalized = box_width_pixel / image_width
height_normalized = box_height_pixel / image_height
类别编号必须从0开始。本项目规定:
0 = mask
1 = no-mask
如果标签中的0实际代表未戴口罩,而YAML却写成mask,模型训练本身可能正常,但最终显示名称会完全相反。
调试提示:
在训练前,可编写一个简单的标签检查脚本,在PyCharm中设置断点查看标签是否正确加载:
import cv2
import numpy as np
img_path = "../MaskDataSet/train/images/000001.jpg"
label_path = "../MaskDataSet/train/labels/000001.txt"
img = cv2.imread(img_path)
h, w = img.shape[:2]
with open(label_path, 'r') as f:
lines = f.readlines()
for line in lines:
cls, xc, yc, bw, bh = map(float, line.strip().split())
x1 = int((xc - bw/2) * w)
y1 = int((yc - bh/2) * h)
x2 = int((xc + bw/2) * w)
y2 = int((yc + bh/2) * h)
cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.putText(img, str(int(cls)), (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 1)
cv2.imshow('check', img)
cv2.waitKey(0)
通过断点观察lines的内容,确认每行恰好包含5个数值,且坐标都在0~1之间。
六、数据集目录为什么必须对应
YOLOv5会根据图片路径自动寻找标签。在这个旧版工程中,它通常把路径中的images替换成labels,并把图片后缀替换成.txt。
例如:
MaskDataSet/train/images/abc.jpg
对应:
MaskDataSet/train/labels/abc.txt
因此以下情况会导致标签无法加载:
- 图片和标签文件名不同;
images或labels目录拼写错误;- 标签扩展名不是
.txt; - 图片被重新命名,但标签没有同步改名。
本项目训练集105张图片与105个标签能够对应,验证集29张图片与29个标签也能对应。测试集中的15张图片曾被改名为1.jpg到15.jpg,标签仍保留原名,所以测试集当前不能可靠用于评价。
七、编写data.yaml
本项目使用的MaskDataSet/data.yaml为:
train: ../MaskDataSet/train/images
val: ../MaskDataSet/valid/images
nc: 2
names: ['mask', 'no-mask']
字段含义如下:
train:训练图片目录;val:验证图片目录;nc:类别数量,number of classes;names:类别名称列表,位置必须和标签编号一致。
这里的路径是相对于运行train.py时的工作目录解释的。我们先进入yolov5_2_0再启动训练,所以../MaskDataSet是正确路径。
如果在其他目录启动脚本,相对路径可能失效。初学阶段最稳妥的方式是先切换到YOLO工程根目录:
cd /d D:\Jupyter_Projects\PythonProject\AI_Projects\Mask_YOLO\yolov5_2_0
测试集修复文件名对应关系后,可以增加:
test: ../MaskDataSet/test/images
在对应关系未修复前不要强行加入测试路径。
八、检查类别编号和样本分布
训练前应检查:
- 所有标签是否恰好包含5列;
- 类别编号是否为0或1;
- 坐标是否都在
0~1; - 图片是否都有同名标签;
- 是否存在标签但缺少图片;
- 各类别标注框数量是否严重失衡。
本项目统计结果:
| 数据划分 | mask | no-mask | 总标注框 |
|---|---|---|---|
| train | 573 | 123 | 696 |
| valid | 142 | 20 | 162 |
| test | 91 | 5 | 96 |
全部数据共954个框。训练集中mask:no-mask约为4.7:1,验证集中约为7.1:1,类别失衡比较明显。
需要区分“图片数量”和“标注框数量”。训练集只有105张图片,但一张图片中可以有多个人脸,所以共有696个训练框。
调试提示:
可在PyCharm中运行以下代码片段,在断点处查看类别分布:
import os
from collections import Counter
label_dir = "../MaskDataSet/train/labels"
class_counts = Counter()
for f in os.listdir(label_dir):
if f.endswith('.txt'):
with open(os.path.join(label_dir, f), 'r') as fp:
for line in fp:
cls = int(line.strip().split()[0])
class_counts[cls] += 1
print(class_counts) # Counter({0: 573, 1: 123})
通过调试器观察class_counts的具体数值,确认类别失衡程度。
九、模型配置与预训练权重
项目使用YOLOv5s:
models/yolov5s.yaml
预训练权重为:
weights/yolov5s.pt
yolov5s.yaml定义网络结构,yolov5s.pt保存预训练参数。二者不是同一个概念。
对于小数据集,推荐从预训练权重开始,而不是完全随机初始化。预训练模型已经学会大量通用视觉特征,可以减少训练难度。
超参数文件为:
hyp.yaml
它包含学习率、动量、权重衰减、颜色增强、缩放和平移等训练设置。初学者应该先使用一套能够工作的配置建立基准结果,再逐项实验,不要一次修改许多参数。
十、训练命令逐项解释
本项目使用的训练命令:
python train.py ^
--data ../MaskDataSet/data.yaml ^
--cfg models/yolov5s.yaml ^
--weights weights/yolov5s.pt ^
--hyp hyp.yaml ^
--epochs 200 ^
--batch-size 4 ^
--img-size 640 640 ^
--device cpu
参数说明如下:
--data:指定数据集YAML。脚本会从这里获得训练目录、验证目录、类别数和类别名;--cfg:指定模型结构。本项目选择体积较小、速度较快的YOLOv5s;--weights:指定初始化权重。填写weights/yolov5s.pt表示迁移学习;--hyp:指定超参数文件;--epochs:表示完整遍历训练集的次数。200个epoch意味着模型会多次看到同一批图片,但每次可能经过随机增强;--batch-size:表示一次送入模型的图片数量。batch越大通常占用更多显存或内存。CPU环境使用4是较保守的选择;--img-size 640 640:表示训练和测试输入尺寸。旧版程序支持分别指定训练、测试尺寸;--device cpu:强制使用CPU。如果安装了可用的CUDA版PyTorch,可使用--device 0指定第一块GPU。
Windows CMD使用^表示命令换行。如果希望减少复制问题,也可以写成一行。
十一、正式开始训练
完整执行顺序:
conda activate pytorch
cd /d D:\Jupyter_Projects\PythonProject\AI_Projects\Mask_YOLO\yolov5_2_0
python train.py --data ../MaskDataSet/data.yaml --cfg models/yolov5s.yaml --weights weights/yolov5s.pt --hyp hyp.yaml --epochs 200 --batch-size 4 --img-size 640 640 --device cpu
第一次训练前可以运行帮助命令,确认当前版本到底支持哪些参数:
python train.py --help
这是避免“照抄了其他版本教程但参数不存在”的有效方法。
CPU训练较慢,终端一段时间没有刷新不一定代表卡死。可以观察CPU使用率、内存和runs目录中的文件更新时间。
调试提示:
训练开始后,可在runs/exp0目录中查看生成的train_batch0.jpg,了解数据增强后的训练图片效果。如果发现明显异常的增强(如人脸翻转、颜色严重失真),可调整hyp.yaml中的增强参数。
十二、训练过程中观察什么
训练日志通常显示当前epoch、显存占用、损失、目标数量和验证指标,例如:
199/199 0G box_loss obj_loss cls_loss total targets img_size P R mAP@.5 mAP@.5:.95
重点观察:
box_loss是否总体下降;obj_loss是否总体下降;cls_loss是否总体下降;- 验证集Precision、Recall和mAP是否提升;
- 后期是否出现训练损失继续下降,但验证指标变差的现象。
日志中的0G表示没有使用GPU显存,即当前在CPU上训练。
某一轮损失轻微上升很正常。随机batch、Mosaic、缩放和颜色增强都会让每轮难度不同。应该看整体趋势,不要根据一两轮波动判断训练失败。
十三、训练输出文件说明
这个旧版工程将每次训练保存在:

本项目效果较完整的一次训练是runs/exp17。其中常见文件包括:
exp17/
├─ hyp.yaml # 本次使用的超参数
├─ opt.yaml # 本次训练命令参数,便于复现实验
├─ results.txt # 每个epoch的损失和指标
├─ results.png # 训练曲线图
├─ labels.png # 标签位置和尺寸分布
├─ train_batch0.jpg # 数据增强后的训练图片
├─ test_batch0_gt.jpg # 真实标签
├─ test_batch0_pred.jpg # 模型预测
└─ weights/
├─ best.pt # 验证集表现最优的模型
└─ last.pt # 最后一个epoch的模型

opt.yaml保存本次训练命令参数,便于复现实验。
hyp.yaml保存本次使用的超参数。
results.txt保存每个epoch的损失和指标。
results.png将训练曲线绘制成图片。
labels.png可用于观察标签位置和尺寸分布。
train_batch*.jpg展示数据增强后的训练图片,可以发现明显错标或异常增强。
test_batch0_gt.jpg是真实标签,test_batch0_pred.jpg是模型预测,可用于直观比较。
调试提示:
训练完成后,打开results.png观察损失曲线。如果val_mAP在后期持续下降,说明可能发生过拟合。如果训练损失持续下降但验证损失上升,也是过拟合的信号。

十四、best.pt与last.pt的区别
last.pt是最后一个epoch保存的模型。
best.pt是训练过程中根据验证表现选出的较优模型。最后一轮不一定是效果最好的一轮,因为后期可能发生过拟合或指标波动。
实际推理通常优先使用:
best.pt
如果训练意外中断并希望继续训练,通常使用last.pt恢复进度。旧版工程的恢复参数可以通过以下命令确认:
python train.py --help
十五、验证模型并查看分类别指标
只看训练日志中的all行不够。应使用--verbose输出每个类别的指标:
python test.py ^
--weights runs\exp17\weights\best.pt ^
--data ..\MaskDataSet\data.yaml ^
--batch-size 4 ^
--img-size 640 ^
--conf-thres 0.001 ^
--iou-thres 0.5 ^
--device cpu ^
--verbose
评估mAP时使用较低的--conf-thres 0.001,是为了让程序收集足够多的候选结果绘制完整的Precision-Recall关系。它不同于实际展示结果时常用的0.25。
项目旧代码原本使用已经被新版NumPy删除的np.int,需要替换为内置int才能正常评估。这属于旧代码兼容问题,并不是数据集错误。
十六、本项目的实际训练结果
exp17完成了200个epoch。最佳权重按类别验证结果如下:
| 类别 | Images | Targets | Precision | Recall | mAP@0.5 | mAP@0.5:0.95 |
|---|---|---|---|---|---|---|
| all | 29 | 162 | 0.671 | 0.905 | 0.872 | 0.557 |
| mask | 29 | 142 | 0.819 | 0.880 | 0.913 | 0.588 |
| no-mask | 29 | 20 | 0.522 | 0.930 | 0.830 | 0.526 |
不能只看到mAP@0.5 = 0.872就认为模型在所有场景都很好。
no-mask的Recall为0.930,说明验证集中大部分未戴口罩目标能够被找到;但Precision只有0.522,说明该类别预测不够稳定。并且验证集中只有20个no-mask框,样本规模不足以全面代表真实摄像头环境。
十七、使用图片测试模型
从验证集图片进行推理:
python detect.py ^
--weights runs\exp17\weights\best.pt ^
--source ..\MaskDataSet\valid\images ^
--output inference\mask_result ^
--img-size 640 ^
--conf-thres 0.25 ^
--iou-thres 0.45 ^
--device cpu
常用参数:
--weights:权重路径;--source:一张图片、图片目录、视频或摄像头编号;--output:输出目录;--conf-thres:最低置信度;--iou-thres:NMS的IoU阈值;--device:CPU或GPU。
应分别测试三类图片:
- 验证集图片,用于确认模型和代码正常;
- 网上或手机拍摄的新图片,用于测试泛化;
- 实际摄像头截图,用于测试部署场景。
如果第一类效果好、第三类效果差,通常说明存在场景差异,而不是权重文件损坏。
十八、使用摄像头实时识别
项目已经提供整理后的:
camera_mask.py
运行方法:
conda activate pytorch
cd /d D:\Jupyter_Projects\PythonProject\AI_Projects\Mask_YOLO\yolov5_2_0
python camera_mask.py
程序默认打开摄像头0:
cap = cv2.VideoCapture(0)
如果摄像头无法打开,可尝试改为1或2。出现检测窗口后按q退出。
程序自动选择设备:
DEVICE = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
当前环境会显示:
Camera started on cpu. Press q to quit.
十九、实时推理代码逐步解释
加载模型:
model = attempt_load(str(WEIGHTS_PATH), map_location=DEVICE)
model.eval()
eval()会将模型切换到推理模式。它与torch.no_grad()作用不同:eval()调整部分网络层行为(如Dropout和BatchNorm),no_grad()关闭梯度记录以节省内存和计算。
读取摄像头帧:
ok, frame = cap.read()
使用Letterbox保持宽高比:
img = letterbox(frame, new_shape=IMG_SIZE)[0]
这里必须使用旧版YOLOv5 2.0的接口。该版本不接受新版教程中的stride=stride参数。
转换颜色通道和数组维度:
img = img[:, :, ::-1].transpose(2, 0, 1)
img = np.ascontiguousarray(img)
OpenCV读取的是BGR,模型训练通常使用RGB;OpenCV数组是[H, W, C],PyTorch模型输入为[C, H, W]。
转换为张量并归一化:
img_tensor = torch.from_numpy(img).to(DEVICE).float() / 255.0
img_tensor = img_tensor.unsqueeze(0)
执行推理:
with torch.no_grad():
prediction = model(img_tensor)[0]
执行NMS:
prediction = non_max_suppression(
prediction,
conf_thres=NMS_CONF,
iou_thres=IOU_THRESH
)
最后使用scale_coords()把处理后图片中的框坐标映射回摄像头原图,再通过cv2.rectangle()和cv2.putText()绘制结果。
调试提示:
在推理代码中加入断点,观察prediction的数据结构。prediction是一个列表,每个元素形状为[N, 6],其中N为检测目标数,6列分别为[x1, y1, x2, y2, conf, cls]。通过调试器可以查看具体检测结果。
二十、关键推理参数如何调整
当前实时程序采用:
MASK_CONF = 0.35
NO_MASK_CONF = 0.15
NMS_CONF = min(MASK_CONF, NO_MASK_CONF)
IOU_THRESH = 0.45
IMG_SIZE = 640
MASK_CONF:戴口罩框的最低显示阈值;NO_MASK_CONF:未戴口罩框的最低显示阈值。安全监控通常更重视不要漏掉未戴口罩目标,所以可以设置得略低,但过低会增加误报;NMS_CONF必须不高于两个类别阈值中的最小值。否则no-mask候选框可能在分类别阈值判断之前就被NMS过滤;IOU_THRESH控制重复框抑制,0.45可以作为起点;IMG_SIZE增大可能改善小目标,但CPU推理更慢。
建议一次只修改一个参数,并使用同一组测试图片比较:
| 实验 | MASK_CONF | NO_MASK_CONF | 目标 |
|---|---|---|---|
| A | 0.35 | 0.15 | 当前基线 |
| B | 0.35 | 0.10 | 检查是否减少no-mask漏检 |
| C | 0.40 | 0.15 | 检查是否减少mask误报 |
阈值不能解决模型把no-mask分类成mask的问题,只能控制已有预测是否显示。
二十一、为什么全部识别成戴口罩
本项目出现“未戴口罩也标成戴口罩”,主要可能来自以下几个方面。
类别失衡
训练集中573个mask框,只有123个no-mask框。模型看到多数类的次数更多。
公开数据集与摄像头画面差异
数据集包含许多新闻和网络图片,实际摄像头则可能是固定室内背景、近距离脸部、特定镜头和特定光线。验证指标只能代表验证集分布。
原始实时代码强制拉伸图片
原代码使用:
cv2.resize(frame, (640, 640))
它会改变人脸比例。现在已经改为letterbox(),与YOLOv5的标准推理预处理保持一致。
验证样本太少
验证集中只有20个no-mask框。即使Recall较高,也不足以覆盖所有未戴口罩情况。
困难情况没有进入训练集
例如手遮挡嘴部、低头、侧脸、逆光和画面模糊等情况,模型可能把皮肤阴影误认为口罩区域。
二十二、如何改善no-mask类别
最有效的方法不是无限调整阈值,而是补充与实际应用一致的数据。
建议使用最终运行程序的同一摄像头采集:
- 不同人物未戴口罩画面;
- 正脸、左侧脸、右侧脸;
- 近距离、中距离、远距离;
- 白天、夜间和室内灯光;
- 坐着、站着、低头和移动;
- 手遮脸、围巾、衣领、眼镜等易混淆情况。
目标是将no-mask标注框从123增加到至少400~600,使其接近mask数量。不要简单复制同一张图片,因为复制不会增加场景多样性。
补充数据后重新划分:
训练集:约70%~80%
验证集:约10%~20%
测试集:约10%~20%
同一段视频的连续帧应尽量放在同一个划分中,避免相邻帧同时进入训练集和验证集造成数据泄漏。
标注时要明确规则。例如口罩没有遮住鼻子时究竟算mask还是no-mask,必须全数据集统一。如果希望检测“错误佩戴”,最好增加第三类:
0:mask
1:no-mask
2:incorrect-mask
增加类别后必须同步修改nc、names和全部标签编号。
二十三、旧版YOLOv5与新环境兼容问题
旧代码运行在较新的NumPy、PyTorch和torchvision上,可能出现兼容警告或错误。
NumPy的np.int错误
错误示例:
AttributeError: module 'numpy' has no attribute 'int'
原因是新版NumPy删除了已经弃用的np.int。旧代码中可以安全替换为:
int
letterbox参数错误
错误示例:
TypeError: letterbox() got an unexpected keyword argument 'stride'
原因是复制了新版接口,但YOLOv5 2.0的letterbox()没有该参数。旧版正确写法为:
letterbox(frame, new_shape=640)
torchvision图片扩展警告
Failed to load image Python extension
当前项目主要使用OpenCV读取图片,模型训练和推理已经实际运行成功,因此该警告不是本次程序退出原因。但它说明torchvision与底层图片库并非完全匹配,未来整理环境时应安装相互兼容的PyTorch与torchvision组合。
torch.load FutureWarning
这是PyTorch对未来默认行为和不可信权重安全风险的提示。自训练且可信的本地权重可以继续用于当前工程,但不要随意加载未知来源的.pt文件。
二十四、常见报错与处理方法
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| ModuleNotFoundError: No module named torch | 当前环境没有PyTorch | 先执行conda activate pytorch |
| 找不到data.yaml或图片目录 | 当前目录不对 | 确认从yolov5_2_0目录启动训练 |
| No labels found | 图片和标签路径对应错误 | 检查目录是否叫images与labels,文件名是否相同 |
| 类别名称显示反了 | 标签编号与names不对应 | 检查TXT中类别编号与names列表的对应关系 |
| 摄像头无法打开 | 设备被占用或ID不对 | 关闭其他摄像头应用,尝试VideoCapture(1) |
| CPU推理卡顿 | 输入尺寸过大 | 降低IMG_SIZE或跳帧处理 |
| numpy的np.int错误 | 新版NumPy不兼容 | 将np.int替换为内置int |
| 训练很好但摄像头很差 | 场景差异 | 保存摄像头失败画面,重新标注训练 |
二十五、一套规范的实验流程
为了避免“改了很多参数却不知道哪个有效”,建议采用固定实验流程。
第一步,保存当前基线:
数据集版本:v1
模型:YOLOv5s
图片尺寸:640
batch:4
epochs:200
预训练权重:yolov5s.pt
第二步,记录每次实验的opt.yaml、hyp.yaml和结果目录,不要覆盖旧结果。
第三步,使用固定验证集比较按类别Precision、Recall和mAP。
第四步,准备一组固定的真实摄像头测试图片,人工记录:
- 未戴口罩漏检数量;
- 未戴口罩错分为戴口罩的数量;
- 戴口罩错分为未戴口罩的数量;
- 完全没有检测框的数量;
- 单张平均处理时间。
第五步,每轮只改变一个主要变量,例如只增加数据、只修改阈值或只调整输入尺寸。
第六步,把失败样本加入下一版数据集,形成:
训练 → 部署测试 → 收集失败样本 → 重新标注 → 再训练
这比盲目堆叠训练轮数更接近真实工程流程。
二十六、总结
使用现成YOLOv5数据集时,最重要的是确保图片、TXT标签和data.yaml三者严格对应。标签必须使用从0开始的类别编号和归一化xywh坐标。
本项目使用Python 3.10的Condapytorch环境、YOLOv5s网络、预训练权重和640输入尺寸完成了200轮训练。模型在验证集上取得总体mAP@0.5 = 0.872,但no-mask类别样本过少,真实摄像头效果仍受类别失衡和场景差异影响。
完整项目的关键经验是:
- 固定正确的Python环境;
- 确认数据集路径和标签对应关系;
- 从预训练权重开始;
- 查看分类别指标,而不是只看总体mAP;
- 保持训练与推理预处理一致;
- 使用实际摄像头失败样本持续扩充数据;
- 不要把阈值调整误认为可以替代重新训练。
更多推荐




所有评论(0)