SENet
Last updated
Last updated
SENet 并不是一个完整的网络结构,而是一个可以插入任意网络结构的模块。 与以往的网络设计思路不同,SENet 显式考虑了特征图的通道之间的关系, 使用了一种 self-attention 机制,从特征图中学习出不同通道的重要性,并对特征图的每个通道重新加权。 SENet 于 2017 年由 Momenta 公司和牛津大学视觉组提出,并获得了当年 ILSVRC 竞赛图像分类项目的冠军。
SENet 模块的设计并不复杂,整体结构如下图所示。
图中, 表示被插入 SENet 模块的网络中的某个卷积层,可以是任意网络结构中的任意一层, 即为网络输出的特征图。 到 的部分为 SENet 模块。
SENet 是 Squeeze and Excitation Network 的缩写。从这个名字中可以看出,这个模块中包含一个压缩过程和一个激发过程,分别对应图中的 和 部分。
压缩过程 是一个简单的全局平均池化层(Global Average Pooling)。 它可以将特征图 压缩成一个 的向量。 向量中的每一个元素是同通道全部空间位置的神经元的均值, 因而一定程度上包含了特征图 全部空间位置的信息。
激发过程 由两个全连接层构成,是一个可学习的模块。 第一个全连接层将 维度的全局特征映射到低维空间,并使用 ReLU 函数激活。 第二个全连接层再将低维向量映射回 维,并使用 Sigmoid 激活。 激发过程的具体构造如下图所示,其中 为通道的压缩系数。
这两个全连接层可以表示一个相对复杂的非线性映射。而通道数先减再增的瓶颈结构可以一定程度上降低计算量。
最后,再用激发后的特征向量(以下简称激发态向量,记为 )对原特征图 的每个通道进行加权。 由于激发过程最后以 Sigmoid 函数作为激活函数,因此所有通道的权重介于 0 到 1 之间。 一个通道的重要性越低,它所对应的系数就越接近 0,在最终输出的特征图 中就会被削弱。
SENet 的使用相对自由,可以插入到任何一个已有网络的任何一个卷积层之后(具体而言是非线性激活层之后),实现对网络的改造。 SENet 原始论文中给出了 Inception 以及残差网络 ResNet 和 ResNeXt 的改进方式,如下图所示。
对于 Inception 网络,我们可以将其直接插入到 Inception 结构之后。 对于 ResNet 和 ResNeXt,我们可以将其插入到残差分支的基本模块或瓶颈模块之后,并保留直通分支不变。
mmclassification 在 backbone 中实现了加入了 SENet 模块的 SE-ResNet 和 SE-ResNeXt。
由于 SENet 是一个插入模块。因此对于通过工厂函数生成的 ResNet 和 ResNeXt 模型,只需要重新定义 SEBottleNeck ,在残差分支的最后加入 SELayer
就可以实现 SE-ResNet 和 SE-ResNeXt。
SELayer
即为 SENet 核心逻辑的实现,定义在在 se_layer.py 中,代码如下:
可以看到,该模块的前传函数由一个全局平均每池化层和两个 1x1 的卷积层串联而成。 池化层即为压缩过程,两个卷积层则等价实现了通道维度的两个全连接层,即激发过程。 在这里,通道的压缩比率默认为 16 。 最后一个带广播的乘法完成了加权操作。