目标检测3--AnchorFree的FCOS

article/2025/9/14 16:43:15

文章目录

    • 1.介绍
    • 2.FCOS中使用的方法
      • 2.1 网络结构
      • 2.2FCOS中使用`FPN`的多级预测
      • 2.3FCOS中的中心度
    • 3.mmdetection中`FCOS`源码
    • 参考资料


欢迎访问个人网络日志🌹🌹知行空间🌹🌹


1.介绍

论文:《FCOS: Fully Convolutional One-Stage Object Detection》
是澳洲阿德莱德大学的Zhi Tian等最早于2019年04月提交的工作成果,发表在ICCV上。

FCOS是全卷积实现的Anchor Free的一阶目标检测器,避免了训练过程中Anchor相关的计算,减少的训练时的计算量和内存占用,移除了anchor相关的一系列超参数。

Anchor Based方法的缺点:

  • 检测性能对anchorsize/aspect ratio/数量比较敏感。
  • 实际对象的检测框大小分布较广泛,anchor不一定能覆盖
  • 为了得到高召回率,anchor based的方法返回了非常多的anchor box,如FPN中,输入短边为800的图像将总共生成大于180KAnchor Box。超级多的anchor box除了影响性能外,还导致了严重的类别不平衡问题,因为180Kanchor box中有大量的都是不包含对象的negative box

neat fully convolution pixel prediction frameworkanchor box的存在不适用于object detection。先前的预测方法在目标检测框重叠时检测效果不好,如DenseBoxFCOS在距离目标中心较远的位置产生很多低质量的预测边框,这会影响检测的效果,为了克服这个问题,引入了中心度的概念,衡量预测框到距目标框的距离。FCOS添加单层分支,与分类分支并行,以预测"Center-ness"位置。

FCOS的优点:

  • FCN结构,与pixel prediction任务的网络统一,更便于复用语义分割中的tricks
  • anchor free框架,减少模型的设计参数。
  • anchor free框架,减少训练中的IoU计算和box match.
  • FCOS可用于two-stage检测网络中的RPN
  • 易于拓展应用于其他视觉任务,如Instance Segmentation

Anchor Free目标检测器有YoloV1,CornerNet

2.FCOS中使用的方法

2.1 网络结构

将目标检测任务形式化为pixel prediction任务,使用多级预测提升召回率,解决重叠目标的模糊问题。

特征图上的点(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)

FCOS直接将(x, y)对应的检测框位置当作训练样本,具体是指,当(x,y)映射到原图上落入任何ground-truth box中,这个点就当成正样本,否则就是负样本。检测定位回归的变量是 t ∗ = ( l ∗ , t ∗ , r ∗ , b ∗ ) t^*=(l^*, t^*, r^*, b^*) t=(l,t,r,b), t ∗ t^* t分别指中心(x, y)距检测框左/上/右/下四条边的距离。

在这里插入图片描述

feature map上的某个点(x,y)同时落入多个bounding box中时,这个点(x,y)被当成ambiguous sampleFPNmulti level机制可以用来解决这个问题。很显然,通过上述介绍可以知道,FCOS中可能有多个feature map上的点(x, y)落入到同个ground truth box中,故可以生成很多positive boxes用于训练。

在这里插入图片描述

网络输出

训练了C个二分类器,而非1个多分类器,可以实现多标签预测。feature map后接有4个卷积层的分类分支位置回归分支,回归分支使用了exp(x),将回归预测变量x变换到了(0, +\infinity)上,输出的变量比anchor based方法少9倍。

损失函数

在这里插入图片描述

分类使用的是Focal Loss解决类别不平衡问题,回归使用的是IoU损失。

2.2FCOS中使用FPN的多级预测

