当前位置:   article > 正文

模型中的featuremap增强模块_特征增强模块

特征增强模块

图像空间金字塔思想在图像处理中被广泛应用,本文主要针对具体的 SPP ,PPM,ASPP和 FPN 结构,以及传统图像处理的SIFT等进行简单的介绍和总结。

1、SPP结构(Spatial Pyramid Pooling)

在何恺明2015年《Spatial Pyramid Pooling in Deep ConvolutionalNetworks for Visual Recognition》被提出,改论文主要改进两点:

解决了CNN需要输入固定尺寸的图像,导致不必要的精度损失问题。

因为带有全连接的网络层都需要输入固定尺寸的图像,当然在后期网络中也有使用卷积来替换FC层的,比如在SSD网络中直接用conv层计算边界框坐标和置信度的。

解决了R-CNN对候选区域的重复卷积计算,导致计算冗余问题。

因为R-CNN网络中基于segment seletive 输出的候选框都要出重新计算feature map,因此提出了候选区域到全图特征之间的对应映射,这样图像只需要计算一次前向传播即可。
之后的fast R-CNN, faster R-CNN都采用这种映射关系,为ROI pooling层。
但是在mask R-CNN中,用ROI Align代替了ROI pooling层,其认为两次量化的候选框与最开始的回归候选框有一定的偏差,影响检测和分割准确度,ROI Align中不进行float量化,通过双线性插值计算四个坐标点,然后进行max pooling。

SPP结构如下:

在这里插入图片描述
将256 channels 的 feature map 作为输入,在SPP layer被分成1x1,2x2,4x4三个pooling结构,对每个输入都作max pooling(论文使用的),这样无论输入图像大小如何,出来的特征固定是(16+4+1)x256维度。这样就实现了不管图像中候选区域尺寸如何,SPP层的输出永远是(16+4+1) x 256 特征向量。

2、PPM结构(Pyramid Pooling Module)

此网络应用在语义分割中,PPMNet网络结构如下:

在这里插入图片描述

(1)Input Image:即自然场景下拍摄的包含不同目标的原始图;
(2)Feature Map:即通过前面CNN获得的特征图,,这个CNN是预训练的ResNet;
(3)Pyramid Pooling Module:上图中方框POOL表示采用1x1、2x2、3x3和6x6四种不同尺寸的pooling操作得到多个尺寸的特征图,并对这些尺寸的特征图再次进行“1x1的Conv”来减少通道数。然后采用双线性插值进行UPSAMPLE,即通过上采样来获得金字塔模块前相同尺寸的特征图,并在通道上进行拼接;
(4)Final Prediction:即最终预测结果;

PPM模块代码如下,结合代码更直观:

#下面是单个PPM模块
def interp_block(prev_layer, level, feature_map_shape, input_shape):
    if input_shape == (473, 473):
        kernel_strides_map = {1: 60,
                              2: 30,
                              3: 20,
                              6: 10}
    elif input_shape == (713, 713):
        kernel_strides_map = {1: 90,
                              2: 45,
                              3: 30,
                              6: 15}
    else:
        print("Pooling parameters for input shape ",
              input_shape, " are not defined.")
        exit(1)

    names = [
        "conv5_3_pool" + str(level) + "_conv",
        "conv5_3_pool" + str(level) + "_conv_bn"
    ]
    kernel = (kernel_strides_map[level], kernel_strides_map[level])
    strides = (kernel_strides_map[level], kernel_strides_map[level])
    prev_layer = AveragePooling2D(kernel, strides=strides)(prev_layer)  #或者maxPooling;
    prev_layer = Conv2D(512, (1, 1), strides=(1, 1), name=names[0],
                        use_bias=False)(prev_layer)
    prev_layer = BN(name=names[1])(prev_layer)
    prev_layer = Activation('relu')(prev_layer)
    # prev_layer = Lambda(Interp, arguments={
    #                    'shape': feature_map_shape})(prev_layer)
    prev_layer = Interp(feature_map_shape)(prev_layer) #此处进行上采样,resize到原来feature map的size;
    return prev_layer

#下面是1,2,3,6的PPM模块
def build_pyramid_pooling_module(res, input_shape):
    """Build the Pyramid Pooling Module."""
    # ---PSPNet concat layers with Interpolation
    feature_map_size = tuple(int(ceil(input_dim / 8.0))
                             for input_dim in input_shape)  #原图经过resnet后变为1/8;
    print("PSP module will interpolate to a final feature map size of %s" %
          (feature_map_size, ))

    interp_block1 = interp_block(res, 1, feature_map_size, input_shape)
    interp_block2 = interp_block(res, 2, feature_map_size, input_shape)
    interp_block3 = interp_block(res, 3, feature_map_size, input_shape)
    interp_block6 = interp_block(res, 6, feature_map_size, input_shape)

    # concat all these layers. resulted
    # shape=(1,feature_map_size_x,feature_map_size_y,4096)
    res = Concatenate()([res,
                         interp_block6,
                         interp_block3,
                         interp_block2,
                         interp_block1])
    return res

