MLP 结构是为了接受一维数据设计的,不能直接处理二维或更高维的数据,除非进行预处理。一维数据也称为表格数据,通常包括分类数据、数值数据,可能还包括文本数据。二维数据或更高维数据是某种形式的图像数据。当图像是灰度格式时,它的数据是二维的;当图像有 RGB 层,并且能较好地表示人眼看到的内容时,数据是三维的;而当图像是高光谱图像时,数据可能超过三维。通常,为了使 MLP 适用于图像数据,你需要将数据展平,并有效地以一维格式表示相同的数据。展平数据在某些情况下可能有效,但丢失了定义图像的空间特性,这就去除了捕捉图像与目标之间关系的潜力。此外,展平数据在处理大图像时并不适用。图像数据的一个重要特征是,待识别的目标可以出现在图像的任何空间位置。简单的 MLP 强烈依赖于数据输入的位置,无法适应图像中目标不断变化的位置和方向。
这正是卷积神经网络(CNN)层发挥作用的地方,它通常是处理图像数据的专家首选方法。至今,顶级的卷积架构在图像数据集上的性能总是超过 MLP 架构。在本章中,我们将涵盖以下内容,重点关注 CNN:
- 理解卷积神经网络层
- 理解池化层
- 构建 CNN 架构
- 为实际应用设计 CNN 架构
- 探索 CNN 架构家族
技术要求
本章包括一些用 Python 编程语言实现的实际操作。为完成本章内容,你需要一台安装了以下库的计算机:
- pandas
- matplotlib
- seaborn
- scikit-learn
- numpy
- keras
- pytorch
本章的代码文件可在 GitHub 上获取:github.com/PacktPublis…
理解卷积神经网络层
现在,让我们关注卷积层的基础,从图 3.1 开始,图中展示了卷积滤波器的操作过程。滤波器是一个小的权重矩阵,用于从输入数组中提取特征或模式。卷积滤波器是一种滤波器,它在图像上滑动,执行卷积操作,通过计算点积来提取特征:
卷积层由多个相同大小的卷积滤波器组成。卷积滤波器是 CNN 中的主要模式检测器,每个滤波器将学习识别图像中存在的多维模式。这些模式可以从低级模式(如线条和边缘)、中级模式(如圆形或方形)到高级模式(如特定的 T 恤类型或鞋子类型),具体取决于 CNN 中卷积层的深度。在第 12 章《解释神经网络》中,我们将探索学习到的模式,并定性和定量地评估这些模式。
卷积滤波器可以是多维的,但对于普通的图像,二维卷积滤波器更为常用。核与 CNN 层中的滤波器类似。这些二维滤波器的权重数量与其大小相同,并对输入图像数据的相同大小部分执行点积操作,以获得一个单一的值;随后,这些值将与偏置项相加。通过在滑动窗口的方式下系统地对同一操作进行处理,从上到下、从左到右,以定义的步长滑动滤波器,卷积滤波器将完成前向传播,并获得一个维度较小的二维输出。这里,步长(stride)指的是滑动滤波器时从左到右和从上到下所跨越的像素步数,最小步长必须至少为 1 像素。此操作基于目标可以出现在图像的任何空间位置的事实,并在整个图像上使用相同的模式识别方法。
图 3.1 显示了一个大小为 5x5 像素的二维卷积滤波器,其中有 25 个权重组件和一个偏置组件可以被学习,以及一张 T 恤的输入图像,大小为 28x28 像素。滤波器的大小可以配置为其他值,通常在 1 到 7 之间,通常是正方形,但也可以设置为不规则的矩形形状。典型的滤波器大小值可能看起来像是一个太小的感受野,无法识别高层特征来预测这张图片中的 T 恤,但当多个滤波器按顺序依次应用时,操作结束时的滤波器将拥有更大部分图像的感受野。感受野指的是卷积滤波器可以“看到”或响应的输入空间的区域。它决定了影响特定输出单元的输入的空间范围。为了捕捉低级模式,滤波器必须具有较小的感受野;而为了捕捉高级模式,滤波器必须具有较大的感受野。图 3.2 描述了这一概念,展示了三个滤波器按顺序应用的效果:
现在,从左到右、从上到下的滑动窗口只是一个很好的方式来可视化这个过程。然而,实际上,这个过程可以通过并行计算一次完成,以利用 GPU 的并行处理能力。图 3.3 显示了一个 4x4 像素尺寸、步长为 4 的卷积滤波器在同一 28x28 的 T 恤图像上应用时,所有窗口位置的情况。这样将得到一个 7x7 的数据输出大小:
考虑一个 CNN 层,包含 16 个大小为 5x5 像素、步长为 1 像素的滤波器。对 T 恤图像进行前向传播时,使用这种层配置将产生 16x26x26(深度 x 宽度 x 高度)像素的输出。如果图像是一个 RGB 图像,具有三个颜色通道(红色、绿色和蓝色),由于卷积滤波器是二维的,相同的滤波器将类似地应用于三个通道中的每一个,使用标准的卷积层。然后,分别应用于三个通道的滤波器的三维输出将会被加在一起。卷积滤波器的数量将是输出数据通道的大小,并将作为随后的卷积层的输入通道大小。图 3.4 描述了卷积滤波器输出 3x3 的通道加法过程。请注意,偏置仅在每个滤波器的通道中加一次,而不是按通道加:
在前面的图中,Conv 是卷积层的缩写,这将是本章中用于简化图示的约定。由于了解神经网络的大小对于确保你有足够的计算资源来存储和处理网络是有益的,让我们也计算一下这个卷积层将持有的参数数量。参数的数量可以通过以下公式计算:
输入通道数 × 滤波器数量 × ((滤波器宽度 × 滤波器高度) + 1)
将相应的数字代入公式,你将得到 416 个参数。如果这些权重以浮动点 32(fp32)格式存储,按字节计算,这意味着 416 × 32 位 / 8 = 1,664 字节。由于输出数据的大小为 16x26x26,空间维度中的数据大小变化非常缓慢,而最终目标是将这些值减少到目标数据的大小,因此我们需要一些方法来减少数据的大小。这时,另一个层——池化层(Pooling Layer)就派上用场了。
理解池化层
通过仅对图像进行一次前向传播,CNN 层输出的二维数据大小可能会减少,但仍然可能保持相当大的尺寸。为了进一步减小数据的尺寸,使用了一种称为池化层的层类型,它通过策略性地聚合和整合值,同时保持有用的信息。可以将这种操作看作是一种图像缩放方法,同时尽可能保留信息。池化层没有学习的参数,主要是用于简洁而有效地减少输出数据。池化层通过应用与卷积层类似的滑动窗口滤波器过程来工作,但与卷积层不同,它不执行点积并添加偏置,而是执行一种聚合操作。聚合函数可以是最大聚合、最小聚合或平均聚合。应用这些聚合的层分别被称为最大池化(Max Pooling)、最小池化(Min Pooling)和平均池化(Average Pooling)。
考虑一个大小为 4,步长为 2 的平均池化层,应用于第一个 CNN 层之后。对 16x26x26 输出进行前向传播后,将得到 16x12x12 的数据大小,极大地减少了数据的大小!
另一种池化层应用全局聚合函数。这意味着数据的整个二维宽度和高度组件将被聚合成一个单一的值。这种池化层的变体通常被称为全局池化层(Global Pooling Layer)。该层用于将数据完全分解成一维结构,从而使其与一维目标兼容。此层在 Keras 库中直接可用,但在 PyTorch 中则需要通过将池化滤波器大小设置为与输入特征图的大小相同来间接实现。
构建 CNN 架构
CNN 架构通常通过将多个概念逻辑层块依次堆叠来构建。这些逻辑块结构相同,具有相同类型的层和层连接,但在其参数配置上可能有所不同,例如滤波器的大小、步长、使用的填充类型和填充量。最简单的逻辑卷积块包括卷积层、池化层和激活函数,按此顺序排列。填充(Padding)是指在输入图像周围添加额外像素的术语,以保持卷积后的空间维度。逻辑块是一种简单高效地描述和引用架构的方法。它们还允许你以深度可扩展的方式构建 CNN 架构,而无需逐一创建和设置每个层的参数。深度(Depth)等同于深度层数,指的是神经网络的层数。
参数的设计可以根据目标是逐渐缩小特征图,还是逐渐放大特征图来进行调整。对于一维目标的情况,目标可能是逐步将特征缩小为一维特征,以便这些特征可以传递到全连接层。这些全连接层可以进一步将(仍然较大的)维度映射到适合目标的维度。你可以在图 3.5 中看到这样的架构的简单设计:
这种设计策略不仅确保了CNN能够高效地处理图像数据,还为更复杂的任务提供了扩展性。在构建卷积神经网络时,深度、卷积层的选择和池化操作的使用,都能够决定模型的训练效率与最终的泛化能力。
在 PyTorch 的代码中,这个示例看起来如下:
class ConvArch(nn.Module):
def __init__(self):
super(ConvArch, self).__init__()
self.conv1 = nn.Conv2d(
in_channels=1, out_channels=12, kernel_size=4,
stride=2, padding=0
)
self.conv2 = nn.Conv2d(
in_channels=12, out_channels=5, kernel_size=3,
stride=1, padding=0
)
self.fc2 = nn.Linear(5, 3)
def forward(self, x):
x = F.relu(
F.avg_pool2d(
self.conv1(x), kernel_size=3, stride=2
)
)
x = F.relu(
F.avg_pool2d(
self.conv2(x), kernel_size=3, stride=1
)
)
x = F.avg_pool2d(x, kernel_size=x.size()[2:])
x = self.fc2(x.reshape((x.size()[:2])))
return x
同样,CNN 架构的反向传播将由深度学习库自动处理。
我们构建的架构基于基本的分类问题类型,这也解释了为什么在网络的最后需要一个全连接网络,这通常被称为网络的“头”。用于的卷积层逻辑块集合被称为网络的“骨干”。网络的头部可以根据问题类型被替换为其他结构,但骨干可以完全适应大多数架构,用于任何问题类型,比如物体检测、图像生成、图像描述或通过表示学习进行的图像识别。某些问题类型将在第 8 章《探索监督式深度学习》中讨论。
现在我们已经成功地手动构建了一个简单的 CNN,并且我们已经理解并同步了卷积网络的核心算法理论,准备好在需要时设计更先进的 CNN 骨干架构。但在此之前,有一个问题:我们如何为我们的使用案例设计 CNN?
为实际应用设计 CNN 架构
对于实际应用案例,CNN 的设计不应与 MLP 的设计相同。实际应用意味着目标不是研究一种新的创新架构来解决未探索的问题类型。如今,基于 CNN 已取得了许多进展。这些进展通常有两种形式:
- 设置了一个新的基准,完全重新设计了 CNN 架构的构建方式
- 在现有的基准 CNN 架构上构建,并补充和提高了基准架构的性能
CNN 的理想设计方法与 MLP 的不同之处在于,应该使用已发布的 CNN 架构结构,而不是从零开始设计架构。CNN 架构的结构定义了层的类型以及不同类型的层如何连接;这些通常是通过逻辑块来实现的。此外,某个特定结构的独特性定义了 CNN 架构的家族。新的 CNN 研究进展通常提供不同的大小配置,以便根据计算资源的限制、运行时要求或数据集和问题的复杂性选择合适的架构。类似于 MLP 的设计,如果资源和运行时不是限制条件,选择了 CNN 架构结构后,可以根据问题的复杂性和数据集的大小,从一个较小尺寸的 CNN 开始。然后,你可以逐步测试更大的 CNN,看看增大尺寸是否能提高性能,或者反之,性能是否会下降。
不同的 CNN 架构结构或架构家族通常旨在捕捉网络的不同内在架构问题。有些架构家族的设计方式可以更好地利用硬件资源,没有这些资源,架构甚至无法执行。为了获得良好的性能,一个好的实践是在初始阶段多样化你使用的架构结构类型。选择具有类似浮动点运算每秒(FLOPS)大小的架构结构的尺寸变体,并进行实验以获得性能得分,理想情况下,使用较小的尺寸来最大化探索的效率。与模型的参数数量相比,更相关的是考虑每秒浮动点运算数作为模型复杂度的指标;因为参数数量并没有考虑到模型的实际运行时,后者可以通过并行化获益。一旦获得了这些数字,就选择最佳的模型家族,并尝试更大尺寸的变体进行基准测试,找到最适合你用例的模型变体。
大多数 CNN 研究的改进是基于一个简单的基准架构。这意味着对相同基准架构所做的所有其他个别改进并没有一起进行基准测试。将这些改进一起测试通常是互补的,但有时它们可能对模型的指标性能产生负面影响。迭代地基准测试不同的配置可能是获得满意的性能改进的最系统和扎实的方式。
研究人员如何评估他们的改进?为了设计一个用于实际应用的 CNN 架构,了解如何评估你的架构将帮助你逐步实现可接受的性能指标。在第 10 章《探索模型评估方法》中,我们将更详细地讨论评估策略。CNN 改进的主要评估方法之一是基于 ImageNet 数据集的 top-1 预测准确性,ImageNet 是一个包含数百万张图像和许多类别的大型公开数据集。ImageNet 被认为是一个高度复杂的问题类型用例,每个类别在现实中可能具有无限的变种,从室内到室外,从真实数据到合成数据。
那么,我们如何考虑改进是否有价值?改进是为了提高基于 ImageNet 数据集的 top-1 准确性,提升模型前向传播的效率,或专门提高网络的训练时间。
仅通过 ImageNet 上的 top-1 准确性指标性能来排名架构是一种偏见评估,因为在不同的图像数据集上应用相同架构时,模型的绝对排名通常会不同。使用它作为选择现成架构的起点是明智的,但确保评估一些 top-performing ImageNet 架构,找出最适合的架构。此外,尽管 ImageNet 是通过手动努力策划的,涉及查询搜索引擎并通过 Amazon Mechanical Turk 对候选图像进行验证步骤,但它仍然包含一些标签噪声,这可能会影响指标性能背后的含义。
至于提高前向传播效率的改进,这通常通过减少架构的参数数量,将计算密集型逻辑组件分解为多个组件以减少操作量,或用具有更高并行潜力的层替换其他层来实现。这些改进要么保持要么提高模型在 ImageNet 验证数据集上的指标性能分数。这个改进方向是专门针对设计用于低资源边缘设备的 CNN 架构家族的一个主要关注点。我们将在后面深入探讨。
在你的用例中,探索不同 CNN 架构家族以实现更好的指标性能的有效方法是选择具有公开实现的模型家族,这些模型家族包括在 ImageNet 上训练的预训练权重。使用预训练权重初始化你的架构带来了许多好处,包括更快的训练、较少的过拟合和更强的泛化能力,即使预训练权重使用的数据集属于不同的问题子集。这个过程叫做迁移学习,我们将在第 8 章《探索监督式深度学习》和第 9 章《探索无监督式深度学习》中更详细地学习这一过程。
探索 CNN 架构家族
现在,除了回顾 CNN 的发展历程,我们来看看不同的手工挑选的模型架构家族。这些架构家族的选择足够多样和不同。需要注意的一点是,神经网络正在以惊人的速度发展。考虑到这一点,这里介绍的架构家族确保是当今仍然相关的。此外,我们将只呈现关于架构家族的最重要信息,以简洁但足够的细节简化大量的研究论文。
在深入探讨这个话题之前,还需要注意的一点是,数据集上的指标性能通常是不同架构之间的主要比较方法,因此要注意,模型的指标性能是由训练方法和架构的集体贡献所决定的。训练方法包括与模型架构无关的细节,例如所使用的损失函数、数据增强策略和数据分辨率等。这些主题将在第 8 章《探索监督式深度学习》中详细讨论。我们将在这里介绍的架构家族有 ResNet、DenseNet、MobileNet、EfficientNet、ShuffleNet 和 MicroNet。
理解 ResNet 模型家族
ResNet 架构于 2015 年提出,基于深度网络难以训练的前提,旨在解决这个问题。梯度消失是神经网络面临的一个广为人知的问题,网络越深,数据的信息就会越减小。然而,纯深度 CNN 架构被证明并不会遭遇梯度消失问题,这通过验证梯度信息得到了证明。梯度消失的主要原因是我们使用了过多的激活函数,将数据压缩到非常小的值范围内。一个例子是 Sigmoid 函数,它将数据映射到 0 到 1 之间。所以,当你不确定时,使用 ReLU 激活函数!
ResNet 中的 “Res” 代表残差(Residuals)。其核心思想是,从残差中学习比从未修改的特征图中学习要容易得多。残差是通过从早期层到后期层添加跳跃连接(skip connections)来实现的。通俗地说,这意味着将早期部分的特征图(而不是串联)加到网络后期部分的特征图上。这样的加法操作生成了残差,随后卷积层将学习这些残差,再次应用更多的跳跃连接,产生更多的残差。残差可以轻松地应用于任何 CNN 架构,并且可以视为对旧基线架构的改进。然而,作者还展示了多个使用跳跃连接的架构变种,使用了不同数量的卷积层,包括 ResNet-18、ResNet-34、ResNet-50、ResNet-101 和 ResNet-152。ResNet 架构家族作为残差网络使用的模板,最终使其成为研究新进展的最受欢迎的基线架构。
实际的架构设计在此不做正式介绍,因为记住这些设计并不会对你理解 CNN 知识产生影响。相反,图 3.6 显示了单个逻辑块的残差计算过程:
为了总结整个基准 ResNet 大小变体,以下表格展示了所有不同大小变体的配置总结:
表格中所示的括号表示的是定义为逻辑块的一组串行卷积层。ResNet 还进一步将多个基本逻辑块分组到一个更高层次的类别中,称为“层名称”。不同大小变体中的层名称具有相同数量的组。逻辑块和更高层次的分组方法只是用来简洁高效地描述和引用复杂架构的一种方式。逻辑块中的前两个数字通过乘法定义卷积滤波器的大小;其后的数字用逗号隔开,定义了滤波器的数量。
研究发现,跳跃连接能够平滑任何神经网络的损失景观,使得学习过程更加容易和稳定。这使得神经网络能够更容易地收敛到最优解。图 3.8 显示了没有跳跃连接的神经网络的损失景观,左侧是一个不平坦的地形,充满了许多山丘和山谷。当使用 ResNet 变体添加跳跃连接后,损失景观变成了一个平滑的地形,明显呈现出一个单一的山谷。
从表格中可以推导出一个值得注意的信息,从 ResNet-50 开始,该架构使用了 1x1 的卷积滤波器。由于该滤波器仅在通道维度上使用单维滤波器权重,因此该操作相当于在通道维度上以窗口方式应用一个全连接层。由于全连接层本身也是一个网络,并且与卷积网络一起工作,这种操作通常被称为“网络中的网络”。接下来,让我们探索基于 ResNet 架构的不同改进。
改进 ResNets
如前所述,ResNet 被认为是一个模型家族,包含许多不同的变种,不仅仅是按大小,还有不同的架构改进。任何基于 ResNet 的 CNN 架构都属于这个模型家族。在这里,我们提到了一些值得注意的架构进展,并提供了基于 ResNet 的主要进展描述;它们按年份排列:
- ResNeXt (2016) :该架构将 ResNet 中逻辑块的串行卷积层转换为并行的卷积层分支,并在逻辑块的末尾合并这些并行层。与 ResNet 变体相比,即使参数数量相同,它在 ImageNet 上提高了指标性能,并且通常也表现得更好。
- Squeeze-and-Excitation Networks (SE-ResNet) (2017) :由于二维卷积没有考虑通道间的关系,仅考虑特征图的局部和空间(宽度和高度)信息,因此提出了一种利用通道关系的方法,该方法包括一个 squeeze 块和一个 excitation 块。这是一种可以反复应用于现有 CNN 架构许多部分的方法。图 3.9 展示了该方法的结构,其中在宽度和高度维度上应用全局平均池化,随后应用两个全连接网络来缩小和放大特征,最终将特征恢复到相同的大小,从而使通道信息能够结合。
结构中的缩放部分是指将值相乘的部分。当与 ResNet 结合时,该架构被称为 SE-ResNet。
- ResNet-D (2019) :这一进展对简单架构参数进行了调整,以提高指标性能,同时保持参数数量不变,尽管 FLOP 规格略有增加。由于 ResNet 的某些路径使用了步长为 2 的 1x1 卷积,导致 ¾ 的信息被丢弃,其中一个调整就是修改了步长大小,以确保没有信息被显式去除。它们还通过将 7x7 卷积改为三个单独的 3x3 卷积串联,从而减少了计算负担。
- ResNet-RS (2021) :这一进展结合了 ResNet-D 和 squeeze-and-excitation 网络,使用的图像大小依赖于网络的大小。然而,它的增长速度比 EfficientNets 慢(EfficientNets 将在后面介绍)。
理解 DenseNet 架构家族
DenseNet 是一个架构家族,最早于 2018 年初推出。该架构基于跳跃连接的理念,类似于 ResNet 架构家族,但在此基础上进行了扩展,意味着它使用了大量的跳跃连接。这个架构家族中的跳跃连接不同于传统的残差连接(通过求和),而是通过连接(concatenation)实现。求和允许早期的信息直接编码到未来层的输出中,而无需修改神经元的数量,尽管在信息上略有劣势,因为未来的层需要学习解码这些信息。连接会增加架构的大小,因为需要创建额外的神经元来处理额外的信息,这使得模型能够直接处理原始数据。两者提供了类似的跳跃连接优势。
该架构的逻辑块被称为密集块(dense blocks),在这些块中,块中的每一层都可以通过特征图连接访问其之前所有层的输出。在这些块中,使用零填充(zero-padding)来确保每一层输出的空间维度得以保持,从而使特征图能够连接在一起。这种设置促进了同一块中各层之间的大量特征重用,并允许模型的参数数量保持不变,同时增加了模型的学习能力。每个块中后续层的滤波器数量固定为一个常数,称为增长率(growth rate),因为需要有一个结构化的方式来添加层,以避免指数增长通道数量。以 32 个滤波器为常数,块中第二层的输入将是一个具有 32 个通道的特征图,第三层的输入将是 64 个通道并进行连接,依此类推。
为了创建完整的网络架构,多个密集块被一个接一个堆叠,在密集块之间插入单独的卷积层和池化层,逐渐减少特征图的空间维度。图 3.10 显示了 DenseNet 模型家族下四种不同 DenseNet 模型架构的网络结构:
这使得 DenseNet 在 top-1 ImageNet 准确度方面超过了其前身的网络架构。
理解 EfficientNet 架构家族
EfficientNet 于 2020 年推出,通过使用自动化神经架构搜索(NAS)方法创建了一系列架构,首先生成一个小型基础高效架构,然后利用易于使用的复合缩放方法来缩放架构的深度、宽度以及图像分辨率。神经架构搜索是在平衡 FLOPS 和准确度的方式下进行的。使用的 NAS 方法来源于另一项研究叫做 MnasNet,并将在第 7 章《深度神经架构搜索》中进行详细介绍。
复合缩放方法简单且可以扩展到任何其他网络,尽管 ResNet-RS 显示,慢速缩放分辨率提供了更多的价值。深度、宽度和分辨率的缩放方法在以下方程中定义,其中结果将乘以原始基础架构的参数来缩放架构:
depth = α φ , width = β φ , resolution = γ φ
这里,φ 是一个系数,可以根据需求缩放到不同的值,其他变量是常数,应该设置为优化某些内容(例如,当我们改变系数时 FLOPS 增长率)。对于 EfficientNet,常数被约束以满足以下条件:
α ∙ β² ∙ γ² ≈ 2
这将约束系数的增长,使得 FLOPS 增长大约为 2 φ。EfficientNet 将此设置为 α = 1.2,β = 1.1,γ = 1.15。这个复合缩放策略使得七种 EfficientNet 模型得以创建,命名为 B0 到 B7。图 3.11 显示了 EfficientNet-B0 的结构:
需要注意的是,MBConv 也被称为倒残差块(inverted residual block),将在稍后在《理解 MobileNetV2》一节中正式介绍。
EfficientNetV2 于 2021 年推出,发现大图像分辨率会拖慢训练时间,因为深度卷积在早期层中计算较慢,同时同时缩放深度、宽度和分辨率并不是最优的。EfficientNetV2 也使用 NAS 来找到基础架构,但增加了一个 MBConv 块的修改版本,具有更多的参数和操作,原因是它有时可以更快,具体取决于输入和输出数据的形状,它们在整个架构中的位置,以及数据如何传递到计算处理器中。稍后我们会在正式介绍 MBConv 时对此进行更详细的解释。EfficientNetV2 还使用了原始的复合缩放方法,但通过设置最大图像分辨率为 480 并在架构的最后几个阶段添加额外层来进行了一些改进,当它想要将网络容量增加到更高比例时。为了减少训练时间,还添加了一种新的训练方法;我们将在下一章中详细讨论这些内容。这些改进使得四个不同的 EfficientNetV2 模型得以推出,分别为 EfficientNetV2-S、EfficientNetV2-M、EfficientNetV2-L 和 EfficientNetV2-XL。这些模型在相似的 FLOP 值下超过了原始 EfficientNet 的 top-1 准确度:
EfficientNetV2-S 作为基础架构,类似于 EfficientNetB0 作为基础架构,其架构结构如图 3.12 所示。
理解用于小型边缘设备的小型快速 CNN 架构家族
CNN 架构中有一类明确的架构家族,它们的目标不是为了可扩展性或超越 ImageNet 基准,而是用于小型设备。小型设备通常被称为边缘设备,因为它们足够小巧紧凑,可以移动,或者能够在数据产生的地方进行实际的数据处理。我们的智能手机就是可以生成图像的移动设备的例子。那些不具备移动性的边缘设备的例子包括 CCTV 摄像头和门铃摄像头。将模型部署到边缘的主要好处如下:
- 减少通信延迟:与简单的数值或分类数据相比,图像和实时视频流较大。通过在边缘进行计算,减少了需要传输到集中服务器的数据量,从而减少了数据传输所需的时间。有时,当计算在边缘完成时,可以消除数据传输的需求,从而显著简化系统。
- 减少带宽需求:当图像在产生地进行处理时,只需返回简单的数据格式,如数值或分类数据,从而避免了高带宽要求的昂贵设备。
- 增加冗余性:集中式服务器意味着单点故障。将处理分发到各个边缘设备可以确保任何一个设备的故障不会影响整个系统。
用于边缘设备的小型 CNN 架构通常在没有显著基线模型的情况下设计整个模型结构,因此没有适当的模型家族来对这些架构进行分类。为了便于引用用于这一目的的架构,建议将以下架构视为适用于边缘设备的架构。我们将在第 15 章《在生产中部署深度学习模型》中探索可以在架构层面应用的其他技术,以进一步优化模型的效率,但现在让我们探索其中的两种架构,即 SqueezeNet 和 MobileNet。
理解 SqueezeNet
SqueezeNet 于 2016 年开发,旨在构建小型快速的 CNN,并具备前一节中描述的好处,尤其强调了在内存有限的硬件上进行部署。可以采用的三种策略如下:
- 对于使用 3x3 滤波器的卷积层,将部分滤波器替换为 1x1 滤波器。这意味着 1x1 滤波器和 3x3 滤波器理论上在同一层中共存,应用于相同的输入。然而,实施细节会有所不同,因为 1x1 滤波器和 3x3 滤波器会在同一输入上应用并行分支路径。这称为扩展层(expand layer)。
- 通过使用少量的 1x1 滤波器,减少输入到并行 1x1 和 3x3 滤波器的数据输入通道。这称为压缩层(squeeze layer)。
- 在架构的后期阶段下采样特征图,使得大部分卷积层可以基于发现访问较大的特征图,从而提高指标性能。这是通过在早期阶段较少使用步长为 2 像素的池化层,而在后期阶段和较大间隔时更频繁使用池化层来实现的。池化层不是在每个卷积层之后使用的。
创建了一个称为 Fire 的逻辑块,提供了轻松创建多个块的方式,以构建架构。这个块使得在压缩层中配置 1x1 滤波器数量、扩展层中的 1x1 滤波器和 3x3 滤波器成为可能。图 3.13 展示了这一结构。需要注意的是,池化层应用于 3x3 卷积层的输出,以确保它可以与扩展层中 1x1 卷积层的输出连接在一起。
八个 Fire 块被用来构建一个名为 SqueezeNet 的架构,在保持历史架构 AlexNet(本书中未介绍,因为现在已不再实用)在 ImageNet 上的性能的同时,体积小了 50 倍。
理解 MobileNet
MobileNet 的第一个版本,称为 MobileNetV1,于 2017 年推出,旨在优化移动设备和嵌入式设备的延迟问题,并通过这种优化副作用使网络变得更小,而不是相反地做出妥协。
在 MobileNet 的第一版中,除了第一层外,整个架构广泛使用了深度可分离卷积层。该架构由 28 层组成。深度可分离卷积层通过将标准卷积层分解为两个层,即深度卷积和逐点卷积来构建。这种新的两层配置基于这样一个理念:使用标准卷积滤波器计算开销较大。深度卷积层为每个输入通道使用一个唯一的滤波器,每个输入通道只有一个滤波器。每个通道一个滤波器是分组卷积的一种独特情况,稍后将更详细地介绍。深度卷积层的输出随后传递到一个标准的 1x1 卷积(称为逐点卷积),用于在通道之间组合信息。总体而言,深度可分离卷积层相比于我们之前介绍的标准卷积层操作,计算运行时减少了八到九倍,同时 ImageNet 上的准确度仅减少了 1%。这个过程还将参数数量减少了大约 5 倍。这实际上是一种因式分解的过程。深度卷积逻辑块如下图所示:
MobileNet 还提供了两个可以配置的参数,用于在牺牲一些性能指标的情况下减少模型的大小和计算需求。第一个是宽度乘数(width multiplier),它可以配置整个架构的输入和输出通道。第二个是分辨率乘数(resolution multiplier),范围在 0 到 1 之间,适用于原始的 224x224 图像大小,用于减少将图像传入网络时的输入和输出特征图的大小。如果需要更快的运行时,这些参数也可以适应其他架构。图 3.15 显示了 MobileNetV1 架构的结构和层配置:
MobileNet 被认为是一个独特的模型家族,基于第一版本的改进有两个新的版本,它们分别是 MobileNetV2 和 MobileNetV3-small,均在 2019 年推出。
理解 MobileNetV2
在介绍 MobileNetV2 之前,我们先定义一下什么是瓶颈层,这是该改进中使用的一个核心概念。瓶颈层通常是指相对于前后层,输出特征图较少的层。MobileNetV2 的构建基于这样的理念:瓶颈层是信息聚集的地方;在瓶颈层中,非线性激活会摧毁太多的信息,因此应用了线性层,最后在瓶颈层使用跳跃连接应用残差。MobileNetV2 基于基础的深度可分离卷积构建块,增加了没有 ReLU 的线性瓶颈层,并为瓶颈层添加了残差。这个构建块如下图所示。这个构建块被称为瓶颈倒残差块(bottleneck inverted residual block):
对于整个网络架构,除了第一层卷积层(具有 3x3 卷积核和 32 个滤波器)外,第一版 MobileNet 中的所有深度可分离层都被替换为新的块,如图 3.16 所示。一个小的额外细节是,它们使用了 ReLU6 激活函数,这对低精度计算具有鲁棒性。MobileNetV2 架构使用上述逻辑块来创建许多重复的层块,具有不同的设置。与 MobileNetV2 相比,该架构在 ImageNet 上的性能曲线提高了大约 5% 到 10%,同时保持相同的 FLOPs。请记住,EfficientNetV2 使用了这个块,并且还使用了这个块的另一个版本,将线性瓶颈层与过滤层融合在一起。使用两个层而不是一个层的目的是减少所需的操作数量,但对于边缘设备来说,由于内存访问成本的瓶颈,实际的延迟可能会有所不同。有时,使用融合版本可能会导致更快的运行时,并通过拥有更多的参数来学习更多的信息。
理解 MobileNetV3-small
对于 MobileNetV3-small,做了一些针对 MobileNetV2 的改进:
- 使用了更先进的非线性激活函数,称为 hard-swish,这提高了 ImageNet 上的 top-1 准确度。
- 进一步减少了初始层和最后几层的计算开销。
- 对于第一层,如图 3.15 所示,32 个滤波器被减少为 16,并且使用了 hard-swish 非线性激活函数,从而使运行时达到了 2 毫秒,并节省了 1000 万 FLOPS。
- 对于最后几层,最后一个 1x1 的瓶颈卷积层被移到了最后的平均池化层之后,之前的瓶颈(1x1)和过滤(3x3)层也被移除。
- 使用了一种名为 Mnasnet 的平台感知网络架构搜索的修改版本,并且使用了一个后搜索的层减少方法,称为 NetAdapt,用于减少延迟,自动根据 MobileNetV1、MobileNetV2 和 squeeze-and-excitation 网络的构建块优化架构,同时考虑延迟和准确性性能。NetAdapt 和 MnasNet 将在第 7 章《深度神经架构搜索》中介绍。
MobileNetV3-small 最终在相同的参数和 FLOPS 下达到了比 MobileNetV2 更高的 top-1 ImageNet 准确度。
理解 ShuffleNet 架构家族
ShuffleNet 有两个版本,ShuffleNetV1 和 ShuffleNetV2,我们将分别讨论这两个版本。
ShuffleNetV1,推出于 2017 年,重用了已知的卷积变体,称为分组卷积(grouped convolutions),其中每个卷积滤波器仅负责一部分输入数据通道。MobileNet 通过为每个通道使用一个滤波器来使用这一变体。分组卷积通过只对输入通道特征的一个小子集进行操作,从而节省了计算成本。然而,当多个分组卷积层依次堆叠时,通道之间的信息不会相互作用,最终导致准确度下降。ShuffleNetV1 在堆叠多个分组卷积层之间使用通道重排(channel shuffling)作为操作,以手动移动信息而不牺牲 FLOPs。这样就实现了一个高效且小巧的网络。
ShuffleNetV2,推出于 2018 年,基于 ShuffleNetV1,并关注于实际运行效率,考虑了内存访问成本、数据输入输出(I/O)和网络并行度等因素。为构建新架构,使用了以下四种设计策略:
- 从输入到输出的通道宽度相等,以最小化内存访问成本。
- 减少分组卷积,以最小化内存访问成本。
- 减少网络碎片化以增加并行性。一个例子是单个构建块中的卷积和池化操作数量。
- 减少逐元素操作,如 ReLU,因为它们有很大的内存访问成本。
在图 3.17 中,左侧的前两个结构展示了 ShuffleNetV1 的两个构建块,而右侧的最后两个结构展示了 ShuffleNetV2 的两个构建块。
理解 MicroNet,当前边缘设备的最先进架构
MicroNet 于 2021 年创建,是目前在延迟和可达到的 top-1 ImageNet 准确度性能方面的最先进架构,适用于非常低的 FLOP 范围,从 400 万到 2100 万。MicroNet 的创新性体现在两个方面:
- 它引入了 MobileNet 中的瓶颈/逐点卷积层和深度卷积层的因式分解版本,称为微型因式分解卷积(micro-factorized convolutions),通过减少输入数据到输出数据的连接/路径数量来实现。这是通过使用多个分组卷积和一些扩张卷积(dilated convolutions)来实现的。扩张卷积是指卷积核中固定间隔的卷积。可以将这些技术视为一种稀疏计算,仅计算最需要的部分,以确保最小化输入到输出路径的冗余。
- 它引入了一种新的激活函数,称为动态移位最大值(dynamic shift-max),它利用分组卷积的输出,通过应用更高阶的非线性(两次),同时增强组之间的连接。其实现方式是使用 squeeze-and-excitation 块的分组输出(每个通道产生一个值)作为加权机制,获得基于组的加权和的最大值。可以将其看作是对 ShuffleNet 中通道重排的改进。图 3.18 显示了动态移位最大值操作结构,示例特征图来自使用分组卷积操作的四个组的输出,共有 12 个通道。
MicroNet 在其创新基础上,利用了 ShuffleNet(通道重排机制)、ResNet(跳跃连接)、SENet(压缩和激励网络)以及 MobileNet(从已因式分解的卷积中创建因式分解版本)等概念,旨在通过聚焦稀疏性概念和高效信息流的改进,创建高效的网络。这个网络的具体细节可能会让人感到有些复杂,坦率地说,也难以完全理解,因此这里提供的信息并未包含所有的细节。
然而,图 3.19 展示了如何将逻辑块应用于当今最先进的网络,基于相同的理念构建不同尺寸的网络。
总结边缘设备的 CNN 架构
为了总结边缘设备的架构,您现在已经掌握了专家在该领域中使用的直观知识,这些知识帮助他们构建了能够以惊人的小体积运行的高效 CNN 架构,与如今像 GPT-3 这样的庞大模型相比,效果显著。以下图表显示了多种不同架构家族的 top-1 ImageNet 准确度性能与 FLOPS 的关系图:
请对这些结果持谨慎态度;不同模型之间的训练策略可能不同,这可能会显著影响可达的 top-1 ImageNet 准确度,同时在不同模型运行的随机初始化之间可能会得到不同的结果。此外,延迟不仅仅由参数数量或 FLOPS 直接表示,还受到单个操作的内存访问成本、I/O 访问成本以及不同操作的并行度的影响。
总的来说,图 3.21 显示了本章中介绍的所有 CNN 模型家族基于 FLOPS 的整体性能图:
再次需要注意的是,我们应对这里呈现的结果保持谨慎态度,因为在对 ImageNet 数据集进行训练时所使用的训练技术并不是在不同基准测试中完全标准化的。训练技术的变化可能会导致结果的差异,且这些内容将在第 8 章《探索监督式深度学习》和第 9 章《探索无监督式深度学习》中更详细地讨论。另一个需要注意的重要事项是,尽管 ImageNet 被认为是一个足够大的图像数据集,可以作为基准,但仍应保持一定的怀疑态度,因为数据本身已经被证明在某些情况下存在带噪声的标签和系统性错误。ImageNet 的修正版本——ImageNet Real 已经发布,但并不是所有模型都在此数据集上进行过基准测试或预训练。为了 100% 确定哪个架构在某些数据集上进行预训练时表现更好,建议在您的数据集上进行训练!此外,FLOPS 指标并不能完全代表模型的实际延迟,实际延迟可能会根据代码结构、模型在多个设备上的分布、可用的 GPU 或 CPU 数量以及模型架构的并行程度等因素发生较大变化。
总结
CNN 是捕捉图像数据中模式的首选模型。本章中介绍的手工挑选的架构是核心骨干,后续可以作为解决更定制化下游任务(如图像目标检测和图像生成)的基础。
本章涉及的 CNN 将在后续章节中作为实际应用的基础,帮助你学习其他基于深度学习的知识。请花时间查看如何在本书的 GitHub 仓库中离线实现不同架构;我们不会在此呈现实际的实现代码。现在我们已经详细介绍了 CNN 的中级到低级细节,在下一章,我们将转向讨论循环神经网络(RNN)。