【目标检测】19、FCOS: Fully Convolutional One-Stage Object Detection

论文:FCOS: Fully Convolutional One-Stage Object Detection

代码:https://github.com/aim-uofa/AdelaiDet/tree/master/configs/FCOS-Detection

出处:ICCV2019

在这里插入图片描述

FCOS 贡献:

  • 证明了目标检测也可以像语义分割那样,使用单阶段来实现
  • 检测任务可以使用 proposal-free 和 anchor-free 来实现,可以很大程度降低超参数的设计和调试,使得目标检测任务更优美简单
  • FCOS 达到了当前单阶段检测的 SOTA,并且也可以被用作两阶段网络中的 RPN 网络
  • 使用 ResNeXt-32x8d-101-FPN,在 COCO 上得到了 42.1% AP

一、背景

当时主流的目标检测算法,如 Faster RCNN、SSD、YOLOv2/v3 等,都是基于 proposal 或 anchor 的方法,使用这些预定义的 anchor 是这些方法成功的主要原因。但这些方法也有一些缺陷:

  • 检测效果严重依赖于预定义框的尺寸、宽高比、数量等等,如 RetinaNet 通过调节这些超参数,就在 COCO 上提高了 4 AP,所以 anchor-based 方法需要细致的调节这些超参数
  • 由于目标大小和尺度跨度较大,所以尽管使用很丰富的参数,也有不能覆盖的情况
  • anchor-based 方法为了提升效果,一般会使用很多的 anchor,但很多 anchor 其实是覆盖到负样本上了,有很严重的正负样本不平衡问题
  • 过多的 anchor 会在训练的时候和真值计算 IoU 的时候增加很大的计算量

基于 FCN 的方法在语义分割、关键点检测、深度估计等领域都取得了较好的效果,同样作为密集预测任务,目标检测由于有 anchor 所以一直不能实现端到端的单阶段预测。

所以研究者就提出了问题:目标检测能通过逐点预测来实现吗?

在 FCOS 之前,也有一些 FCN-based 方法用于解决目标检测的问题,如 Dense-Box 和 UnitBox。这些结构在输出的特征图上,直接预测一个 4D 向量 + class 类别,如图 1 左侧所示,4D 向量表示从某个点到 bbox 的 4 个边的距离。

为了解决 bbox 大小不同的问题,DenseNet 将输入图像 resize 到相同大小,所以就需要使用金字塔的特征来进行目标检测。且这些方法难以解决单个点对应多个目标的问题,如图 1 右侧所示。更多的用于文字检测等目标无相交的情况,难以解决目标高度相交的情况。

在这里插入图片描述

二、方法

FCOS 方法是第一个使用逐个像素点来预测的目标检测方法,并且提出了 centerness 分支,来抑制 low-quality bbox 并提升检测效果。

FCOS 的主要过程:

  • 首先,将图像输入 Backbone,然后将 8 倍、16 倍、32 倍下采样的特征图送入 FPN,得到 FPN 的 5 层输出特征(8/16/32/64/128 倍下采样)
  • 接着,在 FPN 的每一层后面都使用分类和回归头(不同分辨率特征的 head 参数是共享的),对 FPN 特征图上的每个位置都进行得分和位置的预测,得分是属于类别的得分,位置是该特征点到 gt 框的左、上、右、下四条边的距离
  • 然后,将FPN 的每层特征图中的点都当做初始 anchor point,并将 anchor point 映射回原图中,根据 anchor point 是否落入 gt 框内部(或 3x3 区域内)来判断是否为正 anchor,其他的特征点赋值 80,作为负样本
  • 接着,对所有正 anchor 分配对应的 gt,并根据 gt 的真实面积大小将这些 anchor 分配到不同的 FPN 特征图上去 (每层特征图负责对应大小的目标,((-1, 64), (64, 128), (128, 256), (256, 512), (512, INF))),如果某个 anchor 属于多个 gt 框内部,则选择面积最小的作为对应的 anchor

在这里插入图片描述

2.1 全卷积单阶段目标检测器

1、训练样本构建

