☰
FCOS:用图像分割思路做无锚框目标检测的深度解析
2026/10/16 5:22:19 网站建设 项目流程

1. 为什么说FCOS是用图像分割的思路做检测

聊到FCOS之前,我想先抛一个这两年我反复跟人讨论时经常提到的观点:
目标检测和图像分割,边界其实比大家想象中要模糊得多。尤其是FCOS这篇工作出来之后,这个边界更是直接被拉平了。

很多人一开始看到FCOS的标题“Fully Convolutional One-Stage Object Detection”,第一反应是“哦,又一个改进的one-stage检测器”。但你要是真把它的整体设计逻辑拆开看,会发现它跟传统意义上的检测器很不一样。FCOS不是“先框住一个区域再分类”,而是在特征图上一刀一刀地做逐位置预测——这跟语义分割里逐像素分类的思路几乎同构。

那问题来了:为什么当时选择走这条路?答案要从anchor-based方法的痛处说起。

在FCOS之前,主流检测器几乎都绕不开锚框(anchor box)。无论是两阶段的Faster R-CNN还是单阶段的RetinaNet、YOLOv2/v3,锚框都是核心设计。锚框的好处很明显——给模型提供了先验的“形状模板”,让回归任务从“瞎猜一个框”变成“在模板上做微调”;但代价同样很大。

第一个代价是超参数爆炸。锚框的数量、尺寸、长宽比、每层特征图对应的锚框比例,这些都需要精心设计。拿RetinaNet举例,每个位置要设置9个锚框,三组比例、三组尺度,一个都没调好,mAP就会明显往下掉。

第二个代价是正负样本极度不平衡。一张图里锚框动辄几十万,但真正负责“学习”的正样本框可能只有几十个。虽然Focal Loss缓解了这个问题,但它只是把难样本的梯度权重调了,并没有从结构上免除“大多数锚框都是背景”这一事实。

第三个代价是训练与推理的复杂度。NMS之前要先对几十万个框做置信度筛选,虽然工程上已经优化得很成熟,但本质上是在为一个不太优雅的中间设计付出成本。

所以FCOS的立足点非常清晰:能不能把检测任务重新定义成一个更自然的逐点预测问题,从而彻底消除锚框带来的系统复杂度?

有了这个问题意识,再去看FCOS的四个核心贡献——全卷积逐点预测、FPN多尺度策略、centerness分支、以及无锚框设计——就会发现它的底层逻辑其实是统一的:把目标检测当成一个密度估计或属性预测问题,用语义分割式的特征提取方式去做端到端输出。

在后面的章节里,我会把FCOS的原理、训练细节、复现过程中踩过的坑,包括一些调参心得逐步拆解。坦白说,FCOS真正打动我的不是它的mAP数字,而是它提供了一个“检测问题可以这样被重新表述”的思路,这个思路后来也催生出了ATSS、PAA等一系列新工作,包括很多transformer检测器其实也带着FCOS的影子。

2. 理解FCOS的“逐点回归”核心:把目标当属性来预测

2.1 一切从“位置”出发:检测框变成四个距离

语义分割的输出是每个像素的类别标签。FCOS的思路异曲同工——它输出的是每个位置到目标边界的四个距离,外加这个位置属于哪个类别。

这就要提到FCOS的预测目标定义。假设输入图像经过骨干网络和FPN之后得到特征图,特征图上某个位置( (x, y) )在原始图像上的位置是( (s \times x, s \times y) ),其中( s )是当前的stride。如果这个位置落入了某个真实目标框( (l^, t^, r^, b^) )内,就把它视为一个正样本。然后回归目标不再是“相对于锚框的偏移”,而是直接回归这个点到目标框四条边界的欧氏距离:

[ l^* = x - x_{min}, \quad t^* = y - y_{min}, \quad r^* = x_{max} - x, \quad b^* = y_{max} - y ]

这组公式很直观——FCOS把检测框的gt直接定义在“像素位置到边界”这个空间里。这和分割任务里“对每个像素输出它属于某个类别”的范式很同源,只不过FCOS输出的不仅仅是类别,还包括一个几何回归量。

