首页 / PyTorch 入门教程 / transforms 数据变换与数据增强

PyTorch 入门教程

transforms 数据变换与数据增强

本教程共 60 篇 · 第 12 篇 · 更新于 2026-08-17 · 约 3 分钟阅读

PyTorchtransforms数据增强图像预处理Compose归一化

本节目标:学会用 Compose 组合图像变换,理解归一化为什么必要,认识常见的数据增强操作。

变换是什么

图片刚读进来时是 PIL 图像或 NumPy 数组:像素值 0-255,尺寸五花八门。模型只认张量,还要求尺寸统一、数值范围合适。transforms 就是这段「洗菜切菜」的流水线,它来自 torchvision。

最基础的组合长这样:

from torchvision import transforms

transform = transforms.Compose([
    transforms.Resize((128, 128)),                # 统一尺寸
    transforms.ToTensor(),                        # 转张量,像素归一到 [0, 1]
    transforms.Normalize(mean=[0.5], std=[0.5]),  # 标准化
])

Compose 把多个变换包成一个整体,数据按顺序依次穿过。顺序有讲究:Resize 吃的是 PIL 图像,Normalize 吃的是张量,所以 ToTensor 必须夹在两者之间。顺序错了直接报类型错,我第一次写就把 Normalize 放到了 Resize 前面。

三个必学基础变换

ToTensor:把 PIL 图像转成张量,形状从 H×W×C 变成 C×H×W(通道放最前),像素从 [0, 255] 缩到 [0, 1]。它不做别的,但「转张量」这一步没它不行。

Resize:把图像缩放到指定大小。网络第一层的输入维度是定死的,同一批图像必须尺寸一致,这是它能进 batch 的前提。传整数表示短边缩到该长度、长边等比缩放;传元组表示直接定死宽高。

Normalize:按通道做标准化,公式是 (x - mean) / std。好处是把数据拉到零均值附近,模型收敛更稳。mean 和 std 怎么选?两种情况:

  1. 用 ImageNet 预训练模型:老老实实用官方值 mean=[0.485, 0.456, 0.406]std=[0.229, 0.224, 0.225]。这是训练 ImageNet 时用的统计值,乱改会掉精度。
  2. 自己从零训练:可以用 [0.5, 0.5, 0.5] 这种粗略值(把数据压到 [-1, 1]),或者先算数据集的真实统计值。单通道灰度图传单值就行,如 [0.5]

数据增强:免费的新数据

训练集只有 5 万张图,能不能「变出」更多?可以。每张图随机翻转一下、裁一裁、调调亮度,模型看到的就是新样本。这叫数据增强(Data Augmentation)。

它的价值在于逼模型学「本质」:一只猫,翻转了还是猫,裁掉一半也还是猫。模型见得多了,就不会死记某张图的固定细节,泛化能力自然上去。所以增强是防过拟合的廉价神器。

常用随机操作:

# MNIST 是 28×28 灰度图(单通道),别套 ImageNet 的 224 + RGB 均值
train_transform = transforms.Compose([
    transforms.RandomAffine(degrees=15, translate=(0.1, 0.1)),  # 小角度旋转 + 平移
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.1307], std=[0.3081]),          # MNIST 实测统计值
])

# 验证集:不做随机增强,只做 ToTensor + 归一化
valid_transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.1307], std=[0.3081]),
])

裁剪家族有三个兄弟,别搞混:

  • CenterCrop(224):固定裁中间,位置永远不变,验证集常用。
  • RandomCrop(224):随机挑位置裁,训练集可用。
  • RandomResizedCrop(224):先随机裁剪(比例也随机)再缩放,增强力度最大,训练标配。注意尺寸要跟输入匹配——MNIST 这种 28×28 小图,裁到 224 没意义,用 RandomCrop(28, padding=4) 或 RandomAffine 更合适。

增强只在训练集用。验证集和测试集要老老实实,用 Resize + CenterCrop + ToTensor + Normalize 这套固定流程,别加随机。总不能在考场上给学生「随机改题」。

Tip

RandomResizedCrop 让模型见过各种局部画面,比固定 Resize 效果好得多。图像分类的官方示例几乎都靠它撑场子。

训练和验证各一套

上一章讲过,Dataset 的 __getitem__ 负责出样本。变换就挂在这里:数据集读图后、返回前,把 transform 过一遍。所以训练集和验证集要建两个 Dataset,各自带自己的 transform:

from torchvision import datasets

train_dataset = datasets.MNIST(
    root="./data", train=True,
    transform=train_transform, download=True,
)
valid_dataset = datasets.MNIST(
    root="./data", train=False,
    transform=valid_transform, download=True,
)

同一个数据集类,换一个 transform 参数,就得到两个行为不同的数据集。这是 PyTorch 数据管线的标准套路:数据不变,变换分离。

自定义变换

内置变换不够用时,自己写一个类,实现 __call__ 即可:

class ScaleByTwo:
    def __call__(self, x):
        return x * 2

transform = transforms.Compose([ScaleByTwo(), transforms.ToTensor()])

写成类而不是函数,是为了把参数保存在实例里,复用起来干净。还有个场景几乎必须自定义:变换要同时改标签。比如图像翻转了,关键点坐标也得跟着翻,这种「连图带标签一起变」的活,内置变换干不了。

其他增强手段还有随机仿射变换 RandomAffine、高斯模糊 GaussianBlur,甚至自动搜索增强策略的 AutoAugment。入门阶段,翻转、旋转、颜色、裁剪这四样就足够用。

Note

torchvision 现在推荐新版接口 transforms.v2,API 和 v1 基本一致,额外支持更严格的类型检查。新项目可以直接 from torchvision.transforms import v2,本文写法原样照搬即可。

小结

  • Compose 按顺序串起变换,ToTensor 的位置别放错。
  • Resize 统一尺寸、ToTensor 转张量、Normalize 标准化,是图像入模的基本盘。
  • 增强只加在训练集:翻转、旋转、颜色扰动、随机裁剪。
  • 训练、验证各建一套 transform,数据不变、变换分离。
  • 特殊需求写自定义变换,实现 __call__ 就够。

到这里,数据管线闭环了:Dataset 取数据,transforms 加工,DataLoader 喂给模型。下一章进入训练核心——损失函数。