一、图像高级增强:从基础到实战
大家好,我是老张。今天咱们聊聊图像高级增强。
做图像分类、目标检测的朋友,一定遇到过数据不够的问题。我刚开始做CV项目时,总觉得标注数据越多越好。后来发现,光靠数量堆砌不行,质量才是关键。说白了,你得让模型看到更多「花样」——这就是高级增强要做的事。
核心思想:通过模拟真实世界的各种变化,让模型学会「举一反三」。不是简单翻转、旋转,而是更聪明的玩法。
1.1 Cutout:给图像「挖个洞」
Cutout 的思路很直接——随机遮挡图像的一部分。我最早在 Kaggle 比赛里用到它,效果出奇的好。
为什么有效?模型被迫关注局部特征,而不是依赖某个区域。比如识别猫,如果猫脸被遮住,模型就得看耳朵、尾巴来判断。
import torch
import numpy as np
def cutout(image, mask_size=16):
"""随机遮挡一个正方形区域"""
h, w, _ = image.shape
y = np.random.randint(h)
x = np.random.randint(w)
y1 = max(0, y - mask_size // 2)
y2 = min(h, y + mask_size // 2)
x1 = max(0, x - mask_size // 2)
x2 = min(w, x + mask_size // 2)
image[y1:y2, x1:x2] = 0 # 用黑色填充
return image
我的经验:mask_size 别太大,一般设为图像短边的 10%-20%。太大反而让模型学不到东西。
1.2 Random Erasing:更灵活的遮挡
Random Erasing 是 Cutout 的升级版。它不一定是正方形,可以是任意矩形,还能用随机颜色填充。
我记得有一次做行人重识别,光照变化很大。用 Random Erasing 后,模型对遮挡的鲁棒性明显提升。
def random_erasing(image, p=0.5, sl=0.02, sh=0.4):
"""随机擦除,面积比例在 sl 到 sh 之间"""
if np.random.rand() > p:
return image
h, w, _ = image.shape
area = h * w
for _ in range(100):
target_area = np.random.uniform(sl, sh) * area
aspect_ratio = np.random.uniform(0.3, 3.0)
h_erase = int(round(np.sqrt(target_area * aspect_ratio)))
w_erase = int(round(np.sqrt(target_area / aspect_ratio)))
if h_erase < h and w_erase < w:
y = np.random.randint(0, h - h_erase)
x = np.random.randint(0, w - w_erase)
# 用随机颜色填充
color = np.random.randint(0, 255, 3)
image[y:y+h_erase, x:x+w_erase] = color
break
return image
注意:Random Erasing 和 Cutout 不要同时用。我踩过这个坑,效果反而下降。
1.3 Mixup:让两张图「谈恋爱」
Mixup 的思路很巧妙——把两张图按比例混合,标签也按同样比例混合。
你想想看,模型看到的不再是「猫」或「狗」,而是「70% 的猫 + 30% 的狗」。这强迫模型学习线性插值关系,泛化能力自然更强。
def mixup(x1, y1, x2, y2, alpha=1.0):
"""混合两张图像及其标签"""
lam = np.random.beta(alpha, alpha)
x_mixed = lam * x1 + (1 - lam) * x2
y_mixed = lam * y1 + (1 - lam) * y2
return x_mixed, y_mixed
我在做医学图像分类时用过 Mixup。数据量只有 2000 张,但 Mixup 让准确率从 82% 提到了 89%。
1.4 CutMix:结合 Cutout 和 Mixup 的优点
CutMix 是 Cutout 和 Mixup 的「混血儿」。它把一张图的一块区域切掉,贴上另一张图的对应区域,标签按面积比例混合。
说白了,就是「挖个洞,补上别人的内容」。这样既保留了局部特征,又引入了混合信息。
def cutmix(x1, y1, x2, y2, alpha=1.0):
"""CutMix 增强"""
lam = np.random.beta(alpha, alpha)
h, w = x1.shape[1:3]
cut_ratio = np.sqrt(1. - lam)
cut_h = int(h * cut_ratio)
cut_w = int(w * cut_ratio)
# 随机选择裁剪区域
y = np.random.randint(0, h - cut_h)
x = np.random.randint(0, w - cut_w)
# 交换区域
x_mixed = x1.clone()
x_mixed[:, y:y+cut_h, x:x+cut_w] = x2[:, y:y+cut_h, x:x+cut_w]
# 标签按面积比例混合
lam = 1. - (cut_h * cut_w) / (h * w)
y_mixed = lam * y1 + (1 - lam) * y2
return x_mixed, y_mixed
实战对比:
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Cutout | 分类、检测 | 简单、高效 | 信息丢失 |
| Random Erasing | 行人重识别 | 更灵活 | 参数调优 |
| Mixup | 小样本分类 | 泛化强 | 标签模糊 |
| CutMix | 目标检测 | 保留局部 | 计算稍大 |
1.5 AutoAugment:让 AI 自己选策略
AutoAugment 是 Google 提出的方法。它用强化学习搜索最佳增强策略。
嗯,这里要注意——搜索过程很耗时。我试过在 CIFAR-10 上跑一次,用了 4 块 GPU 跑了 3 天。但效果确实好,比手动调参强不少。
搜索出来的策略包含 5 个子策略,每个子策略包含 2 个操作。比如「先旋转 15 度,再剪切 0.2」。这些操作按概率执行,幅度也有范围。
# AutoAugment 的典型策略(CIFAR-10)
policy = [
[('Invert', 0.1, 7), ('Contrast', 0.2, 6)],
[('Rotate', 0.7, 2), ('TranslateX', 0.3, 9)],
[('Sharpness', 0.8, 1), ('ShearY', 0.1, 8)],
[('ShearX', 0.4, 7), ('TranslateY', 0.6, 3)],
[('Solarize', 0.6, 5), ('AutoContrast', 0.5, 1)]
]
我的建议:如果你资源有限,直接用别人搜好的策略。PyTorch 官方库里有现成的。
1.6 RandAugment:简化版 AutoAugment
RandAugment 去掉了搜索过程。它只控制两个参数:操作数量 N 和幅度 M。
为什么能简化?因为研究发现,随机选择操作的效果和搜索出来的差不多。你想想看,这省了多少事。
def rand_augment(image, n=2, m=9):
"""随机选择 N 个操作,幅度为 M"""
operations = [
'autocontrast', 'equalize', 'rotate', 'solarize',
'color', 'posterize', 'contrast', 'brightness',
'sharpness', 'shear_x', 'shear_y', 'translate_x', 'translate_y'
]
for _ in range(n):
op = np.random.choice(operations)
# 应用操作,幅度映射到 [0, 10]
image = apply_op(image, op, m)
return image
我曾经在 ImageNet 子集上对比过:AutoAugment 提升 1.8%,RandAugment 提升 1.5%。差距不大,但 RandAugment 训练时间少了 90%。
知识体系总览
下面这张图,帮你理清这些方法的关系:
实战建议
说了这么多,到底怎么选?我总结几条经验:
- 数据量 < 1万张:优先用 Mixup 或 CutMix。它们能有效缓解过拟合。
- 数据量 1万-10万张:用 RandAugment。效果好,调参简单。
- 数据量 > 10万张:可以考虑 AutoAugment。但说实话,RandAugment 也够用了。
- 目标检测任务:CutMix 效果最好。因为它保留了目标的位置信息。
避坑指南:我曾经在同一个项目里同时用了 Cutout、Mixup 和 RandAugment。结果模型训练了 200 个 epoch 还没收敛。记住,增强不是越多越好,选 1-2 个就够了。
好了,这一章的内容就到这里。下一章我们会聊更高级的玩法——生成式增强。到时候见。