Res2Net: A New Multi-scale Backbone Architecture论文解读以及 tensorflow-slim 实现

Res2Net是一种改进的深度学习网络结构,它通过多尺度特征表示和扩大感受野来提高模型性能。本文详细介绍了Res2Net的工作原理,包括如何在不同尺度上划分输入特征图并进行特征融合,以及如何集成SEBlock来进一步优化模型。此外,还提供了基于TensorFlow的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

原理

Res2Net在多个尺度上表示特征并且增加了每个网络层的感受野范围。

将输入feature map划分为几个组。一组卷积核首先从一组输入feature map中提取特征。然后将输出的feature map与另一组输入feature map再通过另一组卷积核提取特征。这个过程重复几次,直到处理完所有的输入feature map。最后,将所有组输出的feature map拼接起来,再通过1x1的卷积核进行特征融合。当通过3x3的卷积核的时候,感受野也会增加。

此处没有对第一次拆分进行卷积操作,一是可以减少参数的数量,二是可以特征重利用。

Res2Net modual还添加了SE Block(squeeze and excitation),如下图

Res2Net Modual可以集成在ResNet,ResNeXt,DLA这些模型中,其性能都有所提升,只需要修改其中的bottleneck即可。

通过论文中的实验,当 s c a l e = 4 scale=4 scale=4时有很好的效果。

实现

以下代码是我对tensorflow.slim实现的ResNet_v1进行的修改(如果有什么不正确的地方,欢迎指正):

@slim.add_arg_scope
def res2net_bottleneck(inputs, 
                       depth, 
                       depth_bottleneck, 
                       stride, 
                       rate=1, 
                       scale=4, 
                       outputs_collections=None,
                       scope=None, 
                       use_bounded_activations=False, 
                       use_se_block=False):
  with tf.variable_scope(scope, 'bottleneck_v1', [inputs]) as sc:
    depth_in = slim.utils.last_dimension(inputs.get_shape(), min_rank=4)
    if depth == depth_in:
      shortcut = resnet_utils.subsample(inputs, stride, 'shortcut')
    else:
      shortcut = slim.conv2d(
          inputs,
          depth, [1, 1],
          stride=stride,
          activation_fn=tf.nn.relu6 if use_bounded_activations else None,
          scope='shortcut')

    residual = slim.conv2d(inputs, depth_bottleneck, [1, 1], stride, scope='conv1')

    # slice_layer
    single_channel = depth_bottleneck // scale
    output_list = []
    for i in range(scale):
        out = residual[..., i * single_channel:(i + 1) * single_channel]
        output_list.append(out)
    sub_y = []
    for i in range(scale):
        slice_x = output_list[i]
        if i > 1:
            slice_x = tf.add(sub_y[-1], slice_x)
        if i > 0:
            slice_x = resnet_utils.conv2d_same(slice_x, single_channel, 3, stride=1, rate=rate, scope='conv2_' + str(i))
        sub_y.append(slice_x)
    residual = tf.concat(sub_y, axis=-1)


    residual = slim.conv2d(residual, depth, [1, 1], stride=1, activation_fn=None, scope='conv3')

    if use_se_block:
        residual = se_block(residual)
    if use_bounded_activations:
      # Use clip_by_value to simulate bandpass activation.
      residual = tf.clip_by_value(residual, -6.0, 6.0)
      output = tf.nn.relu6(shortcut + residual)
    else:
      output = tf.nn.relu(shortcut + residual)

    return slim.utils.collect_named_outputs(outputs_collections, sc.name, output)

# SE Block的实现
def se_block(inputs, c=16):
    num_chnnels = int(inputs.get_shape()[-1])
    x = tf.reduce_mean(inputs, [1, 2], name='se_pool', keepdims=True)   # 全局平均池化
    x = slim.conv2d(x, num_chnnels // c, [1, 1], padding='VALID', scope='fc1')
    x = slim.conv2d(x, num_chnnels, [1, 1], activation_fn=tf.nn.sigmoid, padding='VALID', scope='fc2')
    return tf.multiply(inputs, x)

论文展示效果

以下几张图片是论文中的实现效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CharlesWu123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值