ResNeXt学习

8,896次阅读
没有评论

共计 3663 个字符,预计需要花费 10 分钟才能阅读完成。

1. 模型介绍

ResNeXt 是由何凯明团队在 2017 年 CVPR 会议上提出来的新型图像分类网络。ResNeXt 是 ResNet 的升级版,在 ResNet 的基础上,引入了 cardinality 的概念,类似于 ResNet,ResNeXt 也有 ResNeXt-50,ResNeXt-101 的版本。那么相较于 ResNet,ResNeXt 的创新点在哪里?既然是分类网络,那么在 ImageNet 数据集上的指标相较于 ResNet 有何变化?之后的 ResNeXt_WSL 又是什么东西?下面我和大家一起分享一下这些知识。

2. 模型结构

在 ResNeXt 的论文中,作者提出了当时普遍存在的一个问题,如果要提高模型的准确率,往往采取加深网络或者加宽网络的方法。虽然这种方法是有效的,但是随之而来的,是网络设计的难度和计算开销的增加。为了一点精度的提升往往需要付出更大的代价。因此,需要一个更好的策略,在不额外增加计算代价的情况下,提升网络的精度。由此,何等人提出了 cardinality 的概念。

下图是 ResNet(左)与 ResNeXt(右)block 的差异。在 ResNet 中,输入的具有 256 个通道的特征经过 1×1 卷积压缩 4 倍到 64 个通道,之后 3×3 的卷积核用于处理特征,经 1×1 卷积扩大通道数与原特征残差连接后输出。ResNeXt 也是相同的处理策略,但在 ResNeXt 中,输入的具有 256 个通道的特征被分为 32 个组,每组被压缩 64 倍到 4 个通道后进行处理。32 个组相加后与原特征残差连接后输出。这里 cardinatity 指的是一个 block 中所具有的相同分支的数目。

ResNeXt 学习

下图是 InceptionNet 的两种 inception module 结构,左边是 inception module 的 naive 版本,右边是使用了降维方法的 inception module。相较于右边,左边很明显的缺点就是参数大,计算量巨大。使用不同大小的卷积核目的是为了提取不同尺度的特征信息,对于图像而言,多尺度的信息有助于网络更好地对图像信息进行选择,并且使得网络对于不同尺寸的图像输入有更好的适应能力,但多尺度带来的问题就是计算量的增加。因此在右边的模型中,InceptionNet 很好地解决了这个问题,首先是 1×1 的卷积用于特征降维,减小特征的通道数后再采取多尺度的结构提取特征信息,在降低参数量的同时捕获到多尺度的特征信息。

ResNeXt 正是借鉴了这种 ” 分割 - 变换 - 聚合 ” 的策略,但用相同的拓扑结构组建 ResNeXt 模块。每个结构都是相同的卷积核,保持了结构的简洁,使得模型在编程上更方便更容易,而 InceptionNet 则需要更为复杂的设计。

ResNeXt 学习

3. 模型实现

ResNeXt 与 ResNet 的模型结构一致,主要差别在于 block 的搭建,因此这里用 paddle 框架来实现 block 的代码

class ConvBNLayer(nn.Layer):
    def __init__(self, num_channels, num_filters, filter_size, stride=1,
                 groups=1, act=None, name=None, data_format="NCHW"
                ):
        super(ConvBNLayer, self).__init__()
        self._conv = Conv2D(
            in_channels=num_channels, out_channels=num_filters,
            kernel_size=filter_size, stride=stride,
            padding=(filter_size - 1) // 2, groups=groups,
            weight_attr=ParamAttr(name=name + "_weights"), bias_attr=False,
            data_format=data_format
        )
        if name == "conv1":
            bn_name = "bn_" + name
        else:
            bn_name = "bn" + name[3:]
        self._batch_norm = BatchNorm(num_filters, act=act, param_attr=ParamAttr(name=bn_name + '_scale'),
            bias_attr=ParamAttr(bn_name + '_offset'), moving_mean_name=bn_name + '_mean',
            moving_variance_name=bn_name + '_variance', data_layout=data_format
        )

    def forward(self, inputs):
        y = self._conv(inputs)
        y = self._batch_norm(y)
        return y


