1. 数据增强让CIFAR-10训练事半功倍的秘诀第一次用CIFAR-10训练模型时我发现准确率死活上不去后来才知道问题出在数据量不足上。32x32的小图包含的细节有限这时候数据增强就像给模型开了外挂。我常用的增强组合是这样的transform_train transforms.Compose([ transforms.RandomCrop(32, padding4), # 随机裁剪 transforms.RandomHorizontalFlip(), # 水平翻转 transforms.ColorJitter(brightness0.2, contrast0.2), # 颜色扰动 transforms.RandomRotation(15), # 随机旋转 transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), ])这个组合我称之为新手大礼包几个关键点需要注意RandomCrop的padding值建议设为4这样能在32x32的图上获得最大程度的多样性ColorJitter的参数不要超过0.2否则图像会失真严重RandomRotation的角度控制在15度以内CIFAR-10的物体方向性较强实测下来这套增强能让模型准确率提升5-8个百分点。有次我忘记加增强测试准确率直接掉了7%这个教训让我记忆深刻。2. 模型优化从结构设计到训练技巧2.1 轻量高效的网络结构设计经过多次实验我发现这个精简版ResNet结构在CIFAR-10上表现很稳class BasicBlock(nn.Module): def __init__(self, in_planes, planes, stride1): super(BasicBlock, self).__init__() self.conv1 nn.Conv2d(in_planes, planes, kernel_size3, stridestride, padding1, biasFalse) self.bn1 nn.BatchNorm2d(planes) self.conv2 nn.Conv2d(planes, planes, kernel_size3, stride1, padding1, biasFalse) self.bn2 nn.BatchNorm2d(planes) def forward(self, x): out F.relu(self.bn1(self.conv1(x))) out self.bn2(self.conv2(out)) return out class CifarResNet(nn.Module): def __init__(self, block, num_blocks, num_classes10): super(CifarResNet, self).__init__() self.in_planes 16 self.conv1 nn.Conv2d(3, 16, kernel_size3, stride1, padding1, biasFalse) self.bn1 nn.BatchNorm2d(16) self.layer1 self._make_layer(block, 16, num_blocks[0], stride1) self.layer2 self._make_layer(block, 32, num_blocks[1], stride2) self.layer3 self._make_layer(block, 64, num_blocks[2], stride2) self.linear nn.Linear(64, num_classes) def _make_layer(self, block, planes, num_blocks, stride): layers [] layers.append(block(self.in_planes, planes, stride)) self.in_planes planes for _ in range(1, num_blocks): layers.append(block(self.in_planes, planes, 1)) return nn.Sequential(*layers)这个结构有三大优势参数量控制在1M以内训练速度快使用残差连接避免了梯度消失BatchNorm让训练更稳定2.2 学习率调度策略固定学习率是新手常犯的错误。我推荐使用余弦退火配合热身optimizer optim.SGD(model.parameters(), lr0.1, momentum0.9, weight_decay5e-4) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max200)具体参数设置要注意初始学习率设为0.1对SGD比较合适weight_decay建议5e-4防止过拟合T_max设为总epoch数3. 性能调优从训练加速到精度提升3.1 混合精度训练实战启用混合精度训练后我的训练时间缩短了40%scaler torch.cuda.amp.GradScaler() for epoch in range(epochs): for inputs, targets in trainloader: inputs, targets inputs.to(device), targets.to(device) with torch.cuda.amp.autocast(): outputs model(inputs) loss criterion(outputs, targets) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() optimizer.zero_grad()关键点必须使用GradScaler防止梯度下溢autocast上下文管理器自动处理精度转换内存占用减少约一半3.2 标签平滑技术当模型出现过拟合时标签平滑是我的秘密武器class LabelSmoothingCrossEntropy(nn.Module): def __init__(self, epsilon0.1): super().__init__() self.epsilon epsilon def forward(self, preds, target): log_probs F.log_softmax(preds, dim-1) nll_loss -log_probs.gather(dim-1, indextarget.unsqueeze(1)) smooth_loss -log_probs.mean(dim-1) loss (1 - self.epsilon) * nll_loss self.epsilon * smooth_loss return loss.mean()这个技巧让我的模型在测试集上的准确率提升了2%特别是对那些容易混淆的类别比如猫和狗效果明显。4. 实战经验那些官方文档不会告诉你的技巧4.1 数据加载的隐藏优化项DataLoader的这些参数设置让我的数据加载速度提升了3倍trainloader torch.utils.data.DataLoader( trainset, batch_size128, shuffleTrue, num_workers4, pin_memoryTrue, persistent_workersTrue, prefetch_factor2 )关键配置说明pin_memoryTrue配合GPU训练必备persistent_workers减少进程反复创建的开销prefetch_factor实现数据预加载4.2 模型初始化技巧正确的初始化让我的模型收敛速度快了一倍def init_weights(m): if isinstance(m, nn.Conv2d): nn.init.kaiming_normal_(m.weight, modefan_out, nonlinearityrelu) elif isinstance(m, nn.BatchNorm2d): nn.init.constant_(m.weight, 1) nn.init.constant_(m.bias, 0) model.apply(init_weights)Kaiming初始化配合ReLU激活函数是经过多次实验验证的最佳组合特别适合深层CNN网络。