Auto Byte

专注未来出行及智能汽车科技

微信扫一扫获取更多资讯

Science AI

关注人工智能与其他前沿技术、基础学科的交叉研究与融合发展

微信扫一扫获取更多资讯

Paul-Louis Pröve作者Panda编译towardsdatascience选自

无需复杂的数学描述,通过简单代码理解卷积模块


比起晦涩复杂的数学或文本描述,也许代码能帮助我们更好地理解各种卷积模块。计算机科学家 Paul-Louis Pröve 用 Keras 对瓶颈模块、Inception 模块、残差模块等进行了介绍和代码说明,并在最后留下了 AmoebaNet Normal Cell 代码实现的练习题。你能够解答吗?不妨在评论区留下答案!

我会尽力定期阅读与机器学习人工智能相关的论文。这是紧跟最新进展的唯一方法。作为一位计算机科学家,当阅读科研文本或公式的数学概念时,我常常碰壁。我发现直接用平实的代码来理解要容易得多。所以在这篇文章中,我希望带你了解一些精选的用 Keras 实现的最新架构中的重要卷积模块。

如果你在 GitHub 上寻找常用架构的实现,你会找到多得让人吃惊的代码。在实践中,包含足够多的注释并用额外的参数来提升模型的能力是很好的做法,但这也会干扰我们对架构本质的理解。为了简化和缩短代码片段,我将会使用一些别名函数:

def conv(x, f, k=3, s=1, p='same', d=1, a='relu'):
 return Conv2D(filters=f, kernel_size=k, strides=s, 
 padding=p, dilation_rate=d, activation=a)(x)
def dense(x, f, a='relu'):
 return Dense(f, activation=a)(x)
def maxpool(x, k=2, s=2, p='same'):
 return MaxPooling2D(pool_size=k, strides=s, padding=p)(x)
def avgpool(x, k=2, s=2, p='same'):
 return AveragePooling2D(pool_size=k, strides=s, padding=p)(x)
def gavgpool(x):
 return GlobalAveragePooling2D()(x)
def sepconv(x, f, k=3, s=1, p='same', d=1, a='relu'):
 return SeparableConv2D(filters=f, kernel_size=k, strides=s, 
 padding=p, dilation_rate=d, activation=a)(x)

我发现,去掉这些模板代码能有好得多的可读性。当然,只有你理解我的单字母缩写时才有效。那就开始吧。

瓶颈模块

一个卷积层的参数数量取决于卷积核(kernel)的大小、输入过滤器的数量以及输出过滤器的数量。你的网络越宽,则 3×3 卷积的成本就会越高。

