IOU、GIOU、DIOU、CIOU详解及代码实现

人工智能104

一、IOU Loss
旷视在2016文章《UnitBox: An Advanced Object Detection Network》中提出了IOU Loss将4个点构成的box看成一个整体做回归。

文章链接:https://arxiv.org/pdf/1608.01471.pdf
1. 函数特性

IOU Loss的定义是先求出预测框和真实框之间的交集和并集之比,再求负对数,但是在实际使用中我们常常将IOU Loss写成1-IOU。如果两个框重合则交并比等于1,Loss为0说明重合度非常高。IOU满足非负性、同一性、对称性、三角不等性,相比于L1/L2等损失函数还具有尺度不变性,不论box的尺度大小,输出的iou损失总是在0-1之间。所以能够较好的反映预测框与真实框的检测效果。
IOU、GIOU、DIOU、CIOU详解及代码实现
IOU、GIOU、DIOU、CIOU详解及代码实现
伪代码如下:
IOU、GIOU、DIOU、CIOU详解及代码实现
IOU的优缺点
普通IOU的优缺点很明显,优点:
1、IOU具有尺度不变性
2、满足非负性
同时,由于IOU并没有考虑框之间的距离,所以它的作为loss函数的时候也有相应的缺点:
1、在A框与B框不重合的时候IOU为0,不能正确反映两者的距离大小。
IOU、GIOU、DIOU、CIOU详解及代码实现

2、IoU无法精确的反映两者的重合度大小。如下图所示,三种情况IOU都相等,但看得出来他们的重合度是不一样的,左边的图回归的效果最好,右边的最差。
IOU、GIOU、DIOU、CIOU详解及代码实现
普通IOU是对两个框的距离不敏感的,如缺点一中的两个图图中,左图预测框的坐标要比右图预测框的坐标更接近真实框。但两者的IOU皆为0,如果直接把IOU当作loss函数进行优化,则loss=0,没有梯度回传,所以无法进行训练。
针对IOU的上述缺点GIOU应运而生
二、GIOU Loss
GIOU是为克服IOU的缺点同时充分利用优点而提出的.(论文:Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression)
IOU、GIOU、DIOU、CIOU详解及代码实现
GIOU公式如下:
IOU、GIOU、DIOU、CIOU详解及代码实现

计算过程如下:
1.假设A为预测框,B为真实框,S是所有框的集合
2.不管A与B是否相交,C是包含A与B的最小框(包含A与B的最小凸闭合框),C也属于S集合
3.首先计算IoU,A与B的交并比
4.再计算C框中没有A与B的面积,比上C框面积;
5.IoU减去前面算出的比;得到GIoU
过程图示如下所示:
IOU、GIOU、DIOU、CIOU详解及代码实现
当IOU为0时,意味着A与B非常远时,A ∪ B / C A ∪ B /C A ∪B /C无限接近于0,GIOU趋近于-1,同理当IOU为1时,两框重合,A ∪ B / C A ∪ B /C A ∪B /C为1。所以GIOU的取值为(-1, 1]。
GIOU作为loss函数时,为$L = 1 − G I O U $ ,当A、B两框不相交时A ∪ B A ∪ B A ∪B值不变,最大化G I O U 就是就小化C,这样就会促使两个框不断靠近。
尽管GIoU解决了在IoU作为损失函数时梯度无法计算的问题,且加入了最小外包框作为惩罚项。但是它任然存在一些问题。下图第一行的三张图片是GIoU迭代时预测框收敛情况。其中黑色框代表anchor,蓝色框代表预测框,绿色框代表真实框。
IOU、GIOU、DIOU、CIOU详解及代码实现
上图中可以看出,GIoU在开始的时候需要将检测结果方法使其与目标框相交,之后才开始缩小检测结果与GT重合,这就带来了需要较多的迭代次数才能收敛问题,特别是对于水平与垂直框的情况下。此外,其在一个框包含另一个框的情况下,GIoU降退化成IoU,无法评价好坏,见下图所示:
IOU、GIOU、DIOU、CIOU详解及代码实现
对此,DIOU又被提出
三、DIOU Loss
论文如下:
https://arxiv.org/pdf/1911.08287.pdf
计算公式如下:
IOU、GIOU、DIOU、CIOU详解及代码实现
式中d = ρ ( A , B ) d = \rho(A, B)d=ρ(A,B)是A框与B框中心点坐标的欧式距离,而c cc则是包住它们的最小方框的对角线距离。
IOU、GIOU、DIOU、CIOU详解及代码实现
完整的DIoU Loss定义如下:
IOU、GIOU、DIOU、CIOU详解及代码实现
其优点如下:
1、DIoU的惩罚项是基于中心点的距离和对角线距离的比值,避免了像GIoU在两框距离较远时,产生较大的外包框,Loss值较大难以优化(因为它的惩罚项是A ∪ B比上最小外包框的面积)。所以DIoU Loss收敛速度会比GIoU Loss快。
2、即使在一个框包含另一个框的情况下,c值不变,但d值也可以进行有效度量。
3、与GIoU loss类似,DIoU loss在与目标框不重叠时,仍然可以为边界框提供移动方向。
4、DIoU loss可以直接最小化两个目标框的距离,而GIOU loss优化的是两个目标框之间的面积,因此比GIoU loss收敛快得多。
5、对于包含两个框在水平方向和垂直方向上这种情况,DIoU损失可以使回归非常快,而GIoU损失几乎退化为IoU损失
一个好的目标框回归损失应该考虑三个重要的几何因素:重叠面积、中心点距离、长宽比。
GIoU:为了归一化坐标尺度,利用IoU,并初步解决IoU为零的情况。
DIoU:DIoU损失同时考虑了边界框的重叠面积和中心点距离。
然而,anchor框和目标框之间的长宽比的一致性也是极其重要的。基于此,论文作者提出了Complete-IoU Loss。
四、CIOU Loss
同时DIoU的作者考虑到,在两个框中心点重合时,c与d的值都不变。所以此时需要引入框的宽高比:
IOU、GIOU、DIOU、CIOU详解及代码实现
其中alpha是权重函数,v 用来度量宽高比的一致性:
IOU、GIOU、DIOU、CIOU详解及代码实现
最终CIoU Loss定义为:
IOU、GIOU、DIOU、CIOU详解及代码实现
YOLOv5中的代码实现:

def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-7):
    """在ComputeLoss的__call__函数中调用计算回归损失
    :params box1: 预测框
    :params box2: 预测框
    :return box1和box2的IoU/GIoU/DIoU/CIoU
"""
    box2 = box2.T

    if x1y1x2y2:
        b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
        b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
    else:
        b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2
        b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2
        b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2
        b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2

    inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
            (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)

    w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
    w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
    union = w1 * h1 + w2 * h2 - inter + eps

    iou = inter / union
    if GIoU or DIoU or CIoU:
        cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1)
        ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1)
        if CIoU or DIoU:
            c2 = cw ** 2 + ch ** 2 + eps
            rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 +
                    (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4
            if DIoU:
                return iou - rho2 / c2
            elif CIoU:
                v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)
                with torch.no_grad():
                    alpha = v / (v - iou + (1 + eps))
                return iou - (rho2 / c2 + v * alpha)
        else:
            c_area = cw * ch + eps
            return iou - (c_area - union) / c_area
    else:
        return iou

Original: https://blog.csdn.net/qq_52302919/article/details/122482345
Author: 小小小~
Title: IOU、GIOU、DIOU、CIOU详解及代码实现