1. 实验概述与核心目标
这次实验的核心是使用YOLO系列模型完成目标检测任务。作为计算机视觉领域最经典的实时检测框架,YOLO(You Only Look Once)以其单阶段检测的高效率著称。我在实验中选择了YOLOv5和YOLOv8两个版本进行对比测试,主要解决以下实际问题:
- 口罩佩戴检测:针对原始数据集中戴口罩/不戴口罩样本不平衡的问题,通过数据增强和样本补充来优化模型性能
- 交通信号识别:将训练好的模型迁移应用到红绿灯检测场景,验证模型的泛化能力
实验环境采用Windows 11系统,搭配NVIDIA RTX 3060显卡(12GB显存)。主要工具链包括:
- Python 3.8
- PyTorch 1.12.1
- CUDA 11.6
- Labelme 5.1.1(数据标注工具)
提示:建议使用Anaconda创建独立的Python环境,避免依赖冲突。实测在16GB内存的机器上,YOLOv8s模型训练batch_size可设为16。
2. 环境配置与数据准备
2.1 核心依赖安装
YOLO模型的运行依赖较多第三方库,推荐使用以下命令安装基础环境:
bash复制conda create -n yolo python=3.8
conda activate yolo
pip install torch==1.12.1+cu116 torchvision==0.13.1+cu116 --extra-index-url https://download.pytorch.org/whl/cu116
pip install labelme ultralytics opencv-python pandas
对于YOLOv5和YOLOv8,需要分别克隆官方仓库:
bash复制# YOLOv5
git clone https://github.com/ultralytics/yolov5
cd yolov5
pip install -r requirements.txt
# YOLOv8
pip install ultralytics
2.2 数据集处理流程
实验使用的MaskDataSet原始数据集包含:
- 图像数量:1,200张(其中戴口罩1,050张,不戴口罩150张)
- 标注格式:Labelme生成的JSON文件
需要将Labelme格式转换为YOLO训练所需的txt标注格式。转换脚本关键代码如下:
python复制import json
import os
def convert(size, box):
dw = 1./size[0]
dh = 1./size[1]
x = (box[0] + box[2])/2.0
y = (box[1] + box[3])/2.0
w = box[2] - box[0]
h = box[3] - box[1]
x = x*dw
w = w*dw
y = y*dh
h = h*dh
return (x,y,w,h)
for json_file in os.listdir(json_dir):
with open(json_file) as f:
data = json.load(f)
txt_name = json_file.replace('.json', '.txt')
with open(txt_name, 'w') as ft:
for shape in data['shapes']:
class_name = shape['label']
if class_name == 'mask':
cls_id = 0
else:
cls_id = 1
points = shape['points']
box = [points[0][0], points[0][1], points[1][0], points[1][1]]
bb = convert((data['imageWidth'], data['imageHeight']), box)
ft.write(f"{cls_id} {' '.join([str(a) for a in bb])}\n")
3. 数据增强与模型训练
3.1 解决样本不平衡问题
原始数据集中戴口罩与不戴口罩样本比例为7:1,这会导致模型对少数类(不戴口罩)的识别性能较差。我们采用两种解决方案:
- 过采样(oversampling):复制不戴口罩样本至700张
- 数据增强:对不戴口罩样本应用以下变换:
- 随机旋转(-15°~15°)
- 亮度调整(0.8~1.2倍)
- 添加高斯噪声(σ=0.01)
- 水平翻转(p=0.5)
增强后的数据集分布:
| 类别 | 原始数量 | 增强后数量 |
|---|---|---|
| 戴口罩 | 1,050 | 1,050 |
| 不戴口罩 | 150 | 750 |
3.2 YOLOv5模型训练配置
创建dataset.yaml配置文件:
yaml复制train: ../datasets/train/images
val: ../datasets/val/images
test: ../datasets/test/images
nc: 2 # 类别数
names: ['mask', 'no_mask'] # 类别名称
启动训练命令:
bash复制python train.py --img 640 --batch 16 --epochs 100 --data dataset.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --name mask_detection
关键训练参数说明:
- img:输入图像尺寸(保持640×640可获得较好速度精度平衡)
- batch:根据显存调整(RTX 3060建议16)
- epochs:100个epoch足够收敛
- weights:使用预训练权重加速收敛
3.3 训练过程监控
使用TensorBoard监控训练指标:
bash复制tensorboard --logdir runs/train
重点关注以下指标变化:
-
损失函数:
- train/box_loss:边界框回归损失
- train/obj_loss:目标存在置信度损失
- train/cls_loss:分类损失
-
验证集性能:
- metrics/precision:精确率
- metrics/recall:召回率
- mAP@0.5:IoU阈值为0.5时的平均精度
注意:当验证集指标连续10个epoch没有提升时,可考虑提前终止训练。
4. 模型评估与结果分析
4.1 测试集性能指标
在独立测试集(200张图像)上的评估结果:
| 模型版本 | 精确率(P) | 召回率(R) | mAP@0.5 | 推理速度(FPS) |
|---|---|---|---|---|
| YOLOv5s | 0.892 | 0.856 | 0.901 | 45 |
| YOLOv8s | 0.915 | 0.873 | 0.927 | 52 |
4.2 混淆矩阵分析
不戴口罩类别的混淆矩阵(YOLOv8s):
| 真实\预测 | 戴口罩 | 不戴口罩 |
|---|---|---|
| 戴口罩 | 98 | 2 |
| 不戴口罩 | 5 | 95 |
关键指标计算:
- 精确率 = TP/(TP+FP) = 95/(95+2) = 0.979
- 召回率 = TP/(TP+FN) = 95/(95+5) = 0.95
- F1分数 = 2*(精确率*召回率)/(精确率+召回率) = 0.964
4.3 可视化检测结果