def bottleneck(x, f=32, r=4):
 x = conv(x, f//r, k=1)
 x = conv(x, f//r, k=3)
 return conv(x, f, k=1)

瓶颈模块背后的思想是使用成本较低的 1×1 卷积以特定速率 r 来降低通道的数量,从而使后续的 3×3 卷积的参数更少。最后,我们再使用另一个 1×1 卷积来拓宽网络。

Inception 模块

Inception 模块引入的思想是:并行地使用不同操作然后融合结果。通过这种方式,网络可以学习不同类型的过滤器。

def naive_inception_module(x, f=32):
 a = conv(x, f, k=1)
 b = conv(x, f, k=3)
 c = conv(x, f, k=5)
 d = maxpool(x, k=3, s=1)
 return concatenate([a, b, c, d])

这里我们使用一个最大池化层融合了卷积核大小分别为 1、3、5 的卷积层。这段代码是 Inception 模块的最简单初级的实现。在实践中,还会将其与上述的瓶颈思想结合起来,代码也就会稍微更复杂一些。

Inception 模块

def inception_module(x, f=32, r=4):
 a = conv(x, f, k=1)
 b = conv(x, f//3, k=1)
 b = conv(b, f, k=3)
 c = conv(x, f//r, k=1)
 c = conv(c, f, k=5)
 d = maxpool(x, k=3, s=1)
 d = conv(d, f, k=1)
 return concatenate([a, b, c, d])

残差模块

ResNet(残差网络)是微软的研究者提出的一种架构,能让神经网络拥有他们想要的任何层数,同时还能提升模型的准确度。现在你可能已经很熟悉这一方法了,但在 ResNet 诞生前情况则很不一样。

def residual_block(x, f=32, r=4):
 m = conv(x, f//r, k=1)
 m = conv(m, f//r, k=3)
 m = conv(m, f, k=1)
 return add([x, m])

残差模块的思想是在卷积模块的输出上添加初始激活。通过这种方式,网络可以通过学习过程决定为输出使用多少新卷积。注意,Inception 模块是连接输出,而残差模块是添加它们。

ResNeXt 模块

从名字上也看得出,ResNeXt 与 ResNet 紧密相关。研究者为卷积模块引入了基数(cardinality)项,以作为类似于宽度(通道数量)和深度(层数)的又一维度。

基数是指出现在模块中的并行路径的数量。这听起来与 Inception 模块(有 4 个并行的操作)类似。但是,不同于并行地使用不同类型的操作,当基数为 4 时,并行使用的 4 个操作是相同的。

如果它们做的事情一样,为什么还要并行呢?这是个好问题。这个概念也被称为分组卷积(grouped convolution),可追溯到最早的 AlexNet 论文。但是,那时候这种方法主要被用于将训练过程划分到多个 GPU 上,而 ResNeXt 则将它们用于提升参数效率。

def resnext_block(x, f=32, r=2, c=4):
 l = []
 for i in range(c):
 m = conv(x, f//(c*r), k=1)
 m = conv(m, f//(c*r), k=3)
 m = conv(m, f, k=1)
 l.append(m)
 m = add(l)
 return add([x, m])

其思想是将所有输入通道划分为不同的组别。卷积仅在它们指定的通道组内操作,不能跨组进行。研究发现,每个组都会学习到不同类型的特征,同时也能提升权重的效率。

假设有一个瓶颈模块,首先使用 4 的压缩率将 256 的输入通道降低到 64,然后再将它们返回到 256 个通道作为输出。如果我们想引入一个 32 的基数和 2 的压缩率,那么我们就会有并行的 32 个 1×1 卷积层,其中每个卷积层有 4 个输出通道(256 / (32*2))。之后,我们会使用 32 个带有 4 个输出通道的 3×3 卷积层,后面跟着 32 个带有 256 个输出通道的 1×1 层。最后一步涉及到叠加这 32 个并行路径,这能在添加初始输入构建残差连接之前提供一个输出。

左图:ResNet 模块;右图:有大致一样的参数复杂度的 RexNeXt 模块

这方面有很多知识需要了解。上图是其工作过程的图示,也许你可以复制这段代码,用 Keras 亲自动手构建一个小网络试试看。这么复杂的描述可以总结成如此简单的 9 行代码,是不是很神奇?

随带一提,如果基数等于通道的数量,那就会得到所谓的深度可分离卷积(depthwise separable convolution)。自从 Xception 架构出现后,这种方法得到了很多人的使用。

Dense 模块

密集(dense)模块是残差模块的一个极端版本,其中每个卷积层都会获得该模块中所有之前的卷积层的输出。首先,我们将输入激活添加到一个列表中,之后进入一个在模块的深度上迭代的循环。每个卷积输出也都连接到该列表,这样后续的迭代会得到越来越多的输入特征图。这个方案会继续,直到达到所需的深度。

def dense_block(x, f=32, d=5):
 l = x
 for i in range(d):
 x = conv(l, f)
 l = concatenate([l, x])
 return l

尽管要得到表现像 DenseNet 一样优秀的架构需要耗费几个月的研究时间,但其实际的基本构建模块就这么简单。很神奇吧。

Squeeze-and-Excitation 模块

SENet 曾短暂地在 ImageNet 上达到过最佳表现。它基于 ResNeXt,并且重在建模网络的通道方面的信息。在一个常规的卷积层中,每个通道的点积计算内的叠加操作都有同等的权重

Squeeze-and-Excitation 模块

SENet 引入了一种非常简单的模块,可以添加到任何已有的架构中。它会创建一个小型神经网络,该网络能学习如何根据输入情况为每个过滤器加权。可以看到,它本身并不是卷积模块,但可以添加到任何卷积模块上并有望提升其性能。我想将其添加到混合模块中。

def se_block(x, f, rate=16):
 m = gavgpool(x)
 m = dense(m, f // rate)
 m = dense(m, f, a='sigmoid')
 return multiply([x, m])

每个通道都被压缩成单个值,并被馈送给一个两层神经网络。根据通道的分布情况,该网络会学习基于它们的重要性为这些通道加权。最后,这些权重会与卷积激活相乘。

SENet 会有少量额外的计算开销,但有改善任何卷积模型的潜力。在我看来,这种模块得到的研究关注还不够多。

NASNet Normal Cell

难点来了。之前介绍的都是一些简单但有效的设计,现在我们进入设计神经网络架构的算法世界。NASNet 的设计方式让人称奇,但实际的架构却又相对复杂。但我们知道,它在 ImageNet 上的表现真的非常好。

NASNet 的提出者通过人工方式定义了一个包含不同类型的卷积和池化层的搜索空间,其中包含不同的可能设置。他们还定义了这些层可以并行或顺序排布的方式以及添加或连接的方式。定义完成之后,他们基于一个循环神经网络构建了一个强化学习(RL)算法,其奖励是提出了在 CIFAR-10 数据集上表现优良的特定设计。

所得到的架构不仅在 CIFAR-10 上表现优良,而且还在 ImageNet 上取得了当前最佳。NASNet 由 Normal Cell 和 Reduction Cell 构成,它们在彼此之后重复。

def normal_cell(x1, x2, f=32):
 a1 = sepconv(x1, f, k=3)
 a2 = sepconv(x1, f, k=5)
 a = add([a1, a2])
 b1 = avgpool(x1, k=3, s=1)
 b2 = avgpool(x1, k=3, s=1)
 b = add([b1, b2])
 c2 = avgpool(x2, k=3, s=1)
 c = add([x1, c2])
 d1 = sepconv(x2, f, k=5)
 d2 = sepconv(x1, f, k=3)
 d = add([d1, d2])
 e2 = sepconv(x2, f, k=3)
 e = add([x2, e2])
 return concatenate([a, b, c, d, e])

你可以这样用 Keras 实现 Normal Cell。其中没什么新东西,但这种特定的层的组合方式和设定效果就是很好。

倒置残差模块

现在你已经了解了瓶颈模块和可分离卷积。让我们将它们放到一起吧。如果进行一些测试,你会发现:由于可分离卷积已能降低参数数量,所以压缩它们可能有损性能,而不会提升性能。

研究者想出了一个做法,做瓶颈残差模块相反的事。他们增多了使用低成本 1×1 卷积的通道的数量,因为后续的可分离卷积层能够极大降低参数数量。它会在关闭这些通道之后再添加到初始激活。

def inv_residual_block(x, f=32, r=4):
 m = conv(x, f*r, k=1)
 m = sepconv(m, f, a='linear')
 return add([m, x])

最后还有一点:这个可分离卷积之后没有激活函数。相反,它是直接被加到了输入上。研究表明,在纳入某个架构之后,这一模块是非常有效的。

AmoebaNet Normal Cell

AmoebaNet 的 Normal Cell

AmoebaNet 是当前在 ImageNet 上表现最好的,甚至在广义的图像识别任务上可能也最好。类似于 NASNet,它是由一个算法使用前述的同样的搜索空间设计的。唯一的区别是他们没使用强化学习算法,而是采用了一种常被称为「进化(Evolution)」的通用算法。该算法工作方式的细节超出了本文范围。最终,相比于 NASNet,研究者通过进化算法用更少的计算成本找到了一种更好的方案。它在 ImageNet 上达到了 97.87% 的 Top-5 准确度——单个架构所达到的新高度。

看看其代码,该模块没有添加任何你还没看过的新东西。你可以试试看根据上面的图片实现这种新的 Normal Cell,从而测试一下自己究竟掌握了没有。

总结

希望这篇文章能帮助你理解重要的卷积模块,并帮助你认识到实现它们并没有想象中那么困难。有关这些架构的细节请参考它们各自所属的论文。你会认识到,一旦你理解了一篇论文的核心思想,理解其它部分就会容易得多。请注意,在实际的实现中往往还会添加批归一化,而且激活函数的应用位置也各有不同。

原文链接:https://towardsdatascience.com/history-of-convolutional-blocks-in-simple-code-96a7ddceac0c

入门卷积神经网络深度残差网络InceptionResNeXtDenseNetAmoebaNet
4
相关数据
Microsoft机构

微软是美国一家跨国计算机科技公司,以研发、制造、授权和提供广泛的计算机软件服务为主。总部位于美国华盛顿州的雷德蒙德,最为著名和畅销的产品为Microsoft Windows操作系统和Microsoft Office办公室软件,以及Xbox的游戏业务。微软是美国《财富》杂志2015年评选的世界500强企业排行榜中的第95名。

https://www.microsoft.com/en-us/about
池化技术

池化(Pooling)是卷积神经网络中的一个重要的概念,它实际上是一种形式的降采样。有多种不同形式的非线性池化函数,而其中“最大池化(Max pooling)”是最为常见的。它是将输入的图像划分为若干个矩形区域,对每个子区域输出最大值。直觉上,这种机制能够有效的原因在于,在发现一个特征之后,它的精确位置远不及它和其他特征的相对位置的关系重要。池化层会不断地减小数据的空间大小,因此参数的数量和计算量也会下降,这在一定程度上也控制了过拟合。通常来说,CNN的卷积层之间都会周期性地插入池化层。

激活函数技术

在 计算网络中, 一个节点的激活函数定义了该节点在给定的输入或输入的集合下的输出。标准的计算机芯片电路可以看作是根据输入得到"开"(1)或"关"(0)输出的数字网络激活函数。这与神经网络中的线性感知机的行为类似。 一种函数(例如 ReLU 或 S 型函数),用于对上一层的所有输入求加权和,然后生成一个输出值(通常为非线性值),并将其传递给下一层。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

机器学习技术

机器学习是人工智能的一个分支,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。因为学习算法中涉及了大量的统计学理论,机器学习与推断统计学联系尤为密切,也被称为统计学习理论。算法设计方面,机器学习理论关注可以实现的,行之有效的学习算法。

人工智能技术

在学术研究领域,人工智能通常指能够感知周围环境并采取行动以实现最优的可能结果的智能体(intelligent agent)

参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

Alex网络技术

AlexNet是一个卷积神经网络的名字,最初是与CUDA一起使用GPU支持运行的,AlexNet是2012年ImageNet竞赛冠军获得者Alex Krizhevsky设计的。该网络达错误率大大减小了15.3%,比亚军高出10.8个百分点。AlexNet是由SuperVision组设计的,由Alex Krizhevsky, Geoffrey Hinton和Ilya Sutskever组成。

密集型连接网络技术

Gao Huang等研究者提出了DenseNet,该论文获得了CVPR 2017的最佳论文。DenseNet的目标是提升网络层级间信息流与梯度流的效率,并提高参数效率。它也如同ResNet那样连接前层特征图与后层特征图,但DenseNet并不会像ResNet那样对两个特征图求和,而是直接将特征图按深度相互拼接在一起。DenseNet最大的特点即每一层的输出都会作为后面所有层的输入,这样最后一层将拼接前面所有层级的输出特征图。这种结构确保了每一层能从损失函数直接访问到梯度,因此可以训练非常深的网络。

批归一化技术

批归一化(Batch Normalization,BN)由谷歌于2015年提出,是一个深度神经网络训练的技巧,它不仅可以加快模型的收敛速度,还能在一定程度上缓解深层网络中的“梯度弥散”问题,从而使得训练深层网络模型更加容易和稳定。目前BN已经成为几乎所有卷积神经网络的标配技巧了。从字面意思看来Batch Normalization(简称BN)就是对每一批数据进行归一化。

强化学习技术

强化学习是一种试错方法,其目标是让软件智能体在特定环境中能够采取回报最大化的行为。强化学习在马尔可夫决策过程环境中主要使用的技术是动态规划(Dynamic Programming)。流行的强化学习方法包括自适应动态规划(ADP)、时间差分(TD)学习、状态-动作-回报-状态-动作(SARSA)算法、Q 学习、深度强化学习(DQN);其应用包括下棋类游戏、机器人控制和工作调度等。

图网技术

ImageNet 是一个计算机视觉系统识别项目, 是目前世界上图像识别最大的数据库。

推荐文章
暂无评论
暂无评论~