第一章 AlexNet网络详解

系列文章目录

第一章 AlexNet网络详解

第二章 VGG网络详解

第三章 GoogLeNet网络详解 

第四章 ResNet网络详解 

第五章 ResNeXt网络详解 

第六章 MobileNetv1网络详解 

第七章 MobileNetv2网络详解 

第八章 MobileNetv3网络详解 

第九章 ShuffleNetv1网络详解 

第十章 ShuffleNetv2网络详解 

第十一章 EfficientNetv1网络详解 

第十二章 EfficientNetv2网络详解 

第十三章 Transformer注意力机制

第十四章 Vision Transformer网络详解 

第十五章 Swin-Transformer网络详解 

第十六章 ConvNeXt网络详解 

第十七章 RepVGG网络详解 

第十八章 MobileViT网络详解 


文章目录

  • AlexNet
  • 0. 前言
  • 1. 摘要
  • 2. AlexNet网络架构
    • 1.AlexNet_Model.py(pytorch实现)
    • 2.
  • 总结


0、前言

1.这篇论文讨论了通过深度卷积神经网络对大规模图像数据进行分类问题。

2.该论文的研究背景是有关图像分类问题,先前的方法存在问题,因此需要诞生新的研究方法。

3.该论文的主要观点是建立了一个大型深度卷积神经网络,能够将图像分类任务的错误率显著提高。

4.先前的研究方法主要是浅层的神经网络模型,以及传统方法如手工设计特征等,这些方法缺乏对于大尺寸数据的适应性和准确性不高的问题。

5.该论文提出了一个深度卷积神经网络模型进行图像分类任务,采用非饱和神经元、子采样和dropout等技巧以提高模型的性能和训练效率。

6.研究的发现表明,该深度卷积神经网络模型能够有效地提高图像分类任务的准确性,但研究的局限性在于其不适用于其他领域的数据集。


1、摘要

        我们训练了一个大规模、深度的卷积神经网络,将ImageNet LSVRC-2010竞赛中的120万张高分辨率图像分类为1000个不同类别。在测试数据上,我们取得了37.5%的top-1误差率和17.0%的top-5误差率,这比之前的最先进技术要好得多。该神经网络有6000万参数和65万个神经元,由五个卷积层和一些最大池层以及三个完全连接层和一个最终的1000路softmax组成。为了加速训练,我们采用了非饱和神经元和非常高效的GPU实现卷积操作。为了减少完全连接层的过拟合,我们采用了一个最近开发的正则化方法,称为“dropout”,证明非常有效。我们还参加了ILSVRC-2012比赛,并取得了15.3%的获胜top-5测试误差率,相比第二名的26.2%要好得多。

2、AlexNet网络结构

AlexNet是在ImageNet Large Scale Visual Recognition Challenge(ILSVRC)比赛中取得大胜的深度卷积神经网络,于2012年由Alex Krizhevsky等人提出。AlexNet是一个8层的卷积神经网络,它的结构如下所示: 输入图像尺寸为224×224,第一层是一个卷积层,使用96个大小为11×11的滤波器提取特征。在此之后,使用ReLU激活函数进行非线性变换,并使用局部响应归一化(LRN)方法进行特征增强。接下来,使用步长为2的2×2最大池化进行下采样。第二层和第三层都是卷积层,分别使用256和384个滤波器,滤波器的大小为5×5。使用ReLU激活函数进行非线性变换。第四层是一个具有256个滤波器的卷积层,大小为3×3。之后再次使用ReLU激活函数进行非线性变换。第五层是一个具有256个滤波器的卷积层,大小为3×3。和前面一样,再次使用ReLU激活函数进行非线性变换。最后使用2×2最大池化进行下采样。 在卷积层和池化层之后,网络连接了三个全连接层。这三个全连接层分别包含4096,4096和1000个神经元。最后一层包含1000个神经元,代表1000个ImageNet类别的预测概率。网络最后使用softmax函数输出预测值。

 该网络的创新点在于:

(1)首次利用GPU进行网络加速训练。

(2)使用了ReLU激活函数代替传统的Sigmoid以及Tanh激活函数。

