动手学深度学习-24

敖炜 Lv5

深度卷积神经网络AlexNet

与训练端到端(从像素到分类结果)系统不同,经典机器学习的流水线看起来更像下面这样:

  1. 获取一个有趣的数据集。在早期,收集这些数据集需要昂贵的传感器(在当时最先进的图像也就100万像素)。
  2. 根据光学、几何学、其他知识以及偶然的发现,手工对特征数据集进行预处理。
  3. 通过标准的特征提取算法,如SIFT(尺度不变特征变换)和SURF(加速鲁棒特征)或其他手动调整的流水线来输入数据。
  4. 将提取的特征送入最喜欢的分类器中(例如线性模型或其它核方法),以训练分类器。

学习表征

深度卷积神经网络的突破出现在2012年。突破可归因于两个关键因素。

缺少的成分:数据

包含许多特征的深度模型需要大量的有标签数据,才能显著优于基于凸优化的传统方法(如线性方法和核方法)。
然而,限于早期计算机有限的存储和90年代有限的研究预算,大部分研究只基于小的公开数据集。例如,不少研究论文基于加州大学欧文分校(UCI)提供的若干个公开数据集,其中许多数据集只有几百至几千张在非自然环境下以低分辨率拍摄的图像。这一状况在2010年前后兴起的大数据浪潮中得到改善。2009年,ImageNet数据集发布,并发起ImageNet挑战赛:要求研究人员从100万个样本中训练模型,以区分1000个不同类别的对象。ImageNet数据集由斯坦福教授李飞飞小组的研究人员开发,利用谷歌图像搜索(Google Image Search)对每一类图像进行预筛选,并利用亚马逊众包(Amazon Mechanical Turk)来标注每张图片的相关类别。这种规模是前所未有的。这项被称为ImageNet的挑战赛推动了计算机视觉和机器学习研究的发展,挑战研究人员确定哪些模型能够在更大的数据规模下表现最好。

缺少的成分:硬件

深度学习对计算资源要求很高,训练可能需要数百个迭代轮数,每次迭代都需要通过代价高昂的许多线性代数层传递数据。这也是为什么在20世纪90年代至21世纪初,优化凸目标的简单算法是研究人员的首选。然而,用GPU训练神经网络改变了这一格局。图形处理器(Graphics Processing Unit,GPU)早年用来加速图形处理,使电脑游戏玩家受益。GPU可优化高吞吐量的矩阵和向量乘法,从而服务于基本的图形任务。幸运的是,这些数学运算与卷积层的计算惊人地相似。由此,英伟达(NVIDIA)和ATI已经开始为通用计算操作优化gpu,甚至把它们作为通用GPU(general-purpose GPUs,GPGPU)来销售。

那么GPU比CPU强在哪里呢?

首先,我们深度理解一下中央处理器(Central Processing Unit,CPU)的核心
CPU的每个核心都拥有高时钟频率的运行能力,和高达数MB的三级缓存(L3Cache)。
它们非常适合执行各种指令,具有分支预测器、深层流水线和其他使CPU能够运行各种程序的功能。
然而,这种明显的优势也是它的致命弱点:通用核心的制造成本非常高。
它们需要大量的芯片面积、复杂的支持结构(内存接口、内核之间的缓存逻辑、高速互连等等),而且它们在任何单个任务上的性能都相对较差。
现代笔记本电脑最多有4核,即使是高端服务器也很少超过64核,因为它们的性价比不高。

相比于CPU,GPU由个小的处理单元组成(NVIDIA、ATI、ARM和其他芯片供应商之间的细节稍有不同),通常被分成更大的组(NVIDIA称之为warps)。
虽然每个GPU核心都相对较弱,有时甚至以低于1GHz的时钟频率运行,但庞大的核心数量使GPU比CPU快几个数量级。
例如,NVIDIA最近一代的Ampere GPU架构为每个芯片提供了高达312 TFlops的浮点性能,而CPU的浮点性能到目前为止还没有超过1 TFlops。
之所以有如此大的差距,原因其实很简单:首先,功耗往往会随时钟频率呈二次方增长。
对于一个CPU核心,假设它的运行速度比GPU快4倍,但可以使用16个GPU核代替,那么GPU的综合性能就是CPU的倍。
其次,GPU内核要简单得多,这使得它们更节能。
此外,深度学习中的许多操作需要相对较高的内存带宽,而GPU拥有10倍于CPU的带宽。

回到2012年的重大突破,当Alex Krizhevsky和Ilya Sutskever实现了可以在GPU硬件上运行的深度卷积神经网络时,一个重大突破出现了。他们意识到卷积神经网络中的计算瓶颈:卷积和矩阵乘法,都是可以在硬件上并行化的操作。
于是,他们使用两个显存为3GB的NVIDIA GTX580 GPU实现了快速卷积运算。他们的创新cuda-convnet 几年来它一直是行业标准,并推动了深度学习热潮。

