深度学习网络中的Hello Word?-AlexNet

?写在前面:这篇文章是一篇最最基础的深度学习的文章,可以作为深度学习的Hello World?。阅读这篇文章的前提是已经阅读过了原Paper,对paper的内容有印象、最好有疑问,以及掌握部分基础知识。这篇文章主要是对AlexNet论文的个人理解,会包含部分原文的内容。如果对AlexNet这篇paper有任何问题或者对这篇文章有任何疑问,欢迎在评论区提问,大家一起讨论。???

掌握这篇论文需要的基础知识有: ⭐⭐⭐

机器学习的基本概念和方法:监督学习、无监督学习、深度学习;

神经网络的基本结构和工作原理:包括前馈神经网络、卷积神经网络;

CV的基本概念和方法:图像分类、目标检测、语义分割;

基础的编程能力:能够使用python等编程语言进行数据处理和模型训练;

文章的结构

摘要 介绍了图像分类的重要性和挑战,以及深度学习和卷积神经网络在图像分类中的作用。
引言 介绍与本文相关的研究工作,包括深度学习、卷积神经网络、图像分类这些方面的研究。作者对这些研究进行了分类和总结,指出了他们的优缺点和不足之处,并指出了本文的创新点和改进之处
数据集和预处理 介绍了本文使用的数据集和数据预处理方法。
模型架构 介绍了本文提出的深度卷积神经网络的架构,包括卷积层、池化层、全连接层等;
训练细节 介绍了本文使用的训练方法和技巧,包括随机梯度下降、数据增。
结果分析 介绍了本文实验的结果和分析,包括在ImageNet数据集上的分类准确率、不同模型的比较、误差分析等。
结论 总结了本文的工作和贡献,并对未来的研究方向进行了展望
参考文献
2. 数据集和图像尺寸调整:

前两段介绍了ImageNet数据集,使用了ILSVRC2012(因为是当时唯一一个可以获得测试集标签的数据集),提到了两个常用的错误率:top-1 和top-5。

第三段介绍了因为文中提出的框架需要一个固定的输入,所以将图像的大小固定在了256 x 256,(原文:we first rescaled the image such that the shorter side was of length 256, and then cropped out the central 256×256 patch from the resulting image),作者强调这里没有做任何的预处理,除了从每个像素中减去训练集上的平均活动(类似于BN),所以作者是在中心化处理后的RGB图像上进行的训练。

3. 模型架构

八个学习层:五个卷积层+三个全连接层。这部分作者花了四个小部分讲解了论文中创新点(或者说叫新奇的不寻常的部分)

3.1 Relu Nonlinearity

这里作者在激活函数上做了创新,同一个数据集CIFAR-10上,以训练误差率(Training error rate)下降到25%需要的迭代次数(Epochs)作为性能指标,对比了ReLU函数和tanh函数这两个激活函数所需要的迭代次数。

| image.png |

实验数据集: CIFAR-10 
模型:四层的卷积神经网络(ReLU VS tanh)
性能指标:训练误差率(Training error rate)下降到25%需要的迭代次数(Epochs) 

 

这里作者指出他们不是第一个考虑替换CNNs中的传统神经模块的团队,指出Jarrett团队在Caltech-101数据集上,在平均池化后使用的非线性激活函数f (x) = |tanh(x)|取得了非常好的效果。Jarrett团队是为了防止过拟合,即观察防止过拟合能力,而作者是为了加快训练速度,即观察eopchs数。作者也强调,更快的学习速度在大数据上的大模型上拥有很重要的影响。

3.2在多GPU上训练

作者将模型放到了两个GPU上进行训练,因为当时小的显存限制了网络模型的尺寸。GPU非常适合交叉GPU并行训练,GPU能够直接从另一个显存中直接进行读写,不需要再经过主存,作者采用的并行化方案基本上是将一半的内核(神经元)放到每个GPU上,并采用了一个额外的技巧:GPU只在某些层进行通信。例如,第三层的神经元接受来自第二层的神经元的输出,然后,第四层的神经元只接受在同一个GPU上第三层的神经元的输出。选择这个这种连接模式对于交叉验证是一个问题为(因为不一致的连接模式选择会导致不可靠的性能评估结果,而为了进行有效的交叉验证,需要保持连接模式的一致性),但这允许我们精确地调整通信量(是如何调整的?),直到它是可接受的计算量的一部分。

第二段作者指出最终的结构有点类似Ciresan提出的柱状CNN,不同的是,他们的柱子是不独立的。然后作者指出这个方案在top-1和top-5的错误率上有下降,并且训练时间比单GPU网络要短。