(3)使用LRN(Local Response Normalization)局部响应归一化。

        LRN局部相应归一化的全称是Local Response Normalization,意为局部响应归一化。它是一种常用的神经网络正则化技术,用于减少过拟合,提高模型的泛化能力。具体来说,LRN会对每个神经元的输出进行归一化,使得神经元的输出值受到相邻神经元的影响程度降低,从而增强了模型的鲁棒性和泛化能力。 在具体实现中,LRN会对每个神经元的输出进行归一化。

b^{^{i}}x,y = a^{^{i}}x,y / (k + \alpha \sum_{min(N-1,i+n/2)}^{j=max(0,i-n/2)}( a^{^{i}}x,y )^{^{2}})^{\beta }

(4) 在全连接层的前两层使用了Dropout随机失活神经元操作以减少过拟合。

ReLU: f(x) = max(0,x) \\ \\ Leaky \: ReLU: f(x) = \left\{\begin{matrix} x \quad \;\;if \; x > 0 & \\ \lambda x \quad if \; x \leqslant 0 \end{matrix}\right.\\ \\ \\ SiLU: f(x) = x*sigmoid(x)\\ \\ Sigmoid: S(x) = \frac{1}{1 + e^{-x}} \\ \\ tanh: tanh(x) = \frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}

过拟合:根本原因是特征维度过多,模型假设过于复杂,参数过多,训练数据过少,噪声过多,导致拟合的参数完美的预测训练集,但对新数据的测试集预测结果差,过度的拟合了训练数据,而没有考虑到泛化能力。

 

经过卷积后的矩阵尺寸大小计算公式为: N = (W - F+2P)/S+1

3.正文分析

目前物体识别的方法重要使用了机器学习方法。为了提高它们的性能,我们可以收集更大的数据集,学习更强大的模型,并使用更好的防止过拟合的技术。直到最近,带标记的图像数据集相对较小,大约只有数万张图像(例如NORB [16],Caltech-101 / 256 [8,9]和CIFAR-10 / 100 [12])。对于这样大小的数据集,简单的识别任务可以得到很好的解决,特别是如果它们与保持标签的转换进行了增强。例如,MNIST数字识别任务的当前最佳误差率(<0.3%)接近人类表现 [4]。但是,现实设置中的物体具有相当大的变异性,因此为了学习认识它们,需要使用更大的训练集。事实上,小图像数据集的缺点已经被广泛认识(例如,Pinto等人[21]),但直到最近才有可能收集包含数百万张图像的标记数据集。新的大型数据集包括LabelMe [23],其中包括数十万张完全分割的图像,以及ImageNet [6],其中包括超过22,000个类别中超过1500万个标记的高分辨率图像。为了从数百万张图像中学习数千个物体,我们需要具有大学习能力的模型。然而,物体识别任务的巨大复杂性意味着即使ImageNet数据集的规模也无法完整表达,因此我们的模型还应具有很多先验知识以弥补我们没有的所有数据。卷积神经网络(CNN)是这类模型之一[16,11,13,18,15,22,26]。通过改变它们的深度和宽度,它们的容量可以得到控制,并且它们也对图像的特性进行了强大且大多正确的假设(即统计学的稳定性和像素相关性的局部性)。因此,与具有相似大小的层的标准前馈神经网络相比,CNN具有更少的连接。

尽管CNN具有吸引人的特点,而且它们的局部架构相对高效,但在大规模高分辨率图像的应用中,它们仍然是代价高昂的。幸运的是,当前的GPU,配合高度优化的二维卷积实现,足以支持对大型CNN的训练。最近的数据集ImageNet包含足够的标记示例,可以在不严重过度拟合的情况下训练这些模型。本文的具体贡献如下:我们在ILSVRC-2010和ILSVRC-2012比赛中使用ImageNet子集之一所使用的最大卷积神经网络之一上进行了训练,取得了迄今为止这些数据集上报告的最佳结果。我们编写了高度优化的GPU实现二维卷积和训练卷积神经网络中所有其他操作,并将其公开1。我们的网络包含许多新的和不寻常的特性,可以提高其性能并减少其训练时间,这些特性在第3节中详细说明。我们的网络大小使过拟合成为一个重要的问题,即使使用了120万个标记的训练示例,因此我们使用了几种有效的技术来防止过拟合,这些技术在第4节中描述。我们最终的网络包含五个卷积层和三个全连接层,而这个深度似乎很重要:我们发现删除任何卷积层(每个卷积层最多包含模型参数的1%)都会导致表现较差。最后,网络的大小主要受到当今GPU可用的内存量和我们愿意承受的训练时间的限制。我们的网络需要在两个GTX 580 3GB GPU上训练五到六天。我们所有的实验都表明,我们的结果可以通过等待更快的GPU和更大的数据集变得更好。

