)-在ImageNet上训练GoogLeNet

Posted wyy_persist

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了)-在ImageNet上训练GoogLeNet相关的知识,希望对你有一定的参考价值。

ImageNetBundle 8.在ImageNet上训练GoogLeNet

//2022.3.1日上午10:29开始学习笔记

8.在ImageNet上训练GoogLeNet

在本章中,我们将实现Szgedy等人在2014年的论文《深入卷积[23]》中介绍的完整GoogLeNet架构。在2014年的ImageNet大规模视觉识别挑战(ILSVRC)中,谷歌网络和VGGNet都是表现最好的,谷歌网络略胜VGGNet成为第一名。googlet还有一个额外的好处,它比VGG16和VGG19小很多,只有28.12MB的模型大小,而VGG的模型大小超过500MB。

也就是说,已经证明VGG网络家族:

  1. 达到更高的分类精度(在实践中)。
  2. 推广更好。

尤其是泛化,这就是为什么VGG更常用于迁移学习问题,如特征提取,特别是微调。GoogLeNet的后来的版本(只是以Inception N的名字命名,其中N是谷歌发布的版本号)扩展了最初的GoogLeNet实现和Inception模块,带来了更大的准确性——也就是说,我们仍然倾向于使用VGG进行迁移学习。

最后,还值得一提的是,许多研究人员(包括我自己)在复制Szegedy等人最初的结果时遇到了困难。独立的ImageNet实验,例如由vfeat(计算机视觉和机器学习的开源库)维持的排行榜,报告显示VGG16和VGG19的表现都大大超过google网络[24]。目前还不清楚为什么会这样,但我们将在本章的其余部分发现,我们的googlet实现并没有优于VGG,这是我们从最初的出版物和ILSVRC 2014年挑战中所期望的。无论如何,对我们来说,研究这个重要的体系结构以及如何在ImageNet数据集上训练它仍然很重要。

8.1 理解GoogLeNet

我们将从快速回顾Inception模块开始这一节,这是Szegedy等人在他们的开创性工作中所做的新贡献。从这里,我们将回顾在ILSVRC 2014挑战赛中使用的完整GoogLeNet架构。最后,我们将使用Python和mxnet实现googlet。

8.1.1 Inception模块

Inception模块是一个在GoogLeNet架构中使用的四个分支的微架构(图8.1)。Inception模块的主要目的是学习多尺度特征(1 × 1,3 × 3,和5 × 5过滤器),然后让网络根据优化算法“决定”哪个权重是最重要的。

Inception模块的第一个分支完全由1 × 1的过滤器组成。第二个分支应用1 × 1卷积,然后是3 × 3滤波器。作为降维的一种形式,我们学习了更少数量的1 × 1滤波器,从而减少了整体架构中的参数数量。第三个分支与第二个分支相同,只是它学习的不是3×3滤波器,而是5 × 5滤波器。

Inception模块中的第四个也是最后一个分支称为池投影分支。池投影应用3×3 max池,然后是一系列1×1卷积。这个分支背后的原因是,最先进的卷积神经网络大约在2014年使用了大量的最大池。假设要在具有挑战性的ImageNet数据集上实现高精度,网络架构必须应用max pooling,因此我们在Inception模块中看到它。我们现在知道,最大池化在网络架构中不是一个要求,我们可以相反地严格通过CONV层来减少卷大小[21,25];然而,这是当时的主流思想。

四个支路的输出沿信道维度串联起来,形成一个滤波器堆栈,然后在网络中传递到下一层。关于Inception模块的更详细的回顾,请参阅实践者包的第12章。

8.1.2 GoogLeNet结构

图8.2详细描述了我们将要实现的GoogLeNet架构,包括初始化模块四个分支中每个分支的过滤器的数量。每次卷积之后,都会隐式地暗示(即,为了节省空间,没有在表中显示)应用批处理归一化,然后激活ReLU。通常我们会将批处理规范化放置在激活之后,但同样地,我们将尽可能地坚持原始GoogLeNet实现。

我们从一个7 × 7的卷积开始,步长为2 × 2我们总共学习了64个滤波器。当内核大小为3 × 3,步幅为2 X 2时,可以立即调用最大池操作。这些CONV和POOL层将我们的输入体积大小从224 × 224 × 3一直降低到56 × 56 × 64(注意图像的空间维度下降得多么显著)。

从那里,另一个CONV层被应用,在那里我们学习192个3 × 3滤波器。然后是POOL层,将我们的空间维度减少到28 × 28 × 192。接下来,我们堆叠两个Inception模块(命名为3a和3b),然后是另一个POOL。

为了学习更深入、更丰富的特性,我们接着堆叠5个Inception模块(4a-4e),接着是一个POOL。加上两个Inception模块(5a和5b),输出体积大小为7 × 7 × 1024。为了避免使用完全连接的层,我们可以使用全局平均池,将7 × 7的体积平均为1 × 1 × 1024。然后可以使用Dropout来减少过拟合。Szegedy等人建议使用40%的退出率;然而,50%往往是大多数网络的标准——在这种情况下,我们将尽可能遵循最初的实现,并使用40%。在dropout之后,我们应用整个体系结构中唯一的全连接层,其中节点的数量是类标签的总数(1000),后面跟着一个softmax分类器。

