结合Tensorflow代码,秒懂 南开大学 Res2net!!!!《Res2Net: A New Multi-scale Backbone Architecture 》

时间:2024-03-21 08:46:35

使用简单,提点结构块!南开大学 Res2net! 看完直接上手!

论文链接:https://arxiv.org/abs/1904.01169

1.来先看看摘要

对于许多视觉任务来说,在多个尺度上表示特征是非常重要的。卷积神经网络(CNNs)不断发展,并显示出较强的多尺度表示能力,在广泛的应用中一致取得了性能的提升。然而,大多数现有的方法以分层的方式表示多尺度特性。在本文提出了一种新的CNNs模块,即Res2Net,通过在一个残差块内构造分层的类残差连接。Res2Net以粒度级别表示多尺度特性,并增加了每个网络层的感受野范围。本文提出的Res2Net块可以插入到最先进的CNN主干模型中,例如ResNet、ResNeXt和DLA。我们在所有这些模型上评估了Res2Net模块,在广泛使用的数据集(如CIFAR-100和ImageNet)上相比基准模型性能都得到了提升。针对典型的计算机视觉任务,如目标检测、分类和显著性目标检测,模型简化测试和实验结果进一步验证了Res2Net相对于最先进的基准方法的优越性。源代码和经过训练的模型将会公开。

2,好了,废话不多说,上结构
结合Tensorflow代码,秒懂 南开大学 Res2net!!!!《Res2Net: A New Multi-scale Backbone Architecture 》
可以看到 res2net策略使用了一个新的维度,即scale(res2net块中的特征组数量)
作为除了现有的深度维度、宽度维度和基数维度之外的一个重要因素。
结构中x1,x2,x3,x4即表示scale维度值为4
结构解析:
举个栗子:送入此结构的feature map经过1x1卷积后feature map为8 channel ,宽高(w,h),根据通道编号1~8,
x1表示channel编号为1,2的feature map,x2表示channel编号为3,4的feature map,依次表示 ,总共四组feature map
k2为x2 经过3x3 卷积 之后,k3,k4, 依次表示,
y1 等于x1,
y2 等于K2 ,
y3 等于 K2 融合 X3(元素相加)后经过3X3卷积所输出的 K3
y4 等于 K3 融合 X4(元素相加)后经过3X3卷积所输出的 K4
最后,y1,y2, y3, y4 经行 concat(又变回8channel),然后再经过1X1卷积输出。

理解完毕!

3,这个模块提取特征效果
结合Tensorflow代码,秒懂 南开大学 Res2net!!!!《Res2Net: A New Multi-scale Backbone Architecture 》
可以看到,红色**区域确实好!

4,代码

def res2net_bottleneck_block(x, f, s=4, expansion=4, use_se_block=False):
    """
    Arguments:
        x: input tensor
        f: number of output  channels
        s: scale dimension
    """
    #获取输入特征的通道
    num_channels = int(x._keras_shape[-1])
    input_tensor = x
    # Conv 1x1
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = Conv2D(f, 1, kernel_initializer='he_normal', use_bias=False)(x)
    # Conv 3x3
    #定义一个数组来存放 y1,y2,y3,y4模块
    subset_x = []

    n = f
    #w表示将通道分成几组后,每组通道数
    w = n // s
    #分几组循环几次
    for i in range(s):
        #实现通道数分组,将x的最后一个维度进行切分
        slice_x = Lambda(lambda x: x[..., i*w:(i+1)*w])(x)
        #当第0组是时,x1不计算,直接保存特征到subset_x,
        #当第1组时,x2经过3X3卷积后产生K2,保存到subset_x
        #当第2组时,x3和从subset_x取出的K2,进行融合,再经过3X3卷积后产生K3,保存到subset_x
        #当第3组时,同上步
        if i > 1:
            slice_x = Add()([slice_x, subset_x[-1]])
        if i > 0:
            slice_x = BatchNormalization()(slice_x)
            slice_x = Activation('relu')(slice_x)
            slice_x = Conv2D(w, 3, kernel_initializer='he_normal', padding='same', use_bias=False)(slice_x)
        subset_x.append(slice_x)
    #将subset_x中保存的 y1,y2, y3, y4 经行 concat
    x = Concatenate()(subset_x)
    
    # Conv 1x1
    x = BatchNormalization()(x)
    x = Activation('relu')(x)
    x = Conv2D(f*expansion, 1, kernel_initializer='he_normal', use_bias=False)(x)
    
    #下面是res2net结合senet块,可用可不用
    if use_se_block:
        x = se_block(x)

    # Add
    if num_channels == f*expansion:
        skip = input_tensor
    else:
        skip = input_tensor
        skip = Conv2D(f*expansion, 1, kernel_initializer='he_normal')(skip)
    out = Add()([x, skip])
    return out

def se_block(input_tensor, c=16):
    num_channels = int(input_tensor._keras_shape[-1]) # Tensorflow backend
    bottleneck = int(num_channels // c)

    se_branch = GlobalAveragePooling2D()(input_tensor)
    se_branch = Dense(bottleneck, use_bias=False, activation='relu')(se_branch)
    se_branch = Dense(num_channels, use_bias=False, activation='sigmoid')(se_branch)

    out = Multiply()([input_tensor, se_branch])
    return out

5,结果,看下论文,在识别,检测,分割领域都有提升
结合Tensorflow代码,秒懂 南开大学 Res2net!!!!《Res2Net: A New Multi-scale Backbone Architecture 》
结合Tensorflow代码,秒懂 南开大学 Res2net!!!!《Res2Net: A New Multi-scale Backbone Architecture 》
结合Tensorflow代码,秒懂 南开大学 Res2net!!!!《Res2Net: A New Multi-scale Backbone Architecture 》
基于Faster Rcnn
结合Tensorflow代码,秒懂 南开大学 Res2net!!!!《Res2Net: A New Multi-scale Backbone Architecture 》
基于DeeplabV3+

6,个人拙见,欢迎指出错误