2.数据集ImageNet

是一个包含超过1,500万张高分辨率标注图像,属于约22,000个类别的数据集。这些图像是从Web上收集并使用Amazon的Mechanical Turk众包工具由人工标注器标注。从2010年开始,作为帕斯卡视觉对象挑战(Pascal Visual Object Challenge)的一部分,每年都会举行一项名为ImageNet Large-Scale Visual Recognition Challenge (ILSVRC)的比赛。ILSVRC使用ImageNet的子集,每个子集包含大约1000张图像和1000个类别。总共有大约1.2百万张训练图像,5万张验证图像和15万张测试图像。ILSVRC-2010是唯一一个测试集标签可用的版本,所以这是我们进行大多数实验的版本。由于我们还参加了ILSVRC-2012比赛,所以在第6节中,我们也会报告我们在这个数据集版本上的结果,但测试集标签是不可用的。在ImageNet上,通常报告两个错误率: top-1和top-5,其中top-5错误率是模型认为前五个最可能的标签中未包含正确标签的测试图像的比例。ImageNet由可变分辨率的图像组成,而我们的系统需要一个固定的输入尺寸。因此,我们将图像下采样到256×256的固定分辨率。给定一个矩形图像,我们首先将图像缩放,使较短的一侧长度为256,然后从结果图像中裁剪出中心的256 x 256补丁。除了从每个像素中减去训练集的平均活动之外,我们没有以其他方式对图像进行前期处理。因此,我们训练了我们的网络模型,基于(中心化的)原始RGB像素值。

我们网络的架构如图2所示,它包含8个学习层,其中包括5个卷积层和3个全连接层。下面,我们将描述一些网络架构中新颖或不寻常的特点。3.1-3.4部分按优先级排序,最重要的首先进行介绍。

神经元的输出f作为其输入x的函数的标准方法是f(x)=tanh(x)或f(x)=(1 + e^(-x)) ^ (-1)。在用梯度下降进行训练时,这些饱和非线性要比非饱和非线性f(x)=max(0;x)慢得多。根据Nair和Hinton [20]的方法,我们将具有这种非线性的神经元称为修正线性单元ReLU。使用ReLU的深度卷积神经网络的训练速度比使用tanh单位的网络快几倍。如图1所示,该图显示了达到CIFAR-10数据集上的25%训练误差所需的迭代次数,这证明了我们如果使用传统的饱和神经元模型就无法对这样的大神经网络进行实验。我们并不是第一个考虑CNN中传统神经元模型替代方案的人。例如,Jarrett等人[11]声称非线性函数f(x)=jtanh(x)j在他们的对比度归一化后跟随局部均值池的类型上在Caltech-101数据集上表现特别好。但是,在这个数据集上,主要关注的是防止过拟合,因此他们观察到的效果与我们使用ReLU时报告的加速适应训练集的能力是不同的。更快的学习速度对于在大数据集上训练的大型模型的性能具有很大影响。

(图1:一个具有ReLU的四层卷积神经网络(实线)在CIFAR-10数据集上的训练误差率比等效具有tanh神经元的网络(虚线)快了六倍,误差率达到了25%。每个网络的学习率都是独立选择的,以使训练尽可能快。没有使用任何形式的正则化。这里展示的效应大小因网络架构而异,但是具有ReLUs的网络始终比具有饱和神经元的等效网络快几倍) 

