目标检测标签分配之 OTA 和 SimOTA 细节学习

本文参考:
https://blog.csdn.net/weixin_46142822/article/details/124074168
该作者写的细节我认为应该是 SimOTA 的细节。
https://zhuanlan.zhihu.com/p/397993315 果然是 SimOTA,其实是抄的这篇的。

OTA 论文回顾: https://www.cnblogs.com/odesey/p/16740854.html

SimOTA 来自于 YOLOX 论文:https://arxiv.org/pdf/2107.08430.pdf ,是 OTA 的简化, OTA 使用 Sinkhorn-Knopp Iteration 来求解 cost 矩阵。 OTA 是直接基于规则,直接用 k 个最小 cost 值的候选框作为正样本。

1. 定义

为了便于理解,我们假设:

  • 一张图片上有 3个目标框,即 3个ground truth
  • 项目有 2个检测类别,比如 cat/dog
  • 网络输出1000个预测框,其中只有少部分是正样本,绝大多数是负样本

bboxes_preds_per_image候选检测框的信息,维度是[1000,4]。预测框的四个坐标。

obj_preds 是目标分数(object score),维度是 [1000,1]。预测框是前景还是背景。

cls_preds 是类别分数,维度是 [1000,2]。预测框的2个检测类别的one-hot。

训练网络需要知道这 1000个预测框的标签,而如何分配标签呢?

使用OTA方法,分为4步,具体做法如下:

step1:生成cost矩阵

OTA 方法分配标签是基于 cost 的,因为有 3个目标框和1000个预测框,所以需要生成 3 × 1000 的 cost matrix(也就是每个真实框都要和1000个预测框计算下 cost)。

那么 cost 怎么计算?

对于目标检测任务,cost 由定位损失和分类损失组成,计算方法如下:

(1) 定位损失

计算 3个目标框,和 1000个候选框,得到每个目标框和 1000 个预测框之间的 iou(pair_wise_ious)。

再通过 -torch.log 计算得到定位损失,即 pair_wise_iou_loss,向量维度为[3, 1000]。3 是 3个真实框,每个都计算1000个值。

pair_wise_ious=bboxes_iou(gt_bboxes_per_image,bboxes_perds_per_image,False)
pair_wise_ious_loss=-torch.log(pair_wise_ious+1e-8)
(2) 分类损失

通过第一行代码,将类别的条件概率(cls_preds:表示分类的概率)和目标的先验概率(obj_preds:是前景的概率)做乘积,得到目标的类别分数(两个乘积得到的)。

再通过第二行代码,F.binary_cross_entroy 的处理,得到 3个目标框和1000个预测框 的综合loss值,得到类别损失,即 pair_wise_cls_loss,向量维度为 [3,1000]。3也是 3个真实框。其实这里就是算一个2分类交叉熵,cls_preds 和 真实框的 1 算下。每个真实框算1000次。

cls_preds=(cls_preds_.float().unsqueeze(0).repeat(num_gt,1,1).sigmoid_()
*obj_preds_.unsqueeze(0).repeat(num_gt,1,1).sigmoid_())

pair_wise_cls_losss=F.binary_cross_entropy(cls_pres_.sqrt_(),gt_cls_per_image,reduction='none').sum(-1)

有了reg_loss和 cls_loss,将两个损失函数加权相加,就可以得到cost成本函数了。

cost 计算公式如下:

C i j = L i j c l s + λ L i j r e g C_{ij} = L_{ij}^{cls} + \lambda L_{ij}^{reg} Cij=Lijcls+λLijreg

加权系数 λ = 3 \lambda=3 λ=3,计算代码如下:

cost=pair_wise_cls_loss
	  +3.0*pair_wise_ious_loss
	  +100000.0*(~is_in_boxes_and_center)
step2:dynamic_k_estimation

每个 gt 提供多少正样本,可以理解为“ 这个 gt 需要多少个正样本才能让网络更好的训练收敛 ”。

直觉上,每个 gt 的大小、尺度和遮挡条件不同,所以其提供的 positive albel 数量也应该是不同的,如何确定每个 gt 的正样本数 k 值呢?论文提供了一个简单的方案,该方法称之为:Dynamic k Estimation,具体做法如下:

从前面的 pair_wise_ious 中,给每个真实框,挑选 10个iou 最大的预测框。因为前面假定有3个目标,因此这里topk_ious的维度为[3,10]。 其实这里就是对于每个真实框选出来的 1000 个 IOU 值中选出来十个。

image

topk_ious 计算代码如下:

ious_in_boxes_matrix = pair_wise_ious
n_candidate_k = min(10, ious_in_boxes_matrix.size(1))
topk_ious, _ = torch.topk(ious_in_boxes_matrix, n_candidate_k, dim=1)

下面通过topk_ious的信息,动态选择预测框。**dynamic_k_matching 代码如下:

dynamic_ks = torch.clamp(topk_ious.sum(1).int(), min=1)

针对每个目标框,计算所有 anchor 的 iou 值之和,再经过 torch.clamp 函数,得到最终左边的dynamic_ks值,给目标框 1 和 3 各分配 3 个候选框,给目标框 2 分配 4个候选框。

image

torch.clamp 就是把每个真实框最少分配一个目标(min=1),参考:

https://blog.csdn.net/hb_learing/article/details/115696206


step3: Sinkhorn-Knopp Iteration 求解 cost 矩阵获得 标签分配方案

