实战:图像分类(CIFAR-10)
引子
MNIST 的准确率刷到 99% 了,然后呢?
你换了张真实照片——模糊的、带噪点的、背景花里胡哨的——CNN 直接掉到 70%。
不是你模型不行,是 MNIST 太简单了。
CIFAR-10 就是下一个台阶:32×32 彩色图片,10 个类别,真正的”AI 能不能分清猫和狗”。
- 训练集:50,000 张
- 测试集:10,000 张
- 彩色(3 通道 RGB),32×32 像素
- 10 类:飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车
跟 MNIST 的本质区别:颜色 + 纹理 + 形状才是特征,纯像素不够。
前置知识
一、基线 CNN
先拿一个比 MNIST 那篇更深的 CNN,看 CIFAR-10 的难度。
1 | import torch |
训练代码跟 MNIST 实测那篇一样,只是加了两个新东西:
BatchNorm2d(批归一化):每一层输出都做归一化,加速收敛、减少过拟合。好消息:加了 BatchNorm 之后,你可以用更大的学习率。
num_workers=2:用 2 个进程预加载数据,GPU 不会被 CPU 拖慢。训 CPU 时可以关掉(=0)。
跑 20 轮:
1 | def train(): |
预期结果:
1 | Epoch 1: loss=1.4167, acc=0.4765 |
84.3%。比瞎猜(10%)好很多,但远不如 MNIST 的 99%。
二、数据增强:免费的精度
CIFAR-10 训练集只有 5 万张图。数据增强相当于白送你更多数据:
1 | # 带增强的数据加载 |
上面四行代码改了之后,跑 20 轮:
1 | Epoch 1: loss=1.5232, acc=0.4421 # 一开始更难了(因为图像被随机改了) |
87.0%,比基线高了 2.7%。
而且注意一个细节:没有增强时,训练 loss 远低于测试 loss(过拟合的苗头)。加了增强后两者差距缩小——泛化能力更强。
重要提醒: 数据增强只能应用到训练集!测试集只用 Normalize。如果对测试集也做 RandomCrop,每次评估结果都会变,你就不知道模型到底怎样。
三、迁移学习:站在巨人肩上
接下来是最大的飞跃。用一个在 ImageNet(1400 万张图片)上预训练好的 ResNet-18,迁移学习到 CIFAR-10。
1 | from torchvision.models import resnet18 |
但 ResNet-18 有 1100 万参数,全套微调太慢了。更好的做法:
1 | # 冻结 backbone,只训练最后的分类头 |
冻结后训练 10 轮:
1 | Epoch 1: loss=0.8421, acc=0.7415 |
82.3%——只用 10 轮,只训分类头,不碰 1100 万参数。
如果再加 10 轮全量微调(解冻 backbone,lr 降到 1e-4):
1 | # 第11轮开始:解冻 backbone,低学习率微调 |
1 | Epoch 11: loss=0.3512, acc=0.8813 |
92.2%——比普通 CNN + 数据增强高了 5 个点。
四、三方案对比
| 方案 | 参数量 | 20 轮精度 | 训练时间(GPU) |
|---|---|---|---|
| 普通 CNN | 4.5M | 84.3% | ~8min |
| + 数据增强 | 4.5M | 87.0% | ~9min(预处理多了) |
| + ResNet 迁移学习 | 11.1M | 92.2% | ~15min |
关键结论:
- 数据增强是性价比最高的技巧——不要钱,改一行代码就 +2.7%
- 迁移学习是上限最高的方案——+7.9%,但预训练模型很难在 CPU 上跑
五、完整代码
1 | """cifar10_demo.py - CIFAR-10 图像分类完整代码""" |
GPU 的话约 15 分钟跑完。如果是 CPU,全量微调可能 2-3 小时——你可以在 Phase 1 后停,拎着 82% 的精度先玩玩。
总结
- CIFAR-10 比 MNIST 难得多(84% vs 99%),但这才是真实世界的入门难度
- 数据增强是白送的精调度,必须上
- 迁移学习是做大模型的捷径——没人真的从零训了
- 学会了两阶段微调:先冻后解,又快又好
接下来你可以:
- 自己收集 10 张猫/狗照片,用这个模型测试
- 把 ResNet-18 换成 ResNet-50,看看精度还能涨多少
- 学习 TensorBoard 来可视化训练过程
- 尝试用 YOLO 做目标检测——下一篇就是这个