一张单独的GTX 580 GPU只有3GB的内存,这限制了可以在其上训练的网络最大尺寸。结果发现,120万个训练样本足以训练超过一个GPU容量的大型网络。因此,我们将网络跨越两个GPU。当前的GPU非常适合跨GPU并行计算,因为它们能够直接从彼此的内存中读取和写入数据,而不需要经过主机内存。我们采用的并行化方案实际上是将卷积层(或神经元)的一半放在每个GPU上,还有一个额外的技巧:GPU只在某些层之间进行通信。这意味着,例如,第3层的卷积核会从第2层的所有卷积核图中提取输入。然而,第4层的卷积核只从同一GPU上的第3层卷积核图中提取输入。选择连接模式是交叉验证的一个问题,但这使我们能够精确调整通信量,直到它成为计算量的可接受比例。结果的架构与Cire¸san等人使用的“柱状”CNN有些相似,不同之处在于我们的柱子不是独立的(见图2)。与在一个GPU上训练卷积层内核数为其一半的网络相比,这个方案将我们的top-1和top-5错误率分别降低了1.7%和1.2%。两个GPU的网络训练时间略短于一个GPU的网络。

3.3 本地响应归一化 ReLU拥有一个良好的性质,即它们不需要输入归一化来防止它们失活。只要有一些训练样例产生ReLU的正输入,那么该神经元就会学习。然而,我们仍然发现以下本地归一化方案有助于泛化。用ai x;y表示通过在位置(x;y)应用核i并应用ReLU非线性计算神经元的活动,那么归一化的响应双ai x;y是由下式给出的bi x;y = ai x;y / ( k +α* Σj=max(0, N-1,i-n/2; i+n/2) (aj x;y)^2 )^β,其中总和运行在相同空间位置的n个“相邻”核图上,N是该层中核数的总数。核映射的排序在训练开始之前是任意确定的,这种响应归一化实现了一种侧抑制的形式,受到真实神经元中发现的类型的启发,通过不同内核计算的神经元输出之间的大活动来创造竞争。常数k,n,α和β是超参数,其值使用验证集确定;我们使用k=2,n=5,α=10^-4和β=0.75。我们在某些层应用了ReLU非线性后进行了此归一化方法(参见第3.5节)。这种方法与Jarrett等人提出的本地对比度归一化方案有一些相似之处,但我们更准确地使用“亮度归一化”来描述它,因为我们不减去平均活动。响应归一化将我们的top-1和top-5错误率分别降低了1.4%和1.2%。我们还验证了这种方案对于CIFAR-10数据集的有效性,四层卷积神经网络在没有归一化的情况下实现了13%的测试误差率,在归一化之后错误率为11%。

在CNN中,3.4重叠汇聚是指将同一卷积核地图中邻近的神经元组输出汇总。传统上,相邻汇聚单元汇总的邻域不重叠(例如[17,11,4])。更准确地说,可以将汇聚层视为由网格池单元组成,距离为s像素,每个汇总大小为z×z的邻域,位于池单元的位置。如果我们设置s = z,则获得常用于CNN的传统本地汇聚。如果我们设置 s < z,则获得重叠汇聚。我们在整个网络中使用此方案,其中s = 2和z = 3。与输出等效尺寸的非重叠方案s = 2; z = 2相比,此方案将top-1和top-5错误率分别降低了0.4%和0.3%。我们通常在训练期间观察到,使用重叠汇聚的模型稍微更难过度拟合。

现在我们准备描述我们CNN的总体架构。如图2所示,网络包含具有权重的8个层,前5个是卷积层,剩下的3个是全连接层。最后一个全连接层的输出被送到一个1000路softmax,产生1000个类标签的分布。我们的网络最大化多项式逻辑回归目标,这等价于最大化在预测分布下对于正确标签的对数概率的平均训练实例。第二、第四和第五个卷积层的卷积核仅连接到上一层在同一GPU上的卷积核映射 (见图2)。第三个卷积层的卷积核连接到第二层的所有卷积核映射。全连接层中的神经元连接到前一层的所有神经元。响应规范化层跟随第一和第二个卷积层。最大池化层,在第三个卷积层以及第五个卷积层之后,都遵循第一和第二个响应规范化层。ReLU非线性函数应用到每个卷积和全连接层的输出。第一个卷积层使用大小为11 x 11 x 3的96个卷积核和4像素步长(相邻神经元在卷积核映射中的感受域中心之间的距离)过滤224×224×3的输入图像。第二个卷积层将第一个卷积层的(响应规范化和池化后的)输出作为输入,并使用大小为5 x 5 x 48的256个卷积核进行过滤。第三、第四和第五个卷积层之间没有任何插入池化或规范化层。第三个卷积层有384个大小为3 x 3 x 256的卷积核,连接到第二个卷积层的(规范化、池化)输出。第四个卷积层有384个3 x 3 x 192个卷积核,第五个卷积层有256个3 x 3 x 192个卷积核,连接到第四个卷积层的输出。

