FCOS长文详解

1. 概述

FCOS是一种one-stage、全卷积(Fully Convolutional)结构的目标检测模型,发表于2019年ICCV。(什么是one-stage?)
论文原地址:https://arxiv.org/abs/1904.01355
作者源码:https://github.com/tianzhi0549/FCOS
作者的源码有些复杂,我找了一个简单的版本https://github.com/zhenghao977/FCOS-PyTorch-37.2AP,作为本文的详解代码。

FCOS不同于在此之前热门的anchor based方法(比如R-CNN系列),没有设置anchor boxes来作为目标的候选区域,而是使用全卷积网络,结合FPN,直接拿去做检测,实现了anchor free,并达到了当时的state-of-art。当然anchor free这个概念不是作者提出来的,很早就有了。

作者在文中主要与anchor based检测方法作对比,首先指出anchor based方法的缺点:

  • 检测性能对anchor box的尺寸、高宽比、数量设置很敏感,而且这些都是超参数,而且人为调整;
  • 难以适应尺度变化大的目标,特别是小目标,因为anchor box限制了泛化能力,因此在新的任务中,需要重新设置anchor box的尺寸、高宽比等等;
  • 绝大多数anchor box都是负样本,这加剧了训练中正负样本不平衡的问题;
  • anchor boxes带来了巨大的计算量,比如计算IoU。

然后对比anchor based方法,阐述了FCOS的优点,其实就是把上边的缺点反过来就是了:

  • FCOS与许多全卷积网络可解决的问题在方法上具有一致性,方便在其他任务中复用;
  • anchor free,最大的贡献,减少了超参数,降低了训练难度;
  • 降低了计算量,速度快,因为没有anchor boxes;
  • FCOS也可以作为two-stage detectors使用,而且比anchor based的RPNs性能好。

2. 推理详细全流程

这一部先讲一下FCOS如何推理,每一步详细做了什么操作,后边再讲FCOS如何进行训练。

2.1 概括

文章作者给出了算法结构图,这也算是推理的流程图,非常重要的一张图

图1. 算法框架(图源:FCOS原文)

从图上明显看出来,FCOS包含了三个部分,分别是BackBone,Feature Pyramid, 还有一个Classification+Centerness+Regression。BackBone主要用于提取特征,作者使用的是ResNet;Feature Pyramid部分借鉴了FPN(feature pyramid networks, https://arxiv.org/abs/1612.03144),将BackBone提取出的三个不同尺寸的特征图进行融合,并输出五个不同尺寸的特征图像;最后将这五个特征图都拿去做识别回归,得到检测结果。

第三部分中的Classification和Regression好理解,分别是目标分类和bounding box 的回归,夹在中间的Centerness是作者的主要创新点之一,旨在减少低分目标框,具体的后边会说。

2.2 BackBone

代码里边的BackBone用的是ResNet50,这个东西我就不展开了,我们可以看一下代码上实现。

下图是ResNet网络的结构,其中,我把作者用到的输出层标注出来了,对应图1 -> Backbone的 C 3 C3 C3 C 4 C4 C4 C 5 C5 C5
在这里插入图片描述

图2. ResNet网络结构(图源:ResNet原文)

这是代码中的ResNet50实现:

class ResNet(nn.Module):
    def __init__(self, block, layers, num_classes=1000,if_include_top=False):
        self.inplanes = 64
        super(ResNet, self).__init__()
        self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3,
                               bias=False)  #对应前图2上conv1
        self.bn1 = nn.BatchNorm2d(64)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
        self.layer1 = self._make_layer(block, 64, 3)    #对应前图上conv2_x
        self.layer2 = self._make_layer(block, 128, 4, stride=2)    #对应前图2上conv3_x
        self.layer3 = self._make_layer(block, 256, 6, stride=2)    #对应前图2上conv4_x
        self.layer4 = self._make_layer(block, 512, 3, stride=2)    #对应前图2上conv5_x
        self.avgpool = nn.AvgPool2d(7, stride=1)
        if if_include_top:
            self.fc = nn.Linear(512 * block.expansion, num_classes)
        self.if_include_top=if_include_top

推理代码:

def forward(self, x):
        x = self.conv1(x)
        x = self.bn1(x)
        x = self.relu(x)
        x = self.maxpool(x)

        x = self.layer1(x)
        C3 = self.layer2(x)
        C4 = self.layer3(C3)
        C5 = self.layer4(C4)
        return (C3,C4,C5)