FCOS中的两个问题:

  • 1) 到最终输出的feature map使用大stridex16会导致低BPR(best possible recall)Anchor Based方法可以对positive box使用低的IoU阈值来补偿这个问题,而对于FCOS,直观的一个猜想是,对于小物体,stride过大时,可能导致feature map上并没有一个点可以与小目标的中心对应,故BPR应该会比较低。
  • 2) 重叠的目标框引入了棘手的模糊性问题,feature map中的一个点(x, y)如何确定应该用来回归重叠框中的哪一个呢?

使用FPN的多级预测解决FCOS中存在的这两个问题。

FPN,使用不同层级中的feature map来预测不同大小的目标。限制不同level feature map回归距离 t ∗ = ( l ∗ , t ∗ , r ∗ , b ∗ ) t^*=(l^*, t^*, r^*, b^*) t=(l,t,r,b)的上限, m i m_i mi表示level ifeature map上每个点回归的最大距离,因此若level ifeature map上某个点回归的距离 t ∗ = ( l ∗ , t ∗ , r ∗ , b ∗ ) t^*=(l^*, t^*, r^*, b^*) t=(l,t,r,b) 大于 m i m_i mi或小于 m i − 1 m_{i-1} mi1时,就将其当作negative box对于 { 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}对应的 m i m_i mi分别为 0 , 64 , 128 , 256 , 512 , + ∞ 0, 64, 128, 256, 512, +\infty 0,64,128,256,512,+

前面介绍的因预测的是距离,故 t ∗ ∈ ( 0 , ∞ ) t^*\in(0, \infty) t(0,)因此使用了exp函数,现在不同level的回归距离范围是不同的,再使用相同的head就不合理了,增加一个参数 s i s_i si,使用 e x p ( s i x ) exp(s_ix) exp(six)函数,对不同level使用不同的 s i s_i si

2.3FCOS中的中心度

可能有多个feature map中的点对应同个物体检测框,而距离中心较远的feature map点会导致引入很多低质量的物体检测框,影响检测的效果。

FCOS引入了中心度centerness来描述一个点距离目标框中心的远近,以过滤掉偏离中心点的低质量检测框。中心度是通过一个与分类分支并行的单层分支来预测的。对于某个位置的回归目标 ( l ∗ , t ∗ , r ∗ , b ∗ ) (l^*, t^*, r^*, b^*) (l,t,r,b),其中心度的定义为:

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^*)}\times \frac{min(t^*,b^*)}{max(t^*,b^*)}} centerness=max(l,r)min(l,r)×max(t,b)min(t,b)

sqrt 运算可以减缓中心度的衰减速度。centerness取值范围0-1,训练使用二分类交叉熵BCE,加到前述的损失函数中一起训练,预测时,将centerness与分类评分score相乘后作为最后检测框的评分,再进行NMS,因此很多偏离中心的框就能被过滤掉了。

3.mmdetection中FCOS源码

FCOS网络结构的定义如上图中二所示,定义的文件在mmdetection工程``文件中。

看一下FCOS Head,从计算loss是使用的self.get_targets方法开始。

