FCOS 详解
FCOS: Fully Convolutional One-Stage Object Detection
论文: FCOS: Fully Convolutional One-Stage Object Detection (ICCV 2019)
作者: Zhi Tian, Chunhua Shen, Hao Chen, Tong He ( Adelaide / 商汤 )
代码: tianzhi0549/FCOS / AdelaiDet
一句话总结:FCOS 抛弃 anchor,把目标检测变成”逐像素预测”–特征图上每个位置直接回归到所在 GT 框四条边的距离 (l, t, r, b)。 它证明了只要配合 FPN 多级预测 + center-ness,anchor-free 检测器就能追平甚至超过 anchor-based。
一、概述:为什么要有 anchor-free
主流检测器(RetinaNet / SSD / YOLOv2+ / Faster R-CNN)都依赖预设 anchor。anchor 的问题:
- 超参敏感:anchor 的尺寸、宽高比、数量对性能影响大(RetinaNet 在 COCO 上仅调这些就能差 4% mAP);
- 泛化差:固定宽高比难以适应新任务的物体形状(尤其小目标);
- 负样本爆炸:为高召回需密集放 anchor(短边 800 输入下 FPN 产生 >180K 个),加剧正负不平衡;
- 计算复杂:训练时要算所有 anchor 与 GT 的 IoU 匹配,占内存。
FCOS 的思路:像语义分割一样,把特征图上每个位置(像素)当作训练样本,直接回归它到所属物体框四条边的距离。无需 anchor、无需 proposal,只需 NMS 后处理。
与 YOLOv1 的区别:YOLOv1 也是 anchor-free,但只用中心区域的点预测,召回低;FCOS 用框内所有点预测,召回与 anchor-based 持平。与 CornerNet/CenterNet 的区别:它们基于关键点(角点/中心点),FCOS 是逐像素回归,更像实例分割。
二、核心思想:逐像素回归 (l, t, r, b)
![]()
设某层特征图 $F_i$ 的 stride 为 $s$,GT 框 $B_i = (x_0, y_0, x_1, y_1, c)$(左上、右下、类别)。
对特征图上每个位置 $(x,y)$,先映射回原图坐标:
$$
(x_{img}, y_{img}) = \left(\left\lfloor \tfrac{s}{2}\right\rfloor + x\cdot s,\ \left\lfloor \tfrac{s}{2}\right\rfloor + y\cdot s\right)
$$
这个映射点近似落在该位置的感受野中心。
如果该位置落在某个 GT 框内部,则它是正样本,负责预测该 GT。它的回归目标是到框四条边的距离:
$$
l^* = x_{img} - x_0,\quad t^* = y_{img} - y_0,\quad r^* = x_1 - x_{img},\quad b^* = y_1 - y_{img}
$$
四个值都 > 0;网络最后一层用
exp(x)(或 ReLU + norm)把输出映射到 $(0, +\infty)$。
歧义问题:如果一个位置落在多个 GT 框内(重叠物体),它该回归哪个?FCOS 的策略:选面积最小的 GT 作为目标。但这只是兜底,真正的解法是 FPN 多级预测(第六节)。
💡 FCOS 能用尽可能多的前景样本训练回归器(框内每个像素都是正样本),而 anchor-based 只把高 IoU 的 anchor 当正样本–这是 FCOS 优于 anchor-based 的重要原因之一。
三、网络架构