这里提一下,论文里的输入图像 x x x尺寸是 [ 800 , 1024 ] [800, 1024] [800,1024] C 3 C3 C3 C 4 C4 C4 C 5 C5 C5的尺寸分别是 [ 100 , 128 ] [100, 128] [100,128], [ 50 , 64 ] [50, 64] [50,64], [ 25 , 32 ] [25, 32] [25,32],对于输入来说, C 3 C3 C3 C 4 C4 C4 C 5 C5 C5的stride分别是 8 8 8 16 16 16 32 32 32,这也是图1最左侧那些数字的含义。
在实际推理的时候,却不用严格按照 [ 800 , 1024 ] [800, 1024] [800,1024]来输入,因为是Backbone是全卷积结构,对输入图像的尺寸没有苛刻的硬性要求,比如输入尺寸 [ 885 , 1000 ] [885, 1000] [885,1000]也是ok的。

2.3 Feature Pyramid

Feature pyramid network是CVPR2017年的一篇文章,它在目标检测中融入了特征金字塔,提高了目标检测的准确率,尤其体现在小物体的检测上。FCOS作者使用FPN的原因是,FPN可以将不同尺度的目标分开检测,达到一个分而治之的效果。具体是怎么“分而治之”,这一节后边讲,先说一下FPN具体是什么东西,怎么实现的。
![在这里插入图片描述](https://img-blog.csdnimg.cn/f24f722260f74f1ea2797f05ce916f40.png#pic_center在这里插入图片描述

图3. FPN结构(图源:FPN原文)

图3 坐上部分对应的是图1的Backbone,是一个全卷积特征提取的过程,右边是一个自上而下的上采样+特征融合。

以图1来说, C 5 C5 C5经过一个 1 ∗ 1 1*1 11卷积得到 P 5 P5 P5 P 3 P3 P3经过 1 ∗ 1 1*1 11卷积,再与 P 5 P5 P5相加,得到 P 4 P4 P4,这里就有一个特征融合的过程了,由于 P 4 P4 P4 P 5 P5 P5的尺寸不一样,正好差了2倍,所以 P 5 P5 P5要经过2倍的上采样才能与 P 4 P4 P4相加,上采样使用的是最近邻采样;相加之后得到的 P 5 P5 P5还要经过一个 3 ∗ 3 3*3 33卷积层才能去做预测,就是图3红色的那部分。同理, P 3 P3 P3则是由 C 5 C5 C5 P 4 P4 P4融合而来。除此之外,FCOS作者做了一些改动,就是增加了 P 6 P6 P6 P 7 P7 P7,他们由 P 5 P5 P5经过 1 ∗ 1 1*1 11卷积层而来,stride为2。

上边,为什么要进行 1 ∗ 1 1*1 11卷积和 3 ∗ 3 3*3 33卷积呢?
我的理解是: 1 ∗ 1 1*1 11卷积核,最明显的目的是解决 C 3 C3 C3 C 4 C4 C4 C 5 C5 C5 通道数不同的问题,因为后边相加需要通道数相同才行,当然 1 ∗ 1 1*1 11卷积还有一些其他好处,我这里就不展开了,有兴趣的可以跳转这里; 3 ∗ 3 3*3 33卷积的作用,FPN原文是这么说的(下边的英文),意思是降低上采样带来的混叠效应。

we append a 3×3 convolution on each merged map to generate the final feature map, which is to reduce the aliasing effect of upsampling.

从FPN获取最终的特征图后,就要塞进Head获得最终结果了,FPN最后输出5个特征图,那么这5个特征图都要塞进Head网络,注意并不是5个不同的Head网络,而是同一个,网络结构、模型参数都是一样的。

好,到这里,FPN是怎么实现的说完了,我当时看到这里的时候,就有疑问,我拿啥去测?框呢,为啥没有候选框?
别急,下一小节慢慢道来

2.4 Classification+Centerness+Regression

如果是anchor based的算法,此时会以特征点为中心,划分出anchor boxes拿去回归;而FCOS直接对特征点对应原图的边框都进行回归。什么意思呢?就是先把特征点映射回原图像上,然后直接对这个点进行分类、回归。注意这里虽然是针对一个特征点进行预测,不代表FCOS是没有候选框的,或者说该特征点的感受野就是候选框。

映射关系为: ( x o r i g i n , y o r i g i n ) = ( x f e a t s + s 2 , y f e a t s + s 2 ) (x_{origin}, y_{origin})=(x_{feat}s+\frac{s}{2},y_{feat}s+\frac{s}{2}) (xorigin,yorigin)=(xfeats+2s,yfeats+2s)
其中, ( x f e a t , y f e a t ) (x_{feat},y_{feat}) (xfeat,yfeat)为特征点坐标, ( x o r i g i n , y o r i g i n ) (x_{origin}, y_{origin}) (xorigin,yorigin)映射回原图后的坐标, s s s为采样倍数stride

再举个例子,现在输入图像是640x640,这个特征图的stride是32,那么这个特征图的尺寸就是20x20,现在我们将特征点(3,4)映射回去,得到该特征点对应的候选框中心为(112,144),这个候选框的尺寸是32x32

此外,候选框的个数就是FPN输出的5个特征图上所有特征点数量,一个特征点对应一个候选框。

好了,说完候选框的由来,继续说由特征图生成最终结果。

Head网络也是全卷积网络,中间是什么结构我就不管了,主要关注模型的输出。输出结果分为三个部分,Classification、Centerness和Regression。
Classification:表示分类结果,尺寸与类别数量有关,如果是20类,就是每一类的得分;
Regression:表示目标位置偏移,相对于候选框,四个值分别表示相对于候选框的上下左右偏移;假设回归结果是 ( l , t , r , b ) (l,t,r,b) (l,t,r,b),候选框左上角坐标是 ( x 1 , y 1 ) (x1,y1) (x1,y1),右下角坐标是 ( x 2 , y 2 ) (x2,y2) (x2,y2),那么回归后的目标位置就是:左上: ( x 1 + l , y 1 + t ) (x1+l,y1+t) (x1+l,y1+t),右下: ( x 2 + r , y 2 + b ) (x2+r,y2+b) (x2+r,y2+b)
在这里插入图片描述

Centerness:表示Regression结果与候选框中心的偏离度,作者认为距离目标中心较远的位置产生很多低质量的预测边框,因此搞了个Centerness来剔除这部分低质量框。回归后的目标框中心相对于原来的中心肯定有偏移,除非 l = r , t = b l=r,t=b l=r,t=b,Centerness就是衡量这个偏离多远的一个指标,是一个0~1之间的数字,值越小表示偏离越大。在后处理中,它还要与Classification结果相乘,作为最终的分类置信度,这个值才拿去与设置的阈值比较。

3. 如何训练

FCOS训练的时候,首先要走一遍推理流程,然后根据推理结果和标签值计算损失函数,最后进行反向传播。

所以,这一节最主要的还是损失函数的计算,这个又牵扯到anchor free里边比较特殊的一部分:正负样本的划分,因此,这一部分主要讲解两个问题:正负样本如何划分LOSS函数

3.1 正负样本如何划分

如果你了解anchor based检测算法,比如yolov3/4/5,那你应该知道他们正负样本划分的依据是IOU,但是FCOS不是这么划分,因为它压根不计算IOU。FCOS的正负样本划分可以分为三步:
1、位置
再看一眼前边的映射公式,最朴素的思想就是:如果一个特征点对应的 ( x o r i g i n , y o r i g i n ) (x_{origin}, y_{origin}) (xorigin,yorigin)落在gt内,就认为该特征点为正样本。例如下图
在这里插入图片描述

黄色点都是正样本,他们都在gt里边,白色点均为负样本。

在源码中,发现了作者进行了改进,并不是所有在gt内的特征点都给正样本标签,而是以gt中心画个圆,半径是1.5倍的stride,在该圆内的特征点作为正样本,这样可以避免边缘区的低质量正样本。

无论画不画圆,这种方法都有一个问题,如果一个特征点同时落在两个gt中,如何分配标签呢?作者称这种现象为ambiguous point(如下图),我们针对这个问题进行改进
在这里插入图片描述
2、尺寸
FCOS非常巧妙地利用FPN层解决ambiguous point这个问题,FPN有两个作用:一、多尺度的特征融合,二、分而治之。FCOS就是利用了FPN的分而治之的作用,把多个尺度的目标分到FPN的多个输出特征层。

具体来说,FPN输出共5层特征层,分配到每层特征层上目标的长宽限制范围依次为:(-1, 64), (64, 128), (128, 256),(256, 512),(512, INF) ,对应的stride分别是[128,64,32,16,8]

作者在代码中是这么实现的,计算5个特征层各个特征点与该gt的 ( l , t , r , b ) (l,t,r,b) (l,t,r,b),保留 ( l , t , r , b ) (l,t,r,b) (l,t,r,b)四个值均大于0的点(特征点在gt内部);计算 ( l , t , r , b ) (l,t,r,b) (l,t,r,b)中的最大值,该最大值落在哪个区间,就由哪个特征层的特征点去预测。

如果还存在ambiguous point,俩gt尺寸相近且有重叠部分,就将小的那个gt的标签赋给这个特征点。这个地方乍一看处理的很粗糙,但是结合下边的Centerness就好很多。

3. Centerness

又讲到Centerness了,待会儿还要提到它,因为损失函数里边还有他一部分呢。

前边提到一次,作者认为距离目标中心较远的位置产生很多低质量的预测边框,即处于gt的边缘,提取的图像特征不正确,自然检测出低质量的框。在训练部分,FCOS会每个正样本赋予一个Centerness标签,用于表示该特征点的质量,计算方式为: c e n t e r n e s s ∗ = m i n ( l ∗ , r ∗ ) m a x ( l ∗ , r ∗ ) ∗ m i n ( t ∗ , b ∗ ) m a x ( t ∗ , b ∗ ) centerness^*=\sqrt{\frac{min(l^*,r^*)}{max(l^*,r^*)}*\frac{min(t^*,b^*)}{max(t^*,b^*)}} centerness=max(l,r)min(l,r)max(t,b)min(t,b) centerness越小,特征点离gt中心越远,质量越低。
在这里插入图片描述
虽然一个gt,可以会给好多个特征点赋予正样本的标签,但是根据Centerness,就能把这些正样本区别开来。

3.2 Loss函数

这里偷个懒,直接放论文里的公式了
在这里插入图片描述
说实话,没太看懂,别的博文也都只是贴出来,不给个讲解,好在我翻代码大致懂了loss函数咋算的

loss函数分为三部分,分类loss,位置loss和centerness loss。

  • 分类loss:采用focal loss,一种改进版的交叉熵,就是给不同样本赋予不同的权重,对于难学习的样本,权重大一点;
  • 位置loss:计算iou损失
  • centerness loss:标签值是公式计算出来的,跟网络输出的centerness计算交叉熵

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/618181.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

本地项目上传到gitee

1. 新建仓库,不要勾选 2. git init git add . git commit -m "test" git remote add origin 【url】 git push --set-upstream origin master

【Java】:方法重写、动态绑定和多态

目录 一个生动形象的例子 场景设定 1. 方法重写(Method Overriding) 2. 动态绑定(Dynamic Binding) 3. 多态(Polymorphism) 归纳关系: 重写 概念 条件 重写的示例 重载与重写的区别 …

STM32 | STC-USB驱动安装Windows 10(64 位)

Windows 10(64 位)安装方法 由于 Windows10 64 位操作系统在默认状态下,对于没有数字签名的驱动程序是不能安装成功的。所以在安装 STC-USB 驱动前,需要按照如下步骤,暂时跳过数字签名,即可顺利安装成功。…

回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测

回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测 目录 回归预测 | Matlab实现GA-LSSVM遗传算法优化最小二乘支持向量机多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 Matlab实现GA-LSSVM遗传算法优化最小…

纯CSS实现步骤条

纯CSS实现纵向Steps步骤条效果 效果图 实现思路 步骤条是一种用于引导用户按照特定流程完成任务的导航条,在各种分步表单交互场景中广泛应用。步骤条通常由编号、名称和引导线三个基本要素组成。本文中要实现的是一个简单的步骤条,包含上述三个基本要素…

Python爬虫实战:爬取【某旅游交通出行类网站中国内热门景点】的评论数据,使用Re、BeautifulSoup与Xpath三种方式解析数据,代码完整

一、分析爬取网页: 1、网址 https://travel.qunar.com/2、 打开网站,找到要爬取的网页 https://travel.qunar.com/p-cs299979-chongqing进来之后,找到评论界面,如下所示:在这里我选择驴友点评数据爬取点击【驴友点评…

天下大爱唯母爱

岁月轮转,人生寻常,又逢一年母亲节。作为子女,这是所有人都参与节日,也是每一位母亲在繁忙日常中,一个短暂的休息,停下手中的忙碌,听孩子的一声祝福:妈妈辛苦了,母亲节快…

树莓派4B-搭建一个本地车牌识别服务器

实现目标: 一、设备自启后能够获得服务的ip与端口号,用于计算机连接设备; 二、计算机可以通过服务ip与端口访问设备服务; 三、上传需要处理的数据,返回结果反馈给用户; 四、上传到服务器的数据不会导致设备…

车载测试系列:CAPL脚本语法

HFP测试内容与测试方法 2.3 接听来电:测试手机来电时,能否从车载蓝牙设备和手机侧正常接听】拒接、通话是否正常。 1、预置条件:待测手机与车载车载设备处于连接状态 2、测试步骤: 1)用辅助测试机拨打待测手机&…

