目 录
1 ResNeXt网络介绍
ResNext网络将ResNet的block替换成了组卷积:
从下图可以看出,ResNeXt网络比ResNet网络的效果更好:
1.1 组卷积
输入特征矩阵channel为4,则每一个卷积核的层数为4;输出的channel为n,则需要n个卷积核来进行处理,需要的参数个数为(假设每个卷积核的高和宽为,输入特征矩阵channel为
,需要
个卷积核):
。
将输入特征矩阵的channel划分成两个组,对每个组分别进行卷积操作;假设将输入特征矩阵划分成个组,则需要的参数个数为:
当分组的个数和输入特征矩阵channel个数
保持一致,并且输出特征矩阵的channel个数
也与输入特征矩阵的channel个数
保持一致,相当于对输入特征矩阵的每一个channel都分配了一个channel为1的卷积核进行卷积,该卷积称为DW卷积。
1.2 block
以上三个block模块在数学计算上是完全等价的,以c为例:通过1×1的卷积层将输入channel从256降为128,然后利用组卷积进行处理,卷积核大小为3×3组数为32,再利用1×1的卷积层进行升维,将输出与输入相加,得到最终输出。
再看b模块,就是将第一层和第二层的卷积分组,将第一层卷积(卷积核大小为1×1,每个卷积核有256层)分为32组,每组4个卷积核,这样每一组输出的channel为4;将第二层卷积也分为32组对应第一层,每一组输入的channel为4,每一组4个卷积核输出channel也为4,再将输出拼接为channel为128的输出,再经过一个256个卷积核的卷积层得到最终输出。
对于a模块,就是对b模块的最后一层进行拆分,就是将第二层的32组的输出再经过一层(卷积核大小为1×1,每个卷积核有4层,一共有256个卷积核)卷积,再把这32组输出相加得到最终输出。
从a推到b再推到c就得到了最终的结构,对于a结构:
假设将输入的channel分为两组,每一组两层,每一组用一个层数为2的大小为1×1的卷积核卷积,将输出相加,得到一个最终输出矩阵。
对于b结构:
将a中的矩阵进行拼接,用一个层数为4的大小为1×1的卷积核卷积,得到的输出和a相同。
1.3 网络搭建
ResNeXt-50(32×4d)中的32是group数,4对应conv2中组卷积每个group的卷积核个数,从上表可以看出改进后的网络结构基本只有组卷积的变化。对于为什么将group数设置为32:
以ResNet-50和101为例,对于相同的计算量,group数增加,错误率是越来越低的。
从上图可以看出,对于只有两层的block而言,拆分没有太大作用,文章中也给予了解释。
2 利用Pytorch实现ResNet网络
2.1 模型定义
从1.3的表中可以看出,ResNeXt网络每一个convx的第一层和第二层卷积的卷积核个数是ResNet网络的两倍,在代码中增加一下两个参数(即为group数和conv2中组卷积每个group的卷积核个数),并且根据这两个参数计算出第一层卷积的输出(为ResNet网络的两倍)。
def __init__(self, in_channel, out_channel, stride=1, downsample=None,
groups=1, width_per_group=64):
super(Bottleneck, self).__init__()
# ResNeXt网络每一个convx的第一层和第二层卷积的卷积核个数是ResNet网络的两倍
width = int(out_channel * (width_per_group / 64.)) * groups
实例化ResNeXt网络时,多输入两个参数即可:
def resnext50_32x4d(num_classes=1000, include_top=True):
groups = 32
width_per_group = 4
return ResNet(Bottleneck, [3, 4, 6, 3],
num_classes=num_classes,
include_top=include_top,
groups=groups,
width_per_group=width_per_group)
2.2 训练结果
ResNet-50训练结果:
ResNeXt-50(32×4d)训练结果:
从上图可以看出,训练三次的正确率ResNeXt-50(32×4d)要优于ResNet-50。