共计 2864 个字符,预计需要花费 8 分钟才能阅读完成。
CIFAR100 是深度学习领域经典的图像分类基准数据集之一,包含 100 个细粒度类别,每个类别有 600 张 32×32 像素的彩色图像。虽然数据集规模不大,但在实际使用中我们常常会遇到数据加载效率低、类别不均衡等问题。本文将分享我在使用 CIFAR100 数据集时的一些实战经验,希望能帮助大家更高效地完成模型训练。

1. 理解 CIFAR100 数据集特性
CIFAR100 数据集有几个显著特点需要我们特别注意:
- 小尺寸图像:32×32 像素的图像意味着模型需要从有限的像素信息中学习特征
- 细粒度分类:100 个类别中有很多相似类别(如不同类型的树木、车辆等)
- 类别不均衡:虽然官方数据集是平衡的,但在实际应用中可能需要处理不平衡问题
2. 数据加载优化实践
PyTorch 的 DataLoader 是数据加载的核心组件,合理配置可以显著提升训练效率。
2.1 DataLoader 关键参数
train_loader = torch.utils.data.DataLoader(
train_dataset,
batch_size=128,
shuffle=True,
num_workers=4, # 根据 CPU 核心数设置
pin_memory=True, # 加速数据转移到 GPU
persistent_workers=True # 避免重复创建 worker
)
2.2 内存缓存优化
对于小型数据集如 CIFAR100,我们可以将整个数据集加载到内存中:
class CachedDataset(torch.utils.data.Dataset):
def __init__(self, dataset):
self.dataset = dataset
self.cache = [None] * len(dataset)
def __getitem__(self, index):
if self.cache[index] is None:
self.cache[index] = self.dataset[index]
return self.cache[index]
3. 数据增强策略
对于 32×32 的小图像,我们需要特别设计数据增强策略:
train_transform = transforms.Compose([transforms.RandomCrop(32, padding=4),
transforms.RandomHorizontalFlip(),
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),
transforms.ToTensor(),
transforms.Normalize((0.5071, 0.4867, 0.4408), (0.2675, 0.2565, 0.2761))
])
4. 完整训练代码示例
以下是一个完整的 ResNet-18 训练示例,包含混合精度训练和 warmup 策略:
import torch
import torch.nn as nn
import torch.optim as optim
from torch.cuda.amp import GradScaler, autocast
# 初始化模型、优化器等
model = ResNet18(num_classes=100).cuda()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4)
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=200)
scaler = GradScaler()
# 训练循环
for epoch in range(200):
model.train()
for batch_idx, (inputs, targets) in enumerate(train_loader):
inputs, targets = inputs.cuda(), targets.cuda()
# Warmup 学习率
if epoch < 5:
lr = 0.1 * (batch_idx + epoch * len(train_loader)) / (5 * len(train_loader))
for param_group in optimizer.param_groups:
param_group['lr'] = lr
# 混合精度训练
with autocast():
outputs = model(inputs)
loss = criterion(outputs, targets)
scaler.scale(loss).backward()
scaler.step(optimizer)
scaler.update()
optimizer.zero_grad()
scheduler.step()
5. 性能优化对比
通过上述优化,我们观察到以下改进:
- GPU 利用率:从约 40% 提升到 70-80%
- 训练速度:单 epoch 时间从 45 秒减少到 18 秒(RTX 3090)
- 内存使用:峰值显存使用量减少了约 30%
6. 常见问题与解决方案
6.1 多进程数据加载问题
当使用多进程数据加载 (num_workers > 0) 时,可能会遇到 CUDA 上下文错误。解决方案是在主程序中设置:
if __name__ == '__main__':
torch.multiprocessing.set_start_method('spawn')
6.2 小图像上采样问题
避免在模型早期使用过大步长的下采样,这会导致小图像丢失过多信息。
6.3 标签平滑技术
对于细粒度分类,可以使用标签平滑减轻模型过拟合:
class LabelSmoothingCrossEntropy(nn.Module):
def __init__(self, smoothing=0.1):
super().__init__()
self.smoothing = smoothing
def forward(self, pred, target):
log_prob = F.log_softmax(pred, dim=-1)
nll_loss = -log_prob.gather(dim=-1, index=target.unsqueeze(1))
nll_loss = nll_loss.squeeze(1)
smooth_loss = -log_prob.mean(dim=-1)
loss = (1.0 - self.smoothing) * nll_loss + self.smoothing * smooth_loss
return loss.mean()
7. 延伸应用
本文介绍的技术可以轻松迁移到其他类似规模的数据集。对于自定义数据集,只需调整数据加载和预处理部分即可。CIFAR100 在对比学习领域也有特殊价值,因为它的细粒度分类特性非常适合学习有判别力的特征表示。
通过本文介绍的方法,我们成功将 CIFAR100 的训练效率提升了 2 - 3 倍,同时保持了模型的准确性。这些优化技巧在工业级图像分类任务中同样适用,希望能对大家的工作有所帮助。
正文完
发表至: 未分类
近一天内
