数据是深度学习的燃料,数据增强是免费的燃料增长器。本课深入各种增强策略,从基础几何变换到高级混合方法。
更多数据 → 更好泛化 → 更少过拟合
数据增强:从现有数据生成"新"样本,增加数据多样性
| 方法 | 参数 | 效果 |
|---|---|---|
| 随机翻转 | p=0.5 | 水平/垂直镜像 |
| 随机旋转 | degrees=15 | 角度变化 |
| 随机裁剪 | size=224 | 位置变化 |
| 仿射变换 | shear=10 | 形状变化 |
| 方法 | 参数 | 效果 |
|---|---|---|
| 颜色抖动 | brightness=0.2 | 亮度变化 |
| 对比度 | contrast=0.2 | 明暗对比 |
| 饱和度 | saturation=0.2 | 颜色丰富度 |
MixUp: x̃ = λxᵢ + (1-λ)xⱼ, ỹ = λyᵢ + (1-λ)yⱼ
CutMix: 将一张图的部分区域替换为另一张图
λ ~ Beta(α, α),通常α=1.0
import torch
import torchvision.transforms as T
import numpy as np
# 数据增强效果演示
print("=== 数据增强方法 ===")
# 模拟图像张量
img = torch.randn(3, 32, 32)
print(f"原始图像: shape={img.shape}, mean={img.mean():.4f}, std={img.std():.4f}")
# 基本变换
transforms_list = {
"随机水平翻转": T.RandomHorizontalFlip(p=1.0),
"随机垂直翻转": T.RandomVerticalFlip(p=1.0),
"随机旋转10°": T.RandomRotation(10),
"随机裁剪": T.RandomCrop(28),
"颜色抖动": T.ColorJitter(brightness=0.5, contrast=0.5),
"高斯模糊": T.GaussianBlur(3),
"随机擦除": T.RandomErasing(p=1.0),
}
for name, transform in transforms_list.items():
try:
augmented = transform(img)
diff = (augmented - img).abs().mean().item()
print(f" {name}: shape={list(augmented.shape)}, 与原图差异={diff:.4f}")
except Exception as e:
print(f" {name}: 需要PIL图像输入 ({str(e)[:50]})")
# MixUp实现
def mixup_data(x, y, alpha=1.0):
lam = np.random.beta(alpha, alpha) if alpha > 0 else 1
batch_size = x.size(0)
index = torch.randperm(batch_size)
mixed_x = lam * x + (1 - lam) * x[index]
y_a, y_b = y, y[index]
return mixed_x, y_a, y_b, lam
# MixUp实验
X = torch.randn(32, 3, 32, 32)
y = torch.randint(0, 10, (32,))
mixed_X, y_a, y_b, lam = mixup_data(X, y, alpha=1.0)
print(f"\nMixUp: λ={lam:.4f}")
print(f" 原图与混合图差异: {(mixed_X - X).abs().mean():.4f}")
# CutMix实现
def cutmix_data(x, y, beta=1.0):
lam = np.random.beta(beta, beta)
rand_index = torch.randperm(x.size(0))
bbx1, bby1, bbx2, bby2 = rand_bbox(x.size(), lam)
x_cut = x.clone()
x_cut[:, :, bbx1:bbx2, bby1:bby2] = x[rand_index, :, bbx1:bbx2, bby1:bby2]
lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (x.size(-1) * x.size(-2)))
return x_cut, y, y[rand_index], lam
def rand_bbox(size, lam):
W = size[2]
H = size[3]
cut_rat = np.sqrt(1. - lam)
cut_w = int(W * cut_rat)
cut_h = int(H * cut_rat)
cx = np.random.randint(W)
cy = np.random.randint(H)
bbx1 = np.clip(cx - cut_w // 2, 0, W)
bby1 = np.clip(cy - cut_h // 2, 0, H)
bbx2 = np.clip(cx + cut_w // 2, 0, W)
bby2 = np.clip(cy + cut_h // 2, 0, H)
return bbx1, bby1, bbx2, bby2
cut_X, y_a2, y_b2, lam2 = cutmix_data(X, y, beta=1.0)
print(f"CutMix: λ={lam2:.4f}")
print(f" 原图与CutMix图差异: {(cut_X - X).abs().mean():.4f}")
# 数据增强对训练的影响
print("\n=== 增强对训练的影响 ===")
torch.manual_seed(42)
X_train = torch.randn(200, 10)
y_train = (X_train[:, 0] + X_train[:, 1] > 0).long()
model = nn.Sequential(nn.Linear(10, 64), nn.ReLU(), nn.Linear(64, 2))
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
loss_fn = nn.CrossEntropyLoss()
for epoch in range(100):
# 在线增强:给输入加噪声
X_aug = X_train + torch.randn_like(X_train) * 0.1
optimizer.zero_grad()
loss = loss_fn(model(X_aug), y_train)
loss.backward()
optimizer.step()
acc = (model(X_train).argmax(1) == y_train).float().mean()
print(f"加噪声增强训练: acc={acc.item():.2%}")
本课的核心知识点构成了CNN学习的重要一环。让我们从更高维度审视这些知识之间的关系:
⚠️ 初学者常犯的错误:
💡 最佳实践:
深度学习是一个整体——每一课的知识都不是孤立的:
💡 继续深入的学习路径:
实现自动增强策略搜索(简化版)。
逐渐增加增强强度,观察对训练和验证精度的影响。
实现TTA,在测试时多次增强取平均,观察精度提升。
⚠️ 需要避免的典型错误:
💡 提升模型性能的系统方法:
理解本课内容需要将其置于更大的知识网络中。每个核心概念都不是孤立的,它们相互关联、相互支撑:
建立正确的直觉比记住公式更重要:
1. 维度直觉:高维空间中,数据分布与低维直觉截然不同(维度诅咒)
2. 信息瓶颈:神经网络逐层压缩信息,保留任务相关的、丢弃无关的
3. 流形假设:高维数据实际分布在低维流形上,学习即发现流形结构
4. 偏差-方差权衡:简单模型欠拟合(高偏差),复杂模型过拟合(高方差)
本课作为CNN阶段的核心内容,与前后课程紧密关联:
| 关联课程 | 关联点 | 协同效应 |
|---|---|---|
| 前序课程 | 提供了本课的基础知识 | 循序渐进的理解 |
| 后续课程 | 本课内容是后续的基础 | 逐步构建能力 |
| 平行课程 | 同一阶段的互补知识 | 多角度深入理解 |
| 实战项目 | 综合运用所有知识 | 理论与实践结合 |
💡 准备面试时,确保能回答以下问题:
掌握本课内容后,可以通过以下方式继续深入:
数据增强是免费的提升——你已经掌握了这门手艺!