第二段下面作者指出,单GPU网络和双GPU网络在最终的卷积层上面有相同的参数,因为大多数参数都是在第一个全连接层上,而这些参数是最后一个卷积层提供的。所以为了让这两个网络拥有近乎相同的参数,没有减半最终卷积层以及紧随其后的全连接层的尺寸。因此,这个比较是倾向于单GPU网络的,因为它比双GPU网络的一半还要大。

(这里我并不完全懂,作者表达两个意思:

单GPU网络和双GPU网络具有相同数量的参数,因为它们共享相同的卷积层参数。在相同参数上,双GPU网络的训练时间更少。

单GPU网络比双GPU网络的一半更大,这样他的参数量就更多,可以更好地拟合数据)

对比实验二 结果
单GPU网络 作者知识给出 采用双GPU方案后的效果
双GPU网络(compared with a net with half as many kernels in each convolutional layer trained on one GPU) This scheme reduces our top-1 and top-5 error rates by 1.7% and 1.2%

 

3.3局部响应归一化

ReLU具有理想的特性,即它们不需要输入规范化来防止它们饱和。作者发现局部响应归一化的方法也有助于结果。image.png表示在位置(x,y)上将被核i进行计算的神经元响应,然后应用ReLU非线性激活函数。最终局部响应活动的 image.png由下面这个公式得到:
image.png

其中求和覆盖了n个“相邻的”位于相同空间位置的核映射,N是该层中的核总数。核映射的顺序当然是任意的,且在训练开始前就确定。受到在真实神经元中发现的类型启发,这种响应归一化实现了一种侧向抑制,在使用不同核计算神经元输出的过程中创造对大激活度的竞争,使得其中响应比较大的值变得相对更大,并抑制其他反馈较小的神经元,增强了模型的泛化能力。常数k,n,α和β是超参数,它们的值要用验证集来确定;我们使用 k = 2, n = 5, α = 10−4, and β = 0.75 。我们在某些层应用ReLU归一化后再应用这种归一化。

3.4重叠池化

使用重叠池化相较于传统的池化,可能防止过拟合。

重叠池化:移动的步长比相邻的池化单元小,就能达到重叠的效果。

3.5整体架构

第二段较为详细的介绍了网络框架,包含了哪些层,层与层之间如何进行通信,哪些层后面又分别包含了哪些模块(上文中提及的)。

第三段进一步讲解了网络的结构,每一层内部的卷积核个数及其大小进行说明。包括全连接层的神经元个数。

第三段原文:

第一个卷积层,使用96个11x11x3大小的卷积核,移动步长为4(相邻神经元在一个卷积核映射中感受野中心之间的距离),对224x224x3的图片进行卷积提取特征。

第二个卷积层,使用256个5x5x48大小的卷积核,对输入(对第一层的输出进行局部响应归一化以及池化操作之后)进行特征提取。

第三和第四以及第四和第五层之间没有任何的池化和归一化层。

第三个卷积层,使用384个3x3x256大小的卷积核,对输入(对第二层的输出进行局部响应归一化以及池化操作之后)进行特征提取。

第四个卷积层,使用384个3x3x192大小的卷积核

第五个卷积层,使用256个3x3x192大小的卷积核

每个全连接层有4096个神经元。

关于一些参数的选取,其中是根据某些依据计算得到来的,不是随便瞎设置的,例如第一个卷积核的移动步长。

以下是torchvision.models中实现AlexNet网络。这个网络与论文中的描述的网络结构有部分区别。(两个GPU之间的通信的代码不在本文的讨论范围之内,我们现在就看单GPU的)

