PyTorch 实现 GoogleNet 用于图像分类
PyTorch 实现 GoogleNet 用于图像分类
本实验主要介绍了如何在昇腾上,使用 pytorch 对经典的 GoogleNet 模型在公开的 CIFAR10 数据集进行分类训练的实战讲解。内容包括 GoogleNet 模型创新点介绍、GoogleNet 网络架构剖析与 GoogleNet 网络模型代码实战分析等等。
本实验的目录结构安排如下所示:
GoogleNet 网络模型创新点介绍
GoogleNet 的网络架构剖析
GoogleNet 网络模型代码实现分析
GoogleNet 网络用于 cifar 数据集分类实战
GoogleNet 网络模型创新点介绍
引入了 Inception 模块,该模块使用不同大小的卷积核和池化层来捕获不同尺度的特征。
Inception 模块内部通过多个并行的卷积层和池化层来处理输入数据,然后将它们的输出进行拼接,从而增加了网络对不同尺度特征的感知能力。这种结构有助于提高网络的表达能力,同时减少了参数数量。
在 Inception 模块中广泛使用了 1x1 卷积;1x1 卷积可以用来进行特征的线性组合,从而降低特征维度,减少计算负担。
这种技术被称为“瓶颈结构”,可以在不引入过多计算负担的情况下增加网络的深度和宽度。
使用全局平均池化替代全连接层,减少参数量,防止过拟合。
在传统的卷积神经网络中,通常使用全连接层来进行分类,这会导致大量的参数和计算量。GoogLeNet 使用了全局平均池化来替代全连接层,通过对特征图的所有通道进行平均池化,生成一个特征向量,然后使用一个 softmax 分类器进行分类。这种做法减少了参数数量,防止过拟合,并降低了计算复杂性。
为于缓解梯度消失问题,促进梯度在网络中的传播,引入了两个辅助分类器,分别连接到中间层的不同位置。
这些辅助分类器在训练过程中引入了额外的损失函数,帮助网络更快地进行训练。在测试阶段,这些辅助分类器不起作用,只有主分类器的输出被使用。
GoogleNet 的网络架构剖析
从 Lent、Alexnet 到 VGG 网络,随着网络的层数不断的增加,模型的表达能力也在不断的增强,但是也带来了参数过大的问题。而解决这一问题的根本方法就是将全连接转到到稀疏矩阵的架构。这是因为神经网络的雏形是参照人类神经元而设计的,而现实生物神经系统的连接也是稀疏的,此外对于大规模稀疏的神经网络,可以通过分析激活值的统计特性和对高度相关的输出进行聚类来逐层构建出一个最优网络。
因此,为了既能保持网络结构的稀疏性,又能利用密集矩阵的高计算性能。GoogleNet 通过使用 Inception 结构将稀疏矩阵聚类为较为密集的子矩阵来提高计算性能的同时又能够将相关性强的特征汇聚到一起。
Inception 模块
论文中提出了两种形式的 Inception 结构,分别是'Inception module'与'Inception module with dimensionality reduction'版本。其主要作用是怎样用密集成分来近似最优的局部稀疏结构。

通过对输入进行多尺度并行卷积、池化并结合 1×1、3×3 与 5×5 的卷积核用来提取不同尺度的特征,此外,根据卷积层输入输出 shape 的计算公式我们只需要将令卷积步长 stride=1,并且分别将 1×1、3×3 与 5×5 的卷积核中的 pad 值分别设置为 0、1、2,那么通过这三个卷积核之后便可以得到相同维度的特征,与此同时在网络的最右侧加了一个 3×3 的最大池化,最后将这些特征图 concat 在一起即可得到不同维度的特征图。
上述 Inception 模块模块虽然能够有效的提取到不同尺度的特征,但是网络越往后特征越抽象且 3x3 和 5x5 卷积的比例也要增加,这就会导致随着网络深度加深会导致大量的计算。此外,由于 pooling 层不改变其通道数,因此通道特征图会变得很大。

