ResNeXt
ResNeXt 是 2017 年 FAIR 提出的一个图像分类网络。ResNeXt 是基于 ResNet 的整体结构提出的一种改进结构。 受启发于 Inception 模块“分离-变换-合并”的思路,把 ResNet 中 BottleNeck 模块中的 64 通道的卷积替换为独立的 32 路 4 通道卷积运算,并在最后按通道合并起来。 这也等价为将 ResNet 的 BottleNeck 结构中的第二个卷积层替换为分组卷积层。 这种修改在保持参数和计算量基本不变的情况下,进一步提高了网络分类精度。 ResNeXt 在 2016 年的 ILSVRC 竞赛图像分类项目中取得了第二名的成绩。
基本思路
ResNet 的 BottleNeck 结构如下图左图所示,其残差分支由三个卷积层串联而成,输入通道数、卷积核大小、输出通道数从左到右标注在图中。 这三个卷积层分别负责压缩特征图的通道数、扩展感受野以及恢复特征图的通道数。

我们知道,一个卷积层所包含的参数总数为 Nparam=CinCoutK2 ,计算量正比于参数量 Nops=HoutWoutNparam 。 因而 BottleNeck 结构的的参数总数为
可以看出,中间 3x3 的卷积层占据了主要的参数量。
为了降低计算量,ResNeXt 结构对 ResNet 的 BottleNeck 结构进行了改进。 ResNeXt 将残差分支扩展到 C=32 个,并将每个分支中中间层的输入和输出通道数降低至 d=4。 在 ResNeXt 结构中,C 称为 cardinality,d 称为 width。
经过这种改造后,残差分支的参数总量变为为
如果我们控制 Cd=64 ,则中间层的参数量仅有 ResNet 结构的 1/C 。
如果我们控制参数量和 ResNet 相近,则可以得到如下 C 和 d 的配置。

其中,(C,d)=(32,4) 是 ResNeXt 的常见配置,而 (C,d)=(64,1) 时退化为 ResNet 。
使用分组卷积实现多路残差
ResNeXt 中的多路残差结构可以由分组卷积实现。为了理解这一点,让我们先来看一下分组卷积是如何计算的。
在标准的卷积中,卷积核的通道数与输入特征图的通道数相同,我们记其为 Cin,卷积核的记为 Cout。 在进行卷积运算时,所有 Cout 个卷积核的所有 Cin 个通道都需要参与输入特征图的所有 Cin 个通道进行内积运算。 形象地说,卷积核和输入特征图在通道维度是一个全连接的结构,如下图所示:

分组卷积则在通道上呈现一种局部连接的状态。 分组卷积将输入特征图按通道分成 G 组,每组 Cin/G 个通道,再将所有卷积核的通道也由 Cin 缩减到 Cin/G 个。 在前传计算时,第 g 个卷积核只与第 g 组中的通道进行内积运算,如下图所示:

不难得出,分组卷积的参数量和计算量仅有普通卷积的1/G
如果我们将空间维度也考虑进去,则分组卷积的前传计算为:
其中, x,y 分别为输入和输出的特征图,kc 为第 c 个卷积核,其形状为 K×K×GCin 。
分组卷积在 AlexNet 中就有所应用。受到当时 GPU 显存的限制,AlexNet 在实现时使用了模型并行的技术,将同一层的特征图按通道切分成两部分,分别放在不同的 GPU 上,即组数为 2 。 在前传时,只有中间一个卷积层和最后的两个全连接层是全连接的,需要 GPU 间进行数据通信,其余卷积层均为组数为 2 的分组卷积,即使用各自 GPU 上的通道数减半的卷积核。
接下来,我们再考察如何使用分组卷积实现 ResNeXt 的多路残差结构。 辅助论文中的图示可以更好的理解。

在每个残差分支中,第一个卷积层都以同样的 256 通道特征图为输入,经由 d 个卷积核,输出 d 个通道的特征图。 我们可以把总共 Cd 个卷积核集合起来,构成一个 Cd 输出通道的卷积层。 这个合并的卷积层输出的 Cd 通道的特征图与原结构中 C 分支,每分支 d 通道的特征图完全相同。 也就是说,合并的第一个卷积层与原结构中的 C 个卷积层等价。
每个分支的第二个卷积层以第一个卷积层输出的 d 通道特征为输入,经由 d 个卷积核,输出 d 通道的特征图,所有分支合计 Cd 通道。 这等价于把合并后的 Cd 个特征拆为 C 组,并使用分组卷积输出 Cd 通道的特征图。 因此,所有分支的第二个卷积层可以等效合并为一个 C 组的分组卷积层。
每个分支的第三个卷积层以第二个卷积层输出的 d 通道特征为输入,经由 Cd 个卷积核,输出 256 通道的的特征图,所有分支的输出求和作为最终结果。 从输出的角度看,每个通道的特征值是 C 个内积的和,每个内积是 d 通道特征图和卷积核对应通道相乘求和而得。 如果我们将所有卷积核按通道拼接,将所有输入特征图按通道拼接,则一个 Cd 通道的内积操作就可以等效替代上述分别内积再求和的操作。 因此,所有分支的第三个卷积层可以合并为一个 Cd 输入通道的卷积层。
经过这种替换,ResNeXt 的多路残差结构就可以等效变换为一个单路结构。这也是诸多深度学习框架所采用的实现方式。
ResNeXt 的 PyTorch 实现
由于 ResNeXt 的整体结构与 ResNet 完全相同,只要将残差分支中的普通卷积替换为分组卷积即可。由于 Pytorch 的 Conv2d类型直接支持了group参数,因此基于 ResNet 的代码实现 ResNeXt 是非常直接的。
在 torchvision 中,ResNeXt 也实现在 resnet.py 中,传入匹配的group和width参数给工厂函数_resnet,就可以实现分组卷积。
在 mmclassification 中,ResNeXt 实现在一个单独的文件 resnext.py 中。与 torchvision 不同 mmclassification 通过继承 ResNet 的 BottleNeck 残差模块和 ResNet 结构,在增加了对分组卷积的实现。
Last updated