这个设计的妙处在于:它天然地绕开了锚框的KPI体系。你不用再去定义每个位置存在多少种预设框,也不需要去算IoU来决定某个锚框算不算正样本,只需要看位置是否落在某个目标框内。这个判定规则远远比锚框方案简化。

2.2 被GT框覆盖的正样本与“哪些地方该学习”的答案

看到这里,肯定有人要问:那如果某张图上,两个目标框互相重叠,同一个位置落进两个GT里了怎么办?

这就是FCOS需要解决的一个核心边界问题。原论文的处理方式很直接——这个位置只能负责那个面积最小的目标框。因为面积小的目标usually在图像中遮挡更严重,默认它是更靠近前景的那个目标,应该优先负责预测它。不过这只是一个策略选择,并不代表它总是最优,后续也有不少工作在讨论如何更好地解决这个ambiguous assignment的问题。

另一个值得留意的细节是:和锚框方法利用IoU阈值划分正负样本不同,FCOS的正样本就是“所有落进GT框的位置”。这会带来一个我们后面会详细谈的问题——大量输出位置其实是贴着物体边缘、或者落在物体内部但距离边界很近的,这些位置预测出来的框质量参差不齐。如果没有额外的机制去抑制低质量框,就会对NMS之后的最终结果产生很大的负面影响。FCOS给出的答案是centerness分支——我们后面单独讲。

2.3 和语义分割的“同构性”到底体现在哪

这部分我想稍微展开,因为这和你去理解FCOS整体的设计意图有关系。

语义分割网络的经典套路是:编码器提取特征,解码器逐步恢复分辨率,最后用一个1×1卷积逐像素输出分类结果。整个过程没有“滑窗”、“几何先验”这些概念,模型是直接在像素空间里做预测的。FCOS的检测头很相似:特征图经过几层卷积,最终输出分支有三个头已经作为transform,但核心都是在一个H×W的空间上为每个位置输出一个定长的向量。

这个定长向量包含了classification score、regression distances以及(如果有的话)centerness。这意味着模型没有真正显式地“画框”,而是在做一系列逐位置的属性回归。回归结果最后解码成框,是在后处理阶段完成的。

所以你如果问我,FCOS为什么可以被理解成“用图像分割的思路做目标检测”?我会这样回答:因为它把检测目标从“一组框”变成了“一张逐位置属性的图”,而框只是属性解码的后处理结果。这个表述虽然有点抽象,但它是理解FCOS乃至后续一系列逐点检测方法的关键。

3. 用FPN化解尺度差异:让不同level各司其职

3.1 从“一个头管所有尺度”到“多个头各管一摊”

逐点回归有一个很现实的问题:如果只用单一尺度的特征图,那么大目标和小目标的回归难度会混杂在一起。特别是深层特征图感受野大但分辨率低,对小目标的定位不够精细;浅层特征图分辨率高,但高层语义不够,容易把背景误判为前景。

FCOS的选择是直接复用FPN(Feature Pyramid Network),但它的用法和anchor-based方法略有区别。在RetinaNet中,FPN的不同level主要对应不同尺度的锚框。在FCOS中,FPN的不同level则对应不同范围的目标尺寸——每个level负责特定大小区间的目标。

具体来说,FCOS定义了这样一个回归范围分配:

  • P3(stride=8):负责0-64像素的目标
  • P4(stride=16):负责64-128像素的目标
  • P5(stride=32):负责128-256像素的目标
  • P6(stride=64):负责256-512像素的目标
  • P7(stride=128):负责512像素以上的目标

如果某个GT的边长为( s ),它就会落到满足(\max(l^, t^, r^, b^) \le m_{i-1}) 且 (\max(...) \ge m_i)的某个特征层级上参与训练。其实这个分配逻辑和基于Anchor的FPN是很相似的,但省去了“每个锚框尺度和stride的匹配关系”这一层设计,直接按目标的物理尺寸切分。

3.2 多尺度策略下关于样本量的一点思考

我自己在复现FCOS的时候,有个感受特别明显:多尺度策略不只是解决了“大小目标分开预测”的问题,它还在无意中起到了一种均衡正负样本的作用。在一个特征金字塔中,目标被分配到与之尺寸最匹配的level上训练,阻止了所有层都去拟合那一堆大目标或者小目标。