1 | 输入 (3×H×W) |
要点:
- Backbone 取 $C_3, C_4, C_5$,FPN 横向连接得 $P_3, P_4, P_5$;$P_6, P_7$ 由 $P_5$ 经 stride=2 卷积得到(注意:来自 $P_5$ 而非 $C_5$,参数更少、语义更强)。
- Head 用 GroupNorm(不是 BN),因为 head 通道少、用 GN 训练更稳。
- 5 个特征图共享同一组 Head 权重(参数高效 + 提性能)。
- 网络每位置输出 =
C(分类) + 4(回归) + 1(center-ness),比 RetinaNet(每位置 9 anchor)少约 9 倍。
四、🔥 数据与目标构造:YOLO 格式如何转 FCOS
这是理解 FCOS 最容易卡住的点。结论先说:FCOS 不需要你在磁盘上准备”特殊的 per-pixel 标注”。l, t, r, b 这些目标是训练时从 GT 框实时算出来的,不存盘。 所以”YOLO 格式转 FCOS”本质上只是把 YOLO 标注转成框架能读的格式(通常是 COCO JSON),剩下的 FCOS 自动处理。
4.1 先理清两个层次
| 层次 | 内容 | 谁来做 |
|---|---|---|
| 磁盘标注格式 | 每张图的框 + 类别 | 你准备(YOLO / COCO / VOC 等) |
| 训练目标 (l,t,r,b + class + centerness) | 每个特征图位置的目标值 | 框架训练时实时计算,不存盘 |
- FCOS 官方代码 / mmdetection 的 FCOS,输入端和 RetinaNet 完全一样:吃 COCO 格式标注(
image+annotations{bbox:[x,y,w,h], category_id})。 - 你看到的 l, t, r, b、center-ness target,都是在
loss/target assignment代码里,每个 batch 从 GT 框现算的。
所以别去找”FCOS 格式数据集生成工具”——不存在那种东西。你要做的只有一件事:把 YOLO 标注转成 COCO JSON。
4.2 YOLO 格式 vs COCO 格式
| YOLO 格式 | COCO 格式(FCOS 框架输入) | |
|---|---|---|
| 存储 | 每图一个 .txt(同名) |
一个 JSON 汇总所有图 |
| 每条标注 | class cx cy w h |
category_id + bbox=[x,y,w,h] |
| 坐标制 | 归一化 (0~1), cxcywh | 绝对像素, xywh(左上角 + 宽高) |
| 类别 | 0~C-1 整数 | 需映射到 category_id(通常 1~C) |
4.3 坐标转换(核心一步)
YOLO 一行 class cx cy w h(归一化 cxcywh)→ 绝对 xyxy:
1 | 设图像宽 W, 高 H |
1 | import numpy as np |
4.4 YOLO 数据集 → COCO JSON 转换脚本
下面这个脚本把一个 YOLO 数据集目录(images/ + labels/,每图同名 .txt)转成 FCOS/mmdetection 直接能用的 COCO JSON:
1 | import json, glob, os |
转完得到
train.json/val.json,在 mmdetection 的 FCOS config 里把ann_file指过去即可–之后 l,t,r,b 全部自动算,你不用再管。
4.5 FCOS 的目标分配代码(l, t, r, b 是怎么算出来的)
这是 FCOS 最核心的部分(来自 AdelaiDet 实现)。看懂这段,就彻底明白”FCOS 的数据怎么造”:
1 | def compute_targets_for_locations(self, locations, targets, size_ranges, num_loc_list): |
center-ness target 由回归 target 直接算出(无需额外标注):
1 | def compute_ctrness_targets(reg_targets): |
📌 总结这条链路:磁盘上只有
bbox(xyxy) + class→ dataloader 取出 →compute_targets_for_locations对每个特征图位置算l,t,r,b+ 分配类别 →compute_ctrness_targets算 center-ness → 送入 loss。你只需要喂框,per-pixel 目标全是代码算的。
4.6 位置生成 + 中心采样 + FPN 分级
位置生成(compute_locations):对每层特征图 (H×W, stride s),生成所有位置坐标并映射回原图:
1 | def compute_locations_per_level(h, w, stride, device): |

中心采样(center sampling):并非”框内所有点”都算正样本,而是只取以 GT 中心为中心、半径 r·s(r=1.5)的子区域内的位置为正。这能减少远离中心的低质量样本,进一步降低歧义(实现时保证子区域不超出 GT)。
FPN 分级:每个 GT 在哪一层预测,由 max(l,t,r,b) 落在哪个区间决定(详见第六节)。阈值 $m_2..m_7 = 0, 64, 128, 256, 512, \infty$。
五、Center-ness 分支
问题:远离物体中心的位置(靠近框边缘)会预测出低质量框–这些位置感受野只看到物体一小部分,且 l,t,r,b 分布不均(如 l=1, r=100),预测不准。这些”高分类分但低 IoU”的框会拉低 precision。

Center-ness:在回归分支末尾加一个分支,预测位置到物体中心的归一化距离,值域 [0,1]:
$$
centerness^* = \sqrt{\frac{\min(l^, r^)}{\max(l^, r^)} \times \frac{\min(t^, b^)}{\max(t^, b^)}}
$$