本地电脑hosts强制解析指定IP的方法

网站接入CDN后,很多时候需要本地强制解析回源查看状态,比如查看是不是源服务器故障,网站修改是否正确,网站更新是否及时,故障查看是CDN问题还是源服务器问题,都需要hosts回源。 今天云加速教大家如何本地电…

AI工具摸索-关于写作(1)

虽然人工智能工具非常多,但是如果想要成为生产力,能达标的工具仍然非常少,除了最常用的chatgpt,其他的工具真的能达标吗,这篇文章主要就是对比市面上的一些工具, 但我这个人非常执拗,我认为作为生产力工具的功能必然是可以真正帮助我们的,而不是说作为一个写作工具结…

docker部署springboot+Vue项目

项目介绍:后台springboot项目,该项目环境mysql、redis 。前台Vue:使用nginx反向代理 方法一:docker run 手动逐个启动容器 1.docker配置nginx代理 将vue项目打包上传到服务器上。创建文件夹存储数据卷,html存放打包…

【Dash】开始学习dash

安装Dash 网上很多安装dash的教程,不再赘述 开始Dash 一个dash页面的基本写法 # dash 的基本写法 import dash from dash import html,dcc,callback,Input,Output# 创建一个 dash 应用 app dash.Dash()# 定义布局,定义一个输入框和一个输出框 app.l…

