发布时间:2025-12-10 11:24:48 浏览次数:7
本文参考:
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 值的候选框作为正样本。
为了便于理解,我们假设:
bboxes_preds_per_image 是候选检测框的信息,维度是[1000,4]。预测框的四个坐标。
obj_preds 是目标分数(object score),维度是 [1000,1]。预测框是前景还是背景。
cls_preds 是类别分数,维度是 [1000,2]。预测框的2个检测类别的one-hot。
训练网络需要知道这 1000个预测框的标签,而如何分配标签呢?
使用OTA方法,分为4步,具体做法如下:
OTA 方法分配标签是基于 cost 的,因为有 3个目标框和1000个预测框,所以需要生成 3 × 1000 的 cost matrix(也就是每个真实框都要和1000个预测框计算下 cost)。
那么 cost 怎么计算?
对于目标检测任务,cost 由定位损失和分类损失组成,计算方法如下:
计算 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)通过第一行代码,将类别的条件概率(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 计算公式如下:
Cij=Lijcls+λLijregC_{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)每个 gt 提供多少正样本,可以理解为“ 这个 gt 需要多少个正样本才能让网络更好的训练收敛 ”。
直觉上,每个 gt 的大小、尺度和遮挡条件不同,所以其提供的 positive albel 数量也应该是不同的,如何确定每个 gt 的正样本数 k 值呢?论文提供了一个简单的方案,该方法称之为:Dynamic k Estimation,具体做法如下:
从前面的 pair_wise_ious 中,给每个真实框,挑选 10个iou 最大的预测框。因为前面假定有3个目标,因此这里topk_ious的维度为[3,10]。 其实这里就是对于每个真实框选出来的 1000 个 IOU 值中选出来十个。
topk_ious 计算代码如下:
ious_in_boxes_matrix = pair_wise_iousn_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个候选框。
torch.clamp 就是把每个真实框最少分配一个目标(min=1),参考:
https://blog.csdn.net/hb_learing/article/details/115696206
有了cost 矩阵 c,supplying vector s∈Rm+1s∈R^{m+1}s∈Rm+1, demanding vector d∈Rnd∈R^nd∈Rn,因此可以通过现有的 Sinkhorn-Knopp Iteration [5]来求解该 OT 问题,从而得到最优运输方案 π∗∈R(m+1)×nπ^∗∈R^{(m+1)×n}π∗∈R(m+1)×n。
在得到 π∗π^∗π∗ 之后,将每个 anchor 分配给运送 labels 量最大的 supplier(真实框) ,从而解码出相应的标签分配方案。
针对每个目标框挑选相应的 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。
这一步就是论文中所谓的考虑了全局信息的意思吧。
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] *= 0matching_matrix[cost_argmin, anchor_matching_gt > 1] = 1matching_matrix 中第5列有两个1,这说明第5列所对应的候选框,被目标检测框1和2 都进行关联。
因此对这两个位置,还要使用 cost值 进行对比,选择较小的值,再进一步筛选。假设第5列两个位置的值分别为0.4和0.3。
经过第三行代码,可以找到最小的值是0.3,即cost_min为0.3,所对应的行数,cost_argmin为2。
经过第四行代码,将matching_matrix第5列都置0。
再利用第五行代码,将matching_matrix第2行,第5列的位置变为1。
最终我们可以得到3个目标框,最合适的一些候选框,即matching_matrix中,所有1所对应的位置。
看来 cost 最低是这个算法的核心。并且也解决了冲突问题。太强了
从上面描述可知,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
OTA方法通常用于精筛选正样本,在精筛选正样本前,可以增加一步粗筛选,有2种方式:
在粗筛选的结果基础上,再使用OTA方法,可以减少运算量和提高精度。
将 r 设置成 3, 5, 7 后,得到粗筛选候选框数量分别为 45,125 和 245。将 OTA 和 ATSS 、PAA 方法作比较,得到2个结论:
上面说明 OTA 比 ATSS 和 PAA 要好!
在使用 Sinkhorn-Knopp 算法前,需要知道每个 gt 需要提供多少 positive label,posivtive label 的数量就是 k ,如下比较了将 k 设置成固定值和动态值的情形,论文提出的 dynamic k 方法可有效提高 AP值。
OTA 论文的主要贡献包括以下几点: