首页 › S 模型训练 › S2 数据处理 › 03

S2-03 · 数据增强:不花钱的提分手段

进阶阶段约 180 分钟阶段:S2 数据处理

阶段:S2-数据处理 | 预计耗时:60-75 分钟 | 前置:S2-02 训练验证测试集划分 代码:本篇代码要你自己敲成 model-learn/s2_augmentation.py

学习目标

  1. 理解数据增强的本质:对同一条数据做保持标签不变的随机变换 = 免费造新数据
  2. 在 MNIST 500 样本小数据场景实测"旋转增强"能提多少分
  3. 记住铁律:增强只加在 train 的 transform 里,val/test 只做标准预处理

核心知识

1. 什么变换"保持标签不变"

  • 图像:旋转几度、平移几像素、翻转、裁剪、加噪——数字 3 转一点点还是 3
  • 文字:同义词替换、回译;表格:加微小噪声
  • 反例:上下翻转会把手写 6 变成 9(标签变了!)——增强必须懂数据,不是无脑套

2. 增强为什么能抗过拟合

模型每次看到的是"同一条数据的不同样子",背不下单一版本,只能学规律 → 和 S4 要讲的正则化殊途同归,但更便宜。

3. 本机写法

transforms.Compose([transforms.RandomRotation(10), transforms.ToTensor()]) - 随机变换放在 ToTensor() 之前(它们作用在 PIL 图上) - torchvision 每次取样本时现场随机——同一张图每个 epoch 长得都不一样

实验任务

任务 1:敲出脚本(30 分钟)

对照组设计(一次只改一个变量,其余全同):

# s2_augmentation.py —— 500 样本上实测旋转增强
import torch, torch.nn as nn
from torchvision import datasets, transforms
from torch.utils.data import DataLoader, Subset

torch.manual_seed(42)
plain = transforms.ToTensor()
aug   = transforms.Compose([transforms.RandomRotation(10), transforms.ToTensor()])

train_raw = datasets.MNIST("data", train=True, download=False, transform=plain)
test_ds   = datasets.MNIST("data", train=False, download=False, transform=plain)
test_dl   = DataLoader(test_ds, batch_size=256)

model = nn.Sequential(nn.Flatten(), nn.Linear(784, 128), nn.ReLU(), nn.Linear(128, 10))

def run(train_transform, tag):
    torch.manual_seed(42)                      # 每组实验重置种子,公平对比
    global model
    model = nn.Sequential(nn.Flatten(), nn.Linear(784, 128), nn.ReLU(), nn.Linear(128, 10))
    train_ds = datasets.MNIST("data", train=True, download=False, transform=train_transform)
    dl = DataLoader(Subset(train_ds, range(500)), batch_size=64, shuffle=True)
    opt = torch.optim.Adam(model.parameters(), lr=1e-3)
    loss_fn = nn.CrossEntropyLoss()
    for epoch in range(6):
        for x, y in dl:
            opt.zero_grad(); loss_fn(model(x), y).backward(); opt.step()
    @torch.no_grad()
    def acc():
        n = ok = 0
        for x, y in test_dl:
            ok += (model(x).argmax(1) == y).sum().item(); n += len(y)
        return ok / n
    print(f"{tag}: 测试集准确率 = {acc():.4f}")

run(plain, "无增强(对照)")
run(aug,   "旋转±10°增强  ")

任务 2:加大剂量(15 分钟)

增强改成 RandomRotation(30) 再跑——增强是不是越猛越好?写进观察记录表。

任务 3:交叉增强(15 分钟)

再加一组 RandomAffine(degrees=10, translate=(0.1, 0.1))(旋转+平移)。三行对比后回答:小数据场景,增强是最便宜的正则化吗?

验收标准

衔接下一阶段

数据侧四大件(Dataset/Loader/划分/增强)已就位 → 进入 S3-01 nn.Module 解剖:换到模型这一侧。

小测验(2 题)

答完立即判分,错题给解析;得分存本地。实验与实操题不上网测:回对话找老师验收。