有了cost 矩阵 c,supplying vector s ∈ R m + 1 s∈R^{m+1} sRm+1, demanding vector d ∈ R n d∈R^n dRn,因此可以通过现有的 Sinkhorn-Knopp Iteration [5]来求解该 OT 问题,从而得到最优运输方案 π ∗ ∈ R ( m + 1 ) × n π^∗∈R^{(m+1)×n} πR(m+1)×n

在得到 π ∗ π^∗ π 之后,将每个 anchor 分配给运送 labels 量最大的 supplier(真实框) ,从而解码出相应的标签分配方案。


step3:得到 matching_matrix(SimOTA 使用的)
for gt_idx in range(num_gt):
	_, pos_idx = torch.topk(cost[gt_idx], k=dynamic_ks[gt_idx], largest=False)
	matching_matrix[gt_idx][pos_idx] = 1

针对每个目标框挑选相应的 cost 值最低的一些候选框。比如右面的matching_matrix 中,cost值最低(largest=False)的一些位置,数值为1,其余位置都为0。

因为目标框1和3,dynamic_ks 值都为3,因此matching_matrix的第一行和第三行,有3个1。而目标框2,dynamic_ks值为4,因此matching_matrix的第二行,有4个1。

image

step4:过滤共用的候选框

这一步就是论文中所谓的考虑了全局信息的意思吧。

anchor_matching_gt = matching_matrix.sum(0)
if (anchor_matching_gt > 1).sum() > 0:
	_, cost_argmin = torch.min(cost[:, anchor_matching_gt > 1], dim=0)
	matching_matrix[:, anchor_matching_gt > 1] *= 0
	matching_matrix[cost_argmin, anchor_matching_gt > 1] = 1

matching_matrix 中第5列有两个1,这说明第5列所对应的候选框,被目标检测框1和2 都进行关联

image

因此对这两个位置,还要使用 cost值 进行对比,选择较小的值,再进一步筛选。假设第5列两个位置的值分别为0.4和0.3。

image

经过第三行代码,可以找到最小的值是0.3,即cost_min为0.3,所对应的行数,cost_argmin为2。

经过第四行代码,将matching_matrix第5列都置0。

再利用第五行代码,将matching_matrix第2行,第5列的位置变为1。

最终我们可以得到3个目标框,最合适的一些候选框,即matching_matrix中,所有1所对应的位置。

image

看来 cost 最低是这个算法的核心。并且也解决了冲突问题。太强了


OTA 和 SimOTA 区别:

从上面描述可知,OTA 和 SimOTA 都是在经过 step2:dynamic_k_estimation 后,OTA 使用的是 Sinkhorn-Knopp Iteration 求解 cost 矩阵来获得最优的标签分配结果。SimOTA 是采用定义的规则使用 torch.topk 根据 dynamic_k_estimation 得到的 k ,选择 k 个 cost 最小的值,作为分配给真实框的 候选框。

因此,SimOTA 有两个 topk :1. step2:dynamic_k_estimation 中的选择比如 10 个 topk_ious。 2. 根据动态获得的 k 选择 k 个候选框。

OTA 只有 step2:dynamic_k_estimation 中的选择比如 10 个 topk_ious。

据我目前的认识,第 4 步两者都是需要的。目前的疑问:OTA 是否需要第 5 步 去掉歧义的候选框还不太清楚。需要调试源码,但是我也不想调。

参考:

OTA的topk用来筛选candidates,是用来求dynamic k过程中使用的,最终的正样本划分有sinkhorn-knopp iter求解得到。SimOTA拿到dynamic k之后,最终正负样本划分依然是greedy的topk
https://github.com/Megvii-BaseDetection/YOLOX/issues/859

代码细节:https://blog.csdn.net/jiaoyangwm/article/details/126638775

2. OTA效果性能

(2)r 的影响

OTA方法通常用于精筛选正样本,在精筛选正样本前,可以增加一步粗筛选,有2种方式:

  • 筛选中心点落在 ground truth bbox 范围内的 anchor 作为正样本;
  • 筛选中心点落在以 ground truth bbox 中心点为中心,r为半径的区域内的anchor 作为正样本;(论文中提到的 Center Prior.中心先验)

在粗筛选的结果基础上,再使用OTA方法,可以减少运算量和提高精度。

将 r 设置成 3, 5, 7 后,得到粗筛选候选框数量分别为 45,125 和 245。将 OTAATSSPAA 方法作比较,得到2个结论:

  • 歧义 anchors 样本 ambiguous anchors(一个 anchor 可能对应多个gt)数量 N a m b N_{amb} Namb 越多,相应的 AP 会下降,说明 歧义样本 会对网络训练产生负面影响;
  • 分配到 歧义样本 的数量:ATSS > PAA > OTA;
  • 对 r 的敏感性:ATSS > PAA > OTA

上面说明 OTA 比 ATSS 和 PAA 要好!

image

(3)k 的影响

在使用 Sinkhorn-Knopp 算法前,需要知道每个 gt 需要提供多少 positive label,posivtive label 的数量就是 k ,如下比较了将 k 设置成固定值和动态值的情形,论文提出的 dynamic k 方法可有效提高 AP值。

3. 总结

OTA 论文的主要贡献包括以下几点:

  • 提出解决目标检测中的标签分配问题的新思路:当作 OT (Optimal Transport problem) 问题来处理;
  • 提出计算每个gt需要提供多少 positive label 的方法,该方法简单有效;dynamic k
  • 分析了歧义样本的影响,ambiguous anchors 会对网络训练产生负面影响,OTA方法可以有效的减少歧义样本的数量。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

理心炼丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值