重读FPN(Feature Pyramid Network)

重读FPN(Feature Pyramid Network)

1 年前 · 来自专栏 深度学习高手笔记

先导知识

前言

目标的多尺度一直是目标检测算法极为棘手的问题。像Fast R-CNN,YOLO这些只是利用深层网络进行检测的算法,是很难把小目标物体检测好的。因为小目标物体本身的像素就比较少,随着降采样的累积,它的特征更容易被丢失。为了解决多尺度检测的问题,传统的方法是使用图像金字塔进行数据扩充。虽然图像金字塔可以一定程度解决小尺度目标检测的问题,但是它最大的问题是带来计算量的极大的增加,而且还有很多冗余的计算。

我们这篇文章要介绍的特征金字塔网络(Feature Pyramid Network,FPN)[1]是一个在特征尺度的金字塔操作,它时通过将自顶向下和自底向上的特征图进行融合来实现特征金字塔操作的。FPN提供的是一个特征融合的机制,并没有引入太多的参数,实现了以增加极小计算代价的情况下提升对多尺度目标的检测能力。

1. 背景知识

在FPN之前,目标检测主要有4种不同的卷积结构类型,如图1所示。其中图1.(a)是早期的目标检测算法常用的图像金字塔,它通过将输入图像缩放到不同尺度的大小构成了图像金字塔。然后将这些不同尺度的特征输入到网络中(可以共享参数也可以独立参数),得到每个尺度的检测结果,然后通过NMS等后处理手段进行预测结果的处理。图像金字塔最大的问题是推理速度慢了几倍,一个是因为要推理的图像数多了几倍,另一个原因是要检测小目标势必要放大图像。

图1.(b)是Fast R-CNN[3],Faster R-CNN[4],YOLO等算法的网络结构,它只使用卷积网络的最后一层作为输出层。这个结构最大的问题就是对小尺寸的目标检测效果非常不理想。因为小尺寸目标的特征会随着逐层的降采样快速损失,到最后一层已经有很少的特征支持小目标的精准检测了。

图1.(c)是SSD[2]采用的结构,它首先提出了使用不同层的Feature Map进行检测的思想。但是SSD只是单纯的从每一层导出一个预测结果,它并没有进行层之间的特征复用。即没有给高层特征赋予浅层特征擅长检测小目标的能力,也没有给浅层的特征赋予高层捕捉到的语义信息,因此带来的小目标的检测效果的提升是非常有限的。

特征融合在其它模型中也有过探索,例如医学分割算法中的U-Net,如图1.(d)所示。U-Net的特点是只在模型的最后一层进行了预测,并没有使用多分辨率预测。

图1:目标检测中常见的卷积网络结构

2. FPN的网络结构

FPN是一个结合了SSD的多分辨率尺度预测和U-Net的多分辨率特征融合的网络结构,如图2所示。FPN可以分成3部分:

  1. 图2左侧的自底向上的卷积;
  2. 图2右侧的自顶向下的上采样;
  3. 图2中间的横向的特征融合。
图2: FPN的网络结构

2.1 自底向上路径

自底向上即是卷积网络的前向过程,我们可以选择不同的骨干网络,例如ResNet-50或者ResNet-101。前向网络的返回值依次是C2,C3,C4,C5,是每次池化之后得到的Feature Map。在残差网络中,C2,C3,C4,C5经过的降采样次数分别是2,3,4,5即分别对应原图中的步长分别是4,8,16,32。这里之所以没有使用C1,是考虑到由于C1的尺寸过大,训练过程中会消耗很多的显存。

2.2 自顶向下路径和横向连接

通过自底向上路径,FPN得到了四组Feature Map。浅层的Feature Map,例如C2含有更多的底层信息(纹理,颜色等),而深层的Feature Map如C5含有更多的语义信息。为了将这四组倾向不同特征的Feature Map组合起来,FPN使用了自顶向下及横向连接的策略,最终得到P2,P3,P4,P5四个输出。

这里我们结合代码讲解FPN的特征融合过程,首先我们通过自底向上的路径得到C2,C3,C4,C5共4个输出。以ResNet-50为例,C5的尺寸是 [H/32, W/32, 512] ,其中 512 是通道数, 32 是步长, H W 是图像的宽和高。在FPN中,我们要得到的P2,P3,P4,P5的通道数都是256。其中P5是由C5计算得到,P4是由P5和C4计算得到,以此类推。FPN的这种计算方式便是自顶向下的路径

以P3为例,P3是由P4和C3共同得到,其中P4的通道数已经是 256 了,但是它的大小只是P3的 1/2 ,因为我们使用上采样将它的尺寸增加到C3的大小,FPN中使用的上采样策略是最近邻居采样。继续,因为C3的通道数是128,而我们需要的P3的通道数是256,所以这里使用 1\times1 卷积将C3的通道数扩充到 256 。最后P3是P4的上采样的Feature Map和C3的调整通道数的Feature Map的单位加。

最后,FPN 在 P2,P3,P4,P5 之后均接了一个 3\times3 卷积操作,该卷积操作是为了减轻上采样的混叠效应(aliasing effect)。

# Top-down Layers
P5 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c5p5')(C5)
P4 = KL.Add(name="fpn_p4add")([ 
    KL.UpSampling2D(size=(2, 2), interpolation="nearest", 
                    name="fpn_p5upsampled")(P5),
    KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c4p4')(C4)])
P3 = KL.Add(name="fpn_p3add")([
    KL.UpSampling2D(size=(2, 2), interpolation="nearest", 
                    name="fpn_p4upsampled")(P4),
    KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c3p3')(C3)])
P2 = KL.Add(name="fpn_p2add")([
    KL.UpSampling2D(size=(2, 2), interpolation="nearest", 
                    name="fpn_p3upsampled")(P3),
    KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (1, 1), name='fpn_c2p2')(C2)])
# Attach 3x3 conv to all P layers to get the final feature maps.
P2 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME",
               name="fpn_p2")(P2)
P3 = KL.Conv2D(config.TOP_DOWN_PYRAMID_SIZE, (3, 3), padding="SAME",