FCOS原理与代码解析(更新改进trick)

  • Post author:
  • Post category:其他



目录


摘要


Pipeline


Loss函数


与RetinaNet的不同


更新一些改进trick(2021.3.25)

摘要

anchor-based目标检测存在的缺陷:

  1. anchor会引入很多需要优化的超参数, 比如anchor number、anchor size、anchor ratio
  2. 因为anchor的大小、比例、数量都是提前确定的,会影响模型的泛化性能。对于新的检测任务,需要重新设计anchor的各种参数。
  3. 为了保证high recall rate,需要大量密集分布的anchor boxes,会导致训练阶段正负样本不均衡的问题。
  4. 因为anchor boxes数量特别多,训练阶段需要计算所有anchor boxes和ground-truth boxes的IOU,导致特别大的计算量和内存(显存)占用

Pipeline

模型采用ResNet50作为backbone,后面接FPN,FPN的P5后接两个stride=2的3*3conv得到P6、P7,P3~P7每个feature map分别接2个不同的FCN分支用于分类和边框回归,其中每个conv分支由4个3*3的conv加最后的预测conv组成,



注意这里centerness和分类共享同一分支



Loss函数

在计算Loss之前首先要确定target,对于feature map \(F_{i}\)上的每个点(x,y),映射回输入图片中的对应位置
(\left \lfloor \frac{s}{2} \right \rfloor+xs, \left \lfloor \frac{s}{2} \right \rfloor+ys)
,s是 \(F_{i}\)相对于输入图片的stride。位于gt box内的点视为正样本,该点分类的target即为对应gt box的类别。该点与gt box四条边的距离\(l^{*}、t^{*}、r^{*}、b^{*}\)为回归的target。由于检测目标可能会重叠,可能存在一个点同时位于多个gt box内的情况,但是作者发现实际发生重叠的gt box之间的尺度变化非常大,而神经网络浅层更多的是细节特征,对小目标检测有利,深层更多的是语义特征,有利于检测大目标,因此通过限制不同层负责回归不同大小的目标,可有效减少这种情况。即
m_{i-1}< max(l^{*},t^{*},r^{*},b^{*})<m_{i}
,对于P3~P7,\(m_{2}\)~\(m_{7}\)分别设为0,64,128,256,512,
\infty
。如果这种情况还存在,就选择小的那个进行回归。

通过多级预测之后作者发现FCOS的检测效果和anchor-based的检测器之间仍然存在着一定的差距,主要原因是距离目标中心较远的位置产生了很多低质量的预测框。因此作者提出了和分类分支并行的单一分支centerness来抑制这些低质量的预测边界框,而且不引入任何超参数。centerness描述的是负责预测某个gt box的点与该gt box中心点的距离大小,范围在0~1之间,公式如下

测试过程中,最终的分类预测值会乘以centerness,这样距离中心远的预测框的score会变小,从而在NMS阶段更有可能被过滤掉。

对于网络的三个输出分支,分类分支采用focal loss,centerness分支采用BCE loss,回归分支采用Iou loss,都是常用的loss,这里不再展开解释。


与RetinaNet的不同

因为FCOS的模型结构和RetinaNet非常相似,作者在论文中也提到backbone阶段的超参数和后处理部分都和RetinaNet完全一样,因此这里列举一下FCOS和RetinaNet的不同来帮助理解。(

https://github.com/xuannianz/keras-fcos

这一版的keras-fcos是在keras-retinanet基础上改的,改动不多,可以对照着看)


模型结构的不同

  • 因为回归目标
    l^{*}

    t^{*}

    r^{*}

    b^{*}
    永远是正的,FCOS的回归分支最终输出多做了一步exp操作

  • 分类和回归分支最后一层卷积核数量分别由


    9


    *


    4





    9


    *


    20


    变成


    4





    20

  • FCOS


    增加了一个


    centerness


    分支,和分类分支共享参数


    。不同的是最后一个卷积核数量是


    1,


    然后


    reshape


    再接一个


    sigmoid


    激活函数

  • Forward


    时,


    __build_anchors函数


    变成了


    __build_locations


    ,其实只是把


    3


    种大小


    *3


    种比例的


    anchor


    变成比例和大小都为


    1





    anchor

  • 回归的target变了,


    retinanet


    的是feature-map映射回原图的点对应的


    anchor


    的左上和右下坐标与


    gt


    的差并分别除以


    anchor


    的宽和长,而


    fcos


    是映射到原图的点到


    gt


    四边的距离




  • filter


    步骤做


    nms


    之前,


    fcos





    scores


    乘以了


    centerness


    并开平方。然后


    select top k


    阶段也对


    classification_score


    乘以了


    centerness


    并开平方。


Loss的不同


  • cla_loss都是用的


    focal_loss


    ,参数也一样。只有一处不同,


    RetinaNet





    gt_box





    iou


    介于


    0.4





    0.5


    之间的


    anchor


    设为


    ignore


    不参与计算。而


    FCOS





    feature_map


    映射回原图的点只有


    pos





    neg


    之分,没有


    ignore




  • reg_loss





    RetinaNet


    用的是


    smooth L1 loss


    ,而


    FCOS


    用的是


    iou loss

  • FCOS


    新增了一条


    centerness


    的分支,这一分支的


    loss


    用的


    binary cross entropy


更新一些改进trick(2021.3.25)

  1. centerness on reg。centerness分支由原始的和cls分支共享权重变成和reg分支共享权重
  2. center sampling。原始是gt box内的点都作为正样本,改为gt box中心radius*stride小区域内的点视为正样本。
  3. norm on bbox。原始的reg分支最终的exp操作改成relu。
  4. giou loss。原始reg分支的loss为iou loss,改为giou loss。
  5. bbox loss weight。由原始的平权改为用 centerness 分支的 target,即离gt中心越近,权重越大。


参考


FCOS 的改进 trick – 知乎


【庖丁解牛】从零实现FCOS(终):CenterSample的重要性 – 知乎


FCOS及其优化实验 – 知乎



版权声明:本文为ooooocj原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。