min
feat_points
bbox_targets
gt_boxes
center_sample_radius
inside_gt_bbox_mask
regress_ranges
inside_regress_range
areas
min_area_inds
labels
labels
bbox_targets
def _get_target_single(self, gt_bboxes, gt_labels, points, regress_ranges,num_points_per_lvl):"""Compute regression and classification targets for a single image."""num_points = points.size(0)num_gts = gt_labels.size(0)if num_gts == 0:return gt_labels.new_full((num_points,), self.num_classes), \gt_bboxes.new_zeros((num_points, 4))areas = (gt_bboxes[:, 2] - gt_bboxes[:, 0]) * (gt_bboxes[:, 3] - gt_bboxes[:, 1])# TODO: figure out why these two are different# areas = areas[None].expand(num_points, num_gts)areas = areas[None].repeat(num_points, 1)regress_ranges = regress_ranges[:, None, :].expand(num_points, num_gts, 2)gt_bboxes = gt_bboxes[None].expand(num_points, num_gts, 4)xs, ys = points[:, 0], points[:, 1]xs = xs[:, None].expand(num_points, num_gts)ys = ys[:, None].expand(num_points, num_gts)left = xs - gt_bboxes[..., 0]right = gt_bboxes[..., 2] - xstop = ys - gt_bboxes[..., 1]bottom = gt_bboxes[..., 3] - ysbbox_targets = torch.stack((left, top, right, bottom), -1)if self.center_sampling:# condition1: inside a `center bbox`radius = self.center_sample_radiuscenter_xs = (gt_bboxes[..., 0] + gt_bboxes[..., 2]) / 2center_ys = (gt_bboxes[..., 1] + gt_bboxes[..., 3]) / 2center_gts = torch.zeros_like(gt_bboxes)stride = center_xs.new_zeros(center_xs.shape)# project the points on current lvl back to the `original` sizeslvl_begin = 0for lvl_idx, num_points_lvl in enumerate(num_points_per_lvl):lvl_end = lvl_begin + num_points_lvlstride[lvl_begin:lvl_end] = self.strides[lvl_idx] * radiuslvl_begin = lvl_endx_mins = center_xs - stridey_mins = center_ys - stridex_maxs = center_xs + stridey_maxs = center_ys + stridecenter_gts[..., 0] = torch.where(x_mins > gt_bboxes[..., 0],x_mins, gt_bboxes[..., 0])center_gts[..., 1] = torch.where(y_mins > gt_bboxes[..., 1],y_mins, gt_bboxes[..., 1])center_gts[..., 2] = torch.where(x_maxs > gt_bboxes[..., 2],gt_bboxes[..., 2], x_maxs)center_gts[..., 3] = torch.where(y_maxs > gt_bboxes[..., 3],gt_bboxes[..., 3], y_maxs)cb_dist_left = xs - center_gts[..., 0]cb_dist_right = center_gts[..., 2] - xscb_dist_top = ys - center_gts[..., 1]cb_dist_bottom = center_gts[..., 3] - yscenter_bbox = torch.stack((cb_dist_left, cb_dist_top, cb_dist_right, cb_dist_bottom), -1)inside_gt_bbox_mask = center_bbox.min(-1)[0] > 0else:# condition1: inside a gt bboxinside_gt_bbox_mask = bbox_targets.min(-1)[0] > 0# condition2: limit the regression range for each locationmax_regress_distance = bbox_targets.max(-1)[0]inside_regress_range = ((max_regress_distance >= regress_ranges[..., 0])& (max_regress_distance <= regress_ranges[..., 1]))# if there are still more than one objects for a location,# we choose the one with minimal areaareas[inside_gt_bbox_mask == 0] = INFareas[inside_regress_range == 0] = INFmin_area, min_area_inds = areas.min(dim=1)labels = gt_labels[min_area_inds]labels[min_area == INF] = self.num_classes  # set as BGbbox_targets = bbox_targets[range(num_points), min_area_inds]return labels, bbox_targets

中心度的计算:

def centerness_target(self, pos_bbox_targets):"""Compute centerness targets.Args:pos_bbox_targets (Tensor): BBox targets of positive bboxes in shape(num_pos, 4)Returns:Tensor: Centerness target."""# only calculate pos centerness targets, otherwise there may be nanleft_right = pos_bbox_targets[:, [0, 2]]top_bottom = pos_bbox_targets[:, [1, 3]]if len(left_right) == 0:centerness_targets = left_right[..., 0]else:centerness_targets = (left_right.min(dim=-1)[0] / left_right.max(dim=-1)[0]) * (top_bottom.min(dim=-1)[0] / top_bottom.max(dim=-1)[0])return torch.sqrt(centerness_targets)

Focal Loss的定义:

