大数跨境
0
0

如何将 FPN 结构应用在 Faster RCNN

如何将 FPN 结构应用在 Faster RCNN AIer Hub
2023-02-09
1
导读:一、Faster RCNN简介标准 Faster RCNN 模型结构图如下图所示,输入的图片经由骨干网络进行

一、Faster RCNN

标准 Faster RCNN 模型结构图如下图所示,输入的图片经由骨干网络进行特征提取,得到深层特征图,将特征图传入 RPN(Region Proposal Networks),特征图经过 RPN Head 的头部卷积神经网络生成前后景分类以及边框回归值,结合 Anchor 生成器生成检测框,而后将检测框传入 ROI Pooling 中从深层特征图上进行切图,再将切得的结果传入后续网络进行分类及回归,并获得最终输出结果。下面将以 Faster RCNN 这一经典的二阶段物体检测模型为基础,介绍 FPN 结构在物体检测模型中的应用。


二、FPN结构所关联的模块

基于 FPN 的结构可知:FPN 作为骨干网络的附加模块,会生成多尺度的特征图(图中 Feature Maps),而后需要将多尺度的特征图传入 RPN 网络生成 proposals,并使用 proposals 在多尺度特征图上进行 ROI Pooling,因此在 Faster RCNN 中添加 FPN 结构将与骨干网络、RPN 网络以及 ROI Pooling 有关,添加 FPN 的骨干网络在上节中已经进行了描述,下面将主要介绍 FPN 是如何对接 RPN 以及 ROI Pooling 的。

三、FPN对接RPN

原始的 RPN 是一个基于滑动窗的物体检测器,输入的单尺度特征图经过一个 3x3 的卷积后,分别由两个 1x1 的卷积输出前/后景置信度以及边框回归值,Anchor 生成器则会生成多尺度(128,256,512)且多长宽比({1:2, 1:1, 2:1})的 Anchors,结合特征图上每一个像素点的回归值与 Anchors,就可计算出 proposals。

RPN Head 结构图如下所示:

如果想用多尺度的 FPN 网络替换单尺度特征图来适应 RPN,则需在各尺度的特征图上套用相同设计的 RPN Head(3×3 Conv 和两个同级的 1×1 Conv),且因为 RPN Head 将在所有尺度特征图的所有位置上进行滑动,所以 Anchor 生成器就无需生成多尺度的锚框,取而代之的是在每一个尺度的特征图上分配一套固定尺度的锚框(长宽比保持不变,即为{1:2, 1:1, 2:1})。

注:在实际应用时,为了生成更大尺度的锚框( ),FPN 论文作者在 P5 特征图的基础上,通过一次 stride=2 的下采样,生成了 P6,P6 仅在 RPN 中使用。

如上图所示,在 P5 的基础上通过下采样生成 P6 之后,将{P2、P3、P4、P5、P6}放入 RPN Head 进行处理,此时 Anchors Generator 为 P2~P6 生成的锚框面积分别为{ }像素,长宽比为{1:2, 1:1, 2:1},因此 Anchors Generator 一共需要生成 15 个锚框。

值得注意的是,{P2, P3, P4, P5, P6}所用的 RPN Head 不仅结构一致(3×3 Conv 和两个同级的 1×1 Conv)),并且参数共享。(FPN 论文作者对 RPN Head 参数共享与否进行了测试,结果表明参数共享与否几乎不会对模型准确度造成影响。共享参数的良好表现表明,金字塔层级中所有层级都具备相近的语义层次,这也证明了 Top-down pathway and lateral connections 结构的有效性。)

后续生成 proposals 以及 filter proposals 的过程与原始 RPN 过程一致,得到 filter proposals 后即可传入 ROI Pooling 以获取特征图。

代码

RPN Head 代码实现:

class RPNHead(nn.Module):
    def __init__(self, in_channels, num_anchors):
        super(RPNHead, self).__init__()

        # 3x3卷积
        self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1)
        # 1x1卷积(用于前后景分类)
        self.cls_logits = nn.Conv2d(in_channels, num_anchors, kernel_size=1, stride=1)
        # 1x1卷积(用于边框回归)
        self.bbox_pred = nn.Conv2d(in_channels, num_anchors * 4, kernel_size=1, stride=1)

        # 参数初始化
        for layer in self.children():
            if isinstance(layer, nn.Conv2d):
                torch.nn.init.normal_(layer.weight, std=0.01)
                torch.nn.init.constant_(layer.bias, 0)

    def forward(self, x):
        logits = []
        bbox_reg = []
        # 遍历5张特征图{P2, P3, P4, P5, P6}
        for feature in x:
            t = F.relu(self.conv(feature))
            logits.append(self.cls_logits(t))
            bbox_reg.append(self.bbox_pred(t))
        return logits, bbox_reg

四、FPN对接ROI Pooling

原理

原始的 ROI Pooling 运算中,将根据 filter proposals 中的坐标信息(这里的坐标是针对于原图的坐标,即为原图尺度),结合当前 feature map 在骨干网络中的缩放尺度(下采样 32 倍),将坐标信息换算至 feature map 的尺度,而后根据换算之后的坐标在 feature map 进行切图,再将切得的结果 Pooling 至 7x7,即可传入后续网络进行运算。

如果想用多尺度的 FPN 网络替换单尺度特征图来适应 ROI Pooling,则会得到多张不同尺度的特征图,以及其对应的缩放比例,此时就需要确定单个 filter proposal 应在哪个尺度的特征图上进行切图。

针对此问题,论文给出了如下公式进行计算:

在本式中:

  • :使用哪一层特征图进行切图。
  • :论文中表示标准 ResNet-based Faster RCNN 是使用 C4 作为单尺度特征图,因此设置 为4。在此处也可理解为,多尺度特征图一共有几层,就设置为几。
  • :单个 proposal 的宽高(对应原图尺度)。
  • 224:ResNet 的标准输入尺寸,可根据实际输入尺寸进行更改。根据论文中给出的条件,假定输入图片尺寸为 224, ,可得:

此时可以发现 代表的是当前 proposal 的面积相对于原图面积的回归值,且 ,即 ,若带入几组 可得:

根据规律可以发现,proposal 的面积越大,则使用越上层的特征图;proposal 的面积越小,则使用越下层的特征图(k 值为非整数时求近似结果即可)。这也与 FPN 结构中“深层特征图(尺度小、分辨率低)适合检测大物体,浅层特征图(尺度大、分辨率高)适合检测小物体”的规律相符。

因此根据此公式,只需输入多尺度特征图的层数、单个 proposal 的宽高以及原图输入尺寸,即可求得当前 proposal 应使用哪一层特征图进行切图。

代码

torchvision.ops.MultiScaleRoIAlign() 可直接实现此功能。


点击👇卡片关注我,第一时间获取干货~


【声明】内容源于网络
0
0
AIer Hub
人工智能算法工程师一站式培养,立体化为AI人才赋能。
内容 99
粉丝 0
AIer Hub 人工智能算法工程师一站式培养,立体化为AI人才赋能。
总阅读27
粉丝0
内容99