3. 数据预处理:数据增强策略与锚框计算
数据预处理,说白了就是给模型“喂饭”前的最后一道工序。你想想看,原始图片千奇百怪,模型要是直接吃下去,肯定消化不良。我做了这么多年目标检测,可以负责任地告诉你:数据预处理做得好,模型训练成功一半。
这一章,我们重点聊三个核心话题:数据增强策略、归一化与锚框计算、配置文件解析。嗯,咱们一个一个来。
3.1 数据增强策略
数据增强不是为了炫技,而是为了解决一个实际问题:数据不够,或者数据太单调。我早期做项目时,数据集只有几千张图,模型怎么训都过拟合。后来加了增强,效果立竿见影。
3.1.1 Mosaic 增强
Mosaic 是 YOLOv4 开始引入的经典策略。它的做法很简单:把 4 张图拼成 1 张。
核心思想:随机取 4 张训练图片,分别缩放、裁剪后,拼成一张大图。模型一次看到 4 张图的内容,相当于变相增大了 batch size。
具体流程是这样的:
- 随机选 4 张图,每张图随机取一个缩放比例(0.3~1.0 之间)
- 按比例缩放后,随机裁剪出固定尺寸区域
- 把 4 块拼成一张完整图,尺寸统一为 640×640(或你设定的输入尺寸)
- 更新标注框坐标,超出边界的框会被裁剪掉
我个人习惯在训练前 80% 的 epoch 开启 Mosaic,后面 20% 关掉。为什么?因为 Mosaic 生成的图片和真实场景差异较大,最后阶段让模型回归到正常分布,能提升精度。
小技巧:Mosaic 的缩放范围不要设得太极端。我试过 0.1~1.0,结果小目标全被缩没了,模型根本学不到。建议 0.3~1.0 比较稳妥。
3.1.2 MixUp 增强
MixUp 比 Mosaic 更“暴力”——它直接把两张图按比例混合。公式很简单:
new_image = alpha * image1 + (1 - alpha) * image2
new_labels = alpha * labels1 + (1 - alpha) * labels2
alpha 一般取 0.5,也就是两张图各占一半。模型看到的是半透明的叠加图,标注框也是两套框共存。
我曾经在某个工业检测项目里试过 MixUp,效果出乎意料的好。因为产品缺陷样本太少,MixUp 相当于生成了大量“合成缺陷”,模型泛化能力明显提升。
注意:MixUp 不适合所有场景。如果你的任务对定位精度要求极高(比如自动驾驶),MixUp 可能会让边界模糊,反而降低性能。我建议先在小数据集上验证一下。
3.1.3 HSV 扰动
HSV 扰动就是调整图片的色相(Hue)、饱和度(Saturation)、明度(Value)。说白了,就是给图片“换滤镜”。
YOLO 默认的 HSV 参数是这样的:
| 参数 | 默认值 | 说明 |
|---|---|---|
| hsv_h | 0.015 | 色相偏移范围(±1.5%) |
| hsv_s | 0.7 | 饱和度缩放范围(±70%) |
| hsv_v | 0.4 | 明度缩放范围(±40%) |
我个人习惯把饱和度调低一点,0.5 左右。因为工业场景的图片颜色变化没那么大,饱和度扰动太强反而会引入噪声。
3.2 归一化与锚框计算
3.2.1 归一化
归一化就是把像素值从 0~255 缩放到 0~1 之间。YOLO 用的是最简单的做法:直接除以 255。
# 归一化代码示例
image = image.astype(np.float32) / 255.0
为什么要归一化?两个原因:
- 加速收敛:不同尺度的特征在同一个量级,梯度更新更稳定
- 避免数值溢出:神经网络里大量乘法运算,大数值容易溢出
嗯,这里要注意:归一化必须在数据增强之后做。先增强再归一化,顺序不能乱。
3.2.2 锚框计算
锚框(Anchor Box)是 YOLO 的核心概念之一。说白了,就是预设一些固定尺寸的框,让模型在这些框的基础上做微调。
YOLOv5 之后引入了自动锚框计算,不需要手动设了。流程是这样的:
- 读取训练集所有标注框的宽高
- 用 K-means 聚类,把框分成 9 类(3 个尺度 × 3 个比例)
- 输出 9 组 (w, h) 作为锚框
我遇到过一个问题:如果数据集里全是正方形物体(比如车牌),聚类出来的锚框也全是正方形。这时候模型检测细长物体(比如行人)就会很差。所以,锚框一定要和数据集匹配。
避坑指南:我曾经直接用了 COCO 的锚框来训练自己的数据集,结果 mAP 掉了 5 个点。后来重新聚类,效果立刻回来了。记住:锚框不是通用的,一定要重新算。
3.3 配置文件解析
YOLO 的配置文件(一般是 .yaml 或 .cfg)是整个训练的“总指挥”。我每次开始一个新项目,第一件事就是改配置文件。
一个典型的 YOLOv5 配置文件长这样:
# 数据集配置
path: ./datasets/coco128 # 数据集根目录
train: images/train2017 # 训练集路径
val: images/val2017 # 验证集路径
# 类别配置
nc: 80 # 类别数
names: ['person', 'bicycle', 'car', ...] # 类别名称
# 模型配置
depth_multiple: 0.33 # 深度缩放因子
width_multiple: 0.50 # 宽度缩放因子
# 训练配置
batch: 16 # 批次大小
epochs: 300 # 训练轮数
imgsz: 640 # 输入图片尺寸
关键参数说明:
| 参数 | 作用 | 我的建议 |
|---|---|---|
| depth_multiple | 控制网络层数 | 小模型用 0.33,大模型用 1.0 |
| width_multiple | 控制通道数 | 0.5 适合移动端,1.0 适合服务器 |
| imgsz | 输入尺寸 | 640 是平衡点,小目标用 1280 |
| batch | 批次大小 | 根据显存调,能大尽量大 |
个人经验:我一般先跑一个小模型(depth=0.33, width=0.5)快速验证数据没问题,再换大模型正式训练。这样能省不少时间。
3.4 数据预处理完整流程
下面这张图展示了数据预处理的完整流程,从原始图片到模型输入,每一步都不可或缺。
整个流程走下来,一张原始图片就变成了模型能吃的 Tensor。你想想看,如果没有这些预处理步骤,模型直接拿原始图片训练,效果会差多少?
总结一下:数据预处理不是可有可无的“调味料”,而是模型性能的“地基”。Mosaic 和 MixUp 解决数据多样性问题,HSV 扰动解决光照变化问题,归一化解决数值稳定性问题,锚框计算解决检测框初始化问题。每一步都有它的道理。