8.1.3 实现GoogLeNet

使用上面详细的表格,我们现在可以使用Python和mxnet库实现googlet。在nn中创建一个名为mxgooglinet .py的新文件。mxconv子模块的pyimagesearch,这样我们可以保持我们的Keras CNN实现独立于我们的mxnet CNN实现(我强烈推荐):

GoogLeNet网络的实现:

在第6行,我们定义了conv_module方法,这是一个方便的函数,用于应用CONV => BN => RELU的层序列。这个函数接受一个输入数据(即来自前一层的输入)、内核大小K、内核kX和kY的大小、零填充垫的数量,最后是卷积的步幅。第8-11行使用这些输入构建CONV => BN => RELU,然后将其返回到第14行上的调用函数。

我们定义conv_module的原因只是为了方便——任何时候我们需要应用CONV => BN => RELU模式(这将是很多的),我们只需调用conv_module。此外,这样做有助于清理我们的代码,因为我们不必明确地写出每一个卷积、BatchNorm和Activation。

接下来,我们可以定义我们的inception_module,它与实践者Bundle的第11章中的实现是相同的,只是我们现在使用mxnet而不是Keras作为实现库:

在第21行,我们创建了Inception模块的第一个分支,它应用了num1x1 1 × 1的卷积。Inception模块中的第二个分支是一组1 × 1卷积和3 × 3卷积:

同样的过程也适用于第三个分支,只是这次我们学习的是5 × 5卷积:

我们的Inception模块的最后一个分支是池投影,它只是一个最大池,后面跟着1 × 1的CONV层:

这四个通道的输出(即卷积)沿着通道维度连接起来,形成Inception模块的输出:

我们能够执行这种连接的原因是,在添加3 × 3和5 × 5卷积时需要特别注意,以使输出体积尺寸相同。如果每个分支的输出卷形状不匹配,那么我们将无法执行连接。

有了conv_module和inception_module,我们现在就可以创建负责的构建方法,或者使用这些构建块来构建googlet架构:

如下图8.2所示,我们首先应用CONV => POOL => CONV => POOL,将空间输入维度从224 × 224像素降至28 × 28像素。

请记住,我们在每次CONV之后都简单地应用了批处理的规范化和激活。这些层在代码(1)和(2)的描述中被省略了,因为我们已经讨论了如何在conv_module函数中应用它们。

每个分支的精确参数可以在上面的表8.2中找到。Szegedy等人通过自己的实验确定了这些参数,建议保留每个分支的滤波器数量不变。在实践者包的第12章的Inception模块中,我对我们对每个CONV层的过滤器数量所做的假设进行了更深入的讨论。

为了学习更深入、更丰富、更有区别的特性,我们接下来应用5个Inception模块(4a-4e),然后是另一个POOL:

请注意,我们在体系结构中了解得越深,输出量变得越小,我们学到的过滤器就越多——这是创建卷积神经网络时的常见模式。

使用另外两个Inception模块(5a和5b),然后是平均池和dropout:

检查第89行和90行,您可以看到,作为Inception模块5b中连接操作的结果,总共输出了384 + 384 + 128 + 128 = 1024个过滤器。因此,该结果产生的输出体积大小为7 × 7 × 1024。为了缓解对全连接层的需求,我们可以将7 × 7的空间维度平均为1 × 1 × 1024,这是GoogLeNet、ResNet和SqueezeNet中常用的技术。这样做可以大大减少网络中参数的总数。

最后,我们为我们的类总数定义一个单一的密集层,并应用softmax分类器:

​​​​​​​8.1.4 训练GoogLeNet网络

略,和第7章中的训练VGGNet相似。

​​​​​​​8.2 评价GoogLeNet网络

为了在ImageNet测试集上评估GoogLeNet,我们将使用在上面的项目结构中提到的test_googlenet.py脚本。该文件与test_alexnet.py和test_vggnet.py相同,因此我们将跳过检查该文件以避免冗余。为了完整起见,我将test_googlenet.py包含在与本书相关的目录结构和下载中。请参阅AlexNet上的第6章来彻底地回顾这个文件。

​​​​​​​8.3 GoogLeNet实验

ILSVRC 2014的结果表明,googlet仅略胜VGGNet,获得第一名[26];然而,许多深度学习研究人员(包括我自己)发现很难重现这些精确的结果[24]-结果应该至少与VGG相当。在训练过程中,我和其他人很可能在Szegedy等人的论文中遗漏了一个参数设置。

无论如何,回顾一下google网的实验和思维过程,并使其达到合理的准确性(也就是说,比AlexNet好,但不如VGG),仍然很有趣。

​​​​​​​8.3.1 实验1

在我第一次GoogLeNet实验中,我使用了SGD优化器(不像亚当优化器详细节8.1.4上图)的初始学习速率1 e−2,作者推荐的学习速率,以及动量词的0.9和0.0002的L2体重衰变。据我所知,这些优化器参数是Szegedy等人在他们的论文中报告的精确复制。然后我开始使用以下命令进行训练:

