【动手学深度学习】7.1. 深度卷积神经网络(AlexNet)
目录
- 7. 现代卷积神经网络
- 7.1. 深度卷积神经网络(AlexNet)
- 1)学习表征
- (1)缺少的成分:数据
- (2)缺少的成分:硬件
- 2)AlexNet
- (1)模型设计
- (2)激活函数
- (3)容量控制和预处理
- 3)读取数据集
- 4)训练AlexNet
- 5)小结
.
7. 现代卷积神经网络
上一章我们介绍了卷积神经网络的基本原理,本章将介绍现代的卷积神经网络架构,许多现代卷积神经网络的研究都是建立在这一章的基础上的。 在本章中的每一个模型都曾一度占据主导地位,其中许多模型都是ImageNet竞赛的优胜者。ImageNet竞赛自2010年以来,一直是计算机视觉中监督学习进展的指向标。
这些模型包括:
-
AlexNet。它是第一个在大规模视觉竞赛中击败传统计算机视觉模型的大型神经网络;
-
使用重复块的网络(VGG)。它利用许多重复的神经网络块;
-
网络中的网络(NiN)。它重复使用由卷积层和卷积层(用来代替全连接层)来构建深层网络;
-
含并行连结的网络(GoogLeNet)。它使用并行连结的网络,通过不同窗口大小的卷积层和最大汇聚层来并行抽取信息;
-
残差网络(ResNet)。它通过残差块构建跨层的数据通道,是计算机视觉中最流行的体系架构;
-
稠密连接网络(DenseNet)。它的计算成本很高,但给我们带来了更好的效果。
虽然深度神经网络的概念非常简单——将神经网络堆叠在一起。但由于不同的网络架构和超参数选择,这些神经网络的性能会发生很大变化。 本章介绍的神经网络是将人类直觉和相关数学见解结合后,经过大量研究试错后的结晶。 我们会按时间顺序介绍这些模型,在追寻历史的脉络的同时,帮助培养对该领域发展的直觉。这将有助于研究开发自己的架构。 例如,本章介绍的批量规范化(batch normalization)和残差网络(ResNet)为设计和训练深度神经网络提供了重要思想指导。
.
7.1. 深度卷积神经网络(AlexNet)
尽管LeNet在小数据集上表现良好,推动了卷积神经网络的发展,但在1990年代初至2012年间,其在更大、更真实数据集上的性能和训练可行性尚不明确,导致卷积神经网络未占据主导地位,常被其他机器学习方法超越,如支持向量机(support vector machines)。
在计算机视觉中,直接将神经网络与传统机器学习方法对比并不公平。卷积神经网络直接以原始或简单预处理的像素为输入,而传统方法依赖人工设计的特征提取流程,其性能提升主要来自更精巧的特征工程,学习算法往往居于次要地位。
尽管上世纪90年代已出现神经网络加速卡,但仍不足以支持大规模、深层、多通道的卷积神经网络训练。加之数据集规模有限,且缺乏关键训练技术——如合理初始化、优化的梯度下降方法、非饱和激活函数和有效正则化——深度神经网络的发展受到严重制约。
因此,与训练端到端(从像素到分类结果)系统不同,经典机器学习的流水线看起来更像下面这样:
-
获取一个有趣的数据集。在早期,收集这些数据集需要昂贵的传感器(在当时最先进的图像也就100万像素)。
-
根据光学、几何学、其他知识以及偶然的发现,手工对特征数据集进行预处理。
-
通过标准的特征提取算法,如SIFT(尺度不变特征变换) (Lowe, 2004)和SURF(加速鲁棒特征) (Bay et al., 2006)或其他手动调整的流水线来输入数据。
-
将提取的特征送入最喜欢的分类器中(例如线性模型或其它核方法),以训练分类器。
机器学习研究者通常认为该领域既重要又优美,强调理论严谨性和模型性质的数学证明,视其为一个蓬勃发展且高度实用的学科。然而,计算机视觉研究者却持不同观点:他们认为推动领域进步的关键是数据和特征,而非学习算法。在实际效果上,更大、更干净的数据集或更优的特征设计,往往比算法改进带来更显著的精度提升。
.
1)学习表征
2012年之前,计算机视觉主流依赖手工设计的特征,如SIFT、SURF、HOG等。
然而,Yann LeCun、Geoff Hinton、Yoshua Bengio等人主张特征应由多层神经网络自动学习。这一理念在Alex Krizhevsky、Ilya Sutskever和Geoff Hinton提出的AlexNet中得到成功验证,其在2012年ImageNet竞赛中取得突破性成绩,推动了深度学习在视觉领域的崛起。
有趣的是,在网络的最底层,模型学习到了一些类似于传统滤波器的特征抽取器。 下图是从AlexNet论文 (Krizhevsky et al., 2012)复制的,描述了底层图像特征。
图7.1.1 AlexNet第一层学习到的特征抽取器。
AlexNet的高层基于底层特征(如边缘、纹理)逐步组合成更复杂的结构,如眼睛、鼻子、草叶,最终识别完整物体,如人、飞机、狗或飞盘。最终层学习到能有效区分不同类别的综合图像表示。尽管长期以来有研究者致力于学习视觉数据的层次化表征,但突破直到2012年才实现,主要归功于两个关键因素。
.
(1)缺少的成分:数据
深度模型要显著超越传统凸优化方法(如线性模型和核方法),需要大量标注数据。然而,受限于早期计算存储和研究预算,2010年前的研究多基于小规模数据集,如UCI的低分辨率、非自然场景图像,样本量仅数百至数千。
这一局面在2009年ImageNet发布后发生转变。该数据集由李飞飞团队构建,利用谷歌图像搜索和亚马逊众包进行筛选与标注,包含100万张图像、1000个类别,规模空前。随后发起的ImageNet挑战赛推动了对大规模数据下最优模型的研究,极大促进了计算机视觉与机器学习的发展。
.
(2)缺少的成分:硬件
深度学习对计算资源需求极高,训练需进行大量迭代,每轮涉及多层昂贵的线性代数运算。因此,20世纪90年代至21世纪初,研究人员更倾向使用优化凸目标的简单算法。这一局面因图形处理器(Graphics Processing Unit,GPU)的引入而改变。GPU最初用于加速图形处理,擅长高吞吐量的矩阵和向量运算,恰好与卷积神经网络的计算高度契合。随后,英伟达和ATI开始优化GPU用于通用计算,并推出通用GPU(general-purpose GPUs,GPGPU),极大推动了深度神经网络的训练效率。
那么GPU比CPU强在哪里呢?
a.CPU:灵活、高效处理复杂任务。不能同时干太多事。
-
CPU 的每个核心非常强大,能处理各种复杂的指令(比如运行操作系统、打开软件、玩游戏)。
-
它有高速缓存、分支预测等高级功能,适合处理逻辑复杂、需要频繁判断的任务。
-
但它的核心数量很少(一般4~64个),不能同时干太多事。
b.GPU:能同时处理海量数据。不适合做逻辑复杂的任务。
-
GPU 有成百上千个简单的处理单元(比如1000个“小工人”),它们都做同一件事。
-
虽然每个“小工人”不聪明,跑得也不快(频率低),但大家一起并行工作,速度极快。
-
特别适合深度学习中的矩阵乘法、卷积运算——这些操作就是“重复计算”。
2012年,Alex Krizhevsky和Ilya Sutskever将深度卷积神经网络成功运行于GPU,实现重大突破。他们利用NVIDIA GTX 580 GPU的并行能力,高效加速卷积和矩阵乘法运算,并通过其开发的cuda-convnet框架显著提升训练速度。这一创新成为行业标准,推动了深度学习的兴起。
.
2)AlexNet
2012年,AlexNet横空出世。它首次证明了学习到的特征可以超越手工设计的特征。它一举打破了计算机视觉研究的现状。 AlexNet使用了8层卷积神经网络,并以很大的优势赢得了2012年ImageNet图像识别挑战赛。
AlexNet和LeNet的架构非常相似。这里稍微精简版本的AlexNet,去除了当年需要两个小型GPU同时运算的设计特点。
图7.1.2 从LeNet(左)到AlexNet(右)
AlexNet和LeNet的设计理念非常相似,但也存在显著差异。
-
AlexNet比LeNet5要深得多。AlexNet由八层组成:五个卷积层、两个全连接隐藏层和一个全连接输出层。
-
AlexNet使用ReLU而不是sigmoid作为其激活函数。
下面的内容将深入研究AlexNet的细节。
.
(1)模型设计
在AlexNet的第一层,卷积窗口的形状是11x11。 由于ImageNet中大多数图像的宽和高比MNIST图像的多10倍以上,因此,需要一个更大的卷积窗口来捕获目标。 第二层中的卷积窗口形状被缩减为5x5,然后是3x3。 此外,在第一层、第二层和第五层卷积层之后,加入窗口形状为3x3、步幅为2的最大汇聚层。 而且,AlexNet的卷积通道数目是LeNet的10倍。
在最后一个卷积层后有两个全连接层,分别有4096个输出。 这两个巨大的全连接层拥有将近1GB的模型参数。 由于早期GPU显存有限,原版的AlexNet采用了双数据流设计,使得每个GPU只负责存储和计算模型的一半参数。 幸运的是,现在GPU显存相对充裕,所以现在很少需要跨GPU分解模型(因此,本书的AlexNet模型在这方面与原始论文稍有不同)。
.
(2)激活函数
AlexNet将sigmoid激活函数改为更简单的ReLU激活函数。 一方面,ReLU激活函数的计算更简单,它不需要如sigmoid激活函数那般复杂的求幂运算。 另一方面,当使用不同的参数初始化方法时,ReLU激活函数使训练模型更加容易。
当sigmoid激活函数的输出非常接近于0或1时,这些区域的梯度几乎为0(梯度消失),因此反向传播无法继续更新一些模型参数。 相反,ReLU激活函数在正区间的梯度总是1。 因此,如果模型参数没有正确初始化,sigmoid函数可能在正区间内得到几乎为0的梯度,从而使模型无法得到有效的训练。
.
(3)容量控制和预处理
AlexNet通过暂退法(Dropout)( 4.6节)控制全连接层的模型复杂度,而LeNet只使用了权重衰减。 为了进一步扩充数据,AlexNet在训练时增加了大量的图像增强数据,如翻转、裁切和变色。 这使得模型更健壮,更大的样本量有效地减少了过拟合。 在 13.1节中更详细地讨论数据扩增。
import torch
from torch import nn
from d2l import torch as d2lnet = nn.Sequential(# 这里使用一个11*11的更大窗口来捕捉对象。# 同时,步幅为4,以减少输出的高度和宽度。# 另外,输出通道的数目远大于LeNetnn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),# 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),# 使用三个连续的卷积层和较小的卷积窗口。# 除了最后的卷积层,输出通道的数量进一步增加。# 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),nn.MaxPool2d(kernel_size=3, stride=2),nn.Flatten(),# 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合nn.Linear(6400, 4096), nn.ReLU(),nn.Dropout(p=0.5),nn.Linear(4096, 4096), nn.ReLU(),nn.Dropout(p=0.5),# 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000nn.Linear(4096, 10))
构造一个224x224的单通道数据,来观察每一层输出的形状。 它与上图AlexNet架构相匹配。
X = torch.randn(1, 1, 224, 224)
for layer in net:X=layer(X)print(layer.__class__.__name__,'output shape:\t',X.shape)
Conv2d output shape: torch.Size([1, 96, 54, 54])
ReLU output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Conv2d output shape: torch.Size([1, 256, 26, 26])
ReLU output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 256, 12, 12])
ReLU output shape: torch.Size([1, 256, 12, 12])
MaxPool2d output shape: torch.Size([1, 256, 5, 5])
Flatten output shape: torch.Size([1, 6400])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])
.
3)读取数据集
尽管AlexNet原来使用ImageNet数据集,但这里使用Fashion-MNIST数据集。由于其图像分辨率(28×28)低于ImageNet,需将其调整为224×224以适配AlexNet结构。使用d2l.load_data_fashion_mnist
函数的resize
参数实现。
batch_size = 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
.
4)训练AlexNet
现在AlexNet开始被训练了。与LeNet相比,这里的主要变化是使用更小的学习速率训练,这是因为网络更深更广、图像分辨率更高,训练卷积神经网络就更昂贵。
lr, num_epochs = 0.01, 10
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())# 输出:
loss 0.331, train acc 0.878, test acc 0.883
3941.8 examples/sec on cuda:0
.
5)小结
-
AlexNet的架构与LeNet相似,但使用了更多的卷积层和更多的参数来拟合大规模的ImageNet数据集。
-
今天,AlexNet已经被更有效的架构所超越,但它是从浅层网络到深层网络的关键一步。
-
尽管AlexNet的代码只比LeNet多出几行,但学术界花了很多年才接受深度学习这一概念,并应用其出色的实验结果。这也是由于缺乏有效的计算工具。
-
暂退法(Dropout)、ReLU和预处理是提升计算机视觉任务性能的其他关键步骤。
.
声明:资源可能存在第三方来源,若有侵权请联系删除!