前言
口罩检测是计算机视觉在公共卫生领域的典型应用,本文将详细介绍如何基于 YOLOv5 框架搭建一个口罩检测模型,实现 "戴口罩" 和 "不戴口罩" 两类目标的实时检测。全程采用 GPU 加速训练,针对口罩这类小目标优化模型参数,适合入门者学习参考。
【如果你对人工智能的学习有兴趣可以看看我的其他博客,对新手很友好!!!】
【本猿定期无偿分享学习成果,欢迎关注一起学习!!!】
【实现效果】
一、环境搭建
1.1 创建虚拟环境
使用 Anaconda 创建专属虚拟环境,避免依赖冲突:
conda create -n yolov5 python=3.9 -y
创建完成后激活环境:
conda activate yolov5
1.2 安装 GPU 版本 PyTorch
这个需要对应自己的GPU的cuda进行,详情请看:
纯干货,无废话CUDA、cuDNN、 PyTorch 环境搭建教程_cuda+cudnn+pytorch-CSDN博客
1.3 配置 YOLOv5 依赖
1.克隆 YOLOv5 仓库或下载源码到本地
推荐直接去github上下载zip,网址如下:
GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite
https://github.com/ultralytics/yolov5
2.打开 PyCharm,选择已创建的yolov5
虚拟环境
3.编辑requirements.txt
文件
删除以下两行(避免覆盖已安装的 GPU 版本 PyTorch):
注意我们已经手动下载了gpu版本的cuda,所以说就需要去把yolo5依赖中的torch删掉,因为自动下载会下载cpu版本的torch而且会覆盖我们的gpu版本。
4.在 PyCharm 终端执行依赖安装:
注意必须要到 requirements.txt路径下
pip install -r requirements.txt
二、项目结构与文件准备
在 YOLOv5 文件夹下创建train
目录,组织结构如下:
其中 VOC.yaml和yolov5m.yaml都是yolov5源码中有的,我们拿来修改一下就能用
data下面的VOC.yaml
以及基于model下面的yolov5m.yaml,因为数据集只有几千张,所以说我使用速度和精度中等的m
三、配置文件修改
3.1 数据集配置(VOC.yaml)
修改VOC.yaml
文件,适配口罩检测数据集:
【注意路径需要自己修改】
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# 口罩检测数据集配置(精确匹配你的路径)
path: D:\yoloStudy\yolov5-master\train\data
train: train\images
val: val\images
test: test\images
# 类别配置(与标注一致)
nc: 3
names: ['with_mask', 'mask_weared_incorrect', 'without_mask']
download: |
pass # 无需自动下载
3.2 模型配置(yolov5m.yaml)
基于yolov5m.yaml
修改,适配口罩检测场景:
1.修改类别数量:
nc: 2 # 将类别数从默认的80改为2
2.优化锚框尺寸:
口罩属于小目标,调整锚框为更适合小目标的尺寸:
anchors:
- [5, 8, 10, 15, 12, 20] # 小尺度锚框
- [18, 25, 25, 35, 30, 45] # 中尺度锚框
- [40, 55, 50, 70, 65, 90] # 大尺度锚框
3.源码:
# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license
# Parameters
nc: 3 # number of classes
depth_multiple: 0.67 # model depth multiple
width_multiple: 0.75 # layer channel multiple
anchors:
- [5, 8, 10, 15, 12, 20] # 更小的锚框,适配口罩
- [18, 25, 25, 35, 30, 45]
- [40, 55, 50, 70, 65, 90]
# YOLOv5 v6.0 backbone
backbone:
# [from, number, module, args]
[
[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3, [1024]],
[-1, 1, SPPF, [1024, 5]], # 9
]
# YOLOv5 v6.0 head
head: [
[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, "nearest"]],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, C3, [512, False]], # 13
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, "nearest"]],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
四、模型训练
4.1 训练脚本(my_train.py)
创建my_train.py
,配置训练参数:
import subprocess
import sys
import os
def train_yolov5():
# 配置参数
data_yaml = "VOC.yaml" # 数据集配置文件路径
model_yaml = "yolov5m.yaml" # 模型配置文件路径
epochs = 100 # 训练轮次
batch = 8 # 批次大小(根据GPU显存调整)
imgsz = 480 # 输入图片尺寸
device = "0" # GPU设备编号(单卡默认为0)
name = "yolov5m_mask_train" # 训练结果保存名称
resume = False # 是否从断点继续训练
# 构建训练命令
command = [
sys.executable,
os.path.abspath("../train.py"), # 指向YOLOv5官方训练脚本
"--data", data_yaml,
"--cfg", model_yaml,
"--epochs", str(epochs),
"--batch", str(batch),
"--imgsz", str(imgsz),
"--device", device,
"--name", name,
"--workers", "4",
]
if resume:
command.append("--resume")
# 执行训练命令
try:
subprocess.run(
command,
check=True,
encoding='utf-8'
)
except subprocess.CalledProcessError as e:
print(f"训练失败,返回码: {e.returncode}")
except FileNotFoundError:
print("错误:未找到train.py,请检查路径")
except Exception as e:
print(f"未知错误: {str(e)}")
if __name__ == "__main__":
train_yolov5()
4.2 开始训练
在 PyCharm 中运行my_train.py
即可开始训练,训练过程中会实时显示损失值、准确率等指标。训练结果默认保存在runs/train/
目录下,包含训练日志、模型权重、评估指标等。
五、模型测试与推理
5.1 项目推理目录结构
在yolov5
主目录下创建推理相关文件夹,结构如下:
关键文件说明:
-
test/
:放入任意格式(jpg、png 等)的测试图,比如从实际场景抓拍的人像图。 -
best.pt
:训练完成后,从runs/train/[训练任务名]/weights/
路径下复制best.pt
(最优权重)到此处 。 -
detect.py
:自定义脚本,负责调用 YOLOv5 官方检测逻辑,简化结果整理流程。
5.2 推理脚本逐行解析
以下是完整的检测脚本代码,并附带详细注释说明:
import warnings
import os
import glob
import subprocess
import shutil
# 忽略不必要的警告信息,使输出更简洁
warnings.filterwarnings("ignore")
# 路径配置 - 可根据实际情况修改
image_dir = "./test" # 测试图片文件夹路径
save_dir = "./out" # 结果保存路径
detect_script_path = "../detect.py"# YOLOv5官方检测脚本路径(注意相对位置)
# 1. 验证测试图片目录是否存在
if not os.path.isdir(image_dir):
# 如果目录不存在则抛出错误并终止程序
raise NotADirectoryError(f"无效目录: {image_dir}")
# 2. 验证YOLOv5官方detect.py是否存在
if not os.path.isfile(detect_script_path):
raise FileNotFoundError(f"未找到detect.py: {detect_script_path}")
# 常见问题:此处路径错误,需确认detect.py在YOLOv5源码中的实际位置
# 3. 检查测试目录中是否有图片文件
has_images = False
# 支持常见图片格式:jpg/jpeg/png/bmp
for ext in ['jpg', 'jpeg', 'png', 'bmp']:
# 查找对应格式的文件
if glob.glob(f"{image_dir}/*.{ext}"):
has_images = True
break
if not has_images:
raise ValueError(f"未找到图片: {image_dir}")
# 解决办法:在test目录中放入至少一张图片
# 4. 创建结果保存目录(如果不存在)
os.makedirs(save_dir, exist_ok=True)
# exist_ok=True表示目录存在时不会报错
# 5. 构建调用YOLOv5官方检测脚本的命令
command = [
"python", detect_script_path, # 指定Python解释器和官方脚本
"--source", image_dir, # 测试图片来源目录
"--weights", "best.pt", # 训练好的模型权重
"--conf", "0.25", # 置信度阈值(可调,0.25表示只保留置信度>25%的结果)
"--project", save_dir, # 结果保存主目录
"--name", "", # 不创建额外子目录(默认会创建exp文件夹)
"--exist-ok" # 允许目录存在,避免重复运行时报错
]
try:
# 6. 执行检测命令
print("开始目标检测...")
result = subprocess.run(
command,
check=True, # 命令执行失败时抛出异常
capture_output=True, # 捕获命令输出
text=True # 输出为文本格式而非字节
)
# 7. 打印检测过程的输出信息
print("检测完成")
print(result.stdout)
# 8. 整理结果目录(解决官方脚本默认创建exp子目录的问题)
# 查找所有以exp开头的目录
exp_dirs = glob.glob(os.path.join(save_dir, "exp*"))
if exp_dirs:
# 按创建时间排序,取最新的exp目录
latest_exp_dir = sorted(exp_dirs)[-1]
# 将exp目录中的所有文件移动到out目录
for file in glob.glob(os.path.join(latest_exp_dir, "*")):
shutil.move(file, save_dir)
# 删除空的exp目录
os.rmdir(latest_exp_dir)
print(f"已将结果移动到: {save_dir}")
else:
print(f"结果保存至: {save_dir}")
# 异常处理
except subprocess.CalledProcessError as e:
# 命令执行出错(如参数错误、模型文件损坏等)
print(f"检测过程出错: {e.stderr}")
except Exception as e:
# 其他未知错误
print(f"发生错误: {str(e)}")
5.3 开始测试
运行detect.py即可开始测试,完成后打开out文件夹下查看结果,例:
六、数据集获取
在kaggle上下载数据集或自己搜集数据集,下面是链接