假设:

  • backbone 的第 i i i 层的特征图为 F i ∈ R H × W × C F_i\in R^{H\times W\times C} FiRH×W×C
  • s s s 是在该层前所经历的 stride
  • bbox 的真值可以表示为 B i {B_i} Bi B i = ( x 0 i , y 0 i , x 1 i , y 1 i , c i ) ∈ R 4 × 1 , 2 , . . . , C B_i = (x_0^i, y_0^i, x_1^i, y_1^i, c^i) \in R^4 \times{1, 2,..., C} Bi=(x0i,y0i,x1i,y1i,ci)R4×1,2,...,C (分别表示左上和右下角点,和类别)

对于特征图 F i F_i Fi 中的任意位置 ( x , y ) (x, y) (x,y),可以将其推回到该层特征图的输入特征图的位置 ( ⌊ s 2 ⌋ + x s , ⌊ s 2 ⌋ + y s ) (\lfloor \frac{s}{2} \rfloor + xs, \lfloor \frac{s}{2} \rfloor + ys) (⌊2s+xs,2s+ys)

本文提出的检测器是直接回归每个位置上的目标的bbox,也就是将每个像素位置看做一个训练样本,而非将每个 anchor box 看做训练样本。(anchor-based 检测器是回归每个 anchor 和真实框的偏移)

如何判定正负样本:

  • 如果某个像素位置落入真实的 bbox 内,而且类别和真实的类别相同,则定义为正样本
  • 否则判定其为负样本,且类别为 0 (background class)

回归的目标:

  • t ∗ = ( l ∗ , t ∗ , r ∗ , b ∗ ) t^* = (l^* , t^* , r^* , b^* ) t=(l,t,r,b) 是每个像素位置(sample)所要回归的目标,分别表示从 sample 的位置到 bbox 的四个边的距离,如图 1 左侧所示。当一个点同时落入多个框的时候,被认为是 “ambiguous sample”,也就是 “模棱两可” 的框,选择最小面积的框作为回归目标。
  • 如果一个像素位置 ( x , y ) (x, y) (x,y) 和 bounding box B i B_i Bi 是相关的,则训练时的回归目标可以被格式化为如下形式,从下面的公式中也能看出,FCOS 能够使用尽可能多的 sample 来作为训练样本(作者认为这也是 FCOS 能超越 anchor-based 方法的一个主要原因)
    在这里插入图片描述

2、网络输出

在 backbone 的后面,连接了 4 层卷积层,来进行分类和回归,并且由于回归的目标总数正的,所以,作者在回归分支的后面使用 e x p ( x ) exp(x) exp(x) 来将任何 ( 0 , ∞ ) (0, \infty) (0,) 的实数进行映射。

  • 80D 的分类结果(以 COCO 为例)
  • 4D 的回归结果 t = ( l , t , r , b ) t = (l, t, r, b) t=(l,t,r,b)

分类器:C 个二分类分类器

优势:输出参数少

  • FCOS 比 anchor-based 方法的输出参数少 9x,因为 anchor-based 方法在每个位置都放置了约 9 个不同大小的 anchors

3、Loss 函数

在这里插入图片描述

  • L c l s L_{cls} Lcls 是 focal loss
  • l r e g l_{reg} lreg 是 IoU loss
  • N p o s N_{pos} Npos 是正样本的数量
  • λ \lambda λ 是 1(为了平衡权重)
  • Σ \Sigma Σ 的作用范围是特征图上的所有像素点
  • 1 c i ∗   0 1_{{c_i^*\>0}} 1ci0 是一个调节因子,当 c i ∗ > 0 c_i^*>0 ci>0 时为 1,其他情况为 0

4、推理

FCOS 的推理是很直接的:

  • 输入图像并经过 backbone 和 head
  • 得到每个位置的特征图分类得分 p x , y p_{x,y} px,y 和回归得分 t x , y t_{x,y} tx,y
  • 选择 p x , y > 0.05 p_{x,y}>0.05 px,y>0.05 的作为正样本,并得到预测框(公式1)

2.2 Multi-level Prediction with FPN for FCOS

下面介绍 FCOS 可能产生的两个问题,但可以通过多尺度特征 FPN 解决的:

1、特征图分辨率大幅降低(如 16x)可能产生的低 Recall