- 位置在中心 → 左右/上下接近 → center-ness → 1;
- 位置靠边 → 一项很小 → center-ness → 0。
作用:
- 训练用 BCE loss(只在正样本上算);
- 测试时,最终分数 = $\sqrt{p_{x,y} \times centerness_{x,y}}$(分类分 × 中心度),用于排序。远离中心的框分数被压低,更易被 NMS 滤除。

实验显示 center-ness 约提升 1 个点 AP。代价是不引入任何超参(是个软阈值,网络自己学)。
⚠️ 局限:center-ness 训练时和分类分开,测试时才相乘,存在训练-测试不一致。后续 Generalized Focal Loss 把质量估计和分类联合训练,且用 IoU 代替 center-ness 评估框质量更好(IoU label 通常比 center-ness 大,更易召回):

六、多级预测(FPN)解决歧义与低召回
FCOS 不用 anchor 带来两个风险:① 大 stride 导致 BPR(最佳召回)低;② 重叠框导致歧义。FPN 多级预测同时解决两者。
6.1 按回归范围分级
不同大小的 GT 分配到不同 FPN 层:每个位置算 max(l,t,r,b),落在哪个区间就由哪层负责:
$$
m_{i-1} < \max(l^, t^, r^, b^) < m_i
$$
| FPN 层 | stride | 回归范围 max(l,t,r,b) | 目标 |
|---|---|---|---|
| P3 | 8 | (0, 64) | 小目标 |
| P4 | 16 | (64, 128) | 中小 |
| P5 | 32 | (128, 256) | 中 |
| P6 | 64 | (256, 512) | 大 |
| P7 | 128 | (512, ∞) | 超大 |
因为重叠物体大概率尺寸不同,会被分到不同层,歧义大幅减少。同级仍冲突时,仍按”面积最小 GT”兜底:

6.2 回归范围差异的处理
不同层回归值范围差很大(P3 是 0~64,P7 是 512+),但 Head 权重共享。早期 FCOS 用可学习 scale $s_i$:输出 $= \exp(s_i \cdot x)$ 调整指数基数。新版直接把回归 target 除以 stride 归一化(norm_reg_targets),等价且更简洁。
6.3 BPR 与歧义统计
FCOS 的 BPR(最佳可能召回)与 RetinaNet 基本持平:

歧义样本占比(采用中心采样 + FPN 后仅 2.66%):

结论:FCOS 的召回并不比 anchor-based 差,歧义也已压到很低。但对同尺度密集重叠物体(如低空行人、密集人群)仍不友好–FCOS 的分级只能解决不同尺寸间的重叠。
七、损失函数
$$
L = \frac{1}{N_{pos}}\sum_{x,y} L_{cls}(p_{x,y}, c^{x,y}) + \frac{\lambda_1}{N{pos}}\sum_{x,y} \mathbf{1}_{c^{x,y}>0} L{reg}(t_{x,y}, t^{x,y}) + \frac{\lambda_2}{N{pos}}\sum_{x,y} \mathbf{1}_{c^{x,y}>0} L{ctr}(centerness_{x,y}, centerness^*_{x,y})
$$
| 分支 | 损失 | 说明 |
|---|---|---|
| 分类 $L_{cls}$ | Focal Loss | C 个二分类,所有位置参与 |
| 回归 $L_{reg}$ | IoU / GIoU Loss | 仅正样本,把 l,t,r,b 当整体算 IoU |
| 中心度 $L_{ctr}$ | BCE Loss | 仅正样本 |
- $\mathbf{1}_{c^*>0}$:正样本指示函数,回归和中心度只在正样本上算;
- $N_{pos}$:正样本数归一化;$\lambda_1, \lambda_2$ 论文取 1;
- 回归用 GIoU(优于 IoU):IoU 在两框不相交时梯度为 0,GIoU 能反映不相交时的距离,$-1 \le GIoU \le 1$,loss = 1 - GIoU。
八、训练与推理
训练:
- ResNet-50 backbone,ImageNet 预训练;
- SGD,lr=0.01,batch=16,weight_decay=1e-4,momentum=0.9;
- 输入短边 800、长边≤1333;数据增强:随机翻转 + 多尺度;
- head 用 GroupNorm。
推理:
- 单次前向 → 每层每位置得到 (分类分, l,t,r,b, centerness);
- 分类分 > 0 的位置为正,用 l,t,r,b 解码出框;
- 最终分数 = $\sqrt{cls \times centerness}$;
- 跨 5 层汇总 → NMS(0.5)。
center-ness 只在推理打分/NMS 时用,不参与框的坐标解码。
九、性能
9.1 FCOS vs RetinaNet