我们的神经网络结构有6000万个参数。虽然ILSVRC的1000个类使得每个训练示例对从图像到标签的映射施加10位约束,但这还不足以在没有相当程度过拟合的情况下学习这么多参数。下面,我们将描述我们对抗过拟合的两种主要方法。

我们计算增广数据的方法与常见且最简单的方法相同,就是使用标签保留的转换来人工扩大数据集。我们采用两种不同的数据增广形式,这两种形式都可以从原始图像中生成经过变换的图像,并且计算量非常小,因此变换后的图像不需要存储在磁盘上。在我们的实现中,变换后的图像是在CPU上的Python代码中生成的,而GPU则在训练之前的图像批次上进行训练。因此,这些数据增广方案实际上是计算自由的。 第一种数据增广形式包括生成图像的平移和水平翻转。我们通过从256×256图像中提取随机的224×224补丁(以及它们的水平翻转)来实现这一点,并在这些提取的补丁上训练我们的网络。这将我们的训练集的尺寸增加了2048倍,尽管结果训练样例高度相互依赖。如果没有这个方案,我们的网络将会遭受严重的过拟合,这将迫使我们使用更小的网络。在测试时,网络通过提取五个224×224补丁(四个角落的补丁和中心补丁)以及它们的水平翻转(因此总共有十个补丁),并对网络的softmax层在十个补丁上做出的预测进行平均,从而进行预测。 第二种数据增广形式是改变训练图像的RGB通道强度。具体地,我们在ImageNet训练集的RGB像素值集合上执行PCA。对于每个训练图像,我们添加多个发现的主成分,其大小与相应的特征值乘以从均值为零、标准差为0.1的高斯分布中绘制的随机变量成比例。因此,对于每个RGB图像像素Ixy =[Ixy R ;Ixy G ;Ixy B ]T,我们添加以下数量:[p1;p2;p3][α1λ1;α2λ2;α3λ3]T,其中π和λi是它们的特征向量和特征值。

4.2 Dropout组合许多不同模型的预测是减少测试误差的非常成功的方法[1,3],但它对于需要几天时间来进行的大型神经网络来说似乎过于昂贵。但是,有一种非常有效的模型组合版本,它在训练期间只需花费约两倍的成本。最近引入的“dropout”[10]技术由于设定每个隐藏神经元的输出为0.5的概率而组成。以这种方式进行“辍学”的神经元不参与向前传播并且不参与反向传播。因此,每次提供输入时,神经网络会对不同的体系结构进行采样,但所有这些体系结构共享权重。此技术降低了神经元的复杂协同作用,因为神经元不能依赖特定的其他神经元的存在。因此,它被迫学习更具有鲁棒性的功能,这些功能与许多不同的其他神经元的随机子集一起使用是有用的。在测试时间,我们使用所有的神经元,但将它们的输出乘以0.5,这是产生指数多的辍学网络所产生的预测分布的几何均值的合理近似。我们在图2的前两个完全连接的层中使用丢失技术。在没有丢失的情况下,我们的网络表现出相当严重的过拟合。丢失技术大约需要两倍的迭代次数才能收敛。