针对上述基础 Inception 模块面临的问题,GoogleNet 中通过采用大量的 1×1 的卷积来解决上述问题,改进后的结构如图中'Inception module with dimensionality reduction 所示,图中在 1×1、3×3 与 5×5 卷积核之前与 3×3 的最大池化与 1x1 的卷积串联,这样不仅能够使得计算量大大减少,而且还能够组合出更多的非线性特征。
GoogleNet 网络代码实现分析

整个 GoogleNet 网络是由若干个 Inception 模块堆叠而成,此外由于此处是 10 分类任务且 LRN 操作对分类任务无明显提升效果,因此本实验在实现时只搭建了 input-> softmax2 主通路网络(没有实现的部分均在图中用 x 标记,如有兴趣可以尝试改动实现)。网络通过实现定义 GoogLeNet 类实现,整个网络结构被分成了 5 个阶段,经过 5 阶段后通过一个 Fc 层得到预测 10 个类别信息。
GoogleNet 网络用于 cifir 数据集分类实战
基于上述搭建好的网络模型,我们现在就可以正式来使用该模型开始训练 cifir 数据集。
导入昇腾 npu 相关库 transfer_to_npu、该模块可以使能模型自动迁移至昇腾上。
torchvision 模块中集成了一些当今比较流行的数据集、模型架构和用于计算机视觉的常见图像转换功能,torchvision 模块中含有本次实验所需要的 CIFAR 数据集,因此导入该模块用于数据集的下载。tqdm 是用于训练过程中训练进度条,便于我们能够清晰的看到整个训练过程。
数据集预处理功能定义: 对图像数据集进行不同程度的变化,包括裁剪、翻转等方式增加数据的多样性,防止过拟合现象的出现,以增强模型的泛化能力。
调用了 torchvision 中的 transform 库中的 compose 方法,使用裁剪(RandomCrop)、翻转(RandomHorizontalFlip)等组合成 tensor 形式后并对 tensor 进行正则化(Normalize)。
cifar 数据集共有 60000 张彩色图像,这些图像是 32*32,分为 10 个类,每类 6000 张图。有 50000 张用于训练,构成了 5 个训练批,每一批 10000 张图;另外 10000 用于测试,单独构成一批。测试批的数据里,取自 10 类中的每一类,每一类随机取 1000 张。抽剩下的就随机排列组成了训练批。注意一个训练批中的各类图像并不一定数量相同,总的来看训练批,每一类都有 5000 张图。

数据集加载: torchvision 中集成了一些通用的开源数据集,其中也包含 cifar,此处通过 torchvision 函数加载 cifar 数据集到工作目录上的指定路径,如果已经下载好了,会直接校验通过,不会二次进行下载。
训练模块: 根据传入的迭代次数'epoch'开始训练网络模型,这里需要在 model 开始前加入'net.train()',使用随机梯度下降算法是将梯度值初始化为 0('zero_grad()'),计算梯度、通过梯度下降算法更新模型参数的值以及统计每次训练后的 loss 值(每隔 100 次打印一次)。
测试模块: 每训练一轮将会对最新得到的训练模型效果进行测试,使用的是数据集准备时期划分得到的测试集,每类约为 1000 张。
主功能调用模块: 该模块用于开启模型在指定数据集(cifar)上训练,其中定义了硬件设备为昇腾 npu(device = 'npu'),定义了损失函数为交叉熵损失'CrossEntropyLoss()',梯度下降优化算法为 SGD 并同时指定了学习率等参数。
训练与测试的次数为 60 次,这里用户可以根据需要自行选择设置更高或更低,每个 epoch 的测试准确率都会被打印出来,如果不需要将代码注释掉即可。
Reference
[1] Szegedy C, Liu W, Jia Y, et al. Going deeper with convolutions[C]//Proceedings of the IEEE conference on computer vision and pattern recognition. 2015: 1-9.
评论