图像分类(三) 全面解读复现VGGNet
解读一
Abstract-摘要
翻译
在这项工作中,我们研究了卷积网络深度在大规模图像识别环境下对其精度的影响。我们的主要贡献是使用具有非常小(3×3)卷积滤波器的体系结构对增加深度的网络进行了彻底的评估,这表明通过将深度推进到16-19个权重层,可以实现对现有技术配置的显著改进。这些发现是我们2014年ImageNet挑战赛提交的基础,我们的团队在局部化和分类路径上分别获得了第一和第二名。我们还表明,我们的表示法很好地推广到了其他数据集,在这些数据集上,它们获得了最先进的结果。我们已经公开了我们的两个性能最好的ConvNet模型,以促进对计算机视觉中深度视觉表示的使用的进一步研究。
精读
本文研究的问题
本文研究了在大规模图像识别中,卷积网络深度对其识别精度的影响。
本文主要贡献
我们的主要贡献是使用具有非常小(3 ×3)卷积滤波器的架构对于增加了深度的网络的全面评估,这表明将通过将深度推到16-19个权重层可以实现对现有技术配置的显著改进。
一、Introduction—介绍
翻译
卷积网络(ConvNets)最近在大规模图像和视频识别方面取得了巨大成功(Krizhevsky等人,2012年;Zeiler&Fergus,2013;Sermanet等人,2014;Simonyan&Zisserman,2014),这要归功于大型公共图像库,例如ImageNet(邓等人,2009),以及高性能计算系统,如GPU或大规模分布式集群(Dean等人,2012。特别地,ImageNet大规模视觉识别挑战(ILSVRC)(Russakovsky等人,2014)在深度视觉识别体系结构的进步中发挥了重要作用,该挑战已经作为几代大规模图像分类系统的试验台,从高维浅层特征编码(Perronnin等人,2010)(ILSVRC-2011的获胜者)到深度ConvNets(Krizhevsky等人,2012)(ILSVRC-201的获胜者)
随着ConvNets越来越成为计算机视觉领域的必需品,已经进行了许多尝试来改进Krizhevsky等人的原始架构。(2012),以期达到更好的准确性。例如,向ILSVRC2013提交的表现最好的性能(Zeiler&Fergus,2013;Sermanet等人,2014)利用了较小的接受窗口大小和较小的第一卷积层步距。另一项改进涉及在整个图像和多个尺度上密集地训练和测试网络(Sermanet et al.,2014;Howard,2014)。在本文中,我们讨论了ConvNet体系结构设计的另一个重要方面-它的深度。为此,我们固定了结构的其他参数,并通过增加更多卷积层来稳步增加网络的深度,这是可行的,因为在所有层中都使用了非常小的(3×3)卷积滤波器。
因此,我们提出了更精确的ConvNet架构,它不仅在ILSVRC分类和局部化任务上实现了最先进的准确性,而且也适用于其他图像识别数据集,在这些数据集中,即使作为相对简单的管道的一部分使用,它们也可以获得优异的性能(例如,无需微调的线性支持向量机对深度特征进行分类)。我们已经发布了两个性能最好的模型,以方便进一步的研究。
论文的其余部分组织如下。在第2节中,我们描述了我们的ConvNet配置。第三节介绍了图像分类训练和评价的具体内容,并在第四节的ILSVRC分类任务中对两种配置进行了比较。第五节对本文进行了总结。为了完整性,我们还在附录A中描述和评估了我们的ILSVRC-2014对象局部化系统,并在附录B中讨论了非常深入的功能对其他数据集的概括。最后,附录C包含主要论文修订的列表。
精读
介绍卷积网络(ConvNets)的发展和应用
**应用方面:**最近在大规模图像和视频识别方面取得了巨大成功(Overfeat)。
**原因:**这是由于大型公共图像存储库,如ImageNet和高性能计算系统,例如GPU或大规模分布式集群(Tensorflow)。特别是,ImageNet大规模视觉识别挑战赛(ILSVRC)(Russakovsky et al.,2014)在深度视觉识别体系结构的发展中发挥了重要作用,它是几代大型图像分类系统的试验台,从高维浅特征编码(Perronnin等人,2010年)(ILSVRC-2011的获胜者)到深度转换(Krizhevsky等人,2012年)(ILSVRC-2012的获胜者)。
之前对ConvNets精度提高的尝试
1.利用了较小的接受窗口大小和第一卷积层的较小步幅**(处理更小的细节)**
2.改进涉及在整个图像和多个尺度上密集地训练和测试网络**(修改输入网络的数据)**
本文对ConvNets精度提高的改进方法和结果
**方法:**在本文中,我们将讨论ConvNet架构设计的另一个重要方面——深度。为此,我们确定了体系结构的其他参数,并通过添加更多卷积层来稳步增加网络的深度,这是可行的,因为在所有层中使用了非常小的(3×3)卷积核。
**结果:**我们提出了更精确的ConvNet体系结构,不仅在ILSVRC分类和定位任务上达到了最先进的精度,而且还适用于其他图像识别数据集,即使仅作为特征提取器,它们也能获得优异的性能(例如,由线性支持向量机分类的深度特征,无需微调)。为了便于进一步研究,我们发布了两个性能最好的模型(VGG16和VGG19)。
二、ConvNet Configurations—ConvNet配置
翻译
为了在公平的环境下衡量ConvNet深度增加带来的改善,我们所有的ConvNet层配置都是根据相同的原则设计的,灵感来自Ciresan等人。(2011);Krizhevsky等人。(2012年)。在本节中,我们首先描述我们的ConvNet配置的一般布局(第2.1节),然后详细说明评估中使用的具体配置(第2.2节)。然后讨论我们的设计选择,并与第2.3节中的现有技术进行比较。
精读
2.1Architecture—结构
翻译
在训练过程中,我们的ConvNet的输入是一幅固定大小的224×224 RGB图像。我们所做的唯一预处理是从每个像素减去在训练集上计算的平均RGB值。图像通过一堆卷积(卷积)。层,其中我们使用带有非常小的接收字段的过滤器:3×3(这是捕捉左/右、上/下、中心的概念的最小尺寸)。在其中一种配置中,我们还使用1×1卷积滤波器,可以将其视为输入通道的线性变换(随后是非线性)。卷积步长固定为1像素;卷积的空间填充。层输入是这样的,即在卷积之后空间分辨率保持不变,即对于3×3卷积,填充是1个像素。层次感。空间池化是由五个最大池化层执行的,这些层紧跟在一些圆锥之后。层(不是所有的。层之后是最大池化)。最大合用是在2×2像素窗口上执行的,步长为2。
卷积层的堆栈(在不同的体系结构中具有不同的深度)后面是三个全连接(FC)层:前两个层各有4096个通道,第三个执行1000路ILSVRC分类,因此包含1000个通道(每个类别一个)。最后一层是softmax层。所有网络中的完全连接层的配置都是相同的。
所有隐藏层都配备了校正(RELU(Krizhevsky等人,2012))非线性。我们注意到,我们的所有网络(除了一个网络)都没有包含本地响应归一化(LRN)归一化(Krizhevsky等人,2012年):如第4节所示,这种归一化不会提高ILSVRC数据集的性能,而是导致内存消耗和计算时间增加。在适用的情况下,LRN层的参数是(Krizhevsky等人,2012年)的参数。
精读
深度是卷积神经网络架构的一个重要方面。为了使深度更深,作者将卷积层中卷积核尺寸都设为很小——3×3,将卷积层数量加大,使深度更深,事实证明是可行的。
方法
**1.输入:**一个固定大小的224*224RGB图像
**2.唯一预处理:**将输入的224×224×3通道的像素值,减去平均RGB值,然后进行训练
**3.卷积核:**①使用最小尺寸的卷积核3×3这个尺寸也是能捕捉上下左右和中间方位的最小尺寸
②有些卷积层中还使用了1×1大小的卷积核(FC层之间的),可看作是输入通道的线性变换
● 为什么3个3x3的卷积核可以代替7x7的卷积?
**①得到更好的拟合效果。**3个3x3的卷积,使用了3个ReLU函数非线性校正,增加了非线性表达能力,比一个ReLU的单层Layer更具有识别能力,使得分割平面更具有可分性
**②减少网络参数个数。**对于C个通道的卷积核,7×7×C×C 比3×3×C×C的参数量大。
● 1x1卷积核的作用?
①在不影响感受野的情况下,增加模型的非线性性
②1x1卷积相当于线性变换,非线性激活函数起到非线性作用
**4.卷积步幅 :**卷积步幅固定为1像素,3×3卷积层的填充设置为1个像素。
**5.池化层:**池化层采用空间池化,空间池化有五个最大池化层,他们跟在一些卷积层之后,但是也不是所有的卷积层后都跟最大池化。最大池化层使用2×2像素,步幅为2。
**6.卷积层:**一个卷积层(在不同的体系结构中具有不同的深度)之后是三个完全连接的(FC)层:前两个层各有4096个通道,第三个层执行1000路ILSVRC分类,因此包含1000个通道(每类一个)(1000分类对应ImageNet-1K)。最后一层是softmax层,用来分类。在所有网络中,完全连接的层的配置都是相同的。
**7.隐藏层:**所有隐藏层都有ReLU非线性函数,网络除了第一个其他都不包含局部响应归一化(LRN)(原因:论文中,作者指出,虽然LRN在AlexNet对最终结果起到了作用,但在VGG网络中没有效果,并且该操作会增加内存和计算,从而作者在更深的网络结构中,没有使用该操作)
2.2Configurations—配置
翻译
该篇论文中卷积网络的设置在表格1中展示出来。在接下来的环节中我们将使用它们的代词(A-E)。所有通用的设置在2.1节中叙述完,唯一的不同点就在于网络的深度:从A中的11层(8层卷积+3层全连接层)到E中的19层(16层卷积+3层全连接层)。卷积层的宽度(即通道数)是相对小的,从第一层的64,每经过一层最大池化层就扩大2倍,直到达到512。
表一:ConvNet配置(以列展示)。配置的深度从左(A)向右(E)增加,添加了更多的层(添加的层以粗体表示)。卷积层参数表示成“conv<感受野大小>-<通道数量>”。为了简洁,未展示ReLU激活函数。
表二:在表2中,我们报告了每种配置的参数数量。尽管有很大的深度,但我们的网中的权重数并不比更浅、更大圆度的网中的权重数多。层宽度和感受野(144m重量(Sermanet等人,2014年))。
精读
1.这个表的对比是一个对照实验组。
2.我们可以看到第一个A组有11层(8卷积层+3全连接层,只算带权重的层 所以池化层不算)。另一个A组加上LRN。D,E组就是在上文中见到的VGG16和VGG19。C和D都是16层,他俩的区别是C组使用了1×1的卷积核,而D组都是3 × 3 卷积核。
3.图中加粗的就是增加的或者修改的层。
4.这里面是有Relu函数的,作者没有标明出来。
具体对比结果我们下一节详细讨论。
2.3Discussion—讨论
翻译
我们的ConvNet配置与ILSVRC-2012(Krizhevsky等人,2012)和ILSVRC-2013比赛(Zeiler&Fergus,2013;Sermanet等人,2014)表现最好的参赛作品中使用的配置有很大不同。而不是在第一层conv中使用相对较大的感受野。(例如,在(Krizhevsky等人,2012)中为11×11,步长为4,或在(Zeiler&Fergus,2013;Sermanet等人,2014)中为7×7,步长为2),我们在整个网络中使用非常小的3×3感受野,这些感受野在每个像素处与输入卷积(步长为1)。很容易看到两个3×3 conv堆叠。各层(中间无空间混合)的有效感受野为5×5,其中3层的有效感受野为7×7。那么,比方说,使用三个3×3卷积的堆叠,我们得到了什么呢?而不是单一的7×7层?首先,我们加入了三个非线性校正层而不是单个校正层,使得决策函数更具区分性。其次,我们减少了参数的数量:假设一个三层3×3卷积叠加的输入和输出都有C个通道,该叠加由3(32C2)=27C2权重参数化;同时,单个7×7卷积,层将需要72C2=49C2参数,即比27C2多81%。这可以看作是对7×7卷积施加了正规化过滤器,迫使它们通过3×3的过滤器进行分解(在其间注入非线性)。
精读
对比第一个卷积层感受野大小:
本文章中的网络配置与前面一些表现非常好的网络配置比较不一样(例如AlexNet和OverFeat),VGG在整个网络使用了非常小的感受野而不是在第一个卷积层使用相对来说比较大的卷积层(AlexNet中卷积核大小为11×11步长为4,OverFeat中卷积核大小为7×7步长为2)
感受野相关问题
**感受野(Receptive Field)**的定义是卷积神经网络每一层输出的特征图(feature map)上的像素点在输入图片上映射的区域大小。再通俗点的解释是,特征图上的一个点跟原图上有关系的点的区域。
我们可以通过上图看出,在卷积神经网络 中,越深层的神经元看到的输入区域越大。上图中的卷积核大小均为3×3,步幅均为1,绿色标记的是Layer2每个神经元看到的区域,黄色标记的是Layer3看到的区域。这样我们就可以很明显的看出来,Layer2每个神经元可看到的Layer1上3×3大小的区域,Layer3每个神经元看到的是Layer2上3×3大小的区域,同时,该区域可以看到Layer1上5×5大小的区域。
动态效果可以看下图:
好处
通过对卷积层作用的评估,可以很容易看出来两个3 × 3的卷积层可以起到一个5 × 5 卷积层的作用,三个3×3的卷积层可以起到一个7 × 7卷积层的作用。
为什么有这样的作用?
1.合并了三个非线性ReLU层,不是只用一个,使得决策函数更具有判别性。
2.减少了参数数量。
三、Classification Framework—分类框架
3.1Training—训练
(1)步骤和参数
翻译
ConvNet训练过程一般遵循Krizhevsky等人的做法。(2012)(除了对来自多尺度训练图像的输入作物进行采样之外,如后面所解释的)。即,通过使用带动量的小批量梯度下降(基于反向传播(LeCun等人,1989))来优化多项式Logistic回归目标来执行训练。批量设置为256,动量为0.9。训练通过权重衰减(L2惩罚倍数设置为5·10−4)和前两个完全连接的层的dropout规则化(dropout率设置为0.5)来归一化。学习速率最初设置为10−2,当验证集精度停止提高时,学习率降低到原来的1/10。总共降低了3倍的学习速率,并在37万次迭代(74个epochs)后停止学习。我们猜测,尽管与(Krizhevsky等人,2012年)相比,我们的网络有更多的参数数量和更深的网络,网络收敛所需的epochs更少由于(a)更大深度和更小Conv过滤器大小施加的隐式正则化;(b)某些层的预初始化。
精读
卷积网络训练步骤大致跟随AlexNet,除了从多尺度训练图像中对输入进行采样,也就是说通过使用小批量梯度下降法优化多项式逻辑回归来进行训练。同时添加了L2正则项进行正则化,使用Dropout减少全连接层过拟合,并且应用了学习率退火,具体参数设置如下:
参数名 | 大小 |
---|---|
batch size(批量大小) | 256 |
momentum(动量) | 0.9 |
weight decay(权重衰减) | 0.0005 |
dropout ratio(随机失活率) | 0.5 |
learning rate(学习率) | 0.01 |
迭代步数 | 370K |
epoches(轮数) | 75 |
● 学习率退火:
当验证集的准确率停止提升的时候除以10,学习率总共下降了三次,一共经过了74个Epochs
网络能更快收敛的原因?(与AlexNet相比,VGGnet有更多的参数和更大的深度)
①较大深度和较小的卷积核所施加的隐式正则化
②某些层的预初始化
正则化相关问题
● 正则化
旨在更好实现模型泛化的补充技术,即在测试集上得到更好的表现。
● L1和L2正则化
L1正则化会让特征变得稀疏,起到特征选择的作用;
L2正则化会让模型变得更简单,防止过拟合,而不会起到特征选择的作用。
● 隐式正则化
没有直接对模型进行正则化约束,但间接获取更好的泛化能力。
1、数据标准化,平滑优化目标函数曲面; 2、数据增强,扩大数据集规模; 3、随机梯度下降算法
(2)初始化权重
翻译
网络权值的初始化很重要,因为由于深层网络中梯度的不稳定性,错误的初始化可能会导致学习停滞。为了绕过这个问题,我们从训练配置A(表1)开始,它足够浅,可以通过随机初始化进行训练。然后,当训练更深的体系结构时,我们用Net A的层初始化前四个卷积层和最后三个全连通层(中间层是随机初始化的)。我们没有降低预初始层的学习速率,允许它们在学习过程中改变。对于随机初始化(如果适用),我们从具有零均值和10−2方差的正态分布中抽样权重。偏差被初始化为零。值得注意的是,在论文提交后,我们发现可以使用Glorot&Bengio(2010)的随机初始化过程来初始化权重,而不需要预先训练。
精读
原因
因为深度网络中梯度的不稳定性,错误的初始化会阻碍学习。
方法
开始训练配置A,通过随机初始化进行训练,然后对更深层次网络结构训练。将前四层卷积层和后三个FC层都按照A网络的初始化配置设置,中间层接着随机初始化。没有减少预初始化层的学习率,而是让它们随着学习的进程发生改变。
采样参数
对于随机初始化,我们从一个均值为0方差为0.01的正态分布中对权重进行采样,偏置初始化为0。
证明结论
即使随机初始化所有的层,模型也能训练的很好。
后期发现
使用随机初始化程序可以在不进行预训练的情况下初始化权重。
(3)数据增广
翻译
为了获得固定大小的224×224 ConvNet输入图像,从重新缩放的训练图像中随机裁剪它们(每次SGD迭代每个图像一个裁剪)。为了进一步增加训练集,这些作物经历了随机水平翻转和随机RGB颜色变换(Krizhevsky等人,2012年)。下面解释训练图像的重新缩放。
Training image size.设S是各向同性重新缩放的训练图像的最小边,从中裁剪ConvNet输入(我们也将S称为训练比例)。当裁剪大小固定为224×224时,原则上S可以采用不小于224时的任何值:对于S=224时,裁剪将捕获整个图像统计,完全覆盖训练图像的最小边;对于S≫224,裁剪将对应于包含小对象或对象部分的图像的一小部分。
我们考虑了两种设置训练尺度S的方法。第一种是固定S,其对应于单尺度训练(请注意,采样作物内的图像内容仍然可以代表多尺度图像统计)。在我们的实验中,我们评估了在两个固定尺度上训练的模型:S=256(这在现有技术中已经被广泛使用(Krizhevsky等人,2012年;Zeiler&Fergus,2013;Sermanet等人,2014))和S=384。在给定ConvNet配置的情况下,我们首先使用S=256训练网络。为了加快S=384网络的训练速度,用S=256时预先训练的权值进行了初始化,并使用了较小的初始学习率10−3。
设置S的第二种方法是多尺度训练,其中每个训练图像通过从特定范围[Smin,Smax] (我们使用Smin=256和Smax=512)随机采样S来单独重新缩放。由于图像中的对象可以具有不同的大小,因此在训练期间考虑这一点是有益的。这也可以被看作是通过尺度抖动来扩大训练集,其中单个模型被训练来识别大范围尺度上的对象。出于速度的原因,我们通过微调具有相同配置的单尺度模型的所有层来训练多尺度模型,预先训练固定的S=384。
精读
方法
对图片进行缩放后裁剪出224 × 224大小的图片,然后进行随机水平翻转和随机的RGB通道切换。
训练尺度S
训练用到的224 × 224的图片是从缩放后的原始图片中裁剪出来的,而缩放不仅仅可以缩小也可以放大,记图片缩放后的最短边的长度为S,也称为训练尺度(training scale)。
**S的取值:**当裁剪尺寸固定为224*224时,原则上S可以取不小于224的任何值:对于S=224来说,裁剪将会捕获整个的图像统计数据,将会完整横跨训练图像的最小边。对于S ≫ 224,裁剪将会对应于图像的一小部分,包括一个小对象或者对象的一部分。
有两种设置训练尺度S的办法
1、使用固定的S(单尺度的训练),本文使用了两种大小:256(应用于AlexNet,ZFNet,Sermanet)和384。
2、使用变化的S(多尺度的训练),给定一个S变化的范围[ Smin , Smax ](文章中使用的范围是[ 256 , 512 ] ),使其在这个范围中随机选值来缩放图片。
3.2Testing—测试
翻译
在测试时,给定一个训练好的ConvNet和一个输入图像,它按以下方式分类。首先,将其各向同性地重新缩放到预定义的最小图像侧,表示为Q(我们也将其称为测试比例)。我们注意到Q不一定等于训练尺度S(正如我们将在第4节中说明的那样,对每个S使用几个Q值可以提高性能)。然后,以类似于Sermanet等人的方式在重新缩放的测试图像上密集地应用网络(Sermanet等人,2014)。也就是说,首先将完全连通的层转换为卷积层(第一FC层转换为7×7卷积。层,最后两个FC层为1×1 Conv。层)。然后,将得到的完全卷积网络应用于整个(未裁剪)图像。结果是一个类分数图,其通道数等于类数,空间分辨率可变,具体取决于输入图像的大小。最后,为了获得图像的固定大小的班级分数向量,对班级分数地图进行空间平均(总和)。我们还通过水平翻转图像来扩充测试集;对原始图像和翻转图像的软最大类后验进行平均,以获得图像的最终分数。
由于全卷积网络应用于整个图像,因此不需要在测试时对多个作物进行采样(Krizhevsky等人,2012),这样效率较低,因为它需要为每个作物重新计算网络。同时,正如Szegedy等人所做的那样,使用了大量的作物。(2014),可以提高精度,因为与全卷积网络相比,它可以对输入图像进行更精细的采样。此外,由于不同的卷积边界条件,多作物评估与密集评估是互补的:当将卷积网络应用于作物时,卷积的特征地图用零填充,而在密集评估的情况下,相同作物的填充自然来自图像的相邻部分(由于卷积和空间汇集),这大大增加了整个网络接收区域,因此捕获了更多的上下文。虽然我们认为,在实践中,多作物计算时间的增加并不能证明在精度方面的潜在收益是合理的,但为了参考,我们也使用每尺度50种作物(5×5规则网格,2个翻转)来评估我们的网络,针对3个尺度上的150个作物,这与Szegedy等人使用的4个尺度上的144个作物相当。
精读
方法
将全连接层等效替换为卷积层进行测试
原因
卷积层和全连接层的唯一区别就是卷积层的神经元和输入是局部联系的,并且同一个通道(channel)内的不同神经元共享权值(weight)。卷积层和全连接层的计算实际上相同,因此可以将全连接层转换为卷积层。
**改造前:**假设网络是这样的 N个卷积 -> 全连接 -> 全连接。假如N个卷积之后的数据变成7x7x512 则此时展成向量变成 25088个元素的向量,通过一个4096神经元的全连接层 ,变成4096个元素的向量,再通过一个1000个神经元的全连接,最后输出1000个元素的向量。
(图片来自b站up主:同济子豪兄。下同)
**改造后:**当得到前面的数据 7x7x512之后,不将其展开成向量,而是直接送去有 4096 个 7×7卷积核的卷积层,对比改造之前看,其实就是将改造之前的全连接层里的4096个单神经元变成了 7×7的卷积核,参数依旧是等量的。同理,后面就变成了1000个1×1卷积核的卷积层(实际上论文中是三层全连接层,改为一个7x7卷积层和两个 1×1卷积层,他这里少画了一层1×1的卷积层)
目的
1.输入图像的大小不再受限制,因此可以高效地对图像作滑动窗式预测。
2.而且全连接层的计算量比较大,等效卷积层的计算量减小了,这样既达到了目的又十分高效。
3.3Implementation Details—实现细节
翻译
我们的实现源自公开可用的C++ Caffe工具箱(Jia,2013)(2013年12月扩展),但包含许多重大修改,允许我们在单个系统中安装的多个GPU上执行训练和评估,以及在多个比例(如上所述)的全尺寸(未裁剪)图像上进行训练和评估。多GPU训练利用数据并行性,通过将每批训练图像分成几个GPU批次来执行,这些批次在每个GPU上并行处理。在计算GPU批次梯度之后,对它们进行平均,以获得整个批次的梯度。所有GPU之间的渐变计算是同步的,因此结果与在单个GPU上训练时完全相同。
虽然最近提出了更复杂的加速ConvNet训练的方法(Krizhevsky,2014),这些方法针对网络的不同层使用模型和数据并行,但我们发现,与使用单个GPU相比,我们在概念上简单得多的方案已经在现成的4-GPU系统上提供了3.75倍的加速比。在配备了四个NVIDIA Titan Black GPU的系统上,根据架构的不同,训练一个网络需要2-3周时间。
精读
**1.多个GPU上训练:**实现使用的是基于C++的Caffe toolbox,并且还做了一系列的优化,可以在单个系统中安装的多个GPU上执行训练和评估,以及训练和评估多尺度的全尺寸(未裁剪)图像。
**2.分为多个GPU批次:**通过将每批训练图像分成几个GPU批次,在每个GPU上并行处理来进行,计算GPU批次梯度后,对它们进行平均可以获得完整批次的梯度。因此结果与在单个GPU上训练的结果是一样是的,但是可以节约很多时间。
**3.花费的时间:**该模型在配备有4个NVIDIA Titan Black GPU的机器上训练一个架构需要花费2-3周的时间
四、Classification Experiments—分类实验
4.1数据集:ILSVRC-2012
翻译
数据集 在本节中,将展示我们提出的卷积网络架构在ILSVRC-2012
数据集(用于ILSVRC2012-2014挑战)
上获得的图像分类结果。数据集包括1000个类的图像,并分为三组:训练(130万张图像)、验证(50K张图像)和测试(100K个保留类标签的图像)。分类性能通过两个指标进行评估: the top-1 and top-5 error
。前者是一种多类分类误差,即错误分类图像的比例;后者是ILSVRC
中使用的主要评价标准,并且计算图像gt 不在top-5 predicted categories
的比例。
对于大多数实验,我们使用验证集作为测试集。某些实验也在测试集上进行,并作为ILSVRC-2014竞赛的“VGG”团队参赛作品提交给官方。
精读
**分类:**这个数据集有1000个类,包含三个部分:训练集(1.3M),验证集(50K),测试集(100K),可以通过两个指标来评估准确率:top-1和 top-5误差。
top-1和 top-5误差
top-1误差:是一个多类分类误差,表示分类错误图片的比例(模型猜的最可能的结果就是正确答案的概率)
top-5误差:是竞赛评估的主要指标,表示了真实的类别不在预测到的概率最大的五个类别中的错误率(模型猜的前五个结果里面包涵正确答案的概率)
4.2Single Scale Evaluation—单尺度评价(测试角度)
翻译
我们首先用章节2.2中描述的网络配置在单一尺度上评估单个ConvNet模型的性能。.测试图像大小设置如下:Q=S,固定的S,Q=0.5(Smin+Smax),S∈[Smin,Smax]。结果如表3所示。首先,我们注意到使用局部响应归一化(A-LRN网络)在没有任何归一化层的改进模型A。因此,我们不在更深层次的架构中使用标准化(B-E)。
其次,我们观察到分类误差随着ConvNet深度的增加而减小:从A的11层减少到E的19层。值得注意的是,尽管有相同的深度,配置C(它包含三个1×1conv层),性能比配置D差,后者使用3×3conv。贯穿整个网络的图层。这表明,虽然额外的非线性确实有帮助(C比B好),但是通过使用大的卷积核的来捕获空间上下文也很重要。(D优于C)。当深度达到19层时,我们的体系结构的错误率达到饱和,但更深的模型可能有利于更大的数据集。我们还比较了B结构,在浅层把每对3×3conv换成1个5×5conv层(它有相同的感受野。)浅层网的前1误差比B((on a center crop)高7%,这证实了具有小滤波器的深网优于大滤波器的浅层网。
最后,在训练时的尺度变化(S∈[256;512])明显比训练固定最小边的图像(S=256或S=384),即使在测试时使用单一的尺度。这证实了通过尺度变化增强训练集确实有助于捕获多尺度图像统计数据。
精读
采用的方法
训练尺度S:(1)一种方法是固定S的大小
(2)另一种方法是从一定区间内随机取S(测试集记为Q)
**具体实现:**测试时所用的scale固定。这里把训练scale和测试的scale分别用S和Q表示。当S为固定值时,令Q=S固定;当S为[Smin,Smax]浮动时,Q固定为=0.5[Smin + Smax]。
结论
(对比表格放在翻译里了~)
1.测试发现A组和A-LRN组的top1和top5错误率几乎持平,LRN局部响应归一化并没有带来精度提升,故在A-LRN之后的B~E类VGG网络中,都没有使用。
2.变动的S比固定的S准确率高。在训练中,采用浮动尺度效果更好,因为这有助于学习分类目标在不同尺寸下的特征。
3.卷积网络越深,损失越小,效果越好。
4.C优于B,表明增加的非线性ReLU有效。
5.D优于C,表明卷积层3×3对于捕捉空间特征有帮助。
6.E深度达到19层后达到了损失的最低点,达到饱和,更深的层次对精度没有提升,但是对于其他更大型的数据集来说,可能更深的模型效果更好。
7.B和同类型卷积核为5×5的网络进行了对比,发现其top-1错误率比B高7%,表明小尺寸卷积核效果更好。
4.3Multi Scale Evaluation—多尺度评价(测试角度)
翻译
在单一尺度上评估了ConvNet模型之后,我们现在评估了测试时尺度抖动的影响。它包括在一个测试图像的几个重新缩放的版本(对应于不同的Q值)上运行一个模型,然后平均得到的类后验。考虑到训练量表和测试量表之间的很大差异会导致性能下降,用固定S训练的模型在三个测试图像大小上进行评估,接近训练一个:Q={S−32,S,S+32}。同时,训练时的尺度抖动允许网络在测试时应用于更广泛的尺度范围,因此使用变量S∈[Smin;Smax]训练的模型在更大的尺寸Q = Smin, 0.5(Smin+Smax) ,Smax范围内进行评估.
结果如表4所示,表明测试时的尺度抖动导致更好的性能(与在单一尺度上评价相同的模型相比,如表3所示)。与之前一样,最深的配置(D和E)表现最好,规模抖动比固定最小边训练更好。我们在验证集上的最佳单网络性能是24.8%/7.5%top1/top5错误(在表4中以粗体突出显示)。在测试集上,配置E达到了7.3%的前5名错误。
精读
方法
multi-scale表示测试时的scale不固定。这里当训练时的S固定时,Q取值是{S-32,S,S+32}这三个值,进行测试过后取平均结果。当S为[Smin,Smax]浮动时,Q取{Smin,0.5(Smin+Smax),Smax},测试后取平均。
结论
1.同single scale一样,模型越深,效果越好
2.同深度下,浮动scale效果好于固定scale
4.4Multi-Crop Evaluation—多剪裁评价(测试输入角度)
翻译
在表5中,我们比较了密集的ConvNet评价和Multi-Crop评价(见第二节。3.2的细节)。我们还通过平均它们的softmax输出来评估这两种评估技术的互补性。可以看出,使用Multi-Crop的性能略优于密集评估,而且这两种方法确实是互补的,因为它们的组合性能优于每一种方法。如上所述,我们假设这是由于对卷积边界条件的不同处理。
精读
dense evaluation 与multi-crop evaluation两种评估方法的区别
**①multi-crop:**即对图像进行多样本的随机裁剪,然后通过网络预测每一个样本的结构,最终对所有结果平均。GoogleNet中使用了很多multi-crop的技巧,可以显著提升精度,因为有更精细的采样。
**②dense :**就是在上章说的将全连接层都变成卷积网络的那种训练方式。
方法
在表5中我们比较了密集评估与多裁剪评估。我们还通过平均Softmax输出来评估两种评估技术的互补性。
结果
ConvNet评估技术对比。在所有的实验中训练尺度S是从[256; 512]中抽取的,3个测试尺度Q是从{256,384,512}中抽取的。
结论
1.使用multi-crop优于dense
2.这两种方法是互补的
3.multi-crop+dense方法结合的效果最好
4.5ConvNet Fusion—ConvNet融合
翻译
到目前为止,我们评估了各个ConvNet模型的性能。在这部分的实验中,我们通过平均它们的类后验来组合几个模型的输出。由于模型的互补性,这提高了性能,并在2012年 (Krizhevsky et al., 2012) and 2013 (Zeiler & Fergus, 2013; Sermanet et al., 2014).
结果如表6所示。到ILSVRC提交时,我们只训练了单尺度网络,以及多尺度模型D(通过只微调全连接的层,而不是所有的层)。7个网络的集成有7.3%的ILSVRC测试误差。提交后,我们只考虑了两个表现最好的多尺度模型(配置D和E)的集合,使用密集评估将测试误差降低到7.0%,使用密集和多作物联合评估将测试误差降低到6.8%。作为参考,我们表现最好的单个模型达到了7.1%的误差(模型E,表5)
精读
方法
到目前为止,我们只计算了一个ConvNet模型的性能。在实验部分,我们通过平均几个模型的soft-max类的后验概率来结合输出。由于模型之间的互补,这种方法提高了性能。
结果
结果展示在表6中。到ILSVRC提交的时间,我们仅仅训练了一个单一尺度的网络,和一个多尺度的模型D(仅仅通过微调了全连接层而不是所有层)。
结论
1.结合多个模型,最后的结果通过softmax平均再结合判断,由于模型之间的互补性质,这会提高他们的性能。
2.融合之后网络的错误率要比单个网络的错误率低0.几个百分点。
3.使用multi-crop+dense结合的方法会使得效果更佳。
4.6Comparision With The State of The Art—与最新技术的比较
(State of the art(SOTA)——当前最佳性能/技术/算法,论文中会经常看到)
翻译
最后,我们将我们的结果与表7中的最新技术水平进行了比较。在ILSVRC-2014挑战的分类任务中,我们的“VGG”团队使用7个模型的集合,以7.3%的测试误差获得了第二名。提交后,我们将使用2个模型的集合错误率降低到 6.8%。
从表7可以看出,我们非常深的ConvNets的表现明显优于上一代的模型,在ILSVRC-2012和ILSVRC-2013的比赛中取得了最好的效果。我们的结果也与分类任务获胜者(GoogLeNet with 6.7% error)
)具有竞争力,大大优于ILSVRC-2013获奖提交的clarfai,在使用外部训练数据达到11.2%,在没有训练数据的情况下达到11.7%。这是值得注意的,因为我们的最佳结果是通过结合两个模型——明显少于在大多数ILSVRC提交中使用的模型。在单网性能方面,我们的架构获得了最佳的结果(7.0%的测试错误),比单个GoogLeNet高出0.9%。值得注意的是,我们并没有背离LeCun等人(1989)的经典ConvNet架构,而是通过大幅增加深度而改进了它。
精读
这部分不重要,作者就是想说我们的模型就是强,你们是弟弟,即使第一名的Googlenet,我们也只和他们差一点点,在雷式对比法中甚至还强些~
五、Conclusion—结论
翻译
在这项工作中,我们评估了非常深的卷积网络(多达19个层)的大尺度图像分类。结果表明,表示深度有利于分类精度,并且可以使用传统的ConvNet大幅增加深度 挑战数据集上实现最先进的性能。在附录中,我们还展示了我们的模型可以很好地推广到广泛的任务和数据集,匹配或优于围绕较不深的图像表示构建的更复杂的识别管道。我们的研究结果再次证实了深度在视觉表征中的重要性。
精读
1.在这次的工作中,我们评估了大尺度图像分类汇总非常深的卷积神经网络的作用,他展示了模型的深度对于分类准确率的重要性。
2.同时在附录中,我们也展示了我们的模型更广范围的任务以及数据集上得到一个很好的泛化效果。
3.最后,我们的结论再一次证明了深度在视觉表征中的重要性
论文十问
Q1:论文试图解决什么问题?
本文研究了在大规模图像识别中,卷积网络深度对其识别精度的影响。
Q2:这是否是一个新的问题?
不算,因为它是在Alex模型基础上增加了深度。
Q3:这篇文章要验证一个什么科学假设?
证明使用更小的卷积核并且增加卷积神经网络的深度,可以更有效地提升模型的性能。
Q4:有哪些相关研究?如何归类?谁是这一课题在领域内值得关注的研究员?
AlexNet,都属于图像识别,提高精度的问题
Q5:论文中提到的解决方案之关键是什么?
1.用三个3×3的卷积核代替7×7的卷积核,有的FC层还用到了1×1的卷积核。以及2×2的池化层。
2.在更深的结构中没有用到LRN(推翻了Alex),避免了部分内存和计算的增加。
3.使用了密集型训练方法(全连接->卷积层),可适应各种尺寸的图片。
4.将图像分为多个GPU批次,在多个GPU上进行训练,节省了时间。
5.进行分类试验。
Q6:论文中的实验是如何设计的?
1.采用ImageNet2012数据集
2.Single Scale Evaluation—单尺度评价
3.Multi Scale Evaluation—多尺度评价
4.Multi Crop Evaluation—多剪裁评价
5.ConvNet Fusion—ConvNet融合
Q7:用于定量评估的数据集是什么?代码有没有开源?
ImageNet2012,代码有开源
Q8:论文中的实验及结果有没有很好地支持需要验证的科学假设?
论文实验结果在ILSVRC-2014挑战赛的分类任务中,我们的“VGG”团队使用7个模型的融合用7.3%的测试错误率达得到了第2。提交之后,我们使用2个模型的融合将错误率减少到了6.8%。足以证明增加深度对精度识别很重要。
Q9:这篇论文到底有什么贡献?
我们的主要贡献是使用具有非常小(3 ×3)卷积核的架构对于增加了深度的网络的全面评估,这表明将通过将深度推到16和19个权重层可以实现对现有技术配置的显著改进。
Q10:下一步呢?有什么工作可以继续深入?
1.VGG在Alex基础上将卷积核都替换为了1×1及3×3的小卷积核以减少参数计算量,虽然 VGG减少了卷积层参数,但实际上其参数空间比 Alex大,其中绝大多数的参数都是来自于第一个FC,耗费更多计算资源。
2.VGG模型比较简单,可以以它为基础进行改进。
VGG在深度学习的历史上是很有意义的,它的结构简单易懂,在当时仅次于大名鼎鼎的GoogLeNet,证明了神经网络更深表现会更好,最重要的是 VGG 向世人证明了更小的卷积核尺寸的重要性。 本篇VGG论文解读就到此为止了,欢迎大家留言交流呀~
解读二
2014年,牛津大学计算机视觉组(Visual Geometry Group)和Google DeepMind公司的研究员一起研发出了新的深度卷积神经网络:VGGNet,并取得了ILSVRC2014比赛分类项目的第二名(第一名是GoogLeNet,也是同年提出的)和定位项目的第一名。
VGGNet探索了卷积神经网络的深度与其性能之间的关系,成功地构筑了16~19层深的卷积神经网络,证明了增加网络的深度能够在一定程度上影响网络最终的性能,使错误率大幅下降,同时拓展性又很强,迁移到其它图片数据上的泛化性也非常好。到目前为止,VGG仍然被用来提取图像特征。
VGG的特点
先看一下VGG的结构图
VGG由5层卷积层、3层全连接层、softmax输出层构成,层与层之间使用max-pooling(最大化池)分开,所有隐层的激活单元都采用ReLU函数。
2、小卷积核和多卷积子层
VGG使用多个较小卷积核(3x3)的卷积层代替一个卷积核较大的卷积层,一方面可以减少参数,另一方面相当于进行了更多的非线性映射,可以增加网络的拟合/表达能力。
小卷积核是VGG的一个重要特点,虽然VGG是在模仿AlexNet的网络结构,但没有采用AlexNet中比较大的卷积核尺寸(如7x7),而是通过降低卷积核的大小(3x3),增加卷积子层数来达到同样的性能(VGG:从1到4卷积子层,AlexNet:1子层)。
VGG的作者认为两个3x3的卷积堆叠获得的感受野大小,相当一个5x5的卷积;而3个3x3卷积的堆叠(卷积核级联)获取到的感受野相当于一个7x7的卷积。这样可以增加非线性映射,也能很好地减少参数(例如7x7的参数为49个,而3个3x3的参数为27),如下图所示:
3、小池化核
相比AlexNet的3x3的池化核,VGG全部采用2x2的池化核。
4、通道数多
VGG网络第一层的通道数为64,后面每层都进行了翻倍,最多到512个通道,通道数的增加,使得更多的信息可以被提取出来。
5、层数更深、特征图更宽
由于卷积核专注于扩大通道数、池化专注于缩小宽和高,使得模型架构上更深更宽的同时,控制了计算量的增加规模。
VGG的网络结构
下图是来自论文《Very Deep Convolutional Networks for Large-Scale Image Recognition》(基于甚深层卷积网络的大规模图像识别)的VGG网络结构,正是在这篇论文中提出了VGG,如下图:
上图中,池化层都不算入层数中,例vgg-16为13个conv+3个FC组成。
在这篇论文中分别使用了A、A-LRN、B、C、D、E这6种网络结构进行测试,这6种网络结构相似,都是由5层卷积层、3层全连接层组成,其中区别在于每个卷积层的子层数量不同,从A至E依次增加(子层数量从1到4),总的网络深度从11层到19层(添加的层以粗体显示),表格中的卷积层参数表示为“conv⟨感受野大小⟩-通道数⟩”,例如con3-128,表示使用3x3的卷积核,通道数为128。为了简洁起见,在表格中不显示ReLU激活功能。
其中,网络结构D就是著名的VGG16,网络结构E就是著名的VGG19。
以网络结构D(VGG16)为例,介绍其处理过程如下,请对比上面的表格和下方这张图,留意图中的数字变化,有助于理解VGG16的处理过程:
整个input→output过程如下:
1、输入224x224x3的图片,经2个3x3的卷积核(out_channel=64)作两次卷积+ReLU,卷积后的尺寸变为224x224x64
2、作max pooling(最大化池化),池化单元尺寸为2x2(stride=2,根据特征图大小计算公式进行计算:https://blog.csdn.net/weixin_45829462/article/details/106581152(如下图),效果为图像尺寸减半),池化后的尺寸变为112x112x64
3、经2个3x3的卷积核(out_channel=128)作两次卷积+ReLU,尺寸变为112x112x128
4、作2x2的max pooling池化,尺寸变为56x56x128
5、经3个3x3的卷积核(out_channel=256)作三次卷积+ReLU,尺寸变为56x56x256
6、作2x2的max pooling池化,尺寸变为28x28x256
7、经3个3x3的卷积核(out_channel=512)作三次卷积+ReLU,尺寸变为28x28x512
8、作2x2的max pooling池化,尺寸变为14x14x512
9、经3个3x3的卷积核作三次卷积+ReLU,尺寸变为14x14x512
10、作2x2的max pooling池化,尺寸变为7x7x512
11、与两层1x1x4096,一层1x1x1000进行全连接+ReLU(共三层)
12、通过softmax输出1000个预测结果(softmax函数的作用是输出概率最大,也就是最有可能的那个类)
从上面的过程可以看出VGG网络结构还是挺简洁的,都是由小卷积核、小池化核、ReLU组合而成。其简化图如下(以VGG16为例):
但是,唯一不能忍受的是vgg产生的网络参数实在是太多了,且大部分都在全连接层,特别是第一个全连接层(标红部分),你难以能想象一个16层的模型产生的预训练权重就有500m之大(darknet53的53层神经也才200m左右)。
A、A-LRN、B、C、D、E这6种网络结构的深度虽然从11层增加至19层,但参数量变化不大,这是由于基本上都是采用了小卷积核(3x3,只有9个参数),这6种结构的参数数量(百万级)并未发生太大变化,这是因为在网络中,参数主要集中在全连接层。
经作者对A、A-LRN、B、C、D、E这6种网络结构进行单尺度的评估,错误率结果如下:
从上表可以看出:
1、LRN层无性能增益(A-LRN)
VGG作者通过网络A-LRN发现,AlexNet曾经用到的LRN层(local response normalization,局部响应归一化)并没有带来性能的提升,因此在其它组的网络中均没再出现LRN层。
2、随着深度增加,分类性能逐渐提高(A、B、C、D、E)
从11层的A到19层的E,网络深度增加对top1和top5的错误率下降很明显。
3、多个小卷积核比单个大卷积核性能好(B)
VGG作者做了实验用B和自己一个不在实验组里的较浅网络比较,较浅网络用conv5x5来代替B的两个conv3x3,结果显示多个小卷积核比单个大卷积核效果要好。
最后进行个小结:
1、通过增加深度能有效地提升性能;
2、最佳模型:VGG16,从头到尾只有3x3卷积与2x2池化,简洁优美;
3、卷积可代替全连接,可适应各种尺寸的图片
为什么要将全连接层转变为全卷积层?
作者将三个全连接层转成了1个7×7,和 2 个 1×1 的卷积层。从下图可以看到,以第一个全连接层为例,要转卷积层,FC6的输入是 7×7×512,输出是4096(也可以看做 1×1×4096),那么就要对输入在尺寸上(宽高)降维(从7×7 降到 1×1)和深度(channel 或者 depth)升维(从512 升到4096)。把7×7降到1×1,使用大小为 7×7的卷积核就好了,卷积核个数设置为4096,即卷积核为7×7×4096(下图中的[7×7×512]×4096 表示有 4096 个 [7×7×512] 这样的卷积核,7×7×4096 是简写形式忽略了输入的深度),经过对输入卷积就得到了最终的 1×1×4096 大小的 feature map。
为什么要在模型测试的时候将全连接层转变为全卷积层呢?最直接的原因是让网络模型可以接受任意大小的尺寸。
我们在前面介绍的时候限定了网络输入图片的尺寸是224x224x3。如果后面三个层都是全连接,遇到宽高大于224的图片就需要进行图片的剪裁、缩放或其它处理,使图片尺寸统一到224x224x3,才能符合后面全连接层的输入要求。但是,我们并不能保证每次裁剪都能将图片中的关键目标保留下来,可能裁剪去的部分恰好包含了目标,造成裁减丢失关键目标信息,影响模型的测试精度。
(输出是一个分类得分图,通道的数量和类别的数量相同,空间分辨率依赖于输入图像尺寸。最终为了得到固定尺寸的分类得分向量,将分类得分图进行空间平均化(求和——池化)。我们同样使用水平翻转来对测试集进行数据增强;在原始图像和翻转图像上的soft-max分类概率的平均值作为这幅图像的最终得分。)
使用全卷积层,即使图片尺寸大于224x224x3,最终经过softmax层得到的得分图就不是1x1x1000,例如是2x2x1000,这里的通道1000与类别的数量相同,空间分辨率2x2依赖于输入图像尺寸。然后将得分图进行空间平均化(求和池化),得到的还是1x1x1000。最后对1000个通道的得分进行比较,取较大值作为预测类别。
这样做的好处就是大大减少特征位置对分类带来的影响。
举个简单的例子:
从上图我们可以看出,猫在原图片中不同的位置,如果使用全连接层很容易使得剪裁之后的图片丢失关键目标。然而使用全卷积层,对原图片直接进行卷积,最终得分图经过求和池化后得到的得分都是1,即不管猫在图片的什么位置,都能判定这张图片中有猫,保证分类正确。保留原图,使用全卷积层,相当于猫在哪我不管,我只要猫,于是我让模型去把这个猫找到,实际就是把feature map整合成一个值,这个值大,就有猫,这个值小,那就可能没猫!和这个猫在图片哪里关系不大了,鲁棒性大大增强。
模型复现
下载数据集集
http://download.tensorflow.org/example_images/flower_photos.tgz
数据集处理
数据集下载后,解压到data_set文件夹,另外,新建sample,output,flower_data文件加夹,使用split_data将数据集分成训练集和验证集,比例在9:1之间,分好后的样本自动存入flower_data文件夹中,总的文件如下:
模型构建
建立model.py,构建神经网络:
import torch
import torch.nn as nn
class VGG(nn.Module):
def __init__(self, features, num_classes=1000, init_weights=True):
super(VGG, self).__init__()
self.features = features
self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
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),
)
if init_weights:
self._initialize_weights()
def forward(self, x):
x = self.features(x)
x = self.avgpool(x)
x = torch.flatten(x, 1)
x = self.classifier(x)
return x
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
if m.bias is not None:
nn.init.constant_(m.bias, 0)
elif isinstance(m, nn.BatchNorm2d):
nn.init.constant_(m.weight, 1)
nn.init.constant_(m.bias, 0)
elif isinstance(m, nn.Linear):
nn.init.normal_(m.weight, 0, 0.01)
nn.init.constant_(m.bias, 0)
def make_layers(cfg, batch_norm=False):
layers = []
in_channels = 3
for v in cfg:
if v == 'M':
layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
else:
conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
if batch_norm:
layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
else:
layers += [conv2d, nn.ReLU(inplace=True)]
in_channels = v
return nn.Sequential(*layers)
cfgs = {
'vgg11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
'vgg13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
'vgg16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
'vgg19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
}
def vgg(model_name="vgg16", **kwargs):
try:
cfg = cfgs[model_name]
except:
print("Warning: model number {} not in cfgs dict!".format(model_name))
exit(-1)
model = VGG(make_layers(cfg), **kwargs)
return model
采用的是迁移学习的训练方式,硬件设施允许的情况下,还是可以试试从零开始训练的:
import torch
import torch.nn as nn
from torchvision import transforms, datasets
import torch.optim as optim
from model import vgg
import os
import json
import time
import torchvision.models.vgg
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)
data_transform = {
"train": transforms.Compose([transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
"val": transforms.Compose([transforms.Resize((224, 224)), # cannot 224, must (224, 224)
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
data_root = os.path.abspath(os.path.join(os.getcwd(), "/content/gdrive/My Drive")) # get data root path
image_path = data_root + "/flower_data/" # flower data set path
train_dataset = datasets.ImageFolder(root=image_path + "/train",
transform=data_transform["train"])
train_num = len(train_dataset)
# {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}
flower_list = train_dataset.class_to_idx
cla_dict = dict((val, key) for key, val in flower_list.items())
# write dict into json file
json_str = json.dumps(cla_dict, indent=4)
with open('class_indices.json', 'w') as json_file:
json_file.write(json_str)
batch_size = 32
train_loader = torch.utils.data.DataLoader(train_dataset,
batch_size=batch_size, shuffle=True,
num_workers=0)
validate_dataset = datasets.ImageFolder(root=image_path + "/val",
transform=data_transform["val"])
val_num = len(validate_dataset)
validate_loader = torch.utils.data.DataLoader(validate_dataset,
batch_size=32, shuffle=True,
num_workers=0)
model_name = "vgg16"
net = vgg(model_name=model_name, init_weights=True)
# 加载预训练模型
model_weights_path = './vgg16.pth'
missing_keys, unexpected_keys = net.load_state_dict(torch.load(model_weights_path), strict=False)
net.to(device)
loss_function = nn.CrossEntropyLoss()
# pata = list(net.parameters())
optimizer = optim.Adam(net.parameters(), lr=0.0002)
if __name__ == '__main__':
save_path = './vgg.pth'
best_acc = 0.0
for epoch in range(20):
# train
net.train()
running_loss = 0.0
t1 = time.perf_counter()
for step, data in enumerate(train_loader, start=0):
images, labels = data
images = images.to(device)
labels = labels.to(device)
optimizer.zero_grad()
outputs = net(images)
loss = loss_function(outputs, labels)
loss.backward()
optimizer.step()
# print statistics
running_loss += loss.item()
# print train process
rate = (step + 1) / len(train_loader)
a = "*" * int(rate * 50)
b = "." * int((1 - rate) * 50)
print("\rtrain loss: {:^3.0f}%[{}->{}]{:.3f}".format(int(rate * 100), a, b, loss), end="")
print()
print(time.perf_counter() - t1)
# validate
net.eval()
acc = 0.0 # accumulate accurate number / epoch
with torch.no_grad():
for val_data in validate_loader:
val_images, val_labels = val_data
outputs = net(val_images.to(device))
predict_y = torch.max(outputs, dim=1)[1]
acc += (predict_y == val_labels.to(device)).sum().item()
val_accurate = acc / val_num
if val_accurate > best_acc:
best_acc = val_accurate
torch.save(net.state_dict(), save_path)
print('[epoch %d] train_loss: %.3f test_accuracy: %.3f' %
(epoch + 1, running_loss / step, val_accurate))
print('Finished Training')
加载预训练模型关键代码:
model_weights_path = ‘./vgg16.pth’ missing_keys, unexpected_keys = net.load_state_dict(torch.load(model_weights_path),
3.4 结果如下:
可以看到,使用了预训练模型,网络收敛非常的快,,随着迭代次数的增加,精度也在不断的上升,检测后的结果保存在了output文件夹,检测效果如下: