【DIoU CIoU】DIoU和CIoU损失函数理解及代码实现

1 引言

目标检测任务的损失函数由Classificition Loss和Bounding Box Regeression Loss两部分构成。

Bounding Box Regression Loss Function的演进路线是:
Smooth L1 Loss --> IoU Loss --> GIoU Loss --> DIoU Loss --> CIoU Loss

之前写到了 Smooth L1 LossIoU LossGIoU Loss
本文介绍DIoU Loss 和 CIoU Loss。

2 问题分析

GIoU Loss 存在的问题:

  • 出现下图中的情况时,IoU和GIoU的值都一样,此时GIoU退化为IoU, 无法区分其相对位置关系。
    在这里插入图片描述
    在这里插入图片描述
  • 收敛的比较慢
  • 回归的还不够准确

3 作者思考

基于IoU和GIoU存在的问题,作者提出了两个问题:

  • 问题一:直接最小化预测框与目标框之间的归一化距离是否可行,以达到更快的收敛速度。
  • 问题二:如何使回归在与目标框有重叠甚至包含时更准确、更快。

好的目标框回归损失应该考虑三个重要的几何因素:重叠面积,中心点距离,长宽比

针对问题一,作者提出了DIoU Loss,相对于GIoU Loss收敛速度更快,DIoU Loss考虑了重叠面积(IoU)和中心点距离( d 2 c 2 \frac{d^{2}}{c^{2}} c2d2),但没有考虑到长宽比;

针对问题二,作者提出了CIoU Loss,其收敛的精度更高,以上三个因素都考虑到了。

4 DIoU Loss计算过程

Distance-IoU(DIoU) Loss计算过程如下:
在这里插入图片描述
图中,b表示预测框中心点坐标, b g t b^{gt} bgt表示GT框中心点坐标。 ρ 2 ( b , b g t ) ρ^2(b, b^{gt}) ρ2(b,bgt)表示两中心点的距离的平方, c 2 c^2 c2表示两矩形最小外接矩形的对角线长度的平方。

DIoU损失能直接最小化两个box之间的距离,因此收敛速度更快。

L D I o U = 1 − D I o U L_{DIoU}=1-DIoU LDIoU=1DIoU
当两个框重合时, L D I o U = 0 L_{DIoU}=0 LDIoU=0;当两个框相距无穷远时, L D I o U = 2 L_{DIoU}=2 LDIoU=2,故 0 ≤ L D I o U < 2 0≤L_{DIoU}<2 0LDIoU<2

可以将DIoU替换IoU用于NMS算法当中,也即论文提出的DIoU-NMS, 实验结果表明有一定的提升。

DIoU相比于GIoU的优点:
DIoU Loss可以直接优化2个框之间的距离,比GIoU Loss收敛速度更快
对于目标框包裹预测框的情况,DIoU Loss可以收敛的很快,而GIoU Loss此时退化为IoU Loss收敛速度较慢

5 CIoU Loss计算过程

Complete-IoU(CIoU) Loss计算过程如下:在DIoU的基础上,考虑长宽比 α v αv αv

在这里插入图片描述
其中, α α α是用于做trade-off的参数, v v v是用来衡量长宽比一致性的参数。

CIoU Loss function的定义为

L C I o U = 1 − C I o U L_{CIoU}=1-CIoU LCIoU=1CIoU

!注意!: CIoU loss的梯度类似于DIoU loss,但还要考虑 v v v的梯度。在长宽在 [0, 1] 的情况下, w 2 + h 2 w^2+h^2 w2+h2的值通常很小,会导致梯度爆炸,因此在 1 w 2 + h 2 \frac{1}{w^2+h^2} w2+h21实现时将替换成1。

6 IoU/GIoU/DIoU/CIoU代码实现可视化

import numpy as np
import cv2
import torch
import math

def CountIOU(RecA, RecB):
    xA = max(RecA[0], RecB[0])
    yA = max(RecA[1], RecB[1])
    xB = min(RecA[2], RecB[2])
    yB = min(RecA[3], RecB[3])
    # 计算交集部分面积
    interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)
    # 计算预测值和真实值的面积
    RecA_Area = (RecA[2] - RecA[0] + 1) * (RecA[3] - RecA[1] + 1)
    RecB_Area = (RecB[2] - RecB[0] + 1) * (RecB[3] - RecB[1] + 1)
    # 计算IOU
    iou = interArea / float(RecA_Area + RecB_Area - interArea)
    
    return iou

