今日目标 :掌握从基础几何变换到MixUp/CutMix的完整数据增强体系,学会用数据增强白嫖准确率
预计阅读 :10分钟 | 动手操作:40分钟
一、数据增强:最便宜的精度提升手段
数据增强 = 在不增加真实数据的情况下,让模型"看到"更多样本
一句话总结:
你花一周收集的1000张数据,通过数据增强能变成10万张
而且这10万张都比原始数据稍微不同,模型学到的特征更鲁棒!
端侧AI特别重要:
端侧场景光照、角度、遮挡变化大
好的数据增强 = 模型在端侧鲁棒性提升10-20%
python
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision.transforms as T
import torchvision.transforms.functional as TF
from torch.utils.data import DataLoader, Dataset
from torchvision import datasets
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
torch.manual_seed(42)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
二、核心知识点
2.1 基础增强:几何变换
python
# ===== 几何变换:改变图像的空间结构 =====
geometric_transforms = {
# 1. 随机裁剪(最常用的增强!)
'RandomCrop(32, padding=4)': T.RandomCrop(32, padding=4),
# 先padding到40×40,再随机裁32×32 → 引入了平移不变性
# 2. 随机水平翻转
'RandomHorizontalFlip(p=0.5)': T.RandomHorizontalFlip(p=0.5),
# 50%概率翻转,对于左右对称的类别(如猫狗)特别有效
# 注意:数字识别不要用!6翻转后变成什么?
# 3. 随机垂直翻转
'RandomVerticalFlip(p=0.3)': T.RandomVerticalFlip(p=0.3),
# 适用于卫星图像、医学图像等
# 自然场景少用(天空不会在下面)
# 4. 随机旋转
'RandomRotation(degrees=15)': T.RandomRotation(degrees=15),
# 旋转±15度,引入旋转不变性
# 5. 随机仿射变换
'RandomAffine(degrees=10, translate=(0.1,0.1))': T.RandomAffine(
degrees=10, translate=(0.1, 0.1), scale=(0.9, 1.1)
),
# 组合:旋转+平移+缩放
# 6. 随机透视变换
'RandomPerspective(distortion_scale=0.2, p=0.5)': T.RandomPerspective(
distortion_scale=0.2, p=0.5
),
# 模拟不同视角
# 7. Resize + 中心裁剪
'Resize(40)+CenterCrop(32)': T.Compose([
T.Resize(40),
T.CenterCrop(32),
]),
}
# 几何变换选型指南
print("几何变换选型指南:")
print(" 分类任务: RandomCrop + RandomHorizontalFlip → 标配")
print(" 检测任务: Mosaic + RandomAffine → YOLO标配")
print(" 分割任务: RandomRotation + RandomCrop → 保持标注一致性")
print(" 人脸识别: RandomHorizontalFlip → 人脸对称")
print(" 文字识别: 不要用翻转!6和9会混淆")
2.2 基础增强:颜色变换
python
# ===== 颜色变换:改变图像的色彩和光照 =====
color_transforms = {
# 1. 颜色抖动(最常用!)
'ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1)':
T.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),
# 2. 灰度化
'RandomGrayscale(p=0.1)': T.RandomGrayscale(p=0.1),
# 10%概率转灰度,让模型不依赖颜色
# 3. 高斯模糊
'GaussianBlur(5, sigma=(0.1, 2.0))': T.GaussianBlur(5, sigma=(0.1, 2.0)),
# 模拟运动模糊或对焦不准
# 4. 随机反转
'RandomInvert(p=0.2)': T.RandomInvert(p=0.2),
# 模拟负片效果
# 5. 随机调整锐度
'RandomAdjustSharpness(sharpness_factor=2, p=0.3)':
T.RandomAdjustSharpness(sharpness_factor=2, p=0.3),
# 6. 随机色调分离
'RandomPosterize(bits=4, p=0.3)': T.RandomPosterize(bits=4, p=0.3),
# 7. 随机均衡化
'RandomEqualize(p=0.3)': T.RandomEqualize(p=0.3),
# 直方图均衡化,增强对比度
}
# 颜色变换选型指南
print("\n颜色变换选型指南:")
print(" 室外场景: ColorJitter + RandomGrayscale → 光照变化")
print(" 监控场景: ColorJitter(亮度为主) → 夜间/白天")
print(" 医学图像: 谨慎使用 → 颜色可能有诊断意义")
print(" 文档图像: 不使用 → 文字颜色是重要特征")
2.3 高级增强:CutOut、MixUp、CutMix
python
# ===== 1. CutOut:随机遮挡 =====
class CutOut:
"""
随机遮挡图像的一部分
原理:强迫模型学习全局特征,不能只依赖局部
效果:在CIFAR-10上提升1-2%准确率
端侧应用:模拟遮挡场景(树枝遮挡、人群遮挡)
"""
def __init__(self, n_holes=1, length=16):
self.n_holes = n_holes
self.length = length
def __call__(self, img):
h, w = img.shape[1], img.shape[2] # img: (C, H, W)
mask = torch.ones_like(img)
for _ in range(self.n_holes):
y = np.random.randint(h)
x = np.random.randint(w)
y1 = max(0, y - self.length // 2)
y2 = min(h, y + self.length // 2)
x1 = max(0, x - self.length // 2)
x2 = min(w, x + self.length // 2)
mask[:, y1:y2, x1:x2] = 0
return img * mask
# ===== 2. MixUp:两张图混合 =====
def mixup_data(x, y, alpha=1.0):
"""
MixUp:两张图像按比例混合,标签也按比例混合
x̃ = λ·x_i + (1-λ)·x_j
ỹ = λ·y_i + (1-λ)·y_j
效果:CIFAR-10提升2-3%,ImageNet提升1-2%
论文:https://arxiv.org/abs/1710.09412
"""
if alpha > 0:
lam = np.random.beta(alpha, alpha)
else:
lam = 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
def mixup_criterion(criterion, pred, y_a, y_b, lam):
"""
MixUp的损失函数
loss = lam * loss(pred, y_a) + (1-lam) * loss(pred, y_b)
"""
return lam * criterion(pred, y_a) + (1 - lam) * criterion(pred, y_b)
# ===== 3. CutMix:CutOut + MixUp =====
def cutmix_data(x, y, alpha=1.0):
"""
CutMix:从一张图切一块,贴到另一张图上
比CutOut更有效:遮挡区域不是黑的,而是另一张图的内容
比MixUp更自然:不是混合,而是真实的区域替换
效果:CIFAR-10提升2-4%,ImageNet提升1-3%
论文:https://arxiv.org/abs/1905.04899
"""
if alpha > 0:
lam = np.random.beta(alpha, alpha)
else:
lam = 1
batch_size = x.size(0)
index = torch.randperm(batch_size)
_, _, H, W = x.shape
cx = np.random.randint(W)
cy = np.random.randint(H)
# 裁剪区域大小
cut_w = int(W * np.sqrt(1 - lam))
cut_h = int(H * np.sqrt(1 - lam))
x1 = max(0, cx - cut_w // 2)
x2 = min(W, cx + cut_w // 2)
y1 = max(0, cy - cut_h // 2)
y2 = min(H, cy + cut_h // 2)
# 实际混合比例
lam = 1 - ((x2 - x1) * (y2 - y1)) / (H * W)
# 把另一张图的区域贴过来
mixed_x = x.clone()
mixed_x[:, :, y1:y2, x1:x2] = x[index, :, y1:y2, x1:x2]
return mixed_x, y, y[index], lam
# 对比三种方法
print("\n三种高级增强对比:")
print("┌──────────┬──────────────┬──────────────┬──────────────────────┐")
print("│ 方法 │ 原理 │ 标签处理 │ 端侧AI适用场景 │")
print("├──────────┼──────────────┼──────────────┼──────────────────────┤")
print("│ CutOut │ 随机遮挡 │ 标签不变 │ 遮挡场景(安防/交通) │")
print("│ MixUp │ 线性混合 │ 线性混合 │ 通用分类任务 │")
print("│ CutMix │ 区域替换 │ 面积比例混合 │ 分类+检测(最推荐) │")
print("└──────────┴──────────────┴──────────────┴──────────────────────┘")
2.4 自动增强:AutoAugment、RandAugment、TrivialAugment
python
# ===== 自动搜索最优增强策略 =====
"""
AutoAugment:用强化学习搜索最优增强策略
- 优点:效果好,策略针对特定数据集优化
- 缺点:搜索成本高(需要训练很多次)
RandAugment:简化版,随机选择N种增强,每种增强强度为M
- 优点:不需要搜索,只需调两个参数(N, M)
- 推荐:N=2, M=9 是常用配置
TrivialAugment:最简单的自动增强
- 随机选一种增强 + 随机强度
- 优点:一个参数都不需要调!
- 推荐:快速实验时使用
"""
# RandAugment
from torchvision.transforms import RandAugment
randaug = RandAugment(num_ops=2, magnitude=9)
# TrivialAugment
from torchvision.transforms import TrivialAugmentWide
trivialaug = TrivialAugmentWide()
# AutoAugment (CIFAR-10预搜索策略)
from torchvision.transforms import AutoAugment, AutoAugmentPolicy
autoaug = AutoAugment(AutoAugmentPolicy.CIFAR10)
print("自动增强选型:")
print(" 追求最好效果: AutoAugment(策略已预搜索好)")
print(" 一般训练: RandAugment(N=2, M=9)")
print(" 快速实验: TrivialAugment(零参数)")
2.5 Mosaic增强:YOLO的杀手锏
python
def mosaic_augment(images, labels, size=640):
"""
Mosaic增强:把4张图拼成1张
这是YOLOv4/v5/v8的标准增强!
特别适合小目标检测场景
原理:
1. 随机选4张图
2. 每张图随机缩放和裁剪
3. 拼成一张大图
4. 标签也跟着调整
效果:
- 一次训练看到4张图的内容
- 丰富小目标样本
- 相当于batch_size×4
"""
# 简化实现
mosaic_img = torch.zeros(3, size, size)
mosaic_labels = []
# 随机分割点
cut_x = np.random.randint(size // 3, 2 * size // 3)
cut_y = np.random.randint(size // 3, 2 * size // 3)
positions = [
(0, 0, cut_y, cut_x), # 左上
(0, cut_x, cut_y, size), # 右上
(cut_y, 0, size, cut_x), # 左下
(cut_y, cut_x, size, size), # 右下
]
print("Mosaic增强示意图:")
print(f" 分割点: ({cut_x}, {cut_y})")
print(f" ┌────────────┬────────────┐")
print(f" │ 图1(左上) │ 图2(右上) │")
print(f" │ {cut_y}×{cut_x} │ {cut_y}×{size-cut_x} │")
print(f" ├────────────┼────────────┤")
print(f" │ 图3(左下) │ 图4(右下) │")
print(f" │ {size-cut_y}×{cut_x} │ {size-cut_y}×{size-cut_x} │")
print(f" └────────────┴────────────┘")
print(f"\n 端侧AI应用:检测模型训练标配,提升小目标检测能力")
mosaic_augment([], [])
三、动手实践
3.1 实战:CIFAR-10增强对比实验
python
def compare_augmentations():
"""对比不同增强策略对CIFAR-10准确率的影响"""
# 定义不同的增强策略
augmentations = {
'Baseline (无增强)': T.Compose([
T.ToTensor(),
T.Normalize((0.4914, 0.4822, 0.4465), (0.2470, 0.2435, 0.2616)),
]),
'基础增强 (几何+颜色)': T.Compose([
T.RandomCrop(32, padding=4),
T.RandomHorizontalFlip(),
T.ColorJitter(0.1, 0.1, 0.1, 0.05),
T.ToTensor(),
T.Normalize((0.4914, 0.4822, 0.4465), (0.2470, 0.2435, 0.2616)),
]),
'强增强 (RandAugment)': T.Compose([
T.RandomCrop(32, padding=4),
T.RandomHorizontalFlip(),
RandAugment(num_ops=2, magnitude=9),
T.ToTensor(),
T.Normalize((0.4914, 0.4822, 0.4465), (0.2470, 0.2435, 0.2616)),
]),
'最强增强 (AutoAugment)': T.Compose([
AutoAugment(AutoAugmentPolicy.CIFAR10),
T.ToTensor(),
T.Normalize((0.4914, 0.4822, 0.4465), (0.2470, 0.2435, 0.2616)),
]),
}
print("增强策略对比(预期CIFAR-10准确率):")
print(f"{'策略':<25s} {'预期准确率':>10s} {'提升':>8s}")
print('-' * 48)
baselines = {
'Baseline (无增强)': '86%',
'基础增强 (几何+颜色)': '90%',
'+ CutOut': '91%',
'+ MixUp': '92%',
'+ CutMix': '93%',
'强增强 (RandAugment)': '93%',
'最强增强 (AutoAugment)': '95%',
}
baseline_acc = 86.0
for name, acc_str in baselines.items():
acc = float(acc_str.replace('%', ''))
improvement = acc - baseline_acc
bar = '█' * int(improvement * 2)
print(f"{name:<25s} {acc_str:>10s} {improvement:>+7.1f}% {bar}")
compare_augmentations()
3.2 实战:MixUp训练完整实现
python
def train_with_mixup(model, train_loader, val_loader, epochs=50, alpha=1.0):
"""
完整的MixUp训练流程
MixUp的关键:
1. 训练时mixup数据,验证时不mixup
2. 损失函数用mixup_criterion
3. 学习率可能需要调大一点(因为标签变软了)
"""
model = model.to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=1e-4)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=epochs)
criterion = nn.CrossEntropyLoss()
best_acc = 0
for epoch in range(epochs):
# 训练
model.train()
train_loss, train_correct, train_total = 0, 0, 0
for x, y in train_loader:
x, y = x.to(device), y.to(device)
# MixUp
mixed_x, y_a, y_b, lam = mixup_data(x, y, alpha)
optimizer.zero_grad()
output = model(mixed_x)
loss = mixup_criterion(criterion, output, y_a, y_b, lam)
loss.backward()
optimizer.step()
train_loss += loss.item() * x.size(0)
# 注意:MixUp的准确率计算不准确,这里简化
pred = output.argmax(1)
train_correct += (lam * pred.eq(y_a).float() +
(1 - lam) * pred.eq(y_b).float()).sum().item()
train_total += y.size(0)
scheduler.step()
# 验证(不mixup)
model.eval()
val_correct = 0
with torch.no_grad():
for x, y in val_loader:
x, y = x.to(device), y.to(device)
val_correct += model(x).argmax(1).eq(y).sum().item()
val_acc = val_correct / len(val_loader.dataset)
if val_acc > best_acc:
best_acc = val_acc
if epoch % 10 == 0:
print(f"Epoch {epoch:3d}: Train Loss={train_loss/train_total:.4f}, "
f"Val Acc={val_acc:.2%}")
print(f"最佳准确率: {best_acc:.2%}")
return model
print("\nMixUp训练要点:")
print(" 1. alpha=1.0 是常用值(Beta分布均匀)")
print(" 2. 训练时用mixup,验证时不用")
print(" 3. mixup让标签变软 → 训练loss看起来更高是正常的")
print(" 4. 可能需要更多epoch才能收敛")
3.3 实战:端侧AI场景的增强策略
python
def edge_ai_augmentation_guide():
"""
端侧AI不同场景的推荐增强策略
"""
scenarios = {
'安防监控(行人/车辆)': {
'几何': 'RandomCrop + RandomHorizontalFlip + RandomAffine(小角度)',
'颜色': 'ColorJitter(brightness=0.3) + RandomGrayscale(0.1)',
'高级': 'Mosaic + CutMix',
'注意': '夜间场景多 → 增强亮度和噪声',
},
'工业缺陷检测': {
'几何': 'RandomRotation(±5°) + RandomAffine(小位移)',
'颜色': 'ColorJitter(contrast=0.2) + GaussianBlur',
'高级': 'CutOut(模拟遮挡)',
'注意': '缺陷可能很小 → 不要过度裁剪',
},
'无人机/航拍': {
'几何': 'RandomRotation(±180°) + RandomVerticalFlip',
'颜色': 'ColorJitter(brightness=0.3, saturation=0.2)',
'高级': 'Mosaic + MixUp',
'注意': '角度任意 → 旋转范围可以大',
},
'人脸识别': {
'几何': 'RandomHorizontalFlip + RandomAffine(小角度)',
'颜色': 'ColorJitter(brightness=0.2) + RandomGrayscale(0.05)',
'高级': 'CutOut',
'注意': '不要垂直翻转!不要大角度旋转!',
},
'车牌/文字识别': {
'几何': 'RandomAffine(小角度) + RandomPerspective',
'颜色': 'ColorJitter(brightness=0.2, contrast=0.2)',
'高级': 'GaussianBlur + GaussianNoise',
'注意': '不要翻转!6和9会混淆',
},
}
print("端侧AI场景增强策略:")
for scenario, strategy in scenarios.items():
print(f"\n [{scenario}]")
for k, v in strategy.items():
print(f" {k}: {v}")
edge_ai_augmentation_guide()
四、常见坑点
坑1:验证集也用了增强
python
# ❌ 错误:验证集用了RandomCrop和RandomHorizontalFlip
# val_transform = T.Compose([T.RandomCrop(32, padding=4), T.RandomHorizontalFlip(), ...])
# ✅ 正确:验证集只做必要的预处理
# val_transform = T.Compose([T.ToTensor(), T.Normalize(mean, std)])
坑2:增强太强反而降低准确率
python
# 增强强度的黄金法则:人眼还能认出原图是什么
# 如果增强后连你自己都认不出来,模型也学不到东西
# 增强强度建议:
# 小数据集(<1k):强增强,但augmentation probability < 0.5
# 中数据集(1k-10k):标准增强强度
# 大数据集(>10k):轻量增强,甚至可以不用高级增强
坑3:MixUp/CutMix训练时准确率看起来低
python
# MixUp训练时,准确率计算不准(因为标签是混合的)
# 不要用训练集准确率判断模型好坏
# 看验证集准确率!
# 而且MixUp通常需要更多epoch才能收敛
坑4:检测/分割任务的增强要保持label一致性
python
# 检测任务:bbox要跟着图像变换一起调整
# 分割任务:mask要跟着图像变换一起调整
# 用专门的库(如albumentations)处理,不要自己写
五、今日作业
- 增强对比:在CIFAR-10上对比"无增强 vs 基础增强 vs RandAugment",记录准确率差异
- MixUp实战:实现MixUp训练,观察训练loss和验证准确率的关系
- 端侧策略:根据你的端侧AI场景,设计一套数据增强策略,写下来
- 打卡 :评论区发你的增强对比结果,格式:"Day 26/100 打卡:数据增强全部掌握!"
今日小结
今天你学会了:
✅ 几何变换:RandomCrop/Flip/Rotation/Affine/Perspective
✅ 颜色变换:ColorJitter/Grayscale/Blur/Invert
✅ CutOut:随机遮挡,强迫学习全局特征
✅ MixUp:两张图线性混合,标签也混合
✅ CutMix:区域替换,CutOut+MixUp的结合
✅ AutoAugment/RandAugment/TrivialAugment:自动搜索最优增强
✅ Mosaic:YOLO的4图拼接增强
✅ 端侧AI各场景的增强策略
✅ 4个经典坑点
明日预告
Day 27:迁移学习与微调 --- 站在巨人的肩膀上
预训练模型、特征提取vs微调、冻结策略、ImageNet预训练、领域自适应
🔥 关注我,每天解锁一个端侧AI技能!
微信公众号:xxx | 小红书:xxx | CSDN:xxx
评论区打卡,一起坚持100天!
附:小红书图文版
封面标题建议:数据增强大全 | 不增加数据,让模型准确率提升10% 📈
P1 --- 封面
标题:数据增强技术
副标题:几何 / 颜色 / CutOut / MixUp / CutMix
关键词:数据增强 / Augmentation / 鲁棒性
P2 --- 基础增强:几何变换
RandomCrop + RandomHorizontalFlip = 标配
RandomRotation:引入旋转不变性
RandomAffine:平移+旋转+缩放
注意:文字识别不要翻转!
P3 --- 基础增强:颜色变换
ColorJitter:亮度/对比度/饱和度/色调
RandomGrayscale:不依赖颜色
GaussianBlur:模拟模糊
端侧场景:室外→强颜色,医学→谨慎
P4 --- 三种高级增强
CutOut:随机遮挡 → 强迫全局特征
MixUp:两张图混合 → 标签也混合
CutMix:切一块贴另一张 → 最推荐!
CIFAR-10提升2-4%
P5 --- 自动增强+YOLO Mosaic
RandAugment:只需调2个参数
TrivialAugment:零参数自动增强
Mosaic:4图拼1图,YOLO标配
小目标检测的利器
P6 --- 今日作业
增强对比实验 + MixUp实战
评论区打卡 Day 26/100
标签:#数据增强 #MixUp #CutMix #深度学习
CSDN发布提示:CSDN版本建议在CutOut/MixUp/CutMix部分各放一张效果示意图,在对比实验部分放准确率柱状图,在Mosaic部分放拼接示意图。