transforms.Compose顺序必须严格遵循:ToTensor→Normalize,几何与颜色变换需在ToTensor前;RandomResizedCrop的size是输出尺寸,scale控制裁剪面积占比,ratio约束宽高比;训练与验证transforms须分离,自定义transform需保持输入输出类型一致。

transforms.Compose 里顺序写错,增强结果就全乱了
数据增强不是把所有操作堆一起就行,Compose 的执行顺序直接影响最终图像状态。比如先 RandomRotation 再 Resize,和先 Resize 再 RandomRotation,旋转的是原始尺寸还是缩放后尺寸,差别很大。
- 常见错误:把
Normalize放在ToTensor前面 ——Normalize要求输入是tensor,但此时还是 PIL 图像,直接报错TypeError: tensor is not a torch.Tensor - 正确顺序必须是:
ToTensor→Normalize(因为ToTensor把像素值从 [0,255] 归一到 [0,1],Normalize才能按均值方差做标准化) - 几何变换(如
RandomHorizontalFlip、RandomCrop)建议放在ToTensor前;颜色变换(如ColorJitter)也得在ToTensor前,否则操作的是 float tensor 而非 uint8 图像,效果会偏弱或异常
RandomResizedCrop 的 size 和 scale 参数到底控制什么
RandomResizedCrop 是最常用也最容易配错的增强之一。它不是简单裁剪+缩放,而是先随机选一块区域(面积占原图 scale 区间),再拉伸到目标 size。
-
size是输出张量的高宽,比如(224, 224),类型是int或tuple -
scale是随机裁剪面积占比范围,例如(0.08, 1.0)表示裁剪区域面积至少为原图 8%,最多 100% -
ratio控制裁剪区域的宽高比范围,比如(0.75, 1.33),避免极端瘦长或扁平裁剪 - 如果只设
size不调scale,默认是(0.08, 1.0),但小目标数据集(如细粒度分类)常要收紧,比如改成(0.5, 1.0)避免裁掉关键部位
训练/验证用同一套 transforms?别这么干
训练和验证阶段对数据增强的诉求完全不同:训练要多样性,验证要稳定性。共用 transforms 会导致验证指标波动大、不可信,甚至模型误判自己“过拟合”。
- 训练集必含随机性操作:
RandomHorizontalFlip、RandomRotation、ColorJitter、RandomResizedCrop - 验证/测试集禁用一切随机操作:用
Resize+CenterCrop替代RandomResizedCrop,用固定尺寸裁剪保证每次加载同一张图都一样 - 注意
Normalize的均值方差参数必须一致(通常用 ImageNet 的mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]),否则训练和推理的分布不匹配
自定义 transform 函数怎么安全接入 torchvision
官方没提供的操作(比如特定噪声、频域增强、文字遮挡)需要自己写函数,但直接塞进 Compose 容易崩——因为 torchvision 期望输入是 PIL Image 或 Tensor,返回也得是同类型。
- 函数签名必须是
def __call__(self, img):,且返回类型和输入一致(PIL → PIL,Tensor → Tensor) - 若内部用了 numpy 或 torch ops,记得处理类型转换:PIL 输入要先
np.array(img),最后用Image.fromarray()回转;Tensor 输入则全程保持torch.Tensor - 别在自定义函数里调
to(torch.device)或.cuda()—— device 应由 dataloader 外部统一管理,transform 层只做 CPU 上的数据变换 - 示例骨架:
class AddGaussianNoise: def __init__(self, std=0.01): self.std = std def __call__(self, img): if isinstance(img, torch.Tensor): noise = torch.randn_like(img) * self.std return torch.clamp(img + noise, 0, 1) else: raise TypeError("Only torch.Tensor supported")
实际用的时候,最常被忽略的是 RandomResizedCrop 的 scale 和 ratio 对小目标的影响,以及自定义 transform 中类型判断不严导致训练时偶尔 crash —— 这类问题不会立刻报错,但会在某个 batch 突然中断,查起来特别费时间。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