我们使用了批量大小为128示例、动量为0.9和权重衰减为0.0005的随机梯度下降方法来训练模型。我们发现,这个小量的权重衰减对模型学习非常重要。换句话说,在这里,权重衰减不仅仅是一个正则化器:它可以降低模型的训练误差。权重w的更新规则是:vi+1 :=0:9 ·vi −0:0005 ··wi −·@w @L wiDi wi+1 :=wi +vi+1,其中i是迭代指数,v是动量变量,是学习率,D@w @L wiEDi是在wi处评估的目标函数关于w的导数取第i批次Di的平均值。我们从标准差为0.01的零均值高斯分布中初始化每个层中的权重。我们使用常数1来初始化第二、第四和第五个卷积层以及完全连接的隐藏层中的神经元偏置,以加速提供正输入的ReLU的早期学习。我们使用常数0来初始化其余层的神经元偏置。我们对所有层使用相同的学习率,这个学习率在训练期间手动调节。我们遵循的启发式方法是,当验证误差率停止以当前学习率改善时,将学习率除以10。学习率的初始值为0.01,在终止之前减小了三次。我们训练了大约90个周期,覆盖了120万张图像的训练集,花费了两个NVIDIA GTX 580 3GB GPU五到六天的时间。

 

 我们在ILSVRC-2010的结果总结如表1所示。我们的网络在测试集中实现了top-1和top-5的误差率分别为37.5%和17.0%。在ILSVRC-2010竞赛中,最好的表现是使用在不同特征上训练的六个稀疏编码模型的平均预测[2],其误差率为47.1%和28.2%,并且从那以后最佳发表结果是使用在两种密集采样特征上计算的Fisher向量(FVs)的两个分类器的预测[24]的平均值为45.7%和25.7%。模型 Top-1 Top-5 稀疏编码 [2] 47.1% 28.2% SIFT + FVs [24] 45.7% 25.7% CNN 37.5% 17.0% 表格1:ILSVRC-2010测试集结果比较。其他最佳结果以斜体显示。我们还参加了ILSVRC-2012竞赛并在表2中报告我们的结果。由于ILSVRC-2012测试集标签不公开,我们无法报告我们尝试的所有模型的测试误差率。在本段剩余部分,我们可以互换使用验证和测试误差率,因为根据我们的经验,它们之间的差异不超过0.1%(请参见表2)。本文所描述的CNN实现了18.2%的top-5误差率。将五个类似的CNN的预测平均值给出了16.4%的误差率。训练一个CNN,其中一个额外的六个卷积层位于最后的池化层上,以对ImageNet Fall 2011发布(15M图像,22K类别)进行分类,然后在ILSVRC-2012上进行“微调”,其误差率为16.6%。将预先在整个Fall 2011版本上训练的两个CNN的预测与上述五个CNN的平均值进行平均可获得15.3%的误差率。第二佳竞赛录取使用从不同类型的密集采样特征计算的FVs训练的几个分类器的预测[7],其误差率为26.2%。 模型 Top-1(val) Top-5(val) Top-5(test) SIFT + FVs [7] —— 26.2% 1 CNN 40.7% 18.2% — 5 CNNs 38.1% 16.4% 16.4% 1 CNN* 39.0% 16.6% — 7 CNNs* 36.7% 15.4% 15.3%

图3展示了网络的两个数据连接层学习到的卷积核。网络已经学习到了各种频率和方向选择性的核和各种有色斑点。注意到GPU 1和GPU 2展示出的专业化是3.5节中所描述的受限连接的结果。GPU 1上的核基本上不与颜色有关,而GPU 2上的核主要与颜色有关。这种专业化发生在每次运行时,与任何特定的随机权重初始化无关(除了GPU重排)。在图4的左面板中,我们通过计算八个测试图像的前五个预测来定性评估网络的学习成果。注意,甚至可以识别偏离中心的物体,比如左上角的小沙尘螨。大多数前五个标签都是合理的。例如,只有其他类型的猫被认为是豹的可能标签。在某些情况下(烤架、樱桃)对于照片的重点有真正的歧义。另一种探测网络视觉知识的方法是考虑最后一个4096维隐藏层对图像引起的特征激活。如果两个图像产生具有小欧氏距离的特征激活向量,则我们可以说神经网络的高层认为它们相似。图4显示了测试集中的五个图像以及根据此度量距离它们最相似的六个训练集图像。请注意,在像素级别上,检索的训练图像通常与第一列的查询图像不接近。例如,所检索的狗和大象出现在各种姿势中。我们在补充材料中展示了更多测试图像的结果。使用两个4096维的实值向量之间的欧几里得距离计算相似性是低效的,但通过训练自动编码器将这些向量压缩到更小的维度可以使其变得高效。

 

