详解:从原理到多框架动手实现)
人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载《动手学深度学习》中文版d2l-zh在现代卷积神经网络一章中完整呈现了 GoogLeNet 的诞生背景、Inception 块设计思想与逐模块可运行实现。本文以 chapter_convolutional-modern/googlenet_origin.md 及其中文版 chapter_convolutional-modern/googlenet.md 为主体结合仓库 d2l/ 下的多框架工具源码系统讲解 GoogLeNet 如何在 2014 年 ImageNet 挑战赛中胜出以及如何用 MXNet、PyTorch、TensorFlow 和 PaddlePaddle 从零实现它并在 Fashion-MNIST 上完成训练。背景为什么需要并行多尺度卷积在 GoogLeNet 之前流行的网络使用小到 $1 \times 1$、大到 $11 \times 11$ 的卷积核。论文《Going Deeper with Convolutions》Szegedy 等2015的核心问题之一是什么样大小的卷积核最合适其洞察是与其选择一个固定大小的卷积核不如同时组合使用不同大小的卷积核——不同尺寸的滤波器可以有效地识别不同范围的图像细节同时可以为不同滤波器分配不同数量的参数。本节介绍的 GoogLeNet 是原始模型的一个简化版本省略了少数为稳定训练而添加的临时特性如辅助分类器因为如今更好的训练算法已使这些特性不再必要。Inception 块四条并行路径的构成GoogLeNet 的基本卷积块被称为Inception 块Inception block很可能得名于电影《盗梦空间》Inception中的台词我们需要走得更深We need to go deeper。如图fig_inception所示Inception 块由四条并行路径组成路径 1单个 $1 \times 1$ 卷积层输出通道数为c1路径 2$1 \times 1$ 卷积层输出c2[0]通道后接 $3 \times 3$ 卷积层输出c2[1]通道padding1路径 3$1 \times 1$ 卷积层输出c3[0]通道后接 $5 \times 5$ 卷积层输出c3[1]通道padding2路径 4$3 \times 3$ 最大汇聚层padding1后接 $1 \times 1$ 卷积层输出c4通道。中间两条路径先在输入上执行 $1 \times 1$ 卷积以减少通道数、降低模型复杂度四条路径都使用合适的填充使输入输出高宽一致最后把四条路径的输出在通道维度上连结构成块的输出。Inception 块中通常调整的超参数是每层输出通道数。下面是 MXNetGluon版本的实现from d2l import mxnet as d2l from mxnet import np, npx from mxnet.gluon import nn npx.set_np() class Inception(nn.Block): # c1--c4是每条路径的输出通道数 def __init__(self, c1, c2, c3, c4, **kwargs): super(Inception, self).__init__(**kwargs) # 线路1单1x1卷积层 self.p1_1 nn.Conv2D(c1, kernel_size1, activationrelu) # 线路21x1卷积层后接3x3卷积层 self.p2_1 nn.Conv2D(c2[0], kernel_size1, activationrelu) self.p2_2 nn.Conv2D(c2[1], kernel_size3, padding1, activationrelu) # 线路31x1卷积层后接5x5卷积层 self.p3_1 nn.Conv2D(c3[0], kernel_size1, activationrelu) self.p3_2 nn.Conv2D(c3[1], kernel_size5, padding2, activationrelu) # 线路43x3最大汇聚层后接1x1卷积层 self.p4_1 nn.MaxPool2D(pool_size3, strides1, padding1) self.p4_2 nn.Conv2D(c4, kernel_size1, activationrelu) def forward(self, x): p1 self.p1_1(x) p2 self.p2_2(self.p2_1(x)) p3 self.p3_2(self.p3_1(x)) p4 self.p4_2(self.p4_1(x)) # 在通道维度上连结输出 return np.concatenate((p1, p2, p3, p4), axis1)PyTorch 版本的实现注意 PyTorch 的卷积层默认不带激活函数需在forward中显式调用F.relufrom d2l import torch as d2l import torch from torch import nn from torch.nn import functional as F class Inception(nn.Module): # c1--c4是每条路径的输出通道数 def __init__(self, in_channels, c1, c2, c3, c4, **kwargs): super(Inception, self).__init__(**kwargs) # 线路1单1x1卷积层 self.p1_1 nn.Conv2d(in_channels, c1, kernel_size1) # 线路21x1卷积层后接3x3卷积层 self.p2_1 nn.Conv2d(in_channels, c2[0], kernel_size1) self.p2_2 nn.Conv2d(c2[0], c2[1], kernel_size3, padding1) # 线路31x1卷积层后接5x5卷积层 self.p3_1 nn.Conv2d(in_channels, c3[0], kernel_size1) self.p3_2 nn.Conv2d(c3[0], c3[1], kernel_size5, padding2) # 线路43x3最大汇聚层后接1x1卷积层 self.p4_1 nn.MaxPool2d(kernel_size3, stride1, padding1) self.p4_2 nn.Conv2d(in_channels, c4, kernel_size1) def forward(self, x): p1 F.relu(self.p1_1(x)) p2 F.relu(self.p2_2(F.relu(self.p2_1(x)))) p3 F.relu(self.p3_2(F.relu(self.p3_1(x)))) p4 F.relu(self.p4_2(self.p4_1(x))) # 在通道维度上连结输出 return torch.cat((p1, p2, p3, p4), dim1)TensorFlowKeras版本的实现所有padding使用same以保持空间尺寸from d2l import tensorflow as d2l import tensorflow as tf class Inception(tf.keras.Model): # c1--c4是每条路径的输出通道数 def __init__(self, c1, c2, c3, c4): super().__init__() # 线路1单1x1卷积层 self.p1_1 tf.keras.layers.Conv2D(c1, 1, activationrelu) # 线路21x1卷积层后接3x3卷积层 self.p2_1 tf.keras.layers.Conv2D(c2[0], 1, activationrelu) self.p2_2 tf.keras.layers.Conv2D(c2[1], 3, paddingsame, activationrelu) # 线路31x1卷积层后接5x5卷积层 self.p3_1 tf.keras.layers.Conv2D(c3[0], 1, activationrelu) self.p3_2 tf.keras.layers.Conv2D(c3[1], 5, paddingsame, activationrelu) # 线路43x3最大汇聚层后接1x1卷积层 self.p4_1 tf.keras.layers.MaxPool2D(3, 1, paddingsame) self.p4_2 tf.keras.layers.Conv2D(c4, 1, activationrelu) def call(self, x): p1 self.p1_1(x) p2 self.p2_2(self.p2_1(x)) p3 self.p3_2(self.p3_1(x)) p4 self.p4_2(self.p4_1(x)) # 在通道维度上连结输出 return tf.keras.layers.Concatenate()([p1, p2, p3, p4])中文版文档还提供了PaddlePaddle的变体Inception(nn.Layer)结构与 PyTorch 完全对应仅在 forward 中使用paddle.concat(x[...], axis1)完整代码见 chapter_convolutional-modern/googlenet.md 第 122-154 行。为什么这个网络如此有效首先考虑滤波器的组合它们以多种滤波器尺寸探索图像意味着不同大小的滤波器可以高效识别不同范围的图像细节同时我们可以为不同滤波器分配不同数量的参数——这正是通道数分配比的设计自由度所在。GoogLeNet 模型九个 Inception 块的堆叠如图fig_inception_full所示GoogLeNet 共使用9 个 Inception 块和全局平均汇聚层的堆叠来生成估计Inception 块之间的最大汇聚层降低维度第一个模块类似 AlexNet 和 LeNetInception 块的组合从 VGG 继承全局平均汇聚层避免了在末端堆叠全连接层该思想来自 NiN详见 chapter_convolutional-modern/nin.md。模块一b1大幅降采样第一个模块使用 64 通道、$7 \times 7$ 卷积层步幅 2、填充 3后接 $3 \times 3$ 最大汇聚层步幅 2、填充 1。它对 $96 \times 96$ 的输入先做 $7 \times 7$ 大感受野特征提取再下采样到 $24 \times 24$b1 nn.Sequential(nn.Conv2d(1, 64, kernel_size7, stride2, padding3), nn.ReLU(), nn.MaxPool2d(kernel_size3, stride2, padding1))Gluon 版本为nn.Conv2D(64, kernel_size7, strides2, padding3, activationrelu)配合nn.MaxPool2D(pool_size3, strides2, padding1)Keras 版本以paddingsame等效。模块二b2)1×1 降维 3×3 扩维第二个模块使用两个卷积层先 64 通道 $1 \times 1$ 卷积再 $3 \times 3$ 卷积将通道数扩大三倍到 192。这对应于 Inception 块中的第二条路径随后接 $3 \times 3$ 最大汇聚层b2 nn.Sequential(nn.Conv2d(64, 64, kernel_size1), nn.ReLU(), nn.Conv2d(64, 192, kernel_size3, padding1), nn.ReLU(), nn.MaxPool2d(kernel_size3, stride2, padding1))模块三b3)两个 Inception 块串联第三个模块串联两个完整的 Inception 块PyTorch 的Inception(in_channels, c1, c2, c3, c4)需要显式传入输入通道数Gluon/Keras 版本自动推导第一个块的输入为 192 通道输出通道数 $641283232256$四路径输出通道数之比为 $64:128:32:32 2:4:1:1$第二、三条路径先把输入通道分别降到 $96/192 1/2$ 和 $16/192 1/12$再接第二层卷积第二个块的输入为 256 通道输出通道数增至 $1281929664480$四路径之比为 $128:192:96:64 4:6:3:2$其中第二、三路径分别先降到 $1/2$ 和 $1/8$。b3 nn.Sequential(Inception(192, 64, (96, 128), (16, 32), 32), Inception(256, 128, (128, 192), (32, 96), 64), nn.MaxPool2d(kernel_size3, stride2, padding1))模块四b4)五个 Inception 块串联第四个模块更复杂串联 5 个 Inception 块其输出通道数分别是$1922084864512$$1602246464512$$1282566464512$$1122886464528$$256320128128832$通道分配思路与模块三一致含 $3 \times 3$ 卷积的第二条路径输出通道最多其次是仅含 $1 \times 1$ 卷积的第一条路径再次是含 $5 \times 5$ 卷积的第三条路径和含 $3 \times 3$ 最大汇聚的第四条路径第二、三条路径会先按比例减小通道数且这些比例在各个 Inception 块中略有不同b4 nn.Sequential(Inception(480, 192, (96, 208), (16, 48), 64), Inception(512, 160, (112, 224), (24, 64), 64), Inception(512, 128, (128, 256), (24, 64), 64), Inception(512, 112, (144, 288), (32, 64), 64), Inception(528, 256, (160, 320), (32, 128), 128), nn.MaxPool2d(kernel_size3, stride2, padding1))模块五b5全局平均汇聚 输出层第五模块包含输出通道数为 $256320128128832$ 和 $3843841281281024$ 的两个 Inception 块。第五模块后面紧跟输出层同 NiN 一样使用全局平均汇聚层将每个通道的高和宽变成 1最后把输出变成二维数组再接一个输出个数为标签类别数Fashion-MNIST 为 10的全连接层b5 nn.Sequential(Inception(832, 256, (160, 320), (32, 128), 128), Inception(832, 384, (192, 384), (48, 128), 128), nn.AdaptiveAvgPool2d((1,1)), nn.Flatten()) net nn.Sequential(b1, b2, b3, b4, b5, nn.Linear(1024, 10))Gluon 版本使用nn.GlobalAvgPool2D()后接nn.Dense(10)TensorFlow 版本则把net封装成函数net()返回Sequential([b1(), b2(), b3(), b4(), b5(), Dense(10)])因为d2l.train_ch6()需要传入一个构建函数以便在strategy.scope()内完成模型构建与编译从而利用可用的 CPU/GPU 设备。各模块输出形状验证GoogLeNet 计算复杂不如 VGG 那样便于修改通道数。为了使 Fashion-MNIST 上的训练短小精悍本节将输入的高和宽从 224 降到 96这简化了计算。以下代码逐层打印各模块输出的形状变化X torch.rand(size(1, 1, 96, 96)) for layer in net: X layer(X) print(layer.__class__.__name__,output shape:\t, X.shape)训练模型和前面的章节一样使用 Fashion-MNIST 数据集训练训练前将图片转换为 $96 \times 96$ 分辨率。训练配置为学习率lr0.1、轮数num_epochs10、批量大小batch_size128lr, num_epochs, batch_size 0.1, 10, 128 train_iter, test_iter d2l.load_data_fashion_mnist(batch_size, resize96) d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())从仓库源码看训练细节d2l.load_data_fashion_mnist在 d2l/torch.py 中实现——当传入resize96时会在ToTensor()前插入transforms.Resize(96)随后以 4 个工作进程get_dataloader_workers()加载 FashionMNIST 数据。d2l.train_ch6定义在 d2l/torch.py它对Linear与Conv2d层用nn.init.xavier_uniform_做权重初始化使用 SGD 优化器与交叉熵损失在 GPU 上逐 epoch 训练并动态绘制训练损失、训练精度与测试精度曲线MXNet、TensorFlow、PaddlePaddle 的对应实现分别在 d2l/mxnet.py、d2l/tensorflow.py、d2l/paddle.py 中。小结Inception 块相当于一个有 4 条路径的子网络通过不同窗口形状的卷积层和最大汇聚层并行抽取信息并使用 $1 \times 1$ 卷积层减少每像素级别上的通道维数从而降低模型复杂度最大汇聚层则降低分辨率。GoogLeNet 将多个设计精细的 Inception 块与其他层卷积层、全连接层串联起来其中 Inception 块的通道数分配之比是在 ImageNet 数据集上通过大量实验得来的。GoogLeNet 和它的后继者们一度是 ImageNet 上最有效的模型之一以较低的计算复杂度提供了类似的测试精度。练习与思考尝试 GoogLeNet 的后续版本并实现运行、观察实验结果包括添加批量规范化层batch normalization详见 chapter_convolutional-modern/batch-norm.md对 Inception 块进行调整Inception-v2/v3Szegedy 等 2016使用标签平滑label smoothing进行模型正则化加入残差连接Inception-ResNetSzegedy 等 2017详见 chapter_convolutional-modern/resnet.md。最小图像尺寸GoogLeNet 能工作的最小图像尺寸是多少可结合各模块的填充与步幅推导空间尺寸的下限并动手验证。参数规模对比将 AlexNet、VGG 和 NiN 的模型参数大小与 GoogLeNet 比较。后两个网络架构是如何显著减少模型参数大小的提示NiN 的全局平均汇聚替代全连接层、VGG 的重复块设计都是减少参数的关键思想。延伸阅读本章所属的现代卷积神经网络章节索引见 chapter_convolutional-modern/index.md其中按历史脉络依次介绍了 AlexNet、VGG、NiN、GoogLeNet、批量规范化batch normalization、ResNet 与 DenseNet完整的多框架工具函数数据加载、训练循环、动画绘制等集中在仓库 d2l/ 目录下包括 d2l/mxnet.py、d2l/torch.py、d2l/tensorflow.py 与 d2l/paddle.py。赞分享人工智能深度学习机器学习教程【免费下载链接】d2l-zh《动手学深度学习》面向中文读者、能运行、可讨论。中英文版被70多个国家的500多所大学用于教学。项目地址https://gitcode.com/GitHub_Trending/d2/d2l-zh点击查看免费下载相关推荐深入解析GoogLeNet并行连接网络架构深入解析GoogLeNet并行连接网络架构 引言 在深度学习的发展历程中2014年ImageNet图像识别挑战赛是一个重要的里程碑。Google团队提出的G人工智能深度学习机器学习教程动手学深度学习DenseNet 稠密连接网络原理与多框架实现详解动手学深度学习DenseNet 稠密连接网络原理与多框架实现详解 DenseNetdense convolutional network是《动手学深度学习人工智能深度学习机器学习教程从零实现GoogLeNet/InceptionNet架构详解从零实现GoogLeNet/InceptionNet架构详解 引言 GoogLeNet也称为InceptionNet是Google团队在2014年提出的深度示例工程机器学习深度学习教程上一篇A2UI React Renderer 样式架构深度解析Light DOM 下的七层样式体系与级联优先级设计下一篇Unleash 前端表格处理架构决策客户端与服务端数据流的设计规范ADR 解读创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考