以上两个突破可以由下面一张对比图看出

数据与硬件的突破

AlexNet

2012年出现的AlexNet首次证明了学习到的特征可以超越手工设计的特征,从而导致了计算机视觉方法论的改变

计算机视觉方法论的改变

AlexNet和LeNet的架构非常相似

这里的示意图是一个稍微精简版本的AlexNet,去除了当年需要两个小型GPU同时运算的设计特点。

AlexNet与LeNet

AlexNet和LeNet的设计理念非常相似,但也存在显著差异。

  1. AlexNet比相对较小的LeNet5要深得多。AlexNet由八层组成:五个卷积层、两个全连接隐藏层和一个全连接输出层。
  2. AlexNet使用ReLU而不是sigmoid作为其激活函数。

模型设计

在AlexNet的第一层,卷积窗口的形状是
由于ImageNet中大多数图像的宽和高比MNIST图像的多10倍以上,因此,需要一个更大的卷积窗口来捕获目标。
第二层中的卷积窗口形状被缩减为,然后是
此外,在第一层、第二层和第五层卷积层之后,加入窗口形状为、步幅为2的最大汇聚层。
而且,AlexNet的卷积通道数目是LeNet的10倍。

在最后一个卷积层后有两个全连接层,分别有4096个输出。
这两个巨大的全连接层拥有将近1GB的模型参数。
由于早期GPU显存有限,原版的AlexNet采用了双数据流设计,使得每个GPU只负责存储和计算模型的一半参数。
幸运的是,现在GPU显存相对充裕,所以现在很少需要跨GPU分解模型(因此,这里的AlexNet模型在这方面与原始论文稍有不同)。

激活函数

此外,AlexNet将sigmoid激活函数改为更简单的ReLU激活函数。
一方面,ReLU激活函数的计算更简单,它不需要如sigmoid激活函数那般复杂的求幂运算。
另一方面,当使用不同的参数初始化方法时,ReLU激活函数使训练模型更加容易。
当sigmoid激活函数的输出非常接近于0或1时,这些区域的梯度几乎为0,因此反向传播无法继续更新一些模型参数。
相反,ReLU激活函数在正区间的梯度总是1。
因此,如果模型参数没有正确初始化,sigmoid函数可能在正区间内得到几乎为0的梯度,从而使模型无法得到有效的训练。

容量控制和预处理

AlexNet通过暂退法控制全连接层的模型复杂度,而LeNet只使用了权重衰减。
为了进一步扩充数据,AlexNet在训练时增加了大量的图像增强数据,如翻转、裁切和变色。
这使得模型更健壮,更大的样本量有效地减少了过拟合。

数据增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import torch
from torch import nn
from d2l import torch as d2l

net = nn.Sequential(
# 使用一个11*11的更大窗口来捕捉对象
# 同时,步幅为4,以减少输出的宽度和高度
# 另外,输出通道的数目远大于LeNet

nn.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,而非论文中的1000
nn.Linear(4096, 10)
)

读取数据集

尽管原文中AlexNet是在ImageNet上进行训练的,但本书在这里使用的是Fashion-MNIST数据集。因为即使在现代GPU上,训练ImageNet模型,同时使其收敛可能需要数小时或数天的时间。
将AlexNet直接应用于Fashion-MNIST的一个问题是,Fashion-MNIST图像的分辨率像素)低于ImageNet图像。
为了解决这个问题,**我们将它们增加到**(通常来讲这不是一个明智的做法,但在这里这样做是为了有效使用AlexNet架构)。
这里需要使用d2l.load_data_fashion_mnist函数中的resize参数执行此调整。

1
2
batch_size = 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)

训练AlexNet

1
2
lr, num_epochs = 0.01, 10
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

小结

  • AlexNet的架构与LeNet相似,但使用了更多的卷积层和更多的参数来拟合大规模的ImageNet数据集。
  • 今天,AlexNet已经被更有效的架构所超越,但它是从浅层网络到深层网络的关键一步。
  • 尽管AlexNet的代码只比LeNet多出几行,但学术界花了很多年才接受深度学习这一概念,并应用其出色的实验结果。这也是由于缺乏有效的计算工具。
  • Dropout、ReLU和预处理是提升计算机视觉任务性能的其他关键步骤。

QA

  • 标题: 动手学深度学习-24
  • 作者: 敖炜
  • 创建于 : 2023-09-03 17:05:38
  • 更新于 : 2024-04-19 09:28:53
  • 链接: https://ao-wei.github.io/2023/09/03/动手学深度学习-24/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论