正如我的前15个时代所展示的,当检查验证集时,学习是非常不稳定的(图8.3,左上角)。随着验证损失的显著增加,验证准确性会急剧下降。为了克服波动性,我在第15个纪元后停止了训练,并将学习率降低到1e−3,然后继续训练:

不幸的是,这一更新导致网络性能在精度略微提高后完全停滞不前(图8.3,右上)。为了证实停滞确实是这样,我在第25纪元之后停止训练,将学习速度降低到1e - 4,然后在接下来的5个纪元继续训练:

正如我的图表所显示的那样,由于SGD能够导航到一个损失较小的区域,所以其准确性会有一个微小的提升,但总的来说,训练已经趋于稳定(图8.3,底部)。在30世纪之后,我终止了训练,并仔细观察了结果。对日志的快速检查显示,我在验证集中获得了57.75%的rank-1和81.15%的rank-5准确性。虽然这不是一个糟糕的开始,但与我的预期相差甚远:精确度介于AlexNet和vggnet级别之间。

​​​​​​​8.3.2 实验2

考虑到1e−2学习速率的极度波动,我决定完全重新开始训练,这次使用1e−3的基础学习速率来帮助平稳学习过程。我使用了与之前实验完全相同的网络架构、动量和L2正则化。这种方法带来了稳定的学习;然而,这个过程非常缓慢(图8.4,左上角)。

当学习在70年代左右开始急剧放缓时,我停止了训练,并将学习速度降低到1e−4,然后继续训练:

我们可以看到准确性的小幅提升和损失的减少,但学习仍然无法取得进展(图8.4,右上)。我让google继续进入80世纪,然后又停止训练,把我的学习速度降低了一个数量级,降到1e−5。

结果,正如您现在所期望的,是停滞(图8.4,底部)。第八十五世纪结束后,我完全停止了训练。不幸的是,这个实验的结果并不是很好,我只达到了53.67%的rank-1和77.85%的rank-5的验证准确性,比我的第一个实验差。

左上角:前70个时代显示出极其缓慢但稳定的学习。右图:在学习停滞后,我使用SGD优化器将学习速率从1e−3降低到1e−4。然而,在最初的颠簸之后,学习很快就停滞了。底部:进一步降低学习率并不能改善结果。

​​​​​​​8.3.3 实验3

考虑到我在练习者包中使用GoogLeNet和Tiny ImageNet的经验,我决定用初始(默认)学习率1e−3来替换Adam的SGD优化器。使用这种方法,我遵循表8.1所示的学习速率衰减时间表。

精度与损失的曲线图如图8.5所示。与其他实验相比,我们可以看到GoogLeNet + Adam很快就达到了> 50%的验证准确率(少于10个epoch,相比之下,它从实验#1获得了15个epoch,这只是因为学习速率的变化)。你可以看到,我把学习速率从1e−3降低到1e−4,在第30纪元时带来了准确性的飞跃。不幸的是,在第45阶段并没有那么大的飞跃,我切换到了1e - 5,并允许训练继续进行5个以上的阶段。

在50世纪之后,我完全停止了训练。这里GoogLeNet在验证集上的rank-1和rank-5的准确率分别达到了63.45%和84.90%,明显优于前两次实验。

 

​​​​​​​8.4 总结

在本章中,我们研究了Szegedy等人在2014年的论文《Going deep with Convolutions[23]》中提出的GoogLeNet架构。然后我们在ImageNet数据集上从头开始训练GoogLeNet,试图复制他们最初的结果。然而,与其复制Szegedy等人的结果,我们不如验证了vlfeat结果[24],其中我们的网络获得≈65%的rank-1精度。根据我们的结果,以及vlfeat报告的结果,似乎还有其他我们不知道的额外参数和/或训练程序,以获得vg级别的准确性。不幸的是,如果没有Szegedy等人的进一步澄清,我们很难准确地指出这些额外的参数是什么。

我们可以继续探索这个架构,并引入进一步的优化,包括:

然而,研究我们将在ImageNet和SqueezeNet上训练的两个剩余的网络架构要有趣得多。ResNet架构是令人兴奋的,因为它引入了剩余模块,能够获得比任何(当前)在ImageNet上发表的论文更高的最先进的精度。然后我们有了SqueezeNet,它获得了alexnet级别的精度——但这样做的参数少了50倍,模型大小为4.9MB。

//截止到2022.3.1 晚上20:04

上述实验代码详见本人github仓库:

TheWangYang/Code_For_Deep_Learning_for_Computer_Vision_with_Python: A code repository for Deep Learning for Computer Vision with Python. (github.com)

以上是关于)-在ImageNet上训练GoogLeNet的主要内容,如果未能解决你的问题,请参考以下文章

Imagenet ILSVRC2014 验证基本事实到同义词集标签翻译不准确

)-在ImageNet上训练VGGNet

)-在ImageNet数据集上训练AlexNet

使用 GOOGLE COLAB TPU 在 IMAGENET 上训练 VGG-16 模型需要多长时间?

GoogLeNet 与 Inception

Keras CIFAR-10图像分类 GoogleNet 篇