(注:此处应为实际检测效果截图,展示正确检测、漏检和误检案例)
典型错误模式分析:
- 遮挡情况:当口罩被手或其他物体部分遮挡时易出现误判
- 极端角度:侧面人脸检测效果较差
- 小目标问题:远距离人脸检测率下降明显
5. 红绿灯检测迁移应用
5.1 数据集准备
使用BDD100K数据集中的交通信号灯子集:
- 训练集:8,000张
- 验证集:2,000张
- 类别:红灯、绿灯、黄灯、无信号
5.2 模型微调策略
基于预训练的YOLOv8模型,采用以下微调方法:
- 冻结骨干网络前20层
- 降低学习率(base_lr=0.001)
- 添加针对小目标的检测头
微调命令:
bash复制yolo train model=yolov8s.pt data=traffic_light.yaml epochs=50 imgsz=640 batch=16 lr0=0.001 freeze=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]
5.3 性能对比
| 方法 | mAP@0.5 | 参数量(M) | FPS |
|---|---|---|---|
| 从头训练 | 0.763 | 11.4 | 48 |
| 微调 | 0.852 | 11.4 | 52 |
6. 实验心得与实用技巧
-
数据标注注意事项:
- 标注框应紧贴目标边缘
- 对于遮挡目标,标注可见部分
- 保持标签一致性(如"mask"和"mask_face"视为不同类别)
-
训练调优经验:
- 学习率预热:前3个epoch逐步提高学习率
- 多尺度训练:添加--multi-scale参数提升小目标检测
- 早停策略:当mAP连续10epoch不提升时停止
-
部署优化建议:
- 使用TensorRT加速推理
- 对于边缘设备,可尝试YOLOv5n/v8n等轻量模型
- 输出结果后处理(如NMS阈值调整)对最终效果影响显著
-
常见问题排查:
- 如果出现CUDA out of memory:
- 减小batch_size
- 使用--img-size 320
- 训练loss震荡严重:
- 检查学习率是否过大
- 验证数据标注质量
- 验证集指标远低于训练集:
- 可能出现过拟合,增加数据增强
- 添加正则化项
- 如果出现CUDA out of memory:
