无需复杂的数学描述,通过简单代码理解卷积模块
作者:媒体转发 时间:2018-12-10 16:45
比起晦涩复杂的数学或文本描述,也许代码能帮助我们更好地理解各种卷积模块。计算机科学家 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(ffilters=f, kkernel_size=k, sstrides=s,
ppadding=p, ddilation_rate=d, aactivation=a)(x)
def dense(x, f, a='relu'):
return Dense(f, aactivation=a)(x)
def maxpool(x, k=2, s=2, p='same'):
return MaxPooling2D(pool_size=k, sstrides=s, ppadding=p)(x)
def avgpool(x, k=2, s=2, p='same'):
return AveragePooling2D(pool_size=k, sstrides=s, ppadding=p)(x)
def gavgpool(x):
return GlobalAveragePooling2D()(x)
def sepconv(x, f, k=3, s=1, p='same', d=1, a='relu'):
return SeparableConv2D(ffilters=f, kkernel_size=k, sstrides=s,
ppadding=p, ddilation_rate=d, aactivation=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)