class AlexNet(nn.Module):


    def __init__(self, num_classes: int = 1000, dropout: float = 0.5) -> None:


        super().__init__()


 


        # 卷积层部分


        self.features = nn.Sequential(



            # 输入图像大小为 256 x 256 x 3


            nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),  
            # 输出大小为 64 x 64 x 64,输出大小N = (W − F + 2P )/S+1=64,这里是64个卷积核,,卷积核的个数确定了输出的channel数。

            nn.ReLU(inplace=True),

            nn.MaxPool2d(kernel_size=3, stride=2),  # 输出大小为 32 x 32 x 64

 

            nn.Conv2d(64, 192, kernel_size=5, padding=2),  # 输出大小为 32 x 32 x 192

            nn.ReLU(inplace=True),

            nn.MaxPool2d(kernel_size=3, stride=2),  # 输出大小为 16 x 16 x 192

 

            nn.Conv2d(192, 384, kernel_size=3, padding=1),  # 输出大小为 16 x 16 x 384

            nn.ReLU(inplace=True),

 

            nn.Conv2d(384, 256, kernel_size=3, padding=1),  # 输出大小为 16 x 16 x 256

            nn.ReLU(inplace=True),

 

            nn.Conv2d(256, 256, kernel_size=3, padding=1),  # 输出大小为 16 x 16 x 256

            nn.ReLU(inplace=True),

            nn.MaxPool2d(kernel_size=3, stride=2),  # 输出大小为 8 x 8 x 256

        )

 

        # 全连接层部分

        self.avgpool = nn.AdaptiveAvgPool2d((6, 6))  # 输出大小为 6 x 6 x 256

        self.classifier = nn.Sequential(

            nn.Dropout(p=dropout),  # 随机丢弃 50% 的神经元

            nn.Linear(256 * 6 * 6, 4096),  # 全连接层,输出大小为 4096

            nn.ReLU(inplace=True),

            nn.Dropout(p=dropout),  # 随机丢弃 50% 的神经元

            nn.Linear(4096, 4096),  # 全连接层,输出大小为 4096

            nn.ReLU(inplace=True),

            nn.Linear(4096, num_classes),  # 全连接层,输出大小为 num_classes(类别数)

        )

 

    def forward(self, x: torch.Tensor) -> torch.Tensor:

        x = self.features(x)

        x = self.avgpool(x)

        x = torch.flatten(x, 1)

        x = self.classifier(x)

        return x
4. 减少过拟合

这里作者讲了两个减少过拟合的方法

4.1 数据增强

最简单最常用的在图像数据上减少过拟合的方法,就是人为的进行标签保留式的转换。作者使用了两种数据增强方式,每一种都只需要很少的计算量,且这些转换的图片不需要保存在磁盘上。CPU生成转换的图片,GPU在之前的batch的图片上进行训练。因此,这些数据增强方案在实际中是计算(时间方面)上免费的。

第一种数据增强形式包括生成图像平移和水平反射。我们通过从256×256图像中截取随机的224×224大小的图像块(及其水平反射)并在这些截取的图片块上训练我们的网络来实现这一点。虽然训练集大小增加了2048倍,但是作者提出这种方式生成的训练样本是高度相关的。如果没有这个方案,网络会遭受严重的过拟合(对过拟合的理解:参数之间高度相关,参数之间和训练数据高度相关),这将迫使我们使用更小的网络。在测试时,网络通过提取五个224×224图片块(四个角图片块和中心图片块)以及它们的水平反射来进行预测

第二种形式的数据增强包括在训练集上改变RGB通道的强度。

Trick训练集上改变RGB通道的强度  
如何改变的? 
对每个像素的RGB值image.png加上如下的值image.png(这里的p和λ是像素值的3*3的协方差矩阵对应的第i个特征向量和特征值) 具体而言,我们对整个ImageNet训练集中的RGB像素值集合执行PCA。获得对应的主成分。每张训练的图像都要增加几倍的主成分。从均值为零,标准差为0.1的高斯分布中随机抽取一个数(α),然后将其乘以对应的特征值(λ),再乘以对应的特征向量(p),最后将这个结果加到RGB图像像素值上。每个αi只会在特定的训练图像中被随机抽取一次,直到该图像再次被用于训练
为什么能这么改变? 自然图像有一个重要特性,即物体的身份对照明强度和颜色的变化是不变的。
**改了之后效果如何? ** reduces the top-1 error rate by over 1%
4.1 Dropout

结合很多不同模型的预测结果能够有效减少错误率,但是对于大型神经网络很费时间。这里作者引入了一种有效的结合方案:Dropout。对每个隐层神经元的输出,有一半的概率将其设置为0。这些被‘Dropout out’的神经元不参与前向和反向传播。每一次神经网络都采样了不同的结构,但是这些结构都共享权重参数。由于一个神经元不能依赖其他神经元的存在,所以dropout减少神经元之间的复杂共适应性(每个神经元都必须学习一些对于不同的随机子集都是有用的特征,而不能依赖于其他特定的神经元)。因此,神经元不得不学习一些对于不同的随机子集(每次前向传递时随机选择的神经元子集,也就是dropout一部分神经元之后,剩下的神经元)都是有用的特征。在测试阶段,对所有的神经元的输出乘以0.5(这是对由指数多个dropout网络产生的预测分布取几何平均数的一个合理近似)。

 

5. 学习细节

