一、背景
- 目标检测和实例分割中的关键问题:
- 现有的大多数边界框回归损失函数在不同的预测结果下可能具有相同的值,这降低了边界框回归的收敛速度和准确性。
- 现有损失函数的不足:
- 现有的基于 ℓ n \ell_n ℓn范数的损失函数简单但对各种尺度敏感。
- 当预测框与真实框具有相同的宽高比但不同的宽度和高度值时,现有损失函数可能会存在问题,限制了收敛速度和准确性。
文章目录
MPDIoU(Intersection over Union with Minimum Points Distance)
是一种用于高效且准确的边界框回归的损失函数。
二、原理
2.1 IoU计算原理
IoU(Intersection over Union)
即交并比,用于衡量预测边界框和真实边界框的重合程度。
1. 交集计算:
- 首先确定预测边界框和真实边界框的交集区域。
- 对于两个以左上角和右下角坐标表示的矩形框,分别找出它们在横坐标和纵坐标方向上的重叠区间。
- 如果两个矩形框在横坐标和纵坐标方向上都有重叠部分,那么这个重叠区域就是一个矩形,其面积就是交集的大小。
2. 并集计算:
- 计算预测边界框和真实边界框的并集区域。
- 并集的大小等于两个矩形框各自的面积之和减去它们的交集面积。
3. 比值计算:
- 最后,IoU的值就是交集面积与并集面积的比值。
2.2. 基于最小点距离的IoU度量
- 原论文中受水平矩形的几何特性启发,设计了一种基于最小点距离的新型
IoU
度量MPDIoU
,直接最小化预测边界框和真实边界框的左上角和右下角点之间的距离。 MPDIoU
的计算通过两个任意凸形状 A A A和 B B B,用其左上角和右下角点的坐标来表示,通过计算两个框的交集与并集之比,再减去左上角和右下角两点距离的归一化值来得到MPDIoU
。
2.3. 作为边界框回归损失函数
- 在训练阶段,通过最小化基于
MPDIoU
的损失函数 L M P D I o U = 1 − M P D I o U L_{MPDIoU}=1-MPDIoU LMPDIoU=1−MPDIoU,使模型预测的每个边界框 B p r d B_{prd} Bprd接近其真实框 B g t B_{gt} Bgt。 - 现有损失函数中的所有因素(如非重叠区域、中心点距离、宽高偏差等)都可以通过左上角和右下角两点的坐标确定,这意味着提出的 L M P D I o U L_{MPDIoU} LMPDIoU不仅考虑了这些因素,还简化了计算过程。
2.4 MPDIoU的计算公式
-
MPDIoU
的计算公式:- M P D I o U = A ∩ B A ∪ B − d 1 2 w 2 + h 2 − d 2 2 w 2 + h 2 MPDIoU=\frac{A\cap B}{A\cup B}-\frac{d_{1}^{2}}{w^{2}+h^{2}}-\frac{d_{2}^{2}}{w^{2}+h^{2}} MPDIoU=A∪BA∩B−w2+h2d12−w2+h2d22
- 其中 A A A和 B B B是两个任意凸形状, ( x A 1 , y A 1 ) (x_{A1}, y_{A1}) (xA1,yA1), ( x A 2 , y A 2 ) (x_{A2}, y_{A2}) (xA2,yA2)表示(A)的左上角和右下角点坐标, ( x B 1 , y B 1 ) (x_{B1}, y_{B1}) (xB1,yB1), ( x B 2 , y B 2 ) (x_{B2}, y_{B2}) (xB2,yB2)表示 B B B的左上角和右下角点坐标。
- d 1 2 = ( x 1 B − x 1 A ) 2 + ( y 1 B − y 1 A ) 2 d_{1}^{2}=(x_{1}^{B}-x_{1}^{A})^{2}+(y_{1}^{B}-y_{1}^{A})^{2} d12=(x1B−x1A)2+(y1B−y1A)2, d 2 2 = ( x 2 B − x 2 A ) 2 + ( y 2 B − y 2 A ) 2 d_{2}^{2}=(x_{2}^{B}-x_{2}^{A})^{2}+(y_{2}^{B}-y_{2}^{A})^{2} d22=(x2B−x2A)2+(y2B−y2A)2。
-
基于
MPDIoU
的损失函数计算公式:- L M P D I o U = 1 − M P D I o U L_{MPDIoU}=1-MPDIoU LMPDIoU=1−MPDIoU。
三、添加步骤
3.1 utils\metrics.py
此处需要查看的文件是utils\metrics.py
metrics.py
中定义了模型的损失函数和计算方法,我们想要加入新的损失函数就只需要将代码放到这个文件内即可。YOLOv9
原模型中使用的是CIoU
,并且在原YOLOv9
的代码中已经实现了MPDIoU
的代码,
MPDIoU
的代码在utils\metrics.py
的第254行,如下:
def bbox_iou(box1, box2, xywh=True, GIoU=False, DIoU=False, CIoU=False, MDPIoU=False, feat_h=640, feat_w=640, eps=1e-7):
# Returns Intersection over Union (IoU) of box1(1,4) to box2(n,4)
# Get the coordinates of bounding boxes
if xywh: # transform from xywh to xyxy
(x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_
else: # x1, y1, x2, y2 = box1
b1_x1, b1_y1, b1_x2, b1_y2 = box1.chunk(4, -1)
b2_x1, b2_y1, b2_x2, b2_y2 = box2.chunk(4, -1)
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
# Intersection area
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)
# Union Area
union = w1 * h1 + w2 * h2 - inter + eps
# IoU
iou = inter / union
if CIoU or DIoU or GIoU:
cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # convex (smallest enclosing box) width
ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # convex height
if CIoU or DIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
c2 = cw ** 2 + ch ** 2 + eps # convex diagonal squared
rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 + (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4 # center dist ** 2
if CIoU: # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
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) # CIoU
return iou - rho2 / c2 # DIoU
c_area = cw * ch + eps # convex area
return iou - (c_area - union) / c_area # GIoU https://arxiv.org/pdf/1902.09630.pdf
elif MDPIoU:
d1 = (b2_x1 - b1_x1) ** 2 + (b2_y1 - b1_y1) ** 2
d2 = (b2_x2 - b1_x2) ** 2 + (b2_y2 - b1_y2) ** 2
mpdiou_hw_pow = feat_h ** 2 + feat_w ** 2
return iou - d1 / mpdiou_hw_pow - d2 / mpdiou_hw_pow # MPDIoU
return iou # IoU
3.2 修改utils\loss_tal_dual.py
utils\loss_tal_dual.py
是损失函数的辅助分支+主分支损失计算文件。
在utils\loss_tal_dual.py
的75行处修改成如下代码,使模型调用此MPDIoU损失函数。
iou = bbox_iou(pred_bboxes_pos, target_bboxes_pos, xywh=False, MPDIoU=True)
四、总结
当发现预测边界框和真实边界框具有相同的宽高比但不同的宽度和高度值时,MPDIoU
损失函数比现有损失函数更有效,此时可以尝试将损失函数修改成MPDIoU
查看效果。