- FCOS(38.9 AP)明显高于原生 RetinaNet(35.9);
- 但当 RetinaNet 也采用 FCOS 的策略(GN、GIoU、P6/P7 从 P5 出),差距缩小到 ~1 点;
- 去掉 center-ness 后两者基本持平。
- ATSS 进一步证明:anchor-free 与 anchor-based 的差异,本质是正负样本定义策略的不同,而非架构。FCOS 的贡献在于把这件事讲清楚、并给出了扎实方案。
9.2 主要结果
- ResNet-101 + 多尺度训练:~40+ AP;
- ResNeXt-64x4d-101:44.7 AP,超越当时一阶段 SOTA。
十、优缺点与总结
优点 ✅
- 彻底去 anchor:免去 anchor 超参设计、IoU 匹配计算,训练内存减半
- 结构简单灵活:易扩展到实例分割、关键点检测
- 召回不输 anchor-based:BPR ~98.95%,框内全像素当正样本,回归更充分
- center-ness 优雅:无超参抑制低质量框
- 范式意义大:与 ATSS 一起,揭示了”样本定义策略”才是关键
局限 ❌
- 小网络难训练:易不收敛,依赖 GN 等技巧
- center-ness 训测不一致:训练分开、测试相乘(GFL 改进)
- 同尺度密集重叠弱:分级只解决不同尺寸重叠,低空行人/密集人群不友好
- 仍依赖 NMS:未摆脱后处理(DETR 才去除)
- 对数据集敏感:需视场景选用
总结
FCOS 的精髓是把检测变成逐像素回归:每个特征图位置直接预测到框四条边的距离 (l,t,r,b)。它的数据准备其实比 anchor-based 更简单–磁盘上只需普通的框标注(COCO/YOLO 都行),per-pixel 的 l,t,r,b + centerness target 全是训练时从框实时算的。理解了 compute_targets_for_locations 这段代码,就理解了 FCOS 的”数据”是怎么来的。
📌 回到你的疑问:把 YOLO 标注转成 COCO JSON(第四节脚本),喂给 FCOS 框架即可。框架会在训练时自动把每个框展开成它覆盖的所有像素位置的 l,t,r,b 回归目标 + 类别 + center-ness。 你不需要、也不应该手工去生成 per-pixel 标签。
十一、相关链接
- 📝 [[RetinaNet 详解]] - FCOS 架构与 RetinaNet 几乎一致,可对照阅读;ATSS 的对照也在此
- 📝 [[YOLOv3 详解]] - 另一类检测器,anchor-based
- 📝 [[YOLO 系列总览]] - 检测器谱系
- 📝 [[YOLO 核心概念]] - FPN / IoU / NMS 共享概念
- 📋 [[10.clippings/感知算法/2D检测/单阶段/FCOS/FCOS算法的原理与实现]] - 知乎 (小小将, 含 compute_targets 核心代码)
- 📋 [[10.clippings/感知算法/2D检测/单阶段/FCOS/FCOS算法详解]] - 知乎 (辣蜗, 含完整网络结构代码)
- 📋 [[10.clippings/感知算法/2D检测/单阶段/FCOS/简单剖析FCOS原理及优势]] - 知乎 (李Nik, GT 编码讲解清晰)
- 📋 [[10.clippings/感知算法/2D检测/单阶段/FCOS/论文阅读笔记10:FCOSFully Convolutional One-Stage Object Detection]] - 论文翻译笔记
- 📋 [[10.clippings/感知算法/2D检测/单阶段/FCOS/详解FCOS《FCOS Fully Convolutional One-Stage Object Detection》]] - cnblogs (Head 解码详解)
- 📋 [[10.clippings/感知算法/2D检测/单阶段/FCOS/FCOS算法详解-CSDN博客]] - CSDN
- 📋 [[10.clippings/感知算法/2D检测/单阶段/FCOS/19.04 FCOS]] - docsaid
- 📋 论文原文: arxiv.org/abs/1904.01355
- 📋 官方代码: tianzhi0549/FCOS