class BottleneckBlock(nn.Layer):
    def __init__(self, num_channels, num_filters, stride, cardinality, shortcut=True,
                 name=None, data_format="NCHW"
                ):
        super(BottleneckBlock, self).__init__()
        self.conv0 = ConvBNLayer(num_channels=num_channels, num_filters=num_filters,
            filter_size=1, act='relu', name=name + "_branch2a",
            data_format=data_format
           )
        self.conv1 = ConvBNLayer(
            num_channels=num_filters, num_filters=num_filters,
            filter_size=3, groups=cardinality,
            stride=stride, act='relu', name=name + "_branch2b",
            data_format=data_format
        )

        self.conv2 = ConvBNLayer(
            num_channels=num_filters,
            num_filters=num_filters * 2 if cardinality == 32 else num_filters,
            filter_size=1, act=None,
            name=name + "_branch2c",
            data_format=data_format
        )

        if not shortcut:
            self.short = ConvBNLayer(
                num_channels=num_channels, num_filters=num_filters * 2
                if cardinality == 32 else num_filters,
                filter_size=1, stride=stride,
                name=name + "_branch1", data_format=data_format
            )

        self.shortcut = shortcut

    def forward(self, inputs):
        y = self.conv0(inputs)
        conv1 = self.conv1(y)
        conv2 = self.conv2(conv1)

        if self.shortcut:
            short = inputs
        else:
            short = self.short(inputs)

        y = paddle.add(x=short, y=conv2)
        y = F.relu(y)
        return y

4. 模型特点

ResNeXt 通过控制 cardinality 的数量,使得 ResNeXt 的参数量和 GFLOPs 与 ResNet 几乎相同。

通过 cardinality 的分支结构,为网络提供更多的非线性,从而获得更精确的分类效果。

5. 模型指标

ResNeXt 学习

上图是 ResNet 与 ResNeXt 的参数对比,可以看出,ResNeXt 与 ResNet 几乎是一模一样的参数量和计算量,然而两者在 ImageNet 上的表现却不一样。result 从图中可以看出,ResNeXt 除了可以增加 block 中 3×3 卷积核的通道数,还可以增加 cardinality 的分支数来提升模型的精度。ResNeXt-50 和 ResNeXt-101 都大大降低了对应 ResNet 的错误率。图中,ResNeXt-101 从 32×4d 变为 64×4d,虽然增加了两倍的计算量,但也能有效地降低分类错误率。
ResNeXt 学习

在 2019 年何凯明团队开源了 ResNeXt_WSL,ResNeXt_WSL 是何凯明团队使用弱监督学习训练的 ResNeXt,ResNeXt_WSL 中的 WSL 就表示 Weakly Supervised Learning(弱监督学习 )。

ResNeXt101_32×48d_WSL 有 8 亿 + 的参数,是通过弱监督学习预训练的方法在 Instagram 数据集上训练,然后用 ImageNet 数据集做微调,Instagram 有 9.4 亿张图片,没有经过特别的标注,只带着用户自己加的话题标签。ResNeXt_WSL 与 ResNeXt 是一样的结构,只是训练方式有所改变。下图是 ResNeXt_WSL 的训练效果。
ResNeXt 学习

6. 参考文献

文章来源: ResNeXt 学习

    正文完
     0
    Yojack
    版权声明:本篇文章由 Yojack 于2024-09-19发表,共计3663字。
    转载说明:
    1 本网站名称:优杰开发笔记
    2 本站永久网址:https://yojack.cn
    3 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
    4 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
    5 本站所有内容均可转载及分享, 但请注明出处
    6 我们始终尊重原创作者的版权,所有文章在发布时,均尽可能注明出处与作者。
    7 站长邮箱:laylwenl@gmail.com
    评论(没有评论)