前言:本篇论文是属于对IOU/GIOU Loss的一个改进,IOU的计算在目标检测里面是一个非常重要的概念,将IOU引入到目标框的回归当中,也是一个常用的操作。而本文提出的DIOU是一种比GIOU更加符合目标框回归的机制,将目标与anchor之间的距离,重叠率以及尺度都考虑进去,使得目标框回归变得更加稳定,不会像IOU和GIOU一样出现训练过程中发散等问题。 一、IOU和GIOU回顾 IoU损失可以表示为: IoU的缺点是当两个框不想相交时,IoU损失总是1,不能给出优化方向。 GIoU损失可以表示为: 可以看到,GIoU在IoU的基础上添加了一个项,其中C表示包含两个框的最小矩形,因此可以优化两个框不相交的情况。不过,GIoU也存在着问题。当两个框相交时,GioU损失退化为IoU损失。因此,当包含预测框bbox和地面真值bbox时,特别是在水平和垂直方向上,很难进行优化。这里的一个猜想是,在水平方向和垂直方向上,损失的值没有在其他方向上增长得快,因此对这两个方向的惩罚不够,导致收敛速度减慢。如下图所示: 在上图的情况下,GIoU损耗退化为IoU损耗,而提出DIoU损耗仍然可以区分。 绿色和红色分别表示目标框和预测框。 二、作者对Iou和GIoU的实验分析 作者通从实验结果的角度说明了IoU和GIoU存在的问题。实验设定如下图所示,
最终的实验结果如下:图中展示的训练同样的代数后(200代),三个loss最终每个anchor的误差分布
上图进一步解释了GIoU不稳定以及收敛很慢的原因。上图中第一行是不同次数的迭代后,anchor的偏移结果。第二行是DIoU的回归过程,其中绿色框为目标框,黑色框为anchor,红色框为不同次数的迭代后,anchor的偏移结果。 从图中可以看到,GIoU在回归的过程中,从损失函数的形式我们发现,当IoU为0时,GIoU会先尽可能让anchor能够和目标框产生重叠,之后GIoU会渐渐退化成IoU回归策略,因此整个过程会非常缓慢而且存在发散的风险。而DIoU考虑到anchor和目标之间的中心点距离,可以更快更有效更稳定的进行回归。 三、作者的思考 基于GIoU存在的问题,作者提出了两个问题:
四、DIoU的提出——第一个问题 DIoU的定义: 上述损失函数中,b,bgt分别代表了anchor框和目标框的中心点,且p代表的是计算两个中心点间的欧式距离。c代表的是能够同时覆盖anchor和目标框的最小矩形的对角线距离。因此DIoU中对anchor框和目标框之间的归一化距离进行了建模。直观的展示如下图所示。 DIoU的优点如下: 1.与GIoU loss类似,DIoU loss在与目标框不重叠时,仍然可以为边界框提供移动方向。 2.DIoU loss可以直接最小化两个目标框的距离,因此比GIoU loss收敛快得多。 3.对于包含两个框在水平方向和垂直方向上这种情况,DIoU损失可以使回归非常快,而GIoU损失几乎退化为IoU损失。 五、CIoU的提出——第二个问题 一个好的目标框回归损失应该考虑三个重要的几何因素:重叠面积、中心点距离、长宽比。
anchor框和目标框之间的长宽比的一致性也是极其重要的。基于此,作者提出了Complete-IoU Loss。 上述损失函数中,CIoU比DIoU多出了α和v这两个参数。其中α是用于平衡比例的参数。v用来衡量anchor框和目标框之间的比例一致性。 从的定义式来看,损失函数会更加倾向于往重叠区域增多的方向优化,尤其是IoU为0的情况,这满足我们的要求。同时,在进行nms阶段,一般的评判标准是IOU,这个地方作者推荐替换为DIOU,这样考虑了中心点距离这一个信息,效果又有一定的提升。 DIoU Loss的优点:
SSD的DIoU计算,可惜是pytorch: def Diou(bboxes1, bboxes2): rows = bboxes1.shape[0] cols = bboxes2.shape[0] dious = torch.zeros((rows, cols)) if rows * cols == 0:# return dious exchange = False if bboxes1.shape[0] > bboxes2.shape[0]: bboxes1, bboxes2 = bboxes2, bboxes1 dious = torch.zeros((cols, rows)) exchange = True # #xmin,ymin,xmax,ymax->[:,0],[:,1],[:,2],[:,3] w1 = bboxes1[:, 2] - bboxes1[:, 0] h1 = bboxes1[:, 3] - bboxes1[:, 1] w2 = bboxes2[:, 2] - bboxes2[:, 0] h2 = bboxes2[:, 3] - bboxes2[:, 1] area1 = w1 * h1 area2 = w2 * h2 center_x1 = (bboxes1[:, 2] + bboxes1[:, 0]) / 2 center_y1 = (bboxes1[:, 3] + bboxes1[:, 1]) / 2 center_x2 = (bboxes2[:, 2] + bboxes2[:, 0]) / 2 center_y2 = (bboxes2[:, 3] + bboxes2[:, 1]) / 2 inter_max_xy = torch.min(bboxes1[:, 2:],bboxes2[:, 2:]) inter_min_xy = torch.max(bboxes1[:, :2],bboxes2[:, :2]) out_max_xy = torch.max(bboxes1[:, 2:],bboxes2[:, 2:]) out_min_xy = torch.min(bboxes1[:, :2],bboxes2[:, :2]) inter = torch.clamp((inter_max_xy - inter_min_xy), min=0) inter_area = inter[:, 0] * inter[:, 1] inter_diag = (center_x2 - center_x1)**2 + (center_y2 - center_y1)**2 outer = torch.clamp((out_max_xy - out_min_xy), min=0) outer_diag = (outer[:, 0] ** 2) + (outer[:, 1] ** 2) union = area1+area2-inter_area dious = inter_area / union - (inter_diag) / outer_diag dious = torch.clamp(dious,min=-1.0,max = 1.0) if exchange: dious = dious.T return dious |
|
来自: taotao_2016 > 《计算机》