论文精读-1:AlexNet

1. Overview && Abstract

论文题目:ImageNet Classification with Deep Convolutional Neural Networks

论文地址:https://papers.nips.cc/paper/2012/hash/c399862d3b9d6b76c8436e924a68c45b-Abstract.html

论文标题为基于深度卷积神经网络的ImageNet图像分类

论文总览:

AlexNet是深度学习浪潮的奠基之作,发布于2012年,他首次把深度卷积神经网络应用在大规模图像分类上,可以说为后续整个计算机视觉和深度卷积网络的发展奠定了基础。而卷积神经网络中的卷积、池化、全连接等基础架构则是在LeCun的LeNet-5中提出的。在多年后的今天在读这篇经典的文章可以看看其中有哪些东西还是成立的,有哪些东西在现在的角度看来已经过时了(比如文中说他们使用了深度的卷积神经网络,但放在今天这个网络还是浅的)

这篇论文摘要基本就只是说做了什么工作,进行了什么创新,取得什么样的效果。主要工作和贡献如下:

  • 在 ILSVRC-2010 的120万图片上训练深度卷积神经网络,获得最优结果,top-1 和 top-5 error 分别为 37.5% 和 17%。

    在这个深度模型中,一共有6000万个参数和65万个神经元,包括5个卷积层和3个全连接层。在这些卷积层中,有一些卷积层卷积之后进行了最大值池化

  • 提出了几个新的网络架构优化技巧,如**ReLU激活函数、数据增强、局部响应归一化(Local Response Normalization)、重叠池化(Overlapping Pooling)**等,这些技巧显著提升了网络的性能

  • 为了防止过拟合,在全连接层采取了 “dropout”正则化

  • 使用了两个GTX 580 3GB显卡并行训练,实现了高效的GPU卷积操作,显著减少了训练时间。

  • 做了一定的可视化与可解释性分析工作,如不同层级的卷积核表示,高维特征向量的相似度计算等。

注:摘要中提到的state-of-the-art:最先进的,简称SOTA

2. Introduction

在文中作者提到大家都在收集更大的数据训练更大的模型,但更大的模型往往会过拟合,所以大家经常都在进行有效的正则化去避免过拟合。

注:其实放在今天,这个观点又好像不对。即现在大家又觉得其实正则不太重要,重要的是整个神经网络的设计,使得你的大网络在没有很好的正则时也有很好的性能。OpenAI近几年的工作也表明只要数据够大,网络够好就可以发挥不错的性能

同时,与具有类似大小层的标准前馈神经网络相比,CNN的连接和参数要少得多,因此更容易训练,而它们的理论最佳性能可能只会比全连接网络稍微差一点。

接着作者主要讲了本文的具体贡献如下:在ILSVRC-2010和ILSVRC-2012比赛中使用的ImageNet子集上训练了迄今为止最大的卷积神经网络之一,并取得了迄今为止在这些数据集上报道的最佳结果。并提出他们在网络中使用了一些新颖的、不寻常的特征来提高网络性能,以及使用了几种有效的技术来防止过拟合。Introduction的最后作者说只要等待更快的gpu和更大的数据集可用,我们的结果就可以得到改善。

3. Dataset && Architecture

3.1 Dataset

ImageNet是一个包含超过1500万张有标签的高分辨率图像的数据集,共有大约22,000个类别。

从2010年开始,ImageNet大规模视觉识别挑战赛(ILSVRC)作为Pascal视觉对象挑战赛的一部分每年都会举行一次。ILSVRC使用ImageNet的一个子集,在1000个类别中每个类别中大约有1000张图像。总共大约有120万张训练图像、5万张验证图像和15万张测试图像。在ImageNet上,习惯上报告两个错误率:top-1和top-5,其中top-5错误率是正确标签不在模型认为最可能的五个标签中的测试图像的比例。

ImageNet由可变分辨率的图像组成,而本文模型需要恒定的输入维度。因此,本文将图像下采样到256 × 256的固定分辨率。具体为给定一个矩形图像,首先重新缩放图像,使较短的边长度为256,然后从结果图像中裁剪出中心的256×256补丁。同时还对图像数据进行了归一化处理。

