共计 3551 个字符,预计需要花费 9 分钟才能阅读完成。
背景痛点
在计算机视觉任务中,使用预训练模型进行迁移学习已成为常见做法。但对于像 CIFAR100 这样的小分辨率(32×32)且类别较多(100 类)的数据集,开发者常遇到以下问题:

- 小样本适应差:预训练模型通常在 ImageNet 等大数据集上训练,直接迁移到 CIFAR100 时特征提取效果不佳
- 类别不平衡:某些类别样本量极少,导致模型预测偏向多数类
- 过拟合风险:模型参数量远大于 CIFAR100 的数据规模,容易过拟合
- 计算资源消耗:大模型在小分辨率图像上可能造成显存浪费
技术选型
以下是主流预训练模型在 CIFAR100 上的对比(Top- 1 准确率):
| 模型 | 参数量 (M) | 输入尺寸 | 准确率 (%) | 适合场景 |
|---|---|---|---|---|
| ResNet50 | 25.5 | 224×224 | 68.2 | 平衡准确率与计算成本 |
| EfficientNetB0 | 5.3 | 224×224 | 65.8 | 移动端 / 资源受限环境 |
| MobileNetV2 | 3.4 | 224×224 | 63.1 | 极致轻量化需求 |
| ViT-Tiny | 5.7 | 224×224 | 62.3 | 尝试 Transformer 架构 |
选择建议:
- 优先尝试 ResNet50,在准确率和计算成本间取得良好平衡
- 对部署环境要求严格时选择 EfficientNetB0
- 需要极轻量模型时考虑 MobileNetV2
核心实现
完整 PyTorch 迁移学习代码
import torch
import torchvision
from torch import nn, optim
from torch.utils.data import DataLoader
from torchvision import transforms, datasets
# 1. 数据加载与增强
train_transform = transforms.Compose([transforms.RandomCrop(32, padding=4),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761))
])
train_set = datasets.CIFAR100(root='./data', train=True, download=True, transform=train_transform)
train_loader = DataLoader(train_set, batch_size=128, shuffle=True)
# 2. 模型加载(以 ResNet50 为例)model = torchvision.models.resnet50(pretrained=True)
# 3. 修改最后一层(100 类分类)num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 100)
# 4. 训练配置
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 5. 训练循环
for epoch in range(50):
model.train()
for inputs, labels in train_loader:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
关键修改点说明:
- 输入尺寸适配:虽然 ResNet 原始输入为 224×224,但可以直接处理 32×32 的 CIFAR100 图像
- 归一化参数:使用 CIFAR100 的统计量而非 ImageNet 的
- 最后一层调整:原始 1000 类分类层替换为 100 类
优化技巧
学习率调整策略
推荐使用 warmup+cosine 衰减:
from torch.optim.lr_scheduler import CosineAnnealingLR
scheduler = CosineAnnealingLR(optimizer, T_max=50)
# 在训练循环中加入 warmup
if epoch < 5: # warmup 阶段
lr = 0.01 * (epoch + 1) / 5
for param_group in optimizer.param_groups:
param_group['lr'] = lr
else:
scheduler.step()
数据增强
针对小数据集推荐组合使用:
- CutMix 增强:
from torchvision.transforms.functional import to_pil_image, to_tensor
import random
def cutmix_data(x, y, alpha=1.0):
lam = np.random.beta(alpha, alpha)
batch_size = x.size()[0]
index = torch.randperm(batch_size)
# 生成裁剪区域
bbx1, bby1, bbx2, bby2 = rand_bbox(x.size(), lam)
x[:, :, bbx1:bbx2, bby1:bby2] = x[index, :, bbx1:bbx2, bby1:bby2]
# 调整 lambda 值
lam = 1 - ((bbx2 - bbx1) * (bby2 - bby1) / (x.size()[-1] * x.size()[-2]))
return x, y, y[index], lam
- AutoAugment 策略:
train_transform.transforms.insert(0, transforms.AutoAugment(transforms.AutoAugmentPolicy.CIFAR10))
类别不平衡处理
- 样本加权:
from torch.utils.data import WeightedRandomSampler
# 计算每个类别的样本权重
class_counts = np.bincount(train_set.targets)
class_weights = 1. / class_counts
sample_weights = class_weights[train_set.targets]
sampler = WeightedRandomSampler(sample_weights, len(sample_weights))
train_loader = DataLoader(train_set, batch_size=128, sampler=sampler)
- 损失函数加权:
criterion = nn.CrossEntropyLoss(weight=torch.from_numpy(class_weights).float().to(device))
避坑指南
- 冻结层数不当
- 问题:冻结全部层导致无法适应 CIFAR100 特征
-
解决:建议冻结前 80% 的层,逐步解冻
-
batch size 过大
- 问题:大 batch 导致梯度更新方向单一
-
解决:保持 batch size 在 64-256 之间
-
学习率未调整
- 问题:直接使用原始学习率导致震荡
-
解决:初始学习率设为原值的 1 /10
-
忽略输入尺寸适配
- 问题:未调整大模型的输入层
- 解决:添加适配卷积层:
model.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
性能验证
| 硬件 | batch=128 | batch=256 | 显存占用 |
|---|---|---|---|
| RTX 3090 | 1200img/s | 1800img/s | 6.8GB |
| GTX 1660 Ti | 450img/s | 620img/s | 4.2GB |
| CPU(i7-10700) | 28img/s | OOM | – |
建议:
– GPU 用户可使用更大 batch size
– CPU 用户建议 batch size 不超过 64
延伸思考
- 如何评估预训练模型的特征提取能力?
-
可以冻结特征提取层,仅训练分类器,通过验证集准确率判断特征质量
-
小分辨率图像是否需要特殊的模型架构?
-
可以尝试专门为 CIFAR 设计的变体,如 ResNet20/32
-
预训练模型是否总是最优选择?
- 对于特定领域任务,从零训练可能效果更好
结语
通过合理选择模型、调整训练策略,可以在 CIFAR100 上获得较好的迁移学习效果。建议先使用 ResNet50 快速验证流程,再尝试其他模型和优化技巧。实践中要注意监控验证集表现,防止过拟合。希望本指南能帮助开发者避开常见陷阱,高效完成计算机视觉任务。
正文完
发表至: 未分类
近一天内