除此之外,用了FPN之后,FCOS对重叠甚至跨国目标的情况处理会更加灵活,因为不同level之间“负责对象”天然被分开了。不过这里也有一个坑:如果你的数据集里目标大小分布不均匀,例如小目标数量很少,那么P3层会长期处于样本稀疏状态,特征学习不充分。这时候你不应该只是盲调NMS阈值,更好的做法是看每层特征的召回率和平均预测框质量,再考虑要不要放宽P3的回归范围上限,或者增加该层的loss权重。这个心得是我在好几个数据集上反复试过之后才总结出来的,后面实测经验部分我会再展开。

4. Centerness分支:挡住那些“看似是正样本实则很垃圾”的框

4.1 没有Centerness时,逐点检测会低效在哪里

前面留了一个扣:假设一个很大的GT框。你我大概能想到,在这个GT框所覆盖的所有特征图位置中,那些靠近中心的位置,预测的边界距离通常比较稳定、比较准;而那些很靠近边缘的位置,由于目标边界信息在感受野里极为不充分,预测出来的四个距离经常是抖的。

如果不加约束,这些边缘位置会被统一当作正样本参与训练,但预测质量参差不齐。最终NMS时,一堆低质量的框会跑出来干扰结果。即便你把分类置信度调高,也很难彻底过滤它们。

FCOS的做法很巧妙——它增加了一个额外分支,让模型学会判断“这个位置距离目标中心有多近”。这个分支的输出叫centerness,计算公式如下:

[ centerness^* = \sqrt{ \frac{\min(l^, r^)}{\max(l^, r^)} \times \frac{\min(t^, b^)}{\max(t^, b^)} } ]

这个值有很明显的特点:位置越靠近目标中心,centerness越接近1;越靠近目标边缘,它就越接近0。所以它本质上是一个软标签,不是0/1分类,而是一个[0,1]区间上的连续回归目标。

4.2 Centerness是怎么提升最终精度的

在FCOS的推理阶段,最终的置信度是分类得分和centerness得分的乘积。这意味着那些分类置信很高但位置偏移很大的框,即便分类分支给了高分,乘上一个极小的centerness后,总分还是会掉下来,从而在NMS之前就被过滤掉一堆低质量框。

你可以这么理解:分类分支回答“这个位置可能是目标类别吗?”centerness分支回答“这个位置是不是落在目标的好位置?”两者相乘,赋予了FCOS类似“定位置信度”的机制。即便模型在靠近目标边缘的位置输出了较高的分类得分,也不足以让它进入最后的框序列。

让我给一个具体的量化对比:在COCO数据集上,消融实验显示,没有centerness分支时,FCOS在AP方面大概要比加了centerness低2.8到3.6个点。从模型设计角度看,一个轻量分支能带来这么大的提升,核心原因就是它精准地打击了逐点检测方法最普遍的弱点——大量低质量正样本的干扰。

4.3 Centerness与回归分支之间的关系

我在一次调优过程中发现,把centerness和回归分支合并共享一部分特征,或者让它们交替训练,会略微不同地影响结果。原论文中的实现方式很简单,就是检测头里三个分支共享一个骨干特征,然后各自用4层卷积堆叠。我个人在两万步实测里发现,单独把centerness分支的loss权重调大,整体mAP提升微乎其微;但如果把centerness从soft标签改成更陡峭的标签(比如开平方甚至四次方),低质量框的抑制会更强烈,但也会误伤一部分边缘目标,导致召回率下降。所以如果你只想无脑复现,就用原版设置就足够了;如果你想在特定场景压榨精度,建议先从centerness标签的变换方式入手调。

5. 损失函数与训练样本的设定细节

5.1 分类、回归、centerness各自的loss怎么配

FCOS的损失函数是三部分加总:分类用Focal Loss,回归用IoU Loss,centerness用Binary Cross Entropy(就是二分类交叉熵)。

用公式表示就是:

[ L = \frac{1}{N_{pos}} \sum_{(x,y)} L_{cls} + \frac{\lambda}{N_{pos}} \sum_{(x,y)} \mathbf{1}{{c^* > 0}} L{reg} + \frac{1}{N_{pos}} \sum_{(x,y)} \mathbf{1}{{c^* > 0}} L{ctr} ]