1.AlexNet_Model.py(pytorch实现)

import torch.nn as nn
import torch

class AlexNet(nn.Module):
    def __init__(self,num_classes=1000,init_weights=False):
        super(AlexNet, self).__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(48, 128, kernel_size=5, stride=1, padding=2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3, stride=2),
            nn.Conv2d(128, 192, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 192, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(192, 128, kernel_size=3, stride=1, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size=3,stride=2)
        )
        self.classifier = nn.Sequential(
            nn.Dropout(p=0.5),
            nn.Linear(128*6*6, 2048),
            nn.ReLU(inplace=True),
            nn.Dropout(p=0.5),
            nn.Linear(2048, 2048),
            nn.ReLU(inplace=True),
            nn.Linear(2048, num_classes)
        )
        if init_weights:
            self._initialize_weights()

    def forward(self, x):
        x = self.features(x)
        x = torch.flatten(x, start_dim=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.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)

2.train.py

import os
import sys
import json
import torch
import torch.nn as nn
from torchvision import transforms, datasets, utils
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
from tqdm import tqdm
from model import AlexNet

def main():
    device = torch.device("cuda:0" if torch.cuda.is_available() else 'cpu')
    print("using {} device.".format(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)),
                                   transforms.ToTensor(),
                                   transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
    data_root = 'D:/100_DataSets/'
    image_path = os.path.join(data_root, "03_flower_data")
    assert os.path.exists(image_path), "{} path does not exits.".format(image_path)
    train_dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"),transform = data_transform['train'])
    train_num = len(train_dataset)
    flower_list = train_dataset.class_to_idx
    cla_dict = dict((val, key) for key, val in flower_list.items())
    json_str = json.dumps(cla_dict, indent=4)
    with open('class_indices.json', 'w') as json_file:
        json_file.write(json_str)
    batch_size = 6
    nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8])
    print('Using {} dataloder workers every process'.format(nw))
    train_loader = torch.utils.data.DataLoader(train_dataset,
                                             batch_size=batch_size,
                                             shuffle=True,
                                             num_workers=nw)
    validate_dataset = datasets.ImageFolder(root=os.path.join(image_path, "val"),
                                            transform=data_transform['val'])
    val_num = len(validate_dataset)
    validate_loader = torch.utils.data.DataLoader(validate_dataset,
                                                 batch_size=4,
                                                 shuffle=False,
                                                 num_workers=nw)
    print("using {} image for train, {} images for validation.".format(train_num, val_num))
    net = AlexNet(num_classes=5, init_weights=True)
    net.to(device)
    loss_fuction = nn.CrossEntropyLoss()
    optimizer = optim.Adam(net.parameters(), lr=0.0002)
    epochs = 10
    save_path = './AlexNet.pth'
    best_acc = 0.0
    train_steps = len(train_loader)
    for epoch in range(epochs):
        net.train()
        running_loss = 0.0
        train_bar = tqdm(train_loader, file=sys.stdout)
        for step, data in enumerate(train_bar):
            images, labels = data
            optimizer.zero_grad()
            outputs = net(images.to(device))
            loss = loss_fuction(outputs, labels.to(device))
            loss.backward()
            optimizer.step()
            running_loss += loss.item()
            train_bar.desc = "train epoch[{}/{}] loss:{:,.3f}".format(epoch+1, epochs, loss)
        net.eval()
        acc = 0.0
        with torch.no_grad():
            val_bar = tqdm(validate_loader, file=sys.stdout)
            for val_data in val_bar:
                val_images, val_labels = val_data
                outputs = net(val_images.to(device))
                predict_y = torch.max(outputs, dim=1)[1]
                acc += torch.eq(predict_y, val_labels.to(device)).sum().item()
        val_accurate = acc / val_num
        print('[epoch % d] train_loss: %.3f val_accuracy: %.3f' %
              (epoch+1, running_loss / train_steps, val_accurate))
        if val_accurate > best_acc:
            best_acc = val_accurate
            torch.save(net.state_dict(),save_path)
    print("Finished Training")

if __name__ == '__main__':
    main()






3.predict.py

import os
import json
import torch
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as plt
from model import AlexNet

def main():
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    data_transform = transforms.Compose(
        [transforms.Resize((224, 224)),
         transforms.ToTensor(),
         transforms.Normalize((0.5, 0.5, 0.5),(0.5, 0.5, 0.5))]
    )
    img_path = "D:/20_Models/01_AlexNet_pytorch/image_predict/tulip.jpg"
    assert os.path.exists(img_path), "file: '{}' does not exist.".format(img_path)
    img = Image.open(img_path)
    plt.imshow(img)
    img = data_transform(img)
    img = torch.unsqueeze(img, dim=0)
    json_path = './class_indices.json'
    assert os.path.exists(json_path), "file: '{}' does not exist.".format(json_path)
    with open(json_path,"r") as f:
        class_indict = json.load(f)
    model = AlexNet(num_classes=5).to(device)
    weights_path = "./AlexNet.pth"
    assert os.path.exists(weights_path), "file: '{}' does not exist.".format(weights_path)
    model.load_state_dict(torch.load(weights_path))
    model.eval()
    with torch.no_grad():
        output = torch.squeeze(model(img.to(device))).cpu()
        predict = torch.softmax(output, dim=0)
        predict_cla = torch.argmax(predict).numpy()
    print_res = "class: {} prob: {:.3f}".format(class_indict[str(predict_cla)],
                                                predict[predict_cla].numpy())
    plt.title(print_res)
    for i in range(len(predict)):
        print("class: {:10} prob: {:.3}".format(class_indict[str(i)],predict[i].numpy()))
    plt.show()

if __name__ == '__main__':
    main()

4.predict.py

import os
from shutil import copy, rmtree
import random

def mk_file(file_path: str):
    if os.path.exists(file_path):
        rmtree(file_path)
    os.makedirs(file_path)

def main():
    random.seed(0)
    split_rate = 0.1
    #cwd = os.getcwd()
    #data_root = os.path.join(cwd, "flower_data")
    data_root = 'D:/100_DataSets/03_flower_data'
    origin_flower_path = os.path.join(data_root, "flower_photos")
    assert os.path.exists(origin_flower_path), "path '{}' does not exist".format(origin_flower_path)
    flower_class = [cla for cla in os.listdir(origin_flower_path) if os.path.isdir(os.path.join(origin_flower_path, cla))]
    train_root = os.path.join(data_root,"train")
    mk_file(train_root)
    for cla in flower_class:
        mk_file(os.path.join(train_root, cla))
    val_root = os.path.join(data_root, "val")
    mk_file(val_root)
    for cla in flower_class:
        mk_file(os.path.join(val_root,cla))
    for cla in flower_class:
        cla_path = os.path.join(origin_flower_path,cla)
        images = os.listdir(cla_path)
        num = len(images)
        eval_index = random.sample(images, k=int(num*split_rate))
        for index, image in enumerate(images):
            if image in eval_index:
                image_path = os.path.join(cla_path, image)
                new_path = os.path.join(val_root, cla)
                copy(image_path, new_path)
            else:
                image_path = os.path.join(cla_path, image)
                new_path = os.path.join(train_root, cla)
                copy(image_path, new_path)
            print("\r[{}] processing [{} / {}]".format(cla, index+1, num), end="")
        print()
    print("processing done!")
    
if __name__ == "__main__":
    main()

总结

我们的研究结果表明,大规模深度卷积神经网络能够在高度具有挑战性的数据集上,仅通过监督学习就实现创纪录的成绩。值得注意的是,如果移除单个卷积层,我们的网络性能会受到破坏。例如,移除任何一个中间层,网络的前1项性能都会损失约2%。因此,深度对于我们的结果的实现非常重要。为简化我们的实验,即使我们预期无监督的预训练将有所帮助,我们也没有使用任何无监督的预训练。特别是如果我们可以获得足够的计算能力来显着增加网络的大小而不会获得相应的标记数据增加。到目前为止,我们的结果随着网络的扩大和训练时间的延长而改善,但我们仍然需要经历许多数量级才能匹配人类视觉系统的推論暂时。最终,我们想在视频序列上使用非常大而深的卷积网络,其中暂时结构提供非常有用的信息,在静态图像中缺少或不太明显。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值