本课目标
从 MNIST 的"标准答案"走向真实图像任务:处理脏数据、数据增强、迁移学习,完成一个能落地的垃圾分类器。
MNIST 是实验室里的玩具——7 万张 28×28 的灰度图,干干净净。你工作中的图像项目呢?数据不够、照片模糊、类别极度不平衡。本讲用真实的垃圾分类任务,教你处理这三个"真实世界专属问题"。
核心内容
数据管道:目录即标签
data/garbage/
├── train/
│ ├── recyclable/ img001.jpg ...
│ ├── kitchen/ ...
│ ├── harmful/ ...
│ └── other/
└── val/ (同结构)
ImageFolder 自动从目录结构建索引——这是工程上最简单的标注格式,不需要额外的 CSV 或 JSON。
数据增强:让 1 张图变 10 张
train_transform = transforms.Compose([
transforms.RandomResizedCrop(224, scale=(0.6, 1.0)),
transforms.RandomHorizontalFlip(),
transforms.ColorJitter(brightness=0.3, contrast=0.3),
transforms.RandomRotation(15),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406],
[0.229, 0.224, 0.225]),
])
增强的本质:告诉模型"翻转的可乐瓶还是可乐瓶,灯光暗的可乐瓶还是可乐瓶"——这些变化不改变类别。但验证集绝不随机增强,只做确定性的 resize + 归一化。这是新手最容易忽略的纪律。
为什么归一化用的是 [0.485, 0.456, 0.406] 这几个数?它们是 ImageNet 120 万张图的 RGB 通道均值和标准差——所有 ImageNet 预训练模型都用这组值训练的,你必须跟它保持一致的输入分布。
迁移学习:数据不够时的唯一出路
几千张图从零训练 CNN → 过拟合。迁移学习是解药:拿 ImageNet 预训练的 ResNet18,冻结骨干,只训分类头。
from torchvision import models
model = models.resnet18(weights='IMAGENET1K_V1')
for param in model.parameters():
param.requires_grad = False
model.fc = nn.Linear(model.fc.in_features, 4)
预训练模型已经在 120 万张图上学过"边缘/纹理/形状"这些通用视觉特征。我们只教它"这些特征怎么组合成四类垃圾"——几千张图就能到 90%+。效果不够再解冻最后几层微调,学习率调小一个数量级。
类别不平衡
有害垃圾样本通常最少,但识别它的重要性最高。对策:WeightedRandomSampler 过采样少数类;或在 loss 函数里给少数类加权——让它"错判有害垃圾的代价更高"。
动手练习
- 搭建数据管道,对比"随机初始化 vs 迁移学习"的准确率差距
- 逐步解冻 ResNet 最后几层,找到性价比最高的微调位置