使用随机梯度下降算法训练模型,每次迭代使用128个样本进行训练,同时使用动量为0.9的方法来加速训练过程,使用了权重衰减(weight decay)技术,其中衰减系数为0.0005。作者发现小的权重衰减系数对于模型的学习很重要。即权重衰减不仅仅达到了正则化的作用,还减小了训练误差。权重w的更新规则如下:

image.png

i是迭代次数,v是动量,image.png是学习率image.png是在batch Di上关于w的导数。

标准差为 0.01 的零均值高斯分布 初始化权重,这种初始化方式可以通过为 ReLU 提供的正输入,来加速早期的学习阶段(加速)。在剩下的层中,我们使用常数0来初始化偏置层。

第三段作者指出,所有的层使用的相同的学习率,在学习的过程中通过手动去调整。作者根据经验,若当前学习率下的验证集错误率不再下降时,就将学习率除以10。最后作者指出,他们的学习率减小了三次,数据集迭代训练了大概90次。

6. 结果

这一部分以top-1和top5为性能指标,在 ILSVRC-2010 和 ILSVRC-2012数据集上,和其他模型进行的对比。

6.1定性评价
image.png 图3这是第一层96个11113的卷积核在2242243的输入图像上,经过学习之后的样子。上面48个是GPU1上。下面48个是GPU2上。

图三展示了由网络的两个数据连接层学习的卷积核,网络已经学习了各种频率和方向选择内核,以及各种颜色的斑点,结合3.5部分的网络结构图,GPU 1上的卷积核在很大程度上不考虑颜色,而GPU 2上的卷积核在很大程度上考虑颜色,这种专业化在每次运行时都会发生,并且与任何特定的随机权重初始化无关(除了重新编号GPU之外)。

image.png 展示了八张测试集中的图片,及其由Alexnet预测的五个类别top-5。即使不在中心的目标也可以被识别,例如第一个螨虫的图。大多数top-5预测的类别都是合理的。例如,只有其他类型的猫被认为是豹子的合理标签。也有一些对照片的预期焦点确实存在模糊不清的地方,例如车预测成栅栏,狗预测成樱桃。
image.png 第一列是ILSVRC-2010 测试集的五张图,后面的六张图是从训练集中检索出来的相似图片。依据是这六张图与第一张图在提取的特征向量上,拥有最小的欧几里得距离。

这两张图展示了两种评估模型学习到的视觉知识的方法。

一种是看预测的种类。

另一种是考虑考虑由图像在最后一个4096维隐藏层激活的特征。如果两个图片产生的特征向量有一个很小的欧几里得距离,那么神经网络更高的学习层会认为他们是相似的。作者指出,这些检索出来的图片在L2距离上并不相近。

使用两个4096维实值向量之间的欧几里得距离计算相似性是低效的,但是可以通过训练自编码器将这些向量压缩为短的二进制代码来提高效率。参考文献14指出这应该会产生比对原始像素应用自编码器更好的图像检索方法,后者不使用图像标签,因此有倾向于检索具有相似边缘模式的图像,无论它们是否在语义上相似。

2. 讨论

几个短语总结一下:

有监督学习、极具挑战性的数据集、获得突破性的成果、大的深的卷积神经网络。深度(层数)很重要(移除任意一层,top-1都会下降2%)、没有使用无监督的方法、仍有很多工作要做来模仿人类的下颞通路、未来在视频上使用大型深度卷积网络(时间结构提供很有帮助的信息,而静态图像上没有)

这篇文章的创新点:

(这肯定是一个新的网络架构,其中也必然包含一些之前的论文提出的有效模块)

1:提出了一种基于深度卷积神经网络的图像分类方法,该方法在当时的图像分类任务中取得了最好的结果;(SOTA)

2:训练了一个非常大的深度卷积神经网络,该网络包含了超过6000万个参数,但是通过GPU的高效计算和优化的实现,使得该网络的训练成为可能;

3:提出了Relu激活函数,可以降低过拟合以及可以将加快训练速度。

4:提出了局部响应归一化,降低训练错误率

5:采用重叠池化,放置过拟合

6:提出了一种数据增强的方法,通过对训练数据进行变换,增加了训练数据的多样性,从而提高了模型的泛化能力;采用dropout,增强模型的泛化能力。

 

文章中提及的数据集

