从LeNet到EfficientNet:手把手带你复现CNN进化史上的5个关键模型(附PyTorch代码)

发布时间:2026/7/27 12:54:22

从LeNet到EfficientNet:手把手带你复现CNN进化史上的5个关键模型(附PyTorch代码) 从LeNet到EfficientNet手把手带你复现CNN进化史上的5个关键模型附PyTorch代码在深度学习的世界里卷积神经网络CNN就像一位不断进化的超级英雄。从最初只能识别手写数字的新手村装备LeNet-5到如今能在移动设备上流畅运行的EfficientNet这场持续30年的技术进化史充满了令人惊叹的智慧闪光。本文将带你穿越时空用PyTorch代码亲手搭建5个里程碑式的CNN模型让你在键盘敲击声中感受架构创新的脉搏。1. 实验环境准备与数据加载工欲善其事必先利其器。我们先配置好实验环境这里推荐使用Python 3.8和PyTorch 1.10的组合。如果你有GPU设备建议安装CUDA 11.3以加速训练过程。conda create -n cnn_evolution python3.8 conda activate cnn_evolution pip install torch torchvision matplotlib tqdm我们将使用两个经典数据集MNIST手写数字识别28x28灰度图像CIFAR-1010类物体分类32x32彩色图像import torch from torchvision import datasets, transforms # 数据预处理管道 transform_mnist transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,)) ]) transform_cifar transforms.Compose([ transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) # 加载数据集 train_mnist datasets.MNIST(../data, trainTrue, downloadTrue, transformtransform_mnist) test_mnist datasets.MNIST(../data, trainFalse, transformtransform_mnist)提示在Jupyter Notebook中运行时建议使用%matplotlib inline魔法命令实时查看训练过程的可视化结果。2. LeNet-5卷积神经网络的黎明1998年Yann LeCun提出的LeNet-5首次证明了CNN在图像识别中的潜力。这个只有5层的小个子模型却奠定了现代CNN的基本架构范式。模型亮点交替的卷积层和池化层使用tanh激活函数当时ReLU还未普及参数量仅60k可在CPU上轻松训练import torch.nn as nn import torch.nn.functional as F class LeNet5(nn.Module): def __init__(self): super(LeNet5, self).__init__() self.conv1 nn.Conv2d(1, 6, 5, padding2) self.conv2 nn.Conv2d(6, 16, 5) self.fc1 nn.Linear(16*5*5, 120) self.fc2 nn.Linear(120, 84) self.fc3 nn.Linear(84, 10) def forward(self, x): x F.tanh(self.conv1(x)) x F.avg_pool2d(x, 2) x F.tanh(self.conv2(x)) x F.avg_pool2d(x, 2) x x.view(-1, 16*5*5) x F.tanh(self.fc1(x)) x F.tanh(self.fc2(x)) return self.fc3(x)训练这个模型时你会发现几个有趣的现象即使使用现代优化器如Adam原始论文中的学习率0.01仍然表现良好在MNIST上20个epoch就能达到98%的准确率将tanh替换为ReLU可以略微提升性能约0.5%3. AlexNet深度学习的寒武纪大爆发2012年AlexNet以压倒性优势赢得ImageNet竞赛将CNN带入深度学习时代。这个8层网络引入了多项革命性设计创新点作用描述现代替代方案ReLU激活函数解决梯度消失问题仍广泛使用Dropout层防止过拟合仍广泛使用局部响应归一化增强局部抑制被BN层取代双GPU并行突破当时显存限制多卡数据并行class AlexNet(nn.Module): def __init__(self, num_classes10): super(AlexNet, self).__init__() self.features nn.Sequential( nn.Conv2d(3, 64, kernel_size11, stride4, padding2), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size3, stride2), nn.Conv2d(64, 192, kernel_size5, padding2), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size3, stride2), nn.Conv2d(192, 384, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.Conv2d(384, 256, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.Conv2d(256, 256, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size3, stride2), ) self.classifier nn.Sequential( nn.Dropout(), nn.Linear(256*2*2, 4096), nn.ReLU(inplaceTrue), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(inplaceTrue), nn.Linear(4096, num_classes), ) def forward(self, x): x self.features(x) x x.view(x.size(0), 256*2*2) x self.classifier(x) return x注意原始AlexNet输入是224x224 ImageNet图像我们在CIFAR-10上使用时需要调整第一个卷积层的stride为1以适应32x32的输入尺寸。4. VGG与ResNet深度革命的辩证法4.1 VGG简约而不简单牛津大学提出的VGG网络证明了深度即力量的假说。其核心思想是使用连续的3x3小卷积核替代大卷积核两个3x3卷积堆叠 一个5x5卷积的感受野参数量更少2×3²18 vs 5²25更多非线性变换class VGG(nn.Module): def __init__(self, num_classes10): super(VGG, self).__init__() self.features nn.Sequential( nn.Conv2d(3, 64, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.Conv2d(64, 64, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), nn.Conv2d(64, 128, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.Conv2d(128, 128, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), nn.Conv2d(128, 256, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.Conv2d(256, 256, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.Conv2d(256, 256, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), ) self.classifier nn.Sequential( nn.Linear(256*4*4, 4096), nn.ReLU(inplaceTrue), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(inplaceTrue), nn.Dropout(), nn.Linear(4096, num_classes), ) def forward(self, x): x self.features(x) x x.view(x.size(0), 256*4*4) x self.classifier(x) return x4.2 ResNet当深度遇到瓶颈当网络深度超过20层时准确率不升反降。何恺明提出的残差连接Residual Connection解决了这一深度悖论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) self.shortcut nn.Sequential() if stride ! 1 or in_planes ! planes: self.shortcut nn.Sequential( nn.Conv2d(in_planes, planes, kernel_size1, stridestride, biasFalse), nn.BatchNorm2d(planes) ) def forward(self, x): out F.relu(self.bn1(self.conv1(x))) out self.bn2(self.conv2(out)) out self.shortcut(x) return F.relu(out) class ResNet(nn.Module): def __init__(self, block, num_blocks, num_classes10): super(ResNet, self).__init__() self.in_planes 64 self.conv1 nn.Conv2d(3, 64, kernel_size3, stride1, padding1, biasFalse) self.bn1 nn.BatchNorm2d(64) self.layer1 self._make_layer(block, 64, num_blocks[0], stride1) self.layer2 self._make_layer(block, 128, num_blocks[1], stride2) self.layer3 self._make_layer(block, 256, num_blocks[2], stride2) self.layer4 self._make_layer(block, 512, num_blocks[3], stride2) self.linear nn.Linear(512, num_classes) def _make_layer(self, block, planes, num_blocks, stride): strides [stride] [1]*(num_blocks-1) layers [] for stride in strides: layers.append(block(self.in_planes, planes, stride)) self.in_planes planes return nn.Sequential(*layers) def forward(self, x): out F.relu(self.bn1(self.conv1(x))) out self.layer1(out) out self.layer2(out) out self.layer3(out) out self.layer4(out) out F.avg_pool2d(out, 4) out out.view(out.size(0), -1) return self.linear(out)5. EfficientNet精度与效率的帕累托最优2019年提出的EfficientNet通过复合缩放Compound Scaling统一了深度、宽度和分辨率三个维度的扩展深度缩放增加网络层数宽度缩放增加每层通道数分辨率缩放增大输入图像尺寸from efficientnet_pytorch import EfficientNet def create_effnet(model_nameefficientnet-b0, num_classes10): model EfficientNet.from_pretrained(model_name) num_ftrs model._fc.in_features model._fc nn.Linear(num_ftrs, num_classes) return model复合缩放系数关系depth α^φ width β^φ resolution γ^φ s.t. α·β²·γ²≈2在CIFAR-10上EfficientNet-B0仅用5.3M参数就能达到94%的准确率而计算量只有ResNet-50的1/8。这种高效特性使其成为移动端部署的理想选择。6. 进化之路从LeNet到EfficientNet的量化对比让我们用一组关键指标来总结这5个模型的进化轨迹模型参数量FLOPsTop-1准确率(CIFAR-10)创新点总结LeNet-560k0.4M70.3%首个实用CNN架构AlexNet60M720M83.5%ReLU/Dropout/并行计算VGG-16138M15.5G92.4%小卷积核堆叠ResNet-3421M3.6G94.2%残差连接解决梯度消失EfficientNet-B05.3M0.39G94.7%复合缩放优化计算资源分配从实验室到工业界从学术论文到手机应用CNN的这场进化远未结束。当你在Colab中跑完这些代码不妨思考一个问题如果LeNet-5是CNN的单细胞生物今天的EfficientNet是否已经进化成了高等智能生命体而下一个突破性的CNN架构或许就藏在你的代码实验里。

相关新闻