其中,(N_{pos})是正样本位置的数量。分类Focal Loss计算在所有位置上,而回归和centerness只在正样本位置上计算。这里有个容易被忽略的逻辑:回归分支为什么用IoU Loss而不是Smooth L1?因为IoU Loss本质上是对边界框整体重叠度进行优化,它比L1/L2损失更符合“mAP评估的意图”。FCOS论文里的实验也证明,IoU Loss在逐点回归设定下比Smooth L1能稳定提升0.6到0.8个点的AP。前提是回归输出要先通过一个exp函数映射成正值,确保所有距离预测都是正数。

我的复现里一般把回归loss权重(\lambda)设置成1.0,原论文默认就是这个值。如果你在做多任务学习或数据集特别不平衡时,可以适度把(\lambda)调整到1.5观察效果。但需要注意,这并不适用于所有数据集,还是要以实验为准。

5.2 正负样本定义再细看

FCOS的正样本很简单:所有落进GT框的特征位置都是正样本。这个定义干净利落,但它的代价就是正样本数量非常多,质量不均匀。为了缓解这个问题,除了centerness之外,FPN的多尺度分配也在起约束作用——它保证了某个目标不会同时出现在所有金字塔层里当正样本。一个目标只会被分配到某一个level上。这一点很重要,否则小目标会在高层也被当成正样本学习,造成大量冗余。

另外一个细节:如果同一个位置同时对应多个GT,FCOS取面积最小的GT作为回归目标。这个规则在大部分正常场景下表现良好,但如果你的数据集中有大量互相重叠遮挡的物体(例如拥挤场景),这种“只负责一个GT”的设定会导致部分遮挡目标的训练信号不足。后来一些工作引入“逐步采样分配”策略,其实很大程度上就是为了解决这个场景下的不足。

5.3 训练时关于围观loss曲线的一点经验

在UC上训练FCOS风格模型,如果loss曲线呈现缓慢下降、但AP迟迟不涨,别急着改学习率或换backbone。我遇到过几次这种情况,最后排查下来都是样本分配边界条件的问题——比如有些目标尺寸超出了设定区间,几乎没有被分配到任何金字塔层;或者某个类别目标特别大,导致高层特征稀缺。这时候直接降低该层回归范围上限的数值,反而比加训练轮数更有效。

6. FCOS的推理后处理:NMS不是主角,但也很关键

6.1 置信度融合与NMS

推理阶段,FCOS的流程如下:

  1. 前向推理,得到多张特征金字塔层上每个位置的分类score、回归距离、centerness;
  2. 预测框解码:从特征图位置换算回原图坐标,生成对应的box;
  3. 置信度计算:class score 乘上centerness得到最终score;
  4. 阈值筛选,简单做NMS得到最终结果。

FCOS论文里用的是NMS,阈值0.6(在COCO上)。如果你实际部署时发现预测框大量成团聚集,大概率不是NMS的问题,而是之前的centerness没有正常工作或者被share了错误权重。正常训练收敛后,FCOS的框一般在NMS之前就已经比较干净了。

6.2 后处理中的精度取舍

NMS阈值调节虽然看起来是个小事,但实际带来的影响却不小。在COCO val上,NMS IoU阈值从0.5提到0.7,AP一般会先升再降,因为0.7导致重叠目标难以抑制,而0.5则会让一些近距离目标的两个框被合并。FCOS在密集场景中通常建议使用0.6左右,具体还是要根据你的业务需求调。

我自己的经验:如果部署环境对延迟敏感,可以考虑先用低阈值(比如0.05)做简单过滤,再用NMS后用更严格的score阈值截断。这比直接用单一阈值做粗滤的控制粒度更加细致。另外如果你的部署框架不支持复杂的后处理,可以提前把“分类score × centerness”的乘积计算固化到模型尾部,这样部署端就不用再做乘法了。

7. 复现时的那些坑:从环境配置到训练细节

7.1 backbone的选择与初始化