NIOS II实现LED流水灯以及串口输出(DE2-115开发板)

NIOS II实现LED流水灯以及串口输出(DE2-115开发板) 前言什么是Qsys?什么是NIOSII?注意事项1、管脚配置2、配置NIOSII时的连接3、注意中断配置好后是这样的4、注意名称的配置5、设置双功能引脚 NIOS II的报错代码以及效果演示流水灯输出到电脑串口助手 …

【020】基于JavaWeb实现的批报管理系统

项目介绍 基于jspservlet实现的批报管理系统采用B/S架构,该项目设计了一个角色管理员,管理员实现了我的案件、查询统计、项目维护等三大功能模块 技术栈 开发工具:Idea2020.3 运行环境:jdk1.8tomcat9.0mysql5.7 服务端技术:j…

【机器学习数据可视化-04】Pyecharts数据可视化宝典

一、引言 在大数据和信息爆炸的时代,数据可视化成为了信息传递和展示的关键手段。通过直观的图表和图形,我们能够更好地理解数据,挖掘其背后的信息。Pyecharts,作为一款基于Python的数据可视化库,凭借其丰富的图表类型…

获取Linux上的Redis的用户名、密码、端口、host等信息

目录 进入redis-cli的目录 启动./redis-cli服务 查询密码 查询用户名 查询端口 查询host 参考文章:解决redis-cli连接时出现Could not connect to Redis at 127.0.0.1:6379: Connection refused-阿里云开发者社区 (aliyun.com) linux查看redis用户和密码_mo…

Java构造方法详解

在Java方法内部定义一个局部变量时,必须要初始化,否则就会编译失败,如下: 要让上述代码通过编译,只需在使用a之前给a赋一个初始值即可 如果是对象:下面用一个日期类演示 我们没有给年月日赋值,…

纯血鸿蒙APP实战开发——首页下拉进入二楼效果案例

介绍 本示例主要介绍了利用position和onTouch来实现首页下拉进入二楼、二楼上划进入首页的效果场景,利用translate和opacity实现动效的移动和缩放,并将界面沉浸式(全屏)显示。 效果图预览 使用说明 向下滑动首页页面超过触发距…

实验室纳新宣讲会(java后端)

前言 2024-5-12 22:00:39 这是陈旧已久的草稿 2021-09-16 15:41:38 发布一下 当时我进入实验室,也是大二了,实验室纳新需要宣讲, 但是当时有疫情,又没宣讲成。 实验室纳新宣讲会(java后端) 首先&#x…