在 anchor-based 检测器中,由于降低分辨率导致的低 recall 可以通过使用低 IoU 阈值来得到补偿。

但对于 FCOS,可能第一眼会觉得低分辨率会造成其 recall 比 anchor-based 方法低的原因在于其不可能恢复在最终的特征图上没有对应sample的目标。

但在表 1 中,作者也验证了 FCOS 能达到和 RetinaNet 等方法甚至更好的 recall,而且通过使用 FPN,能进一步提高。

在这里插入图片描述

2、真值框的重合可能导致训练时候的样本模棱两可

在训练过程中,到底该位置应该回归哪个框呢?

这个模棱两可的问题可能降低 FCN based 检测器。

本文也验证了可以很好的解决该问题:

和 FPN 一样,本文作者也在不同分辨率的特征图上来预测不同尺度的目标,使用了 5 个 level 的特征图 P 3 , P 4 , P 5 , P 6 , P 7 {P_3, P_4, P_5, P_6, P_7} P3,P4,P5,P6,P7,其总 stride 分别为 8、16、32、64、128。

  • P 3 , P 4 , P 5 P_3, P_4, P_5 P3,P4,P5 是通过 backbone C 3 , C 4 , C 5 C3, C_4, C_5 C3,C4,C5 经过 1x1 卷积来得到的(如图 2)
  • P 6 P_6 P6 是在 P 5 P_5 P5 后使用 stride=2 的卷积得到的, P 7 P_7 P7 是在 P 6 P_6 P6 后使用 stride=2 的卷积得到的

Anchor-based 是怎么给不同分辨率的特征图分配 anchor 的呢?

Anchor-based 方法是给不同 level 的特征图分配不同大小的 anchor box

FCOS 是怎么分配 anchor 的呢?

FCOS 直接限制 bbox 回归的数值的范围

  • 首先,在每个特征图的每个位置上计算回归目标值 t ∗ = ( l ∗ , t ∗ , r ∗ , b ∗ ) t^* = (l^* , t^* , r^* , b^* ) t=(l,t,r,b)
  • 接着,如果某个位置的结果满足 m a x ( l ∗ , t ∗ , r ∗ , b ∗ ) > m i max(l^* , t^* , r^* , b^*)>m_i max(l,t,r,b)>mi m a x ( l ∗ , t ∗ , r ∗ , b ∗ ) < m i − 1 max(l^* , t^* , r^* , b^*)<m_{i-1} max(l,t,r,b)<mi1,则认定该位置为负样本,也不用回归 bbox。 m i m_i mi 是在 level i i i 的特征图需要回归的最远距离。 m 2 , m 3 , m 4 , m 5 , m 6 m_2, m_3, m_4, m_5, m_6 m2,m3,m4,m5,m6 分别设置为 0, 64, 128, 256, 512 和 ∞ \infty 。由于不同大小的目标被分配到了不同 level 的特征图上,而且有重叠的目标一般大小都不一样,可以被分配到不同尺度的特征图上去,所以,多尺度金字塔特征,能够很好的解决 FCOS 的前景模棱两可问题。
  • 最后,作者对不同尺度特征共享 head,可以提高检测效果,并提升了效率。但是,由于不同 level 的特征图需要回归不同尺度的目标(如 P3 回归的尺度为 [0,64]),所以使用一个共享头是不太合理的。故此,作者没有使用标准的 e x p ( x ) exp(x) exp(x),而是使用了 e x p ( s i x ) exp(s_ix) exp(six) s i s_i si 也是一个可训练的参数,可以根据特征图的 level 自动调节尺度。

在这里插入图片描述

2.3 Center-ness for FCOS

虽然使用 FPN 可以弥补不同尺度目标的识别问题,但 FCOS 还是和 anchor-based 方法的效果有一定的差距。

主要原因在于,预测产生了很多距离目标中心点很远的低质量 bbox

如何解决距离中心点很远的低质量 bbox?

作者在原来的两个 branch 的基础上,添加了一个 centerness 分支,来预测每个位置的 “centerness”,即该位置和真实目标中心点的位置,如图 2 所示。

