FPN(Feature Pyramid Networks)详解

图像金字塔结构

FPN(Feature Pyramid Networks)详解_第1张图片

图a

图a是在传统的图像处理当中是比较常见的一个方法。针对我们要检测不同尺度的目标时,会将图片缩放成不同的尺度,然后将每个尺度的图片依次通过我们的算法进行预测。 优点是它创建的多尺度特征的所有层次都包含很强的语义特征,包括高分辨率的层次。这种方法的优点是精度比较高。缺点是我们生成多少尺度的图片我们就要重新去预测多少次,需要大量的算力和内存空间。

图b

图b是Fast R-CNN和Faster R-CNN中采用的一种方式。将图片通过进行卷积和池化操作得到我们最终的特征图,然后在最终的特征图上进行预测。它只使用了最后卷积层的结果,卷积网络中的不同层次会产生不同空间分辨率的特征图,但是不同的卷积层得到的特征图会有很大的语义鸿沟。高分辨率具有很好的低层次特征,但是不利于识别物体,低分辨率的特征具有很好的高层次特征,但是不利于识别小物体。

图c

SSD网络中使用的是图c所示金字塔,SSD中将卷积网络中不同层计算出的特征图组成了一个特征金字塔。但是为了避免使用低层次的特征,在构建特征金子塔的时候是从后面的层次开始,并且又追加了几个新层。这样就损失了高分辨率的特征图,对检测小目标是不利的。

图d

也就是FPN结构,将不同特征图上的特征去进行融合,在融合得到的特征图上再进行预测。主要分了自下向上的一条路径和自上到下的一条路径。自下向上就是深度卷积网络的前向提取特征的过程,自上而下则是对最后卷积层的特征图进行上采样的过程,横向的连接则是融合深层的卷积层特征和浅层卷积特征的过程。这也就是为什么对小物体也有很好的检测效果,它融合了深层卷积层的高级别特征和浅层卷积层的低级别特征。

FPN结构

FPN(Feature Pyramid Networks)详解_第2张图片

第一步: 自下而上的路径。取深度卷积网络,每次卷积图片尺度缩小一倍,我们记为C2 , C3 , C4。C4为最小的特征图。将空间信息少但是语义信息强的最深层卷积层的C4进行1x1卷积调整通道数再进行最大池化操作得到P5,注意P5只用于RPN部分,不在Fast-RCNN中使用。

第二步: 自上而下的路径。首先得到P4;将P4进行2倍的上采样与进行1x1的卷积调整通道后的C3利用横向连接加到一起得到P3;最后将P3进行2倍的上采样与进行1x1的卷积调整通道后的C2利用横向连接加到一起得到P2。

FPN(Feature Pyramid Networks)详解_第3张图片

第三步: 得到的结果P4,P3,P2后面接一个3x3的卷积来减轻上采样的混叠效应(aliasing effect),进行预测。

LevelMapper

Mapper是FPN中引入的一个新的概念,我们通过RPN得到的一系列Proposal之后,该如何将他映射到相应的预测特征层上呢?论文中给出了计算公式:

在这里插入图片描述

实现如下:

class LevelMapper:
    """Determine which FPN level each RoI in a set of RoIs should map to based
    on the heuristic in the FPN paper.

    Args:
        k_min (int)
        k_max (int)
        canonical_scale (int)
        canonical_level (int)
        eps (float)
    """

    def __init__(
        self,
        k_min: int,
        k_max: int,
        canonical_scale: int = 224,
        canonical_level: int = 4,
        eps: float = 1e-6,
    ):
        self.k_min = k_min
        self.k_max = k_max
        self.s0 = canonical_scale
        self.lvl0 = canonical_level
        self.eps = eps

    def __call__(self, boxlists: List[Tensor]) -> Tensor:
        """
        Args:
            boxlists (list[BoxList])
        """
        # Compute level ids
        s = torch.sqrt(torch.cat([box_area(boxlist) for boxlist in boxlists]))

        # Eqn.(1) in FPN paper
        target_lvls = torch.floor(self.lvl0 + torch.log2(s / self.s0) + torch.tensor(self.eps, dtype=s.dtype))
        target_lvls = torch.clamp(target_lvls, min=self.k_min, max=self.k_max)
        return (target_lvls.to(torch.int64) - self.k_min).to(torch.int64)

你可能感兴趣的:(深度学习,深度学习,目标检测)