从零到一:ResNet18在CIFAR-10上的实战调优与避坑指南
1. 环境准备从零搭建深度学习开发环境第一次接触深度学习时最让人头疼的就是环境配置。记得我刚开始用Windows电脑跑ResNet18时光是安装Anaconda就折腾了大半天。这里分享几个真实踩坑后总结的经验帮你避开那些新手必踩的雷区。虚拟环境管理是第一个要掌握的技能。很多教程会直接让你用conda create创建环境但没人告诉你这可能会把环境默认装在C盘。我的D盘明明有200G空间结果conda一声不吭就把环境塞进了快满的C盘。后来发现只要在创建环境前先修改用户目录下的.condarc文件没有就新建一个加入这行配置envs_dirs: - D:\anaconda\envsPyCharm与conda的联动也是个坑点。有次创建项目时PyCharm死活找不到conda重启、重装都没用。最后发现是系统PATH环境变量被其他软件修改了。解决方法很简单在PyCharm的设置里手动指定conda可执行文件路径通常是Anaconda安装目录/Scripts/conda.exe。CPU训练时依赖包版本特别重要。有次我按教程装了最新版PyTorch结果训练时内存直接爆满。后来换成不带CUDA的CPU版本才解决pip install torch1.8.0cpu torchvision0.9.0cpu -f https://download.pytorch.org/whl/torch_stable.html2. 数据准备CIFAR-10的特殊处理技巧CIFAR-10虽然只有6万张32x32的小图但对内存紧张的电脑来说仍然是个挑战。我第一次加载数据集时8GB内存直接占满导致死机。后来发现用这两个技巧可以省下30%内存按需下载比一次性加载更聪明。很多教程会教你直接用torchvision.datasets.CIFAR10下载但默认会缓存到系统目录。我改成这样既控制下载位置又避免重复下载transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)) ]) dataset CIFAR10(root./data, trainTrue, downloadTrue, transformtransform)DataLoader的num_workers参数在Windows下是个陷阱。教程里常建议设为4或8加速加载但在WindowsCPU环境下非零值反而可能引发BrokenPipeError。我的经验值是loader DataLoader(dataset, batch_size64, shuffleTrue, num_workers0)3. 模型改造轻量级ResNet18实战方案原始ResNet18是为ImageNet设计的直接用在CIFAR-10上就像用大炮打蚊子。我在CPU上跑第一个epoch花了2小时果断开始魔改。通道数减半是最有效的瘦身方法class BasicBlock(nn.Module): def __init__(self, in_planes, planes, stride1): super(BasicBlock, self).__init__() # 原版通道数64-128-256-512 # 修改后32-64-128-256 self.conv1 nn.Conv2d(in_planes, planes, kernel_size3, stridestride, padding1, biasFalse) self.bn1 nn.BatchNorm2d(planes) ...学习率策略对CPU训练至关重要。我发现用余弦退火比固定学习率收敛更快optimizer torch.optim.SGD(model.parameters(), lr0.1, momentum0.9) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max200)4. 训练技巧CPU环境下的生存法则在只有CPU的笔记本上训练时内存管理决定成败。有次训练到第10个epoch突然崩溃发现是Windows的虚拟内存没开。设置16GB虚拟内存后问题解决。另外这些技巧也很实用梯度累积能模拟大batch效果for i, (inputs, labels) in enumerate(train_loader): outputs model(inputs) loss criterion(outputs, labels) loss.backward() if (i1) % 4 0: # 每4个batch更新一次 optimizer.step() optimizer.zero_grad()混合精度训练在CPU上也能省内存scaler torch.cpu.amp.GradScaler() with torch.cpu.amp.autocast(): outputs model(inputs) loss criterion(outputs, labels) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()5. 调试指南常见报错与解决方案权重加载失败是我遇到最多的问题。有次加载预训练模型时报错RuntimeError: Error(s) in loading state_dict: Missing key(s) in state_dict...根本原因是模型结构不匹配。我的解决方案是# 先创建空模型 model ResNet18() # 只加载匹配的参数 state_dict torch.load(resnet.pth) model.load_state_dict({k:v for k,v in state_dict.items() if k in model.state_dict()})NumPy报错也很常见特别是这种ImportError: DLL load failed while importing _multiarray_umath这通常是因为多个Python环境混用导致的。我的解决步骤完全卸载当前numpypip uninstall numpy删除残留文件到site-packages目录手动删除numpy开头的文件夹重装指定版本pip install numpy1.19.36. 性能优化从85%到92%的调参细节经过上述改造我的ResNet18在CIFAR-10上从初始85%准确率提升到92%。关键调整包括数据增强比想象中重要transform_train transforms.Compose([ transforms.RandomCrop(32, padding4), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize(...) ])标签平滑能防止过拟合criterion nn.CrossEntropyLoss(label_smoothing0.1)学习率预热帮助稳定训练scheduler torch.optim.lr_scheduler.LambdaLR( optimizer, lr_lambdalambda epoch: min((epoch 1) / 10, 1) # 前10epoch线性增长 )7. 模型部署训练成果的实用化处理训练好的模型需要妥善保存。我吃过没保存优化器状态的亏后来都用这种方式torch.save({ epoch: epoch, model_state_dict: model.state_dict(), optimizer_state_dict: optimizer.state_dict(), loss: loss, }, checkpoint.pth)ONNX导出方便后续部署dummy_input torch.randn(1, 3, 32, 32) torch.onnx.export(model, dummy_input, resnet18.onnx)最后提醒TensorBoard日志要定期清理。有次我忘了关记录一个月后发现logs文件夹占了20GB空间。现在我都用这个命令启动tensorboard --logdirlogs --port6006 --reload_interval 30