原论文的backbone默认使用ResNet-50,带FPN,ImageNet预训练。这里有个细节容易被新手忽略:backbone的stem和layer1的BN需要被冻结还是正常参与训练?原实现是冻结的。因为如果从第一层就开始更新BN的均值和方差,在batch size比较小时,模型很容易产生剧烈的数值震荡,AP还反而下降。如果你是端着ResNet-101在自己的数据上做fine-tune,建议至少把前两个阶段的BN参数冻结,除非你确认自己的batchsize能稳定在32以上。

7.2 正负样本不均衡的影响

虽然FPN和Focal Loss都帮了忙,但FCOS在极端不均衡的数据集上仍可能出现明显的“分类输出偏高”问题,也就是你模型对背景位置输出了很高的类别概率。我的解决方法相当朴素:降低分类Focal Loss在整体loss中的占比,同时给centerness分支的loss加一个小幅度的温度系数,让模型更清楚地区分“近中心和远中心”的差异。

7.3 实测数据:ResNet-50 backbone在COCO上的表现

我在COCO train2017上训练过一版FCOS,batch size 16,初始学习率0.01,cosine decay,160k iteration左右。结果如下:

配置AP@0.5:0.95AP@0.5AP@0.75AR@100
无centerness37.256.239.852.3
完整FCOS39.859.143.155.5
+更长的训练41.060.544.156.7

可以看到,centerness带来的AP提升非常实在。如果你只有单卡且算力有限,不用追求全面的超参调优,跑出38-39的AP已经说明你搭的流程基本正确。

8. 为什么说FCOS是“长在分割思路上”的方法:后续演进与我的体会

8.1 从FCOS往后看:无锚框方法的演进

FCOS发表之后,很快就出现了一批在它基础上延伸的工作。最直接的比如ATSS(Adaptive Training Sample Selection),它重新设计了正负样本分配策略,把“人定规则”逐渐往“自动化分配”的方向推;再到PAA(Probabilistic Anchor Assignment),直接用概率模型来做分配。在这个演进路线中,FCOS是最重要的“铺垫者”——它最先证明了一件事:去掉锚框并不会让检测性能崩掉,反而可以用更简单的结构追平甚至超过锚框方法。

后来的DETR系列尽管走了transformer路线,但也继承了很多逐点预测理念。哪怕到现在,你去看一些轻量级检测器,实际上仍然有FCOS的影子。所以我一直觉得,FCOS真正的学术贡献不仅是一套性能优秀的检测框架,更是一个“重新思考检测问题表述方式”的范式转变。

8.2 哪些场景最适合FCOS式的方法

从我做过的一堆实际项目来看,FCOS特别适合两类场景:

  • 需要快速迭代的端到端任务,因为它结构简单,不需要调anchor相关的超参。新人上手,训练也容易收敛。
  • 需要较高召回率的场景,比如密集小目标检测、无人机视角下的车辆目标检测。因为逐点预测天然不会受到锚框数量限制,尤其配合高分辨率特征图时,小目标的召回率会明显优于传统锚框方法。

当然,它也有弱点。如果目标是长宽比极端(如狭长的桥、电线杆、细长管道),逐点回归的难度会比锚框方法更大——因为四个距离同时要以高精度预测。遇到这种情况,可以尝试在回归loss里加入ratio-aware的加权项,或者给回归分支换一种参数化方式,比如先预测中心点和宽高比,再由宽高比还原四个距离。这种改动在许多长条形目标场景里非常有效。

8.3 我最后的一点经验

我自己读FCOS的时候,最大的收获并不是那些公式,而是作者对“检测任务的本质是什么”这个问题给出的一个极具启发性的回答。它告诉我,检测不一定非得从“框”的几何先验出发,它可以和图像分割一样,从“逐位置预测”出发,让网络自己学会什么样的位置、什么样的大小、什么样的形状。这种表述上的自由,往往是更优质模型的起点。

如果你正在入门目标检测,我的建议是:不要只背FCOS的公式,而是自己从头搭一个简化版跑通,看每个模块产生的影响。训练曲线、NMS输出、每个金字塔层的样本分布,这些细节才是真正帮你内化的东西。等你对逐点预测的“体感”建立了,再去读后毫米波的方法,你会发现一切都连贯起来了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询