def Giou(rec1,rec2):
    # 分别是矩形左上、右下的坐标
    x1,y1,x2,y2 = rec1 
    x3,y3,x4,y4 = rec2
    iou = CountIOU(rec1,rec2)
    area_C = (max(x1,x2,x3,x4)-min(x1,x2,x3,x4))*(max(y1,y2,y3,y4)-min(y1,y2,y3,y4))
    area_1 = (x2-x1)*(y1-y2)
    area_2 = (x4-x3)*(y3-y4)
    sum_area = area_1 + area_2

    w1 = x2 - x1   #第一个矩形的宽
    w2 = x4 - x3   #第二个矩形的宽
    h1 = y1 - y2
    h2 = y3 - y4
    W = min(x1,x2,x3,x4)+w1+w2-max(x1,x2,x3,x4)    # 交叉部分的宽
    H = min(y1,y2,y3,y4)+h1+h2-max(y1,y2,y3,y4)    # 交叉部分的高
    # 交叉的面积
    Area = W * H    
    # 两矩形并集的面积
    add_area = sum_area - Area    
    # 闭包区域中不属于两个框的区域占闭包区域的比重
    end_area = (area_C - add_area)/area_C    
    giou = iou - end_area
    return giou


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

def bbox_overlaps_ciou(bboxes1, bboxes2):
    rows = bboxes1.shape[0]
    cols = bboxes2.shape[0]
    cious = torch.zeros((rows, cols))
    if rows * cols == 0:
        return cious
    exchange = False
    if bboxes1.shape[0] > bboxes2.shape[0]:
        bboxes1, bboxes2 = bboxes2, bboxes1
        cious = torch.zeros((cols, rows))
        exchange = True

    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
    u = (inter_diag) / outer_diag
    iou = inter_area / union
    with torch.no_grad():
        arctan = torch.atan(w2 / h2) - torch.atan(w1 / h1)
        v = (4 / (math.pi ** 2)) * torch.pow((torch.atan(w2 / h2) - torch.atan(w1 / h1)), 2)
        S = 1 - iou
        alpha = v / (S + v)
        w_temp = 2 * w1
    ar = (8 / (math.pi ** 2)) * arctan * ((w1 - w_temp) * h1)
    cious = iou - (u + alpha * ar)
    cious = torch.clamp(cious,min=-1.0,max = 1.0)
    if exchange:
        cious = cious.T
    return cious


img = np.zeros((512,512,3), np.uint8)   
img.fill(255)

# 分别是矩形左上、右下的坐标
RecA = [30,30,300,300]
RecB = [60,60,350,340]

cv2.rectangle(img, (RecA[0],RecA[1]), (RecA[2],RecA[3]), (0, 255, 0), 5)
cv2.rectangle(img, (RecB[0],RecB[1]), (RecB[2],RecB[3]), (255, 0, 0), 5)

IoU = CountIOU(RecA,RecB)
GIoU = Giou(RecA,RecB)
RecA_tensor,RecB_tensor = torch.tensor([RecA]), torch.tensor([RecB])
DIoU = Diou(RecA_tensor,RecB_tensor)
CIoU = bbox_overlaps_ciou(RecA_tensor,RecB_tensor)

font = cv2.FONT_HERSHEY_SIMPLEX

cv2.putText(img,"IOU = %.2f"%IoU,(130, 150),font,0.8,(0,0,0),2)
cv2.putText(img,"GIOU = %.2f"%GIoU,(130, 180),font,0.8,(0,0,0),2)
cv2.putText(img,"DIOU = %.2f"%DIoU,(130, 210),font,0.8,(0,0,0),2)
cv2.putText(img,"CIOU = %.2f"%CIoU,(130, 240),font,0.8,(0,0,0),2)

cv2.imshow("image",img)
cv2.waitKey()
cv2.destroyAllWindows()

结果输出:
在这里插入图片描述

7 感谢链接

DIoU和CIOU用于目标检测与实例分割,作者已开源,可参考:

https://github.com/Zzh-tju?tab=repositories

其它感谢链接:

