【源头活水】YOLOX解读与感想
“问渠那得清如许,为有源头活水来”,通过前沿领域知识的学习,从其他研究领域得到启发,对研究问题的本质有更清晰的认识和理解,是自我提高的不竭源泉。为此,我们特别精选论文阅读笔记,开辟“源头活水”专栏,帮助你广泛而深入的阅读科研文献,敬请关注。
01
最近一段时间yolox在各公众号平台被刷屏,文章刚发出来的时候粗略的看了一样感觉并没有像公众号里面说的那么惊艳,后面认真读了一下论文和代码感觉还是没像公众号说的那样吊打一切yolo。不过yolox的代码我还是很喜欢的,层次结构很清楚,比yolo5的代码读起来要舒服不少。yolox主要提出解耦Head、anchor-free和SimOTA,下面会具体分析。
02
从图1可以看出yolox各系列确实比yolo5精确要高出一点(也就是各公众号平台吊打一切yolo的数据来源),但是仔细看图2可以看出yolox的参数量和浮点计算量都比yolo5各系列高出一些,所以这样对比貌似不太公平的样子。再来看看图3,这个yolo5 github上的试验结果,可以看出最新的p6系列精度有了较大的提升,(开始我以以yolo5m6与yolox-m对比,这个地方不严谨,经评论区里面提醒这是在640输入下的flops,1280下flops应该是差不多4倍。期待yolox的P6结构出来)
03
解耦Head这个比较常见,比如RetinaNet和SSD等都有两个分支(分类和回归),主要认为分类的特征与回归的特征不太一样,分类更细腻一些回归特征则更多是一些轮廓边界特征。如果放在一起反向传播的时候可能会导致网络收敛速度慢,精度降低。我以前在用yolo做人脸检测的时候尝试过把检测跟分类分两个分支,收敛速度确实加快了,在fddb的精度也提高了一点点,但是我怀疑这个精度提升是我split的后面又加了几个卷积有关,毕竟计算量增加了。
04
yolox把原来的yolo的anchor-base框架改成了anchor-free框架,这种改进其实很早就有论文提出了,FASF在anchor-base的基础上添加anchor-free的分支,anchor-base与anchor-free联合训练与inference,如图5所示。yolox相当于放弃了anchor-base的部分仅用anchor-free部分,如果加上anchor-base的部分联合训练我相信精度还会再提升一些,哪怕inference的时候把anchor-base部分去掉,相当于anchor-base部分当成一个辅助loss部分,这样精度因该也会提升一些,至少误检会少一些。我在人脸检测的时候通常会加一个人脸关键点回归的分支来辅助检测,这样检测结果通常会稍好一点。
05
我觉得这篇文章还是这一部分有含金量一些,当然这一部分是在他自家OTA基础上做优化,省掉Sinkhorn-Knopp迭代求解过程,减小训练时间。说起SimOTA 必须要了解OTA,我又去把这篇文章认真读了一遍。OTA解决的是anchor assignment,通常我们在分配正负样本的时候是根据anchor与gt的iou来进行分配,作为认为目标在不同大小、形状和遮挡条件下正负样本的分界面应该也不一样,同时正负样本的分配也需要考虑上下文信息,所以把anchor assignment当成一个线性规划问题中的Optimal Transport问题来处理,核心思想就是建立一个代价矩阵,假设我有M个gt与N个anchor,那么代价矩阵的大小就是 ,矩阵中的每个元素就是该gt与anchor的代价(一般是loss值),loss越大则说明选取这对gt和anchor的代价越大,op的目的是去选取gt与anchor的匹配对,使得总体代价最小。这里有篇外文博客介绍OP问题挺详细的,如果有疑惑可以参考:
https://michielstock.github.io/posts/2017/2017-11-5-OptimalTransport/
fg_mask, is_in_boxes_and_center = self.get_in_boxes_info(
gt_bboxes_per_image,
expanded_strides,
x_shifts,
y_shifts,
total_num_anchors,
num_gt,
)
cost = (
pair_wise_cls_loss
+ 3.0 * pair_wise_ious_loss
+ 100000.0 * (~is_in_boxes_and_center)
)
3. dynamic_k_matching
def dynamic_k_matching(self, cost, pair_wise_ious, gt_classes, num_gt, fg_mask):
# Dynamic K
# ---------------------------------------------------------------
matching_matrix = torch.zeros_like(cost)
ious_in_boxes_matrix = pair_wise_ious
n_candidate_k = 10
topk_ious, _ = torch.topk(ious_in_boxes_matrix, n_candidate_k, dim=1)
dynamic_ks = torch.clamp(topk_ious.sum(1).int(), min=1)
for gt_idx in range(num_gt):
_, pos_idx = torch.topk(
cost[gt_idx], k=dynamic_ks[gt_idx].item(), largest=False
)
matching_matrix[gt_idx][pos_idx] = 1.0
del topk_ious, dynamic_ks, pos_idx
anchor_matching_gt = matching_matrix.sum(0)
a = anchor_matching_gt.sum()
aa = cost[:, anchor_matching_gt == 1]
if (anchor_matching_gt > 1).sum() > 0:
cost_min, cost_argmin = torch.min(cost[:, anchor_matching_gt > 1], dim=0)
matching_matrix[:, anchor_matching_gt > 1] *= 0.0
matching_matrix[cost_argmin, anchor_matching_gt > 1] = 1.0
fg_mask_inboxes = matching_matrix.sum(0) > 0.0
num_fg = fg_mask_inboxes.sum().item()
fg_mask[fg_mask.clone()] = fg_mask_inboxes
matched_gt_inds = matching_matrix[:, fg_mask_inboxes].argmax(0)
gt_matched_classes = gt_classes[matched_gt_inds]
pred_ious_this_matching = (matching_matrix * pair_wise_ious).sum(0)[
fg_mask_inboxes
]
return num_fg, gt_matched_classes, pred_ious_this_matching, matched_gt_inds
06
本文目的在于学术交流,并不代表本公众号赞同其观点或对其内容真实性负责,版权归原作者所有,如有侵权请告知删除。
“源头活水”历史文章
ICCV‘21论文:通过概率建模深度检测目标的主动学习法
Few-shot 医学图像分割
当源任务和目标任务之间的相似度很低时,如何实现知识迁移?
联合检索和记忆块的多action的Dialog Policy Learning模型
ICCV‘21论文:自动驾驶中看不见车辆的安全-觉察运动预测
源码解析GraphSAGE原理与面试题汇总
Copying Mechanism缓解未登录词问题的模型--CopyNet
旋转目标检测方法解读(KLD, NeurIPS2021)
NeurIPS-2021 | 图像未必值16x16词:可变序列长度的动态视觉Transformer来了
单目3D物体检测——基于不确定度的几何投影模型
ICCV-2021 Oral | AdaFocus:利用空间冗余性实现高效视频识别
CoSTA:用于空间转录组分析的无监督卷积神经网络学习方法
CARE-GNN论文理解
结构重参数化:利用参数转换解耦训练和推理结构
CodeVIO:紧耦合神经网络与视觉惯导里程计的稠密深度重建
更多源头活水专栏文章,
请点击文章底部“阅读原文”查看
分享、在看,给个三连击呗!