Centerness 是给所有判定为正样本的样本点来计算的,判定为负样本的样本点是不会被计算 Centerness 的,可以看做是对所有的正样本,按其距离 gt 中心点的距离来设置权重,距离越近,则质量越高,权重越大,越有可能被 NMS 排序的时候排到前面。

下面的公式展示了 centerness 真值的计算方法,loss 使用的是二值交叉熵损失函数。

在这里插入图片描述

  • 为了减缓衰落,使用了根号
  • centerness 的范围是 (0,1),使用二值交叉熵损失来训练(添加到公式 2 的 loss 函数)
  • 在测试时,final score(用于 NMS 框排序)是 centerness × \times × classification score 得到的,所以可以降低远离中心点的位置(即 low-quality 位置)的权重,可以通过 NMS 过滤掉很大一部分 low-quality 位置,提升检测效果。

极端情况下:

  • 如果某一个点在box边界,那么centerness就是0
  • 如果刚好在box中心,这个值就是1。centerness的值在0-1之间
  • 测试的时候,作者将centerness乘以类别score作为新的score,这样就降低了远离中心点的location的分数,在NMS阶段将会大概率过滤掉它们,NMS 的 IoU 过滤阈值为 0.5。

从 anchor-based 检测器的角度来看,anchor-based 方法使用两个 IoU 阈值( T l o w T_{low} Tlow T h i g h T_{high} Thigh 来将 anchor 分为 negative、ignore、positive,centerness 可以被看做一个 soft threshold。

在这里插入图片描述

三、效果

使用 ResNeXt-32x8d-101-FPN,在 COCO 上得到了 42.1% AP

使用 centerness 的效果对比:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如图 7 所示:

  • 使用 centerness 前,有很多 low-quality bbox 的类别得分很高,很难被 NMS 消除
  • 使用 centerness 后,这些点都被推到了左上角,即降低类别得分置信度,更容易被消除
    在这里插入图片描述
    如图 8 所示,FCOS 可以很好的检测被遮挡、高重叠的各种不同大小的目标。

在这里插入图片描述

四、训练代码

在 mmdetection 中,可以打印 FCOS Head 的结构如下:

1、loss 函数:

<bound method FCOSHead.forward_single of FCOSHead(
  (loss_cls): FocalLoss()
  (loss_bbox): IoULoss()
  (loss_centerness): CrossEntropyLoss(avg_non_ignore=False)
  
  (conv_cls): Conv2d(256, 80, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (conv_reg): Conv2d(256, 4, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (conv_centerness): Conv2d(256, 1, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
  (scales): ModuleList(
    (0): Scale()
    (1): Scale()
    (2): Scale()
    (3): Scale()
    (4): Scale()
  )

2、分类的卷积层

  (cls_convs): ModuleList(
    (0): ConvModule(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (gn): GroupNorm(32, 256, eps=1e-05, affine=True)
      (activate): ReLU(inplace=True)
    )
    (1): ConvModule(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (gn): GroupNorm(32, 256, eps=1e-05, affine=True)
      (activate): ReLU(inplace=True)
    )
    (2): ConvModule(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (gn): GroupNorm(32, 256, eps=1e-05, affine=True)
      (activate): ReLU(inplace=True)
    )
    (3): ConvModule(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (gn): GroupNorm(32, 256, eps=1e-05, affine=True)
      (activate): ReLU(inplace=True)
    )
  )

3、回归的卷积层

 (reg_convs): ModuleList(
    (0): ConvModule(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (gn): GroupNorm(32, 256, eps=1e-05, affine=True)
      (activate): ReLU(inplace=True)
    )
    (1): ConvModule(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (gn): GroupNorm(32, 256, eps=1e-05, affine=True)
      (activate): ReLU(inplace=True)
    )
    (2): ConvModule(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (gn): GroupNorm(32, 256, eps=1e-05, affine=True)
      (activate): ReLU(inplace=True)
    )
    (3): ConvModule(
      (conv): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
      (gn): GroupNorm(32, 256, eps=1e-05, affine=True)
      (activate): ReLU(inplace=True)
    )
  )
)
init_cfg={'type': 'Normal', 'layer': 'Conv2d', 'std': 0.01, 'override': {'type': 'Normal', 'name': 'conv_cls', 'std': 0.01, 'bias_prob': 0.01}}>
(

输入 FCOS Head 的 FCN 共有 5 个尺度:

(Pdb) feats[0].shape
torch.Size([2, 256, 100, 152])
(Pdb) feats[1].shape
torch.Size([2, 256, 50, 76])
(Pdb) feats[2].shape
torch.Size([2, 256, 25, 38])
(Pdb) feats[3].shape
torch.Size([2, 256, 13, 19])
(Pdb) feats[4].shape
torch.Size([2, 256, 7, 10])

这 5 组特征相比原图的 strides 如下:

self.strides = [8, 16, 32, 64, 128]

下面以第一组特征(最大的一组)为例,来看看 centerness 的输入和输出,FPN 的 5 组特征都会经过下面的操作,在每个特征点位置上获得对应的 cls_score 和 box_pred:

# 下面这 2 组特征,都是从 FCOS 的 head 输出来的特征
# bbox_pred.shape = [2, 4, 100, 152], 每个位置输出 4 个距离,一般后面还会对 bbox_pred 使用 exp 操作来进行映射
# cls_score.shape = [2, 80, 100, 152],每个位置输出 80 个向量组成的类别特征

# 下面这两组特征,都是倒数第二层特征,一般使用 cls_feat 输入到 centerness conv 中去,在每个位置都输出一个 centerness 值
# cls_feat.shape = [2, 256, 100, 152]
# reg_feat.shape = [2, 256, 100, 152]

# self.conv_centerness = Conv2d(256, 1, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
centerness = self.conv_centerness(cls_feat)
# centerness.shape = [2, 1, 100, 152]

5 组 FPN 特征得到的分类得到特征图大小分别为:

[2, 80, 100, 152]
[2, 80, 50, 76]
[2, 80, 25, 38])
[2, 80, 13, 19])
[2, 80, 7, 10])

5 层特征图分别负责的目标大小为:

((-1, 64), (64, 128), (128, 256), (256, 512), (512, INF))

Loss 的计算:

mmdet/models/builder.py                       # 整体结构
mmdet/models/dense_heads/base_dense_head.py   # dense_head 的基本框架
mmdet/models/dense_heads/anchor_free_head.py  # 继承 dense_head 并实现 anchor-free 的结构
mmdet/models/dense_heads/fcos_head.py         # fcos_head 特有的内容会写在这里边
mmdet/core/anchor/point_generator.py          # 生成 point 的位置,然后在 fcos_head 中再进行正负样本的判断
mmdet/models/losses/focal_loss.py             # 计算分类的 focal_loss

1、先在 /mmdet/core/anchor/point_generator.py(80)grid_priors() 中生成 point,输入为 featmap_size,即为 [torch.Size([100, 152]), torch.Size([50, 76]), torch.Size([25, 38]), torch.Size([13, 19]), torch.Size([7, 10])] ,会给每层特征单独生成 point feature。

五层特征图对应的 point feature 大小分别如下,分别对应原图的 [4, 8, 16, 32, 64] 间隔的位置点:

(Pdb) all_level_points[0].shape
torch.Size([15200, 2])
(Pdb) all_level_points[1].shape
torch.Size([3800, 2])
(Pdb) all_level_points[2].shape
torch.Size([950, 2])
(Pdb) all_level_points[3].shape
torch.Size([247, 2])
(Pdb) all_level_points[4].shape
torch.Size([70, 2])

最小的一层特征图生成的 point 如下:

all_level_points[4]
tensor([[  64.,   64.],
        [ 192.,   64.],
        [ 320.,   64.],
        [ 448.,   64.],
        [ 576.,   64.],
        [ 704.,   64.],
        [ 832.,   64.],
        [ 960.,   64.],
        [1088.,   64.],
        [1216.,   64.],
        [  64.,  192.],
        [ 192.,  192.],
        [ 320.,  192.],
        [ 448.,  192.],
        [ 576.,  192.],
        [ 704.,  192.],
        [ 832.,  192.],
        [ 960.,  192.],
        [1088.,  192.],
        [1216.,  192.],
        [  64.,  320.],
        [ 192.,  320.],
        [ 320.,  320.],
        [ 448.,  320.],
        [ 576.,  320.],
        [ 704.,  320.],
        [ 832.,  320.],
        [ 960.,  320.],
        [1088.,  320.],
        [1216.,  320.],
        [  64.,  448.],
        [ 192.,  448.],
        [ 320.,  448.],
        [ 448.,  448.],
        [ 576.,  448.],
        [ 704.,  448.],
        [ 832.,  448.],
        [ 960.,  448.],
        [1088.,  448.],
        [1216.,  448.],
        [  64.,  576.],
        [ 192.,  576.],
        [ 320.,  576.],
        [ 448.,  576.],
        [ 576.,  576.],
        [ 704.,  576.],
        [ 832.,  576.],
        [ 960.,  576.],
        [1088.,  576.],
        [1216.,  576.],
        [  64.,  704.],
        [ 192.,  704.],
        [ 320.,  704.],
        [ 448.,  704.],
        [ 576.,  704.],
        [ 704.,  704.],
        [ 832.,  704.],
        [ 960.,  704.],
        [1088.,  704.],
        [1216.,  704.],
        [  64.,  832.],
        [ 192.,  832.],
        [ 320.,  832.],
        [ 448.,  832.],
        [ 576.,  832.],
        [ 704.,  832.],
        [ 832.,  832.],
        [ 960.,  832.],
        [1088.,  832.],
        [1216.,  832.]], device='cuda:0')

2、生成 anchor point 后,先将所有的 anchor 都映射到原图中去,对每个 anchor 都根据是否在 gt 框内部来区分正负样本,将负样本赋值为背景 80,得到每个样本为正或为负的结果。并且会根据计算得到的 gt 的面积来划分应该在哪一层被检测,如下所示:

# 0  表示正样本及类别
# 80 表示负样本
[ 0, 80, 80,  0,  0, 80, 80, 80, 80,  0,  0 ...]

3、计算分类 loss ,将预测类别、正负样本标记结果、正样本数量都送入 loss 函数,focal loss 的 γ = 2 \gamma=2 γ=2 α = 0.25 \alpha=0.25 α=0.25

F o c a l _ L o s s = { − α ( 1 − p ) γ l o g ( p ) , y = 1 − ( 1 − α ) p γ l o g ( 1 − p ) , y = 0 Focal\_Loss = \begin{cases} -\alpha (1-p)^\gamma log(p), & y=1 \\ -(1-\alpha) p^\gamma log(1-p), & y=0 \end{cases} Focal_Loss={α(1p)γlog(p),(1α)pγlog(1p),y=1y=0

loss_cls = self.loss_cls(flatten_cls_scores, flatten_labels, avg_factor=num_pos)

得到 loss:

tensor(1.1565, device='cuda:0', grad_fn=<MulBackward0>)

4、计算回归 loss 和 centerness loss,首先将正样本处的 bbox 和 centerness 选择出来,然后再做 loss

(Pdb) loss_bbox
tensor(7.9373, device='cuda:0', grad_fn=<MulBackward0>)
(Pdb) loss_centerness
tensor(0.7539, device='cuda:0', grad_fn=<MulBackward0>)

5、回到 mmdet/models/detectors/base.py (251) ,得到最后的 loss 结构:

{'loss': tensor(9.8477, device='cuda:0', grad_fn=<AddBackward0>), 'log_vars': OrderedDict([('loss_cls', 1.1565027236938477), ('loss_bbox', 7.937312602996826), ('loss_centerness', 0.7539195418357849), ('loss', 9.847734451293945)]), 'num_samples': 2}

五、推理

  • 首先,输入图像经过 backbone,并得到 FPN 的 5 层输出特征
  • 然后,FPN 特征经过分类和回归头,得到每个位置上的分类和回归结果,将分类得分 > 0.05 的位置看做正样本,保留前 1000 个位置
  • 接着,对正样本,根据回归得到的左、上、右、下的距离,反推出框的边界
  • 最后,使用 NMS,将分类得分和 centerness 得分相乘(过滤掉距离远的低质量样本)作为 NMS 排序准则,NMS 的 IoU 过滤阈值为 0.5
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

呆呆的猫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值