#pspnet网络结构
def build_pspnet(nb_classes, resnet_layers, input_shape, activation='softmax'):
    """Build PSPNet."""
    print("Building a PSPNet based on ResNet %i expecting inputs of shape %s predicting %i classes" % (
        resnet_layers, input_shape, nb_classes))

    inp = Input((input_shape[0], input_shape[1], 3))
    res = ResNet(inp, layers=resnet_layers)
    psp = build_pyramid_pooling_module(res, input_shape)
#后面是经过3×3,1×1的卷积后一次上采样到原图
    x = Conv2D(512, (3, 3), strides=(1, 1), padding="same", name="conv5_4",
               use_bias=False)(psp)
    x = BN(name="conv5_4_bn")(x)
    x = Activation('relu')(x)
    x = Dropout(0.1)(x)

    x = Conv2D(nb_classes, (1, 1), strides=(1, 1), name="conv6")(x)
    # x = Lambda(Interp, arguments={'shape': (
    #    input_shape[0], input_shape[1])})(x)
    x = Interp([input_shape[0], input_shape[1]])(x)
    x = Activation('softmax')(x)

    model = Model(inputs=inp, outputs=x)

    # Solver
    sgd = SGD(lr=learning_rate, momentum=0.9, nesterov=True)
    model.compile(optimizer=sgd,
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])
    return model

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

3、 ASPP结构(Atrous Spatial Pyramid Pooling)

SPP结构在语义分割中的应用,结合了空洞卷在不丢失分辨率的情况下增大了卷积核的感受野。ASSP结构首次出现在deepLab v3 网络中,如下图所示:

在这里插入图片描述
其中的1*1卷积,论文中的解释是当 rate = feature map size 时,dilation conv 就变成了 1 ×1 conv,所以这个 1 × 1 conv相当于rate很大的空洞卷积。还加入了全局池化,再上采样到原来的 feature map size,思想来源于PSPnet。为什么用 rate = [6, 12, 18] ?是论文实验得到的,因为这个搭配比例的 mIOU 最高。

在 backbone 的每一个block里面又参考了HDC的思想,设置了 [1,2,1] 的rate,所以每个conv的rate = Rate * rate。论文给出的 Multi-grid 部分结果如下所示。

在这里插入图片描述
这里提一下deeplab v3+ 结构,是对V3的一个加强,主要有两个改进点:

对ASPP中的 upsample 进行了改进;

下图来自 deeplab v3+ 论文中,(a) 是deeplab v3的结构,( c) 是deeplab v3+的结构,v3+ 中将上采样变成了2次 4× 的 upsample,相比于v3中直接进行 8× 的 upsample,具有更丰富的语义信息,所以对物体边缘分割效果较好。

在这里插入图片描述
deeplab v3+中另一个改进点,将 modify xception 作为 backbone;(这个改进点与ASPP无关)

在这里插入图片描述

4、 FPN结构(Feature Pyramid Networks for Object Detection)

FPN通常用在 object detection 网络中,通常低层的特征语义信息比较少,但是目标位置准确;高层的特征语义信息比较丰富,但是目标位置比较粗略。FPN 即是对两者进行了融合,同时利用低层特征高分辨率和高层特征的高语义信息,通过融合这些不同层的特征达到预测的效果。并且预测是在每个融合后的特征层上单独进行的,这和常规的特征融合方式不同。

FPN结构如下图:

在这里插入图片描述
自底向上的路径:

具体而言,当 backbone 是 ResNet 时,我们使用每个阶段的最后一个residual block输出的特征激活输出。 对于conv2,conv3,conv4 和 conv5 输出,我们将这些最后residual block的输出表示为 {C2,C3,C4,C5},并且它们相对于输入图像具有 {4, 8, 16, 32} 的步长。

自顶向下的路径:

通过对在空间上更抽象但语义更强高层特征图进行上采样来幻化高分辨率的特征。在C5上附加一个1×1卷积层来生成低分辨率图P5,随后通过侧向连接从底向上的路径,使得高层特征得到增强。将低分辨率的特征图做2倍上采样,最终的特征映射集称为{P2,P3,P4,P5},分别对应于{C2,C3,C4,C5},具有相同的尺寸。通过按元素相加,将上采样映射与相应的自底而上映射合并。

最后,在每个合并的图上附加一个3×3卷积来生成最终的特征映射,这是为了减少上采样的混叠效应。

作者在将其应用到 RPN 和 fast / faster R-CNN 中,在论中有详细的实验数据,大家有兴趣可自行查阅。

在YOLO v3中也采用了类似 FPN 的结构,但里面用了concat 进行特征融合;

重点在此处有创新点: 双FPN结构

总结

空间金字塔思想在图像处理中具有很重要的作用,
传统图像处理中:

在SIFT 中利用高斯差分金字塔 (DOG) 保持尺度不变性;
在配准 / 匹配算法中利用空间金字塔进行粗匹配和细匹配达到效率优化;

CNN网络中:

在含有FC层网络中利用 SPP 改进输入需要固定尺度的问题;
在语义分割中利用 ASPP在不丢失信息时组合不同感受野的语义信息,提高分割精度;
在 object detection 网络中利用 FPN 改善小目标难检测的问题;

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号