3.2 Overall Architecture

网络架构创新包括ReLU非线性激活函数、多GPU训练、局部响应归一化(Local Response Normalization)和重叠池化(Overlapping Pooling)等

模型结构:

在这里插入图片描述

上图表面AlexNet中共有八个需要进行学习权重的层,分别是五个卷积层和三个全连接层。可以看到把模型放在俩个GPU上进行训练,上下俩个GPU进行并行训练,只在最后的全连接层与中间第三个卷积层进行互相连接通信,其余层只接受一个GPU的数据输入

在卷积层的第一层和第二层中还有一个局部响应归一化LRN层(Local Response Normalization),在1、2、5层中使用了最大值池化,池化使用的是重叠池化(Overlapping Pooling)

在最后的两层全连接层中都是共有4096个神经元,一个GPU2048个神经元

最后的输出层是一个1000个神经元的线性分类层,激活函数使用线性的softmax归一化函数,不使用非线性的激活函数,每个神经元输出对应这个类别的概率

在这里插入图片描述

上图表明了各层卷积核的个数、大小和池化层Padding的大小以及各层的feature map的尺寸维度,具体如下:

  • 第一个卷积层输入图像大小为227×227×3,使用96个大小为11×11×3的卷积核,步长为4像素(这是核映射中相邻神经元的接受野中心之间的距离)。经过卷积FeatureMap为(227-11+0×2+4)/4 = 55,即55×55×96。

    接着依次通过LRN、ReLU激活与最大池化。

    其中池化核大小为3×3,步长为2,不使用零填充,池化后的FeatureMap为(55-3+0×2+2)/2=27, 即输出为27×27×96(若按照原论文将数据分到两个GPU中处理,每组输出为27×27×48)

  • 第二个卷积层将第一个卷积层的输出作为输入,并使用256个大小为5 × 5 × 48的步长为1的卷积核对其进行过滤(一组48,俩组共96)。FeatureMap为(27-5+2×2+1)/1 = 27,即27×27×256。

    接着依次通过LRN、ReLU激活与最大池化。池化核参数同上,最终FeatureMap为13×13×256(若按原论文分配到两个GPU,则每组输出为13×13×128)

  • 第三层、第四层和第五层卷积层相互连接,没有任何中间池化层或归一化层。第三个卷积层有384个大小为3 × 3 × 256的核,这些核从第二个卷积层的输出(归一化,池化)连接过来。第四个卷积层有384个大小为3 × 3 × 192的核(192是因为俩个GPU分了),第五个卷积层有256个大小为3 × 3 × 192的核。

在这里插入图片描述

上为各层的参数数量和运算次数,相比于后续的VGG这样的模型,他各层的参数数量分布是比较均匀的

如果把AlexNet的架构变成单GPU,那么模型结构图就是:

在这里插入图片描述

紧随其后是网络结构中采用的创新之处:

3.2.1 ReLU

作者通过在 CIFAR-10上进行的实验发现,相比使用tanh(x)和sigmoid(x)这种饱和激活函数,使用非饱和的激活函数可以使训练速度快几倍,比如使用ReLU(Rectified Linear Unit,修正线性单元)激活函数:f(x) = max(0, x)。文中比较了使用ReLU激活函数比使用tanh双曲正切激活函数要快六倍

注:饱和即很大或很小的x经过激活函数之后差别会变小。饱和的激活函数会导致梯度消失,导致训练收敛时间变长。

虽然不同网络结构采用ReLU的效果不同,但收敛更快是普遍的。所以哪怕在今天,ReLU及其变体仍是目前最常用的激活函数之一,如Leaky ReLU、Parametric ReLU(PReLU)和Randomized ReLU等

更快的学习可以进行更多的实验,对在大数据集上训练的大型模型的性能有很大的影响。

3.2.2 Training on Multiple GPUs

该模型作者用了两块GPU进行训练,即使用了模型并行的方法,具体并行方法在上面模型结构图已经讲了

