五大经典CNN网络演进解析:从LeNet到ResNet的技术突破

发布时间:2026/7/14 2:35:33

五大经典CNN网络演进解析:从LeNet到ResNet的技术突破 如果你正在学习深度学习特别是计算机视觉方向可能会被各种卷积神经网络CNN的名字搞得头晕LeNet、AlexNet、VGGNet、GoogleNet、ResNet...这些网络看起来复杂但实际上它们的发展脉络非常清晰每个网络都解决了前一个网络的关键问题。这篇文章不会用复杂的数学公式吓跑你而是用最直白的方式带你一口气理解这五大经典CNN网络的核心思想和演进逻辑。无论你是刚入门的新手还是想系统梳理知识的老手都能找到实实在在的收获。1. 这篇文章真正要解决的问题深度学习入门最大的障碍不是数学基础不够而是面对众多模型时不知道从哪里开始。很多教程一上来就堆砌公式和结构图却很少解释为什么这个网络要这样设计它解决了什么问题。本文要解决的核心问题是用最直观的方式理解五大经典CNN网络的演进逻辑。你将看到每个网络诞生的历史背景和要解决的具体问题网络结构设计背后的直观思考为什么加这一层为什么这样连接从简单到复杂的自然过渡而不是孤立地记忆每个网络实际项目中如何选择适合的网络架构特别适合以下读者刚接触深度学习想要系统学习CNN的新手学过一些模型但感觉知识碎片化想要梳理脉络的学习者需要为项目选择合适的预训练模型的实践者2. 卷积神经网络基础概念在深入具体网络之前我们需要先理解几个核心概念。不用担心这里不会有复杂的数学推导重点是理解这些概念的作用和意义。2.1 卷积层Convolutional Layer想象一下你在看一张图片时不会一次性看完整个图片而是会移动视线先看左上角再看中间最后看右下角。卷积层做的就是类似的事情。通俗理解用一个小的窗口卷积核在图片上滑动每次只处理窗口覆盖的一小块区域。这个窗口会学习识别特定的图案比如边缘、角点、纹理等。# 简单的卷积操作示例概念性代码 import torch import torch.nn as nn # 定义一个卷积层输入通道1输出通道6卷积核大小3x3 conv_layer nn.Conv2d(in_channels1, out_channels6, kernel_size3, stride1, padding1) # 假设输入是一张28x28的灰度图片 input_image torch.randn(1, 1, 28, 28) # (batch_size, channels, height, width) output conv_layer(input_image) print(f输入尺寸: {input_image.shape}) print(f输出尺寸: {output.shape}) # 经过卷积后的特征图尺寸关键参数解释in_channels输入图片的通道数灰度图1RGB图3out_channels卷积核的数量每个核学习不同的特征kernel_size卷积核的大小常见3x3、5x5stride滑动步长决定每次移动的距离padding边缘填充防止图片尺寸缩小太快2.2 池化层Pooling Layer池化层的作用是浓缩信息。就像你看书时会总结段落大意一样池化层把一片区域的重要信息提取出来忽略细节。最大池化Max Pooling取区域内的最大值保留最显著的特征平均池化Average Pooling取区域内的平均值更平滑# 池化层示例 pool_layer nn.MaxPool2d(kernel_size2, stride2) # 使用刚才卷积层的输出 pooled_output pool_layer(output) print(f池化前尺寸: {output.shape}) print(f池化后尺寸: {pooled_output.shape}) # 尺寸减半特征更集中2.3 全连接层Fully Connected Layer全连接层就像传统的神经网络每个神经元都与前一层的所有神经元连接。它负责把前面提取的特征进行综合判断最终输出分类结果。容易混淆的概念卷积层特征提取关注局部 patterns池化层降维压缩减少计算量全连接层综合判断输出最终结果这三个基础组件的不同组合就构成了我们要学习的各种CNN网络。3. 环境准备与工具选择在学习具体网络之前先准备好实验环境。这里推荐使用PyTorch因为它更Pythonic适合学习和实验。3.1 基础环境配置# 创建虚拟环境推荐 conda create -n deep-learning python3.8 conda activate deep-learning # 安装PyTorch以CPU版本为例GPU版本请参考官网 pip install torch torchvision torchaudio3.2 验证安装import torch import torchvision print(fPyTorch版本: {torch.__version__}) print(fTorchVision版本: {torchvision.__version__}) print(fCUDA是否可用: {torch.cuda.is_available()}) # 如果有GPU会显示True # 测试简单的张量操作 x torch.randn(2, 3, 224, 224) # 模拟2张224x224的RGB图片 print(f输入张量形状: {x.shape})3.3 数据集准备我们将使用CIFAR-10数据集进行实验它包含10个类别的6万张32x32彩色图片适合快速验证模型。from torchvision import datasets, transforms # 数据预处理 transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) ]) # 下载并加载数据集 train_dataset datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtransform) test_dataset datasets.CIFAR10(root./data, trainFalse, downloadTrue, transformtransform) print(f训练集样本数: {len(train_dataset)}) print(f测试集样本数: {len(test_dataset)}) print(f类别数量: {len(train_dataset.classes)}) print(f类别名称: {train_dataset.classes})4. LeNet-5CNN的开山之作4.1 历史背景与要解决的问题LeNet-5由Yann LeCun在1998年提出最初用于手写数字识别。在那个时代主要的挑战是如何让机器自动学习特征而不是手工设计特征如何应对图像的平移、缩放、变形等变化4.2 网络结构详解LeNet-5的结构非常简单明了输入(32x32) → 卷积1(628x28) → 池化1(614x14) → 卷积2(1610x10) → 池化2(165x5) → 全连接 → 输出关键创新首次成功应用卷积-池化结构使用tanh激活函数当时ReLU还没普及特征图尺寸逐渐减小通道数逐渐增加4.3 PyTorch实现代码import torch.nn as nn import torch.nn.functional as F class LeNet5(nn.Module): def __init__(self, num_classes10): super(LeNet5, self).__init__() self.conv1 nn.Conv2d(1, 6, 5, padding2) # 输入1通道输出6通道 self.pool1 nn.AvgPool2d(2, 2) # 平均池化 self.conv2 nn.Conv2d(6, 16, 5) self.pool2 nn.AvgPool2d(2, 2) self.fc1 nn.Linear(16 * 5 * 5, 120) self.fc2 nn.Linear(120, 84) self.fc3 nn.Linear(84, num_classes) def forward(self, x): x F.tanh(self.conv1(x)) # 原始使用tanh x self.pool1(x) x F.tanh(self.conv2(x)) x self.pool2(x) x x.view(-1, 16 * 5 * 5) # 展平 x F.tanh(self.fc1(x)) x F.tanh(self.fc2(x)) x self.fc3(x) return x # 现代改进版使用ReLU和最大池化 class ModernLeNet5(nn.Module): def __init__(self, num_classes10): super(ModernLeNet5, self).__init__() self.conv1 nn.Conv2d(3, 6, 5, padding2) # 适应RGB输入 self.pool1 nn.MaxPool2d(2, 2) # 最大池化效果更好 self.conv2 nn.Conv2d(6, 16, 5) self.pool2 nn.MaxPool2d(2, 2) self.fc1 nn.Linear(16 * 5 * 5, 120) self.fc2 nn.Linear(120, 84) self.fc3 nn.Linear(84, num_classes) def forward(self, x): x F.relu(self.conv1(x)) # 使用ReLU x self.pool1(x) x F.relu(self.conv2(x)) x self.pool2(x) x x.view(-1, 16 * 5 * 5) x F.relu(self.fc1(x)) x F.relu(self.fc2(x)) x self.fc3(x) return x # 测试网络 model ModernLeNet5(num_classes10) print(model) # 计算参数量 total_params sum(p.numel() for p in model.parameters()) print(f总参数量: {total_params:,}) # 约6万个参数4.4 LeNet的局限性虽然LeNet-5在当时很先进但随着问题复杂度的增加它的局限性显现网络太浅无法学习复杂特征参数量小表达能力有限只适合小尺寸简单图片5. AlexNet深度学习复兴的标志5.1 突破性进展AlexNet在2012年ImageNet竞赛中一举成名将Top-5错误率从26%降到了15.3%。它的成功主要归功于使用ReLU激活函数解决梯度消失问题训练更快Dropout正则化防止过拟合数据增强扩大训练数据量GPU加速使训练深层网络成为可能5.2 网络结构分析AlexNet可以看作是放大版的LeNet但有几个关键改进输入(227x227x3) → 卷积1(9655x55) → 池化1 → 卷积2(25627x27) → 池化2 → 卷积3(38413x13) → 卷积4(38413x13) → 卷积5(25613x13) → 池化3 → 全连接 → 输出核心变化深度增加到8层5卷积3全连接使用更大卷积核11x11, 5x5引入局部响应归一化LRN5.3 PyTorch实现class AlexNet(nn.Module): def __init__(self, num_classes1000): super(AlexNet, self).__init__() self.features nn.Sequential( nn.Conv2d(3, 96, kernel_size11, stride4, padding2), # 第一层卷积 nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size3, stride2), nn.Conv2d(96, 256, kernel_size5, padding2), # 第二层卷积 nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size3, stride2), nn.Conv2d(256, 384, kernel_size3, padding1), # 第三层卷积 nn.ReLU(inplaceTrue), nn.Conv2d(384, 384, kernel_size3, padding1), # 第四层卷积 nn.ReLU(inplaceTrue), nn.Conv2d(384, 256, kernel_size3, padding1), # 第五层卷积 nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size3, stride2), ) self.classifier nn.Sequential( nn.Dropout(), # Dropout防止过拟合 nn.Linear(256 * 6 * 6, 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 * 6 * 6) # 展平 x self.classifier(x) return x # 简化版AlexNet适应CIFAR-10的32x32输入 class SimpleAlexNet(nn.Module): def __init__(self, num_classes10): super(SimpleAlexNet, self).__init__() self.features nn.Sequential( nn.Conv2d(3, 64, kernel_size3, stride1, padding1), # 适应小图片 nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, stride2), nn.Conv2d(64, 192, kernel_size3, padding1), nn.ReLU(inplaceTrue), nn.MaxPool2d(kernel_size2, 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_size2, stride2), ) self.classifier nn.Sequential( nn.Dropout(0.5), nn.Linear(256 * 4 * 4, 1024), # 调整全连接层尺寸 nn.ReLU(inplaceTrue), nn.Dropout(0.5), nn.Linear(1024, 512), nn.ReLU(inplaceTrue), nn.Linear(512, num_classes), ) def forward(self, x): x self.features(x) x x.view(x.size(0), -1) x self.classifier(x) return x # 测试 model SimpleAlexNet(num_classes10) print(fAlexNet参数量: {sum(p.numel() for p in model.parameters()):,})5.4 AlexNet的意义与局限历史意义证明了深层神经网络的有效性开启了深度学习在计算机视觉的应用热潮建立了现代CNN的基本范式局限性参数量大约6000万训练需要大量数据全连接层参数过多容易过拟合网络结构还不够深6. VGGNet深度的重要性6.1 核心思想堆叠小卷积核VGGNet的关键洞察是使用多个小卷积核3x3代替大卷积核。比如两个3x3卷积核的感受野相当于一个5x5卷积核但参数量更少非线性更多。优势对比1个5x5卷积核25个参数2个3x3卷积核3x3 3x3 18个参数参数量减少28%但增加了非线性激活6.2 VGG16与VGG19结构VGGNet有多个版本最著名的是VGG16和VGG19数字代表带参数的层数VGG16结构 输入(224x224) → 2x[卷积64] → 池化 → 2x[卷积128] → 池化 → 3x[卷积256] → 池化 → 3x[卷积512] → 池化 → 3x[卷积512] → 池化 → 全连接6.3 PyTorch实现class VGG16(nn.Module): def __init__(self, num_classes1000): super(VGG16, self).__init__() self.features self._make_layers() self.classifier nn.Sequential( nn.Linear(512 * 7 * 7, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, 4096), nn.ReLU(True), nn.Dropout(), nn.Linear(4096, num_classes), ) def forward(self, x): x self.features(x) x x.view(x.size(0), -1) x self.classifier(x) return x def _make_layers(self): layers [] in_channels 3 # VGG16的卷积层配置每组的通道数和卷积层数量 cfg [64, 64, M, 128, 128, M, 256, 256, 256, M, 512, 512, 512, M, 512, 512, 512, M] for x in cfg: if x M: # 池化层 layers [nn.MaxPool2d(kernel_size2, stride2)] else: # 卷积层 layers [ nn.Conv2d(in_channels, x, kernel_size3, padding1), nn.BatchNorm2d(x), # 原版VGG没有BN这里加上效果更好 nn.ReLU(inplaceTrue) ] in_channels x return nn.Sequential(*layers) # 适合CIFAR-10的VGG变体 class VGGSmall(nn.Module): def __init__(self, num_classes10): super(VGGSmall, self).__init__() self.features nn.Sequential( # 第一组2个卷积 池化 nn.Conv2d(3, 64, 3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.Conv2d(64, 64, 3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.MaxPool2d(2, 2), # 第二组2个卷积 池化 nn.Conv2d(64, 128, 3, padding1), nn.BatchNorm2d(128), nn.ReLU(inplaceTrue), nn.Conv2d(128, 128, 3, padding1), nn.BatchNorm2d(128), nn.ReLU(inplaceTrue), nn.MaxPool2d(2, 2), # 第三组3个卷积 池化 nn.Conv2d(128, 256, 3, padding1), nn.BatchNorm2d(256), nn.ReLU(inplaceTrue), nn.Conv2d(256, 256, 3, padding1), nn.BatchNorm2d(256), nn.ReLU(inplaceTrue), nn.Conv2d(256, 256, 3, padding1), nn.BatchNorm2d(256), nn.ReLU(inplaceTrue), nn.MaxPool2d(2, 2), ) self.classifier nn.Sequential( nn.Linear(256 * 4 * 4, 1024), nn.ReLU(True), nn.Dropout(0.5), nn.Linear(1024, 512), nn.ReLU(True), nn.Dropout(0.5), nn.Linear(512, num_classes), ) def forward(self, x): x self.features(x) x x.view(x.size(0), -1) x self.classifier(x) return x # 测试 vgg_small VGGSmall(num_classes10) print(fVGGSmall参数量: {sum(p.numel() for p in vgg_small.parameters()):,})6.4 VGGNet的贡献与问题主要贡献证明了网络深度对性能的重要性统一使用3x3卷积核简化了网络设计结构规整易于理解和实现存在的问题参数量巨大VGG16约1.38亿训练困难全连接层参数占比过大约90%计算量大推理速度慢7. GoogleNet inception模块的智慧7.1 核心创新Inception模块GoogleNet最大的创新是提出了Inception模块其核心思想是在同一层使用不同尺寸的卷积核捕捉多尺度特征。传统的做法是人工选择卷积核大小而Inception模块让网络自己学习如何组合不同尺度的特征。7.2 网络结构特点GoogleNet有22层深但参数量只有500万比AlexNet少12倍主要得益于全局平均池化代替全连接层大幅减少参数辅助分类器在中间层添加分类输出缓解梯度消失高效的Inception模块多路径并行计算7.3 基础Inception模块实现class BasicInceptionModule(nn.Module): def __init__(self, in_channels, out_1x1, red_3x3, out_3x3, red_5x5, out_5x5, out_pool): super(BasicInceptionModule, self).__init__() # 1x1卷积分支 self.branch1 nn.Sequential( nn.Conv2d(in_channels, out_1x1, kernel_size1), nn.BatchNorm2d(out_1x1), nn.ReLU(inplaceTrue) ) # 1x1卷积降维 → 3x3卷积 self.branch2 nn.Sequential( nn.Conv2d(in_channels, red_3x3, kernel_size1), nn.BatchNorm2d(red_3x3), nn.ReLU(inplaceTrue), nn.Conv2d(red_3x3, out_3x3, kernel_size3, padding1), nn.BatchNorm2d(out_3x3), nn.ReLU(inplaceTrue) ) # 1x1卷积降维 → 5x5卷积 self.branch3 nn.Sequential( nn.Conv2d(in_channels, red_5x5, kernel_size1), nn.BatchNorm2d(red_5x5), nn.ReLU(inplaceTrue), nn.Conv2d(red_5x5, out_5x5, kernel_size5, padding2), nn.BatchNorm2d(out_5x5), nn.ReLU(inplaceTrue) ) # 3x3最大池化 → 1x1卷积 self.branch4 nn.Sequential( nn.MaxPool2d(kernel_size3, stride1, padding1), nn.Conv2d(in_channels, out_pool, kernel_size1), nn.BatchNorm2d(out_pool), nn.ReLU(inplaceTrue) ) def forward(self, x): branch1 self.branch1(x) branch2 self.branch2(x) branch3 self.branch3(x) branch4 self.branch4(x) # 在通道维度拼接 outputs [branch1, branch2, branch3, branch4] return torch.cat(outputs, 1) # 简化版GoogleNet class SimpleGoogleNet(nn.Module): def __init__(self, num_classes10): super(SimpleGoogleNet, self).__init__() self.pre_layers nn.Sequential( nn.Conv2d(3, 64, kernel_size3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.Conv2d(64, 64, kernel_size3, padding1), nn.BatchNorm2d(64), nn.ReLU(inplaceTrue), nn.MaxPool2d(3, stride2, padding1), ) # 三个Inception模块 self.inception3a BasicInceptionModule(64, 64, 96, 128, 16, 32, 32) self.inception3b BasicInceptionModule(256, 128, 128, 192, 32, 96, 64) self.maxpool nn.MaxPool2d(3, stride2, padding1) self.inception4a BasicInceptionModule(480, 192, 96, 208, 16, 48, 64) # 全局平均池化代替全连接 self.avgpool nn.AdaptiveAvgPool2d((1, 1)) self.dropout nn.Dropout(0.4) self.fc nn.Linear(512, num_classes) def forward(self, x): x self.pre_layers(x) x self.inception3a(x) x self.inception3b(x) x self.maxpool(x) x self.inception4a(x) x self.avgpool(x) x x.view(x.size(0), -1) x self.dropout(x) x self.fc(x) return x # 测试 googlenet SimpleGoogleNet(num_classes10) print(fGoogleNet参数量: {sum(p.numel() for p in googlenet.parameters()):,})7.4 GoogleNet的设计哲学核心优势参数效率高深度增加但参数量控制得很好多尺度特征融合不同感受野的特征同时提取避免了梯度消失问题后续发展Inception v2/v3加入BN优化结构Inception v4与ResNet思想结合Xception深度可分离卷积的极致8. ResNet深度网络的终极解决方案8.1 残差学习的基本思想ResNet要解决的核心问题是网络越深训练效果反而越差。这不是过拟合而是梯度消失导致的训练困难。残差学习的巧妙之处在于不直接学习目标映射H(x)而是学习残差F(x) H(x) - x。这样网络只需要学习输出与输入的差异部分。8.2 残差块结构残差块是ResNet的基本构建单元输入x → 卷积层 → 激活 → 卷积层 → 与输入x相加 → 激活如果输入输出维度不匹配可以通过1x1卷积进行维度调整。8.3 ResNet18/34/50/101/152实现# 基础残差块用于ResNet18/34 class BasicBlock(nn.Module): expansion 1 def __init__(self, in_channels, out_channels, stride1, downsampleNone): super(BasicBlock, self).__init__() self.conv1 nn.Conv2d(in_channels, out_channels, kernel_size3, stridestride, padding1, biasFalse) self.bn1 nn.BatchNorm2d(out_channels) self.relu nn.ReLU(inplaceTrue) self.conv2 nn.Conv2d(out_channels, out_channels, kernel_size3, stride1, padding1, biasFalse) self.bn2 nn.BatchNorm2d(out_channels) self.downsample downsample def forward(self, x): identity x out self.conv1(x) out self.bn1(out) out self.relu(out) out self.conv2(out) out self.bn2(out) if self.downsample is not None: identity self.downsample(x) out identity # 残差连接 out self.relu(out) return out # 瓶颈残差块用于ResNet50/101/152 class Bottleneck(nn.Module): expansion 4 def __init__(self, in_channels, out_channels, stride1, downsampleNone): super(Bottleneck, self).__init__() self.conv1 nn.Conv2d(in_channels, out_channels, kernel_size1, biasFalse) self.bn1 nn.BatchNorm2d(out_channels) self.conv2 nn.Conv2d(out_channels, out_channels, kernel_size3, stridestride, padding1, biasFalse) self.bn2 nn.BatchNorm2d(out_channels) self.conv3 nn.Conv2d(out_channels, out_channels * self.expansion, kernel_size1, biasFalse) self.bn3 nn.BatchNorm2d(out_channels * self.expansion) self.relu nn.ReLU(inplaceTrue) self.downsample downsample def forward(self, x): identity x out self.conv1(x) out self.bn1(out) out self.relu(out) out self.conv2(out) out self.bn2(out) out self.relu(out) out self.conv3(out) out self.bn3(out) if self.downsample is not None: identity self.downsample(x) out identity out self.relu(out) return out class ResNet(nn.Module): def __init__(self, block, layers, num_classes1000): super(ResNet, self).__init__() self.in_channels 64 self.conv1 nn.Conv2d(3, 64, kernel_size7, stride2, padding3, biasFalse) self.bn1 nn.BatchNorm2d(64) self.relu nn.ReLU(inplaceTrue) self.maxpool nn.MaxPool2d(kernel_size3, stride2, padding1) self.layer1 self._make_layer(block, 64, layers[0]) self.layer2 self._make_layer(block, 128, layers[1], stride2) self.layer3 self._make_layer(block, 256, layers[2], stride2) self.layer4 self._make_layer(block, 512, layers[3], stride2) self.avgpool nn.AdaptiveAvgPool2d((1, 1)) self.fc nn.Linear(512 * block.expansion, num_classes) def _make_layer(self, block, out_channels, blocks, stride1): downsample None if stride ! 1 or self.in_channels ! out_channels * block.expansion: downsample nn.Sequential( nn.Conv2d(self.in_channels, out_channels * block.expansion, kernel_size1, stridestride, biasFalse), nn.BatchNorm2d(out_channels * block.expansion), ) layers [] layers.append(block(self.in_channels, out_channels, stride, downsample)) self.in_channels out_channels * block.expansion for _ in range(1, blocks): layers.append(block(self.in_channels, out_channels)) return nn.Sequential(*layers) def forward(self, x): x self.conv1(x) x self.bn1(x) x self.relu(x) x self.maxpool(x) x self.layer1(x) x self.layer2(x) x self.layer3(x) x self.layer4(x) x self.avgpool(x) x x.view(x.size(0), -1) x self.fc(x) return x # 创建ResNet18 def resnet18(num_classes10): return ResNet(BasicBlock, [2, 2, 2, 2], num_classes) # 创建ResNet34 def resnet34(num_classes10): return ResNet(BasicBlock, [3, 4, 6, 3], num_classes) # 测试 model resnet18(num_classes10) print(fResNet18参数量: {sum(p.numel() for p in model.parameters()):,})8.4 ResNet的革命性影响关键技术突破残差连接解决了深度网络的梯度消失问题恒等映射确保网络至少不会比浅层网络差批量归一化稳定训练过程实际效果可以训练超过1000层的网络在ImageNet上错误率降至3.57%超越人类水平成为现代深度学习的标准基础架构9. 模型对比与选择指南9.1 五大网络关键指标对比网络提出时间层数参数量关键创新适用场景LeNet-519985~60K首个成功CNN手写数字识别AlexNet20128~60MReLU/Dropout图像分类入门VGGNet201416-19~138M3x3卷积堆叠特征提取器GoogleNet201422~5MInception模块移动端/高效模型ResNet201518-152~11-60M残差连接各类视觉任务9.2 如何选择合适的网络根据任务复杂度选择简单任务MNIST、CIFAR-10LeNet、简单CNN

相关新闻