从LeNet到ResNet50:用PyTorch复现5个经典CNN模型,在COIL20数据集上跑出100%准确率

张开发
2026/4/21 17:35:11 15 分钟阅读

分享文章

从LeNet到ResNet50:用PyTorch复现5个经典CNN模型,在COIL20数据集上跑出100%准确率
从LeNet到ResNet50用PyTorch复现5个经典CNN模型的技术演进之旅在计算机视觉领域卷积神经网络CNN的发展历程堪称一部技术进化史。本文将带您亲自动手使用PyTorch框架从零实现LeNet、AlexNet、GoogLeNet、VGG16和ResNet50这五个里程碑式的模型并在COIL20数据集上进行实战测试。不同于简单的代码复现我们将深入探讨每个模型背后的设计哲学分析它们如何逐步解决图像识别中的关键挑战。1. 环境准备与数据集介绍COIL20数据集包含20类物体的1440张灰度图像每类物体有72个不同角度的拍摄样本。这个规模适中的数据集非常适合用来验证经典CNN模型的性能。我们先配置基础环境import torch import torch.nn as nn from torch.utils.data import Dataset, DataLoader from torchvision import transforms from PIL import Image import glob import random # 数据预处理管道 transform transforms.Compose([ transforms.Resize((128, 128)), transforms.ToTensor() ])数据集划分采用9:1的比例训练集1296张测试集144张。这种小规模数据集上的优异表现能直观反映模型的特征提取能力。提示COIL20的简单性使其成为验证模型设计有效性的理想选择但要注意避免过拟合问题2. LeNet-5CNN的开山之作1998年Yann LeCun提出的LeNet-5是最早的实用卷积网络用于手写数字识别。其核心贡献在于证明了局部连接和权值共享的有效性。关键创新点交替的卷积层和下采样层使用Sigmoid激活函数末端全连接层进行分类class LeNet(nn.Module): def __init__(self): super(LeNet, self).__init__() self.conv_layers nn.Sequential( nn.Conv2d(1, 6, 5), # 原始论文使用5x5卷积 nn.Sigmoid(), nn.AvgPool2d(2), # 原始使用平均池化 nn.Conv2d(6, 16, 5), nn.Sigmoid(), nn.AvgPool2d(2) ) self.fc_layers nn.Sequential( nn.Linear(16*29*29, 120), # 适配COIL20的输入尺寸 nn.Sigmoid(), nn.Linear(120, 84), nn.Sigmoid(), nn.Linear(84, 20) )在COIL20上原始LeNet架构经过200轮训练后准确率约85%。这反映出Sigmoid激活函数的局限性——容易出现梯度消失问题。3. AlexNet深度学习复兴的标志2012年AlexNet在ImageNet竞赛中一战成名其设计理念影响深远创新点作用描述ReLU激活函数解决梯度消失加速收敛Dropout层防止过拟合最大池化保留更显著特征数据增强提升泛化能力class AlexNet(nn.Module): def __init__(self): super(AlexNet, self).__init__() self.features nn.Sequential( nn.Conv2d(1, 96, 11, stride4), nn.ReLU(inplaceTrue), nn.MaxPool2d(3, 2), nn.Conv2d(96, 256, 5, padding2), nn.ReLU(inplaceTrue), nn.MaxPool2d(3, 2), nn.Conv2d(256, 384, 3, padding1), nn.ReLU(inplaceTrue), nn.Conv2d(384, 384, 3, padding1), nn.ReLU(inplaceTrue), nn.Conv2d(384, 256, 3, padding1), nn.ReLU(inplaceTrue), nn.MaxPool2d(3, 2) ) self.classifier nn.Sequential( nn.Dropout(), nn.Linear(256*6*6, 4096), nn.ReLU(inplaceTrue), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(inplaceTrue), nn.Linear(4096, 20) )在相同条件下AlexNet仅需50轮训练就能达到95%的准确率验证了ReLU相对于Sigmoid的优越性。4. VGG16深度与规整的力量牛津大学提出的VGG网络证明了深度的重要性。其统一使用3×3小卷积核的堆叠策略成为后续模型的参考标准。VGG16的结构特点全部使用3×3卷积核步长1padding 1每经过池化层(2×2步长2)通道数翻倍共16层权重层(13卷积3全连接)def make_layers(cfg): layers [] in_channels 1 for v in cfg: if v M: layers [nn.MaxPool2d(2, 2)] else: conv2d nn.Conv2d(in_channels, v, 3, padding1) layers [conv2d, nn.ReLU(inplaceTrue)] in_channels v return nn.Sequential(*layers) cfg [64, 64, M, 128, 128, M, 256, 256, 256, M, 512, 512, 512, M, 512, 512, 512, M] class VGG16(nn.Module): def __init__(self): super(VGG16, self).__init__() self.features make_layers(cfg) self.classifier nn.Sequential( nn.Linear(512*4*4, 4096), nn.ReLU(inplaceTrue), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(inplaceTrue), nn.Dropout(), nn.Linear(4096, 20) )VGG16在COIL20上实现了98%的准确率但其大量参数(1.38亿)也暴露了计算效率问题。5. ResNet50残差连接的突破2015年何恺明提出的残差网络解决了深层网络梯度消失的难题。其核心创新是跳跃连接(skip connection)残差块公式F(x) x其中F(x)是待学习的残差class Bottleneck(nn.Module): expansion 4 def __init__(self, in_planes, planes, stride1): super(Bottleneck, self).__init__() self.conv1 nn.Conv2d(in_planes, planes, 1, biasFalse) self.bn1 nn.BatchNorm2d(planes) self.conv2 nn.Conv2d(planes, planes, 3, stridestride, padding1, biasFalse) self.bn2 nn.BatchNorm2d(planes) self.conv3 nn.Conv2d(planes, planes*self.expansion, 1, biasFalse) self.bn3 nn.BatchNorm2d(planes*self.expansion) self.shortcut nn.Sequential() if stride ! 1 or in_planes ! planes*self.expansion: self.shortcut nn.Sequential( nn.Conv2d(in_planes, planes*self.expansion, 1, stridestride, biasFalse), nn.BatchNorm2d(planes*self.expansion) ) def forward(self, x): out F.relu(self.bn1(self.conv1(x))) out F.relu(self.bn2(self.conv2(out))) out self.bn3(self.conv3(out)) out self.shortcut(x) out F.relu(out) return outResNet50在COIL20上仅需30轮训练就达到100%准确率验证了残差结构的有效性。实际测试中发现训练曲线更加平滑稳定对学习率变化不敏感深层网络也能快速收敛6. 模型对比与演进启示通过五个模型的实践我们可以总结CNN发展的关键脉络模型参数量创新点COIL20准确率训练轮数LeNet60k首个CNN架构85%200AlexNet60MReLU/Dropout/最大池化96%50VGG16138M小卷积核堆叠98%40ResNet5025.5M残差连接100%30从技术演进角度看CNN的发展主要解决了以下问题梯度传播问题Sigmoid→ReLU→残差连接过拟合问题Dropout→BatchNorm特征提取效率大卷积核→小卷积核堆叠→多尺度融合(Inception)网络深度问题几层→几十层→上百层# 统一测试函数 def evaluate(model, test_loader): model.eval() correct 0 total 0 with torch.no_grad(): for images, labels in test_loader: outputs model(images) _, predicted torch.max(outputs.data, 1) total labels.size(0) correct (predicted labels).sum().item() return 100 * correct / total在实际项目中选择模型时需要权衡精度要求vs计算资源数据规模vs模型复杂度实时性需求vs推理速度经过这次完整的实践最深刻的体会是理解经典模型的设计动机比单纯复现更重要。每个创新点都是针对特定问题的优雅解决方案这种解决问题的思维方式值得深入学习。

更多文章