pred_sigmoid = pred.sigmoid()
target = target.type_as(pred)
pt = (1 - pred_sigmoid) * target + pred_sigmoid * (1 - target)
focal_weight = (alpha * target + (1 - alpha) *(1 - target)) * pt.pow(gamma)
loss = F.binary_cross_entropy_with_logits(pred, target, reduction='none') * focal_weight

参考资料

  • 1.https://zhuanlan.zhihu.com/p/63868458
  • 2.https://zhuanlan.zhihu.com/p/32423092

http://chatgpt.dhexx.cn/article/ynvXH6C0.shtml

相关文章

浅谈Anchor-Free发展历程

1.早期探索&#xff1a; DenseBox: https://arxiv.org/abs/1509.04874 YOLO: https://arxiv.org/abs/1506.02640 2.基于关键点&#xff1a; CornerNet: https://arxiv.org/abs/1808.01244 ExtremeNet: https://arxiv.org/abs/1901.08043 3.密集预测: FSAF: https://arxiv.org/a…

Anchor-Free系列之FCOS:A Simple and Strong Anchor-free Object Detector

Anchor-Free系列之CornerNet: Detecting Objects as Paired Keypoints_程大海的博客-CSDN博客 Anchor-Free系列之CenterNet&#xff1a;Objects as Points_程大海的博客-CSDN博客 Anchor-Free系列之FCOS&#xff1a;A Simple and Strong Anchor-free Object Detector_程大海的…

Anchor Based和Anchor Free

Anchor Based和Anchor Free之间区别主要有以下两点&#xff1a;1.分类差异&#xff08;关键正负样本定义&#xff09;2.回归差异 1.分类差异&#xff1a; 现阶段的算法多尺度预测&#xff0c;即GT是由哪一个特征层和位置Anchor预测。 Anchor Based是由IoU来确定哪层和哪个位置…

解读《Bridging the Gap Between Anchor-based and Anchor-free Detection》

张士峰大佬近期发了一篇论文解读Anchor-base和Anchor-free方法间的差别&#xff0c;其本质在于正负样本的选取方式不同。 论文&#xff1a;《Bridging the Gap Between Anchor-based and Anchor-free Detection via Adaptive Training Sample Selection》 链接&#xff1a;ht…

anchor-free方法总结

cornernet&#xff0c;centernet&#xff0c;onenet&#xff0c;fcos 这几篇论文的引用关系&#xff08;提出先后顺序&#xff09;&#xff1a; 将按照上面的顺序&#xff0c;从背景、标签分配等方面说明区别于联系。 一、背景&#xff1a; Cornernet&#xff1a;认为使用a…

anchor free和anchor base

仅供个人学习使用 1、anchor base anchor base的方法需要先在图片上生成候选框&#xff0c;无论是RPN生成还是通过k-means生成的先验框&#xff0c;都需要在分类回归之前有存在的框可使用。在框的基础上进行之后的操作。 超参数较为难调&#xff0c;正负样本不平衡&#xff…

Anchor free的心得

问题&#xff1a; 没有了Anchor框的监督信息&#xff0c;我们怎么针对检测任务做到正确回归&#xff1f; 本质&#xff1a;样本与ground truth的对应&#xff0c;如何选择合适样本与真实场景对应 Anchor&#xff1a; 其加入降低了回归问题难度&#xff0c;为分类问题提供选择…

Anchor-based 与 Anchor-free

参考 Anchor-based 与 Anchor-free - 云社区 - 腾讯云 1. Feature Selective Anchor-Free Module for Single-Shot Object Detection 参考&#xff1a;CVPR2019 | CMU提出Single-Shot目标检测最强算法&#xff1a;FSAF 2. FCOS: Fully Convolutional One-Stage Object Det…

Anchor-free

找到了一个说在工业领域很好的 目标检测 下面几篇paper有异曲同工之妙&#xff0c;开启了anchor-based和anchor-free的轮回。 1. Feature Selective Anchor-Free Module for Single-Shot Object Detection 2. FCOS: Fully Convolutional One-Stage Object Detection 3. Fo…

