VarifocalNet:交并比感知的密集目标检测器.
本文指出目前目标检测最大瓶颈依然是分类分支和回归分支分值不一致问题,为此作者提出了两个改进:
- 提出了正负样本不对称加权的 Varifocal Loss
- 提出星型bbox特征提取refine网络,对输出初始bbox进行refine
作者对ATSS的推理过程进行了详细分析:
- 在没有centerness分支时map是38.5,训练时候加入centerness即w/ctr(标准结构)从而得到39.2。
- gt_ctr是指在baseline基础上,测试时把centerness分支替换为对应label值,可以发现map仅仅提高到41.1。说明centerness的作用其实非常不明显,引入这个额外分支无法完全解决分类和回归分支不一致性问题。
- 如果将centerness分支的输出变成预测bbox和gt bbox的iou值(gt_ctr_iou),此时map是43.5。
- 把预测bbox回归分支值全部替换为真实gt bbox,map没有很大改变。说明影响mAP性能的主要因素不是bbox预测不准确,centerness的作用非常微弱。
- 将分类分支的输出对应真实类别设置为1,也就是类别预测完全正确(gt_cls),此时map是43.1,加入centerness后提升到58.1,说明在类别预测完全正确的情况下,centerness可以在一定程度上区分准确和不准确的边界框。
- 如果把分类分值的输出中对应真实类别设置为预测bbox和真实bbox的iou(gt_cls_iou),即使不用centernss也可以达到74.7,说明目前的目标检测bbox分支输出的密集bbox中存在非常精确的预测框,关键是没有好的预测分值来选择出来。
通过上述分析,可以总结下:
- centernss作用还不如iou分支
- 单独引入一条centernss或者iou分支,作用非常有限
- 目前目标检测性能瓶颈不在于bbox预测不准确,而在于没有一致性极强的分值排序策略选择出对应bbox
- 将iou感知功能压缩到分类分支中是最合适的,理论mAP上限最高。
1. varifocal Loss
广义focal loss将focal loss只能支持离散label的限制推广到了连续label,并且强制将分类分支对应类别处的预测值变成了bbox预测准确度。
\[QFL(p) = -|y-p|^\beta \left( y\log p + (1-y) \log(1-p) \right)\]其中$y$为$0$~$1$的质量标签,来自预测的bbox和gt bbox的iou值,注意如果是负样本,则$y$直接等于$0$;$p$是分类分支经过sigmoid后的预测值。
focal loss和Generalized Focal Loss都是对称的。Varifocal Loss主要改进是提出了非对称的加权操作,在正样本中也存在不等权问题,突出正样本的主样本:
\[VFL(p) = \begin{cases} -y \left( y\log p + (1-y) \log(1-p) \right) & y > 0 \\ -\alpha p^\gamma \log(1-p) & y = 0 \end{cases}\]正样本时没有采用focal loss,而是普通的bce loss,只不过多了一个自适应iou加权,用于突出主样本。而为负样本时是标准的focal loss。
def varifocal_loss(pred, target, alpha=0.75, gamma=2.0, iou_weighted=True):
"""
pred (torch.Tensor): 预测的分类分数,形状为 (B,N,C) , N 表示 anchor 数量, C 表示类别数
target (torch.Tensor): 经过对齐度归一化后的 IoU 分数,形状为 (B,N,C),数值范围为 0~1
alpha (float, optional): 调节正负样本之间的平衡因子,默认 0.75.
gamma (float, optional): 负样本 focal 权重因子, 默认 2.0.
iou_weighted (bool, optional): 正样本是否用 IoU 加权
"""
pred_sigmoid = pred.sigmoid()
target = target.type_as(pred)
if iou_weighted:
# 计算权重,正样本(target > 0)中权重为 target,
# 负样本权重为 alpha*pred_simogid^2
focal_weight = target * (target > 0.0).float() + \
alpha * (pred_sigmoid - target).abs().pow(gamma) * \
(target <= 0.0).float()
else:
focal_weight = (target > 0.0).float() + \
alpha * (pred_sigmoid - target).abs().pow(gamma) * \
(target <= 0.0).float()
# 计算二值交叉熵后乘以权重
loss = F.binary_cross_entropy_with_logits(
pred, target, reduction='none') * focal_weight
loss = weight_reduce_loss(loss, weight, reduction, avg_factor)
return loss
2. bbox refinement
本文还提出bbox refinement进一步提高性能。其整个网络结构如下:
bbox refinement的基本流程是:
- 任何一个head,对分类和回归分支特征图堆叠一系列卷积,输出通道全部统一为$256$
- 对回归分支特征图进行回归预测,得到初始bbox预测值,输出通道是$4$,代表lrtb预测值,然后对预测值进行还原得到原图尺度的lrtb值
- 利用lrtb预测值对每个特征图上面点生成$9$个offset坐标:$(x, y), (x-l’, y), (x, y-t’), (x+r’, y), (x, y+b’), (x-l’, y-t’),(x+l’, y-t’), (x-l’, y+b’)$ 和 $(x+r’, y+b’)$
- 将offset作为变形卷积的offset输入,然后进行可变形卷积操作,此时每个点的特征感受野就可以和初始时刻预测值重合,也就是常说的特征对齐操作,此时得到refine后的bbox预测输出值$\Delta l,\Delta r,\Delta t,\Delta b$,将该refine输出值和初始预测值相乘即可得到refine后的真实bbox值
- 对分类分支也是同样处理,加强分类和回归分支一致性