NOBR数据集 NORB数据集是美国空军研究实验室发布的一个立体物体识别数据集,包含50,000个灰度图像,用于测试算法在立体物体识别方面的性能。
Caltech数据集 加州理工学院发布的一个图像分类数据集,包含101个类别的图像,共计9,144张图像。该数据集用于测试算法在图像分类方面的性能。
CIFAR数据 加拿大计算机科学家Alex Krizhevsky等人发布的一个图像分类数据集,包含10个类别的图像,共计60,000张32×32像素的彩色图像。该数据集被广泛用于测试算法在图像分类方面的性能。
LabelMe 图像标注和分割数据集,由麻省理工学院人工智能实验室发布。该数据集包含超过10,000个图像,每个图像都有详细的像素级别的标注和分割信息。
ImageNet ImageNet数据集被广泛用于图像分类、目标检测、图像分割等计算机视觉任务的研究和评估

涉及的实验和对比

3.1 Relu Nonlinearity这里作者在激活函数上做了创新,同一个数据集CIFAR-10上,以训练误差率(Training error rate)下降到25%需要的迭代次数(Epochs)作为性能指标,对比了ReLU函数和tanh函数这两个激活函数所需要的迭代次数。 自制一个简单的四层卷积神经网络,将其中的激活函数作为修改变量(RELU和tanh),训练并记录迭代和对应training error
# 定义四层卷积神经网络模型


class FourLayerCNNRelu(nn.Module):


    def __init__(self, num_classes):


        super(FourLayerCNNRelu, self).__init__()


 


        self.features = nn.Sequential(



            nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1),


            nn.ReLU(),

            nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1),

            nn.ReLU(),

            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),

            nn.ReLU(),

            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),

            nn.ReLU()

        )

 

        self.fc = nn.Linear(131072, num_classes)  # 调整全连接层的输入大小

 

    def forward(self, x):

        out = self.features(x)

        out = out.view(out.size(0), -1)

        out = self.fc(out)

        return out

 

 

# 定义四层卷积神经网络模型

class FourLayerCNNTanh(nn.Module):

    def __init__(self, num_classes):

        super(FourLayerCNNTanh, self).__init__()

 

        self.features = nn.Sequential(

            nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1),

            nn.Tanh(),

            nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1),

            nn.Tanh(),

            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),

            nn.Tanh(),

            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),

            nn.Tanh()

        )

 

        self.fc = nn.Linear(131072, num_classes)

 

    def forward(self, x):

        out = self.features(x)

        out = out.view(out.size(0), -1)

        out = self.fc(out)

        return out

通过这两个模型去对比,只是将激活函数更换。

image.png

3.2在多GPU上训练
3.3局部响应归一化(后期争议在2015年 Very Deep Convolutional Networks for Large-Scale Image Recognition.提到LRN基本没什么用。image.png 因而在后面的Googlenet,以及之后的一些CNN架构模型,LRN已经不再使用,因为出现了更加有说服能力的块归一化,也称之为批量归一化,即BN。) image.png  这个公式中的a表示卷积层(包括卷积操作和池化操作)后的输出结果,这个输出结果的结构是一个四维数组[batch,height,width,channel]。这里可以简单解释一下,batch就是批次数(每一批为一张图片),height就是图片高度,width就是图片宽度,channel就是通道数可以理解成一批图片中的某一个图片经过卷积操作后输出的神经元个数(或是理解成处理后的图片深度)。ai(x,y)表示在这个输出结构中的一个位置[a,b,c,d],可以理解成在某一张图中的某一个通道下的某个高度和某个宽度位置的点,即第a张图的第d个通道下的高度为b宽度为c的点。论文公式中的N表示通道数(channel)。a,n/2,k,α,β分别表示函数中的input,depth_radius,bias,alpha,beta,其中n/2,k,α,β都是自定义的,特别注意一下∑叠加的方向是沿着通道方向的,即每个点值的平方和是沿着a中的第3维channel方向的,也就是一个点同方向的前面n/2个通道(最小为第0个通道)和后n/2个通道(最大为第d-1个通道)的点的平方和(共n+1个点)。而函数的英文注解中也说明了把input当成是d个3维的矩阵,说白了就是把input的通道数当作3维矩阵的个数,叠加的方向也是在通道方向。 公式看上去比较复杂,但理解起来非常简单。i表示第i个核在位置(x,y)运用激活函数ReLU后的输出,n是同一位置上临近的kernal map的数目,N是kernal的总数。参数K,n,alpha,belta都是超参数,一般设置k=2,n=5,aloha=1*e-4,beta=0.75。
3.4重叠池化 步长小于窗口
6结果与两个当时的SOTA模型进行对比这部分在以后的论文对比方面,可以直接拿官方的数据。 image.png

写在最后:

万事开头难,可以多花一些时间在理解这篇文章的提出创新点的思想上,深度学习是一个以实验为重点的方向,将论文中涉及的模块和数学方面的知识结合代码,可以理解的更加充分。???

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYXW9k8S' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片