AnchorFree系列算法详解

目录 前言一、Anchor-Based方法回顾二、Anchor Free系列方法简介1. Anchor Free系列算法历史2. Anchor free经典算法详解2.1. 基于关键点的Anchor Free检测算法1. CornerNet 2. 2 基于中心的Anchor Free检测算法1. FCOS2. CenterNet3. TTFNet -- CenterNet的改进版 3. AnchorFr…

目标检测算法——anchor free

一、anchor free 概述 1 、 先要知道anchor 是什么&#xff08;这需要先了解二阶段如faster rcnn&#xff0c;一阶检测器如YOLO V2以后或SSD等&#xff09;。 在过去&#xff0c;目标检测通常被建模为对候选框的分类和回归&#xff0c;不过&#xff0c;按照候选区域的产生方式不…

Scala解释器

Scala解释器 后续我们会使用scala解释器来学习scala基本语法&#xff0c;scala解释器像Linux命令一样&#xff0c;执行一条代码&#xff0c;马上就可以让我们看到执行结果&#xff0c;用来测试比较方便。 启动scala解释器 要启动scala解释器&#xff0c;只需要以下几步&…

Pycharm修改python解释器

Pycharm修改python解释器 在python学习过程中&#xff0c;遇到了这样的一个问题&#xff0c;早先通过pip安装的库在pycharm中无法使用&#xff0c;例如之前学习的numpy库在pycharm中无法调用&#xff1a; 下面给出两个解决办法 1.通过pycharm自带的方式再次进行安装 具体操作…

【jvm系列-07】深入理解执行引擎,解释器、JIT即时编译器

JVM系列整体栏目 内容链接地址【一】初识虚拟机与java虚拟机https://blog.csdn.net/zhenghuishengq/article/details/129544460【二】jvm的类加载子系统以及jclasslib的基本使用https://blog.csdn.net/zhenghuishengq/article/details/129610963【三】运行时私有区域之虚拟机栈…

java的解释器是什么_java编译器和java解释器、JVM

作用: JVM:JVM有自己完善的硬件架构,如处理器、堆栈(Stack)、寄存器等,还具有相应的指令系统(字节码就是一种指令格式)。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需要生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM是Ja…

【详解】JVM中,编译器和解释器的作用和区别

一、前言 随着互联网的发展&#xff0c;现在虚拟机地表最稳定&#xff0c;最强的默认是Hotspot虚拟机。先查看下&#xff1a; 查看方式&#xff1a;cmd进行黑框框&#xff0c;然后输入&#xff1a;java -version 会出现以下参数&#xff1a; java version&#xff1a;当前jav…

pycharm查看解释器

1.查看pycharm的解释器&#xff1a; 2.查看自己现在这个项目的解释器

python的编译器与解释器

作者介绍&#xff1a; &#x1f425;作者&#xff1a;小刘在C站 &#x1f446;每天分享课堂笔记&#xff0c;一起努力&#xff0c;共赴美好人生 &#x1f341;夕阳下&#xff0c;是最美的绽放 目录 一.为什么会有编译器和解释器 二.编译器和解释器的区别 三.python解释器种类…

修改Python解释器和包路径

环境检查 1. 查看当前解释器的位置 在Python文件中执行或者在终端中先进入Python import sys print(sys.executable) 以我的电脑为例子&#xff0c;输出 /Library/Frameworks/Python.framework/Versions/3.8/bin/python3 2. 查看当前指向的包存放路径 在Python文件中执行…

python解释器怎么添加_Python解释器安装与环境变量添加

python解释器安装与环境变量添加 python解释器安装(3.6和2.7): 这个是python解释器的官网,一定要牢记。 鉴于市场上有两种python版本(2和3),今天两种版本都装一下,互相学习,如有错误还请各位评论指正。 windows系统(如果是苹果的系统就下mac os x) 进来后 python3版本 选择…