https://zhuanlan.zhihu.com/p/94799295
https://zhuanlan.zhihu.com/p/104236411
https://www.bilibili.com/video/BV1yi4y1g7ro?p=4
<think>嗯,我现在需要了解CIoU损失函数的概念、公式及其实现方法,还有它在深度学习中的用途。首先,我应该回忆一下之前学过的相关损失函数,比如IoU、GIoU、DIoU这些,这样有助于理解CIoU的改进之处。 根据引用[3],CIoU的全称是Complete IoU loss,它是在DIoU的基础上提出的。而DIoU解决了GIoU收敛速度的问题,但可能没有考虑高宽比。CIoU同时考虑重叠面积、中心点距离高宽比这三个几何因素。所以,CIoU应该是在DIoU的基础上增加了高宽比的惩罚项。 接下来,我需要找到CIoU的公式。根据引用[3]提到的,CIoU损失函数应该包含三个部分:重叠面积、中心点距离高宽比。假设损失函数的形式可能是L = 1 - IoU + 距离项 + 高宽比项。比如DIoU的公式是L_{DIoU} = 1 - IoU + (ρ²(b, b^gt))/(c²),其中ρ是中心点之间的欧氏距离,c是最小包围框的对角线长度。那么CIoU可能在此基础上加上一个关于高宽比的项,比如α*v,其中v是衡量高宽比一致性的参数,α是权重系数。 然后,实现方法方面,CIoU需要计算这些额外的项。在代码中,可能需要计算预测框真实框的中心点距离,找到最小包围框的对角线长度,计算高宽比的差异。比如在PyTorch中,可以分别用坐标计算出中心点坐标,计算欧氏距离,然后计算高宽比的参数v,最后整合到损失函数中。 用途方面,CIoU主要用于目标检测任务中的边界框回归,尤其是在需要更精准的框位置时,比如YOLO系列、Faster R-CNN等模型。它能够提高边界框的预测精度,因为综合考虑了多个几何因素,使得模型在训练时能更快收敛,并且预测框更贴合真实物体。 不过,我需要确认一下具体的公式参数。比如,高宽比的项v具体是怎么计算的?根据论文,v可能是一个关于预测框真实框高宽比相似度的函数。例如,v = (4/π²)(arctan(w^gt/h^gt) - arctan(w/h))²,然后用这个v乘以一个系数α。而α可能是v/(1 - IoU + v),或者其他形式。 另外,在实现时需要注意梯度计算是否正确,避免出现数值不稳定的情况。例如,当高或宽趋近于零时,如何处理。可能需要加入小的epsilon值来防止除以零的情况。 最后,总结一下,CIoU的公式应该包含IoU项、中心点距离项高宽比项,其具体实现需要计算这些部分,并组合成最终的损失值。在目标检测中应用CIoU可以提升检测框的准确性,特别是在处理不同形状的物体时效果更好。</think>### CIoU损失函数详解 #### 1. 概念解析 CIoU(Complete Intersection over Union)损失函数目标检测中用于边界框回归的优化指标,在DIoU基础上引入**高宽比惩罚项**,形成三要素协同优化的损失函数: - **重叠面积**(IoU):衡量预测框与真实框的重叠比例 - **中心点距离**:计算两个框中心点的欧式距离 - **高宽比一致性**:通过角度差异评估宽高比例匹配程度 #### 2. 数学公式 CIoU损失函数定义为: $$ \mathcal{L}_{CIoU} = 1 - IoU + \frac{\rho^2(b,b^{gt})}{c^2} + \alpha v $$ 其中: - $\rho$:预测框与真实框中心点的欧氏距离 - $c$:最小包围框对角线长度 - $v = \frac{4}{\pi^2}\left( \arctan\frac{w^{gt}}{h^{gt}} - \arctan\frac{w}{h} \right)^2$ 衡量宽高比差异 - $\alpha = \frac{v}{(1-IoU)+v}$ 自适应权重系数 #### 3. 实现方法(PyTorch示例) ```python def CIoU_loss(pred, target): # 计算交集坐标 inter_ul = torch.max(pred[:, :2], target[:, :2]) inter_br = torch.min(pred[:, 2:], target[:, 2:]) # 计算IoU inter_area = torch.prod(inter_br - inter_ul, dim=1) * (inter_br > inter_ul).all(dim=1).float() area_pred = torch.prod(pred[:, 2:] - pred[:, :2], dim=1) area_target = torch.prod(target[:, 2:] - target[:, :2], dim=1) union = area_pred + area_target - inter_area + 1e-16 iou = inter_area / union # 中心点距离 center_pred = (pred[:, :2] + pred[:, 2:])/2 center_target = (target[:, :2] + target[:, 2:])/2 center_distance = torch.sum((center_pred - center_target)**2, dim=1) # 最小包围框对角线 enclose_ul = torch.min(pred[:, :2], target[:, :2]) enclose_br = torch.max(pred[:, 2:], target[:, 2:]) c_distance = torch.sum((enclose_br - enclose_ul)**2, dim=1) # 宽高比惩罚项 w_pred = pred[:, 2] - pred[:, 0] h_pred = pred[:, 3] - pred[:, 1] w_target = target[:, 2] - target[:, 0] h_target = target[:, 3] - target[:, 1] v = (4/(math.pi**2)) * torch.pow(torch.atan(w_target/h_target) - torch.atan(w_pred/h_pred), 2) alpha = v / (1 - iou + v + 1e-16) return 1 - iou + center_distance/c_distance + alpha*v ``` #### 4. 核心优势 1. **快速收敛**:相比IoU、GIoU,中心点距离项加速训练收敛[^3] 2. **形状适应**:高宽比惩罚项提升不规则形状物体的检测精度 3. **三要素平衡**:同时优化定位的三个关键几何因素 #### 5. 应用场景 - **密集物体检测**:人群计数、车辆检测等场景 - **小目标检测**:无人机航拍图像分析 - **旋转物体检测**:遥感图像中的倾斜目标识别
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值