这种方法会给模型的工程实践带来困难,所以在之后几年,随着显卡性能的提升已很少使用。但目前由于在大模型训练中再次遇到了算力瓶颈,所以GPT为代表的大模型又再次使用模型并行的方法进行训练。

3.2.3 局部响应归一化层(Local Response Normalization,LRN)

局部响应归一化层(Local Response Normalization,LRN)的主要目的是对神经元的输出进行归一化处理,以增强模型的泛化能力。(目前已证明LRN无用,所以已被弃用)

原理

LRN层的核心思想是对局部神经元的活动进行归一化,从而创建一个竞争机制,使得响应较大的神经元相对增强,而响应较小的神经元相对抑制,有助于模型学习到更加鲁棒的特征表示。

具体来说,LRN层对每个神经元的输出应用一个归一化函数,该函数考虑了该神经元及其相邻神经元的响应。这个归一化函数可以写成一个数学表达式,其中涉及到每个神经元的输出、一个归一化项(通常是相邻神经元输出的加权和),以及一些可调整的超参数(如归一化的半径和幂次)。

即,LRN层会沿着通道方向应用归一化,即feature map中的每一个值根据附近通道的值进行归一化,即自己作为分子,附近几个值的平方和作为分母进行归一化,这样子操作的好处:同一个位置不需要太多的高激活神经元,即就像人类神经元中,一个神经元激活了那么它周围的神经元会变成静息状态。这一归一化操作就刚好可以使一个激活了会抑制附近的激活

数学公式

局部响应归一化的数学公式如下:
( b x , y i = a x , y i ( k + α ∑ j = m a x ( 0 , i − n / 2 ) m i n ( N − 1 , i + n / 2 ) ( a x , y j ) 2 ) β ) (b_{x,y}^i = a_{x,y}^i \left( k + \alpha \sum_{j=max(0, i-n/2)}^{min(N-1, i+n/2)} (a_{x,y}^j)^2 \right)^{\beta}) (bx,yi=ax,yi k+αj=max(0,in/2)min(N1,i+n/2)(ax,yj)2 β)
其中:

  • ax,yi 是第 i 个通道在位置 (x, y) 的激活值。
  • bx,yi是经过LRN后的输出值。
  • N 是通道的总数。
  • n表示在归一化同一空间(即不同核的相同位置)的n个近邻核映射值,这是一种横向抑制,使不同核产生的值之间进行竞争。

应用

在早期的深度学习模型中,如AlexNet,LRN层被用作一种正则化手段,以提高模型的泛化能力。**然而,随着时间的推移,更先进的技术如批归一化(Batch Normalization)和层归一化(Layer Normalization)等被开发出来,并逐渐取代了LRN层的位置。**这些新技术不仅考虑了相邻神经元之间的关系,还引入了更多的统计信息,从而能够更有效地控制模型的训练过程和提高模型的性能。VGG的论文中专门做了一个实验证明了LRN层没什么作用

3.2.4 重叠池化(Overlapping Pooling)

即池化层中窗口进行滑动时窗口与窗口之间会重叠,AlexNet认为滑动窗口的步长小于窗口的尺寸大小时(即窗口之间重叠时),可以防止过拟合。

但后续其他论文的工作认为这一步对防止过拟合意义不大,已经很少使用重叠池化了。

现在有的网络中仍采用了池化层,但一般窗口都是不重叠的,保留主要特征的同时降低数据的维度并减少参数和计算量,有助于防止过拟合,提高模型的泛化能力

但也有一些研究开始探索替代池化层的方法,例如使用步长大于1的卷积操作来实现降维。

除此之外还有一种特殊的池化:全局平均池化(Global Average Pooling,GAP),它对整个特征图进行平均操作,而不是在特定的空间区域内。这样,每个特征图最终会被压缩成一个单一的值,这有助于减少模型的参数数量,同时增强模型的鲁棒性。通过这种方式,每个特征图都与分类概率直接联系起来,这替代了全连接层的功能,并且不 产生额外的训练参数,减小了过拟合的可能,但需要注意的是,使用全局平均池化会导致网络收敛的速度变慢

4. Reducing Overfitting

使用数据增强(如图像平移、翻转和RGB通道强度调整)和dropout技术来减少过拟合

