3. 数据预处理:数据增强策略与锚框计算

数据预处理,说白了就是给模型“喂饭”前的最后一道工序。你想想看,原始图片千奇百怪,模型要是直接吃下去,肯定消化不良。我做了这么多年目标检测,可以负责任地告诉你:数据预处理做得好,模型训练成功一半。

这一章,我们重点聊三个核心话题:数据增强策略、归一化与锚框计算、配置文件解析。嗯,咱们一个一个来。

3.1 数据增强策略

数据增强不是为了炫技,而是为了解决一个实际问题:数据不够,或者数据太单调。我早期做项目时,数据集只有几千张图,模型怎么训都过拟合。后来加了增强,效果立竿见影。

3.1.1 Mosaic 增强

Mosaic 是 YOLOv4 开始引入的经典策略。它的做法很简单:把 4 张图拼成 1 张。

核心思想:随机取 4 张训练图片,分别缩放、裁剪后,拼成一张大图。模型一次看到 4 张图的内容,相当于变相增大了 batch size。

具体流程是这样的:

  1. 随机选 4 张图,每张图随机取一个缩放比例(0.3~1.0 之间)
  2. 按比例缩放后,随机裁剪出固定尺寸区域
  3. 把 4 块拼成一张完整图,尺寸统一为 640×640(或你设定的输入尺寸)
  4. 更新标注框坐标,超出边界的框会被裁剪掉

我个人习惯在训练前 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 之后引入了自动锚框计算,不需要手动设了。流程是这样的:

  1. 读取训练集所有标注框的宽高
  2. 用 K-means 聚类,把框分成 9 类(3 个尺度 × 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 数据预处理完整流程

下面这张图展示了数据预处理的完整流程,从原始图片到模型输入,每一步都不可或缺。

数据预处理完整流程 原始图片 数据增强 Mosaic | MixUp | HSV 扰动 归一化 (÷255) 锚框匹配 (K-means 聚类) 模型输入 Tensor 关键顺序 先增强 → 再归一化 → 最后匹配锚框 顺序不能乱!

整个流程走下来,一张原始图片就变成了模型能吃的 Tensor。你想想看,如果没有这些预处理步骤,模型直接拿原始图片训练,效果会差多少?

总结一下:数据预处理不是可有可无的“调味料”,而是模型性能的“地基”。Mosaic 和 MixUp 解决数据多样性问题,HSV 扰动解决光照变化问题,归一化解决数值稳定性问题,锚框计算解决检测框初始化问题。每一步都有它的道理。