4.1 数据增强(Data Augmentation)

虽然数据集中的数据量已经很大了,但是AlexNet还是觉得数据量不够多,因此进行了数据增强,通过对每张图片进行一系列变换,如水平翻转、平移变换、颜色变换等,从而增加数据量并提升模型的泛化能力,并且有效防止了过拟合。

并且这些数据增强操作是在CPU上进行的,转换后的图像不需要存储在磁盘上,即一组图片送入GPU中训练的同时,CPU开始进行数据增强生成下一组图片,在上一组图片训练完一个轮次之后下一个轮次使用新生成的图片进行训练,这样每次模型训练时使用的数据相同而又不完全相同,从而增强模型泛化性能与减少过拟合。

其中水平翻转、平移变换使用24x24的小方块在一张256x256的图上进行裁剪,可以将一张图片变成2048张图片。虽然这2048张图片是高度相似的,但他可以有效防止过拟合与扩充数据集。

而颜色变换则是使用主成分分析(PCA)求出RGB3x3协方差矩阵的特征值与特征向量,原来的图片再加上一个随机数乘以主成分,从而改变训练图像中RGB通道的强度。

4.2 Dropout

Dropout即在训练的每一步中,随机“丢弃”一些神经元,“丢弃”即让这个神经元的输出为0,从而阻断这个神经元的前向和反向传播。Dropout可以减少过拟合的一些可能的解释:

  • 使得每个神经元都不知道每一次训练中跟他一起活下来的神经元有哪些,所以每次输入时,神经网络的结构在每次都略有不同,这就逼得每个神经元都必须和不同的神经元相协作,打破了他们之间的联合依赖适应性,每个神经元都被迫学习更多的鲁棒特征,从而防止过拟合。

  • 比如一层中有10个神经元,每次随机掐死一半的神经元,这使得每个神经元都有死与活俩种可能的状态,那么潜在的就有210个模型,相当于对这么多个模型进行了集成,而集成学习是一种有效防止过拟合的手段

    但实际上后来人们研究发现Dropout并不是一种模型集成的方法,而是一个类似正则化效果的东西,现在普遍认为dropout相当于一个L2正则项

在AlexNet的前两个全连接层中使用dropout。采用Dropout之后,在进行测试推理的时候,使用所有神经元,但对每个神经元的输出乘以0.5

因为在测试或评估阶段,由于训练时随机“丢弃”了一部分神经元,实际上每一层的输出都被缩小了约(1 - p)倍,为了补偿这种缩小,确保输出的稳定性,通常会对输出进行缩放,即乘以1 / (1 - p),其中p是每个神经元被Dropout的概率。

在算力进步、大模型当道的今天,已经不怎么使用Dropout等防止过拟合的手段了,有人认为只要网络够好、数据量够大,不存在过拟合,因此无需Dropout

因此大部分CNN相关模型都不怎么使用Dropout了,RNN和Transformer相关模型也只用一点Dropout了

5. Details of learning

  • 使用带动量的随机梯度下降(SGD)

  • 在原来的多分类交叉熵损失函数中加入了L2正则化(管他叫优化函数中的权重衰减weight decay)

  • 学习率在训练过程中手动调整,当验证错误率不再随着当前学习率而提高时,将学习率除以10,但其实现在没必要手动调,自动设置过几个轮次之后进行下降即可

  • 权重在进行初始化时,使用均值为0、 方差为0.01的高斯随机变量进行初始化

    实际上在后续研究经验中,一般对这种比较小的模型都是使用均值为0、 方差为0.01的高斯随机变量进行初始化

    但如果网络特别深的时候需要更多的优化,比如BERT,会选择使用均值为0、 方差为0.02的高斯随机变量进行初始化

6. Results

这一块第一部分总结来说,表达了四个字:性能飞跃

剩下部分在配图中做了一个初步的可解释性分析:

图三:

在这里插入图片描述

配图3中通过可视化网络学习到的卷积核,展示了网络对频率和方向选择性以及颜色的敏感性

同时由这个图还可以看出这俩个GPU训练出来的卷积核偏向提取的特征是不一样的,第一个GPU的卷积核中偏向提取边缘、频率和方向等特征,第二个GPU训练出来的卷积核偏向提取颜色、斑块特征

图四:

在这里插入图片描述

文中配图四左边说明哪怕是错误预测的例子,也都是一些情有可原的例子,不能全怪网络,说明网络能提取图像的语义特征

文中配图四右边第一列是ImageNet2010年比赛的测试集中的五张图片,把这些测试集中的图片喂到网络中,将最后一个全连接层4096维的向量取出来,再将训练集中所有图片的最后一个全连接层4096维的向量取出来,与测试集的这五个向量计算欧氏距离(L2距离),找出与测试集欧式距离最接近的六张图片,发现每一组的六张图片都和测试集图片非常类似

这个结果表明,卷积神经网络对相似的图片提取出的特征向量也是相似的,这也就说明了深度神经网络的特征提取能力特别强,也就是说网络并不在意图片在像素维度的差异,而是更加关注图像中的语义信息

7. Discussion

AlexNet团队通过减少与增加神经网络层数,得出一个结论:神经网络层数越多,效果越好。值得注意的是,站在今天的角度上去看,其实他们只是对单个卷积层的移除,这样得出的结论是不太严谨的,实际上只要搜参进行的好,减少一个卷积层并不会对效果产生太大的影响。同时神经网络不应只是单纯的深就行,还要考虑宽度:太宽或者太扁的网络都是不太好的。即深度与宽度的比例也是很重要的。

宽度可以理解为卷积核的个数,

同时AlexNet聚焦于监督学习,这使得之后很多年深度学习界掀起了监督学习的浪潮,直到BERT、GPT等模型的成功,才使得无监督学习继续火起来。

最后作者提出了未来可能的研究方向,如在视频序列上应用大型深度卷积网络,以及利用时间结构提供的信息。但哪怕在今天看,深度学习在视频中的应用还远不及在图像上取得的成就。

8. PyTorch code

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Project Name: torch_gpu_demo
# @Package Name: 
# @File Name   : AlexNet_demo.py
# @author      : LJH
# @Version     : 1.0
# @Start Date  : 2023/1/26 2:37
# @Classes     : 
import torch
from torch import nn

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')


class AlexNet(nn.Module):
    def __init__(self, num_classes=1000):
        super(AlexNet, self).__init__()
        # 卷积层
        self.conv = nn.Sequential(
            # 由于LRN层已经证明无用,所以这里比起原始架构少了LRN
            # 第一层
            nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2),
            # 输入通道数, 输出通道数及其他参数,input:[3, 224, 224] output:[96, 55, 55]
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3, stride=2),  # output:[96, 27, 27]

            # 第二层,开始减小卷积窗口且增大输出通道数,从而提取更多特征
            nn.Conv2d(96, 256, 5, 1, 2),  # output: [256, 27, 27]
            nn.ReLU(),
            nn.MaxPool2d(3, 2),  # output: [256, 13, 13]
            # 连续3个卷积层,且使用更小的卷积窗口。除了最后的卷积层外,进一步增大了输出通道数。
            # 前两个卷积层后不使用池化层来减小输入的高和宽
            nn.Conv2d(256, 384, 3, 1, 1),  # output: [384, 13, 13]
            nn.ReLU(),
            nn.Conv2d(384, 384, 3, 1, 1),  # output: [384, 13, 13]
            nn.ReLU(),
            nn.Conv2d(384, 256, 3, 1, 1),  # output: [256, 13, 13]
            nn.ReLU(),
            nn.MaxPool2d(3, 2)  # output: [256, 6, 6]
        )
        # 全连接层
        self.fc = nn.Sequential(
            nn.Linear(256 * 5 * 5, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(4096, 4096),
            nn.ReLU(),
            nn.Dropout(0.5),
            # 输出层
            nn.Linear(4096, num_classes),
        )

    # 前向传播
    def forward(self, img):
        feature = self.conv(img)
        output = self.fc(feature.view(img.shape[0], -1))
        return output


if __name__ == '__main__':
    pass
  • 20
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值