传统回归loss都是回归表征一个矩形框的四个变量,但这基于一个过于简化的假设,即这四个变量之间是相互独立的。实际上,这四个变量之间是相互关联的,简单的分开计算每个变量的回归loss无法反映这种相关性,而将预测框与GT框之间的iou引入回归loss则很好的解决了这一问题。
一、IOU Loss
IOU Loss,即预测框与GT框之间的交集/预测框与GT框之间的并集,这种损失函数会存在一些问题,具体的问题如下图所示:
1)当预测框和GT框不相交时(即IOU=0),此时该损失函数不可导,即IOU_Loss无法优化两个框不相交的情况。
2)当两个预测框尺寸且交集范围一致时,IOU_Loss也保持一致,无法区分两者相交这种情况。(无法区分这两种情况,会导致什么问题?)
二、GIoU Loss
对于两个任意形状的物体A和B,我们计算包括A和B的最小凸包形状C。直观上来说,IOU的弱点是指的是当A和B的交集为0时,失去目标,所以GIOU就是防止这种情况:C的面积中A∪B的面积占比越大越好。
三、DIoU Loss
当两个框处于包含关系时,GIOU-Loss退化为IOU。导致在包含的时候,优化变得困难,特别是在水平和垂直方向收敛难。DIOU在GIOU基础上加入了anchor框与目标框之间的归一化距离。
四、CIoU Loss
当GT框包裹预测框时,此时预测框的中心点的位置都是一样的。因此,按照DIoU Loss的计算公式,三者的值都是相同。为了解决这个问题,CIoU Loss在DIoU Loss的基础上增加了一个影响因子,将预测框和GT框的长宽也考虑进来。
Box Loss代码
import math
import torch
#pytorch版本
def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False):
# Returns the IoU of box1 to box2. box1 is 4, box2 is nx4
box2 = box2.t()
# Get the coordinates of bounding boxes
if x1y1x2y2: # x1, y1, x2, y2 = box1
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: # transform from xywh to xyxy
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
# 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:并集的面积
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1
union = (w1 * h1 + 1e-16) + w2 * h2 - inter
# iou的计算公式
iou = inter / union
if GIoU or DIoU or CIoU:
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 GIoU: # Generalized IoU https://arxiv.org/pdf/1902.09630.pdf
c_area = cw * ch + 1e-16 # convex area
return iou - (c_area - union) / c_area # GIoU
if DIoU or CIoU: # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
# convex diagonal squared
c2 = cw ** 2 + ch ** 2 + 1e-16
# centerpoint distance squared
rho2 = ((b2_x1 + b2_x2) - (b1_x1 + b1_x2)) ** 2 / 4 + ((b2_y1 + b2_y2) - (b1_y1 + b1_y2)) ** 2 / 4
if DIoU:
return iou - rho2 / c2 # DIoU
elif 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 / (1 - iou + v)
return iou - (rho2 / c2 + v * alpha) # CIoU
return iou
#numpy版本
def bbox_iou_libra(box1, box2, GIOU =False, DIOU =False, CIOU =False):
eps = 1e-6
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]
inter = (min(b1_x2, b2_x2) - max(b1_x1, b2_x1) ).clamp(0) *(min(b1_y2 - b1_y2) - max(b2_y1 - b1_y1)).clamp(0)
w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1
w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1
union = w1*h1 + w2*h2 + eps - inter
iou = inter / union
##计算外界矩形面积
cw = max(b1_x2, b2_x2) - min(b1_x1, b2_x1)
cy = max(b1_y2, b2_y2) - min(b1_y1, b2_y1)
if GIOU:
c_area = cw*cy + eps
return iou - (c_area - union)/c_area
if DIOU or CIOU:
c2 = cw**2 + cy**2 + eps
rho2 = ( (b2_x1 + b2_x2) + (b1_x1 + b1_x2))**2 /4 + ((b2_y1 + b2_y2) - (b1_y1 + b1_y2)) ** 2 / 4
if DIOU:
return iou - rho2/c2
elif CIOU:
v = (4 / math.pi ** 2) * pow(math.atan(w2 / h2) - math.atan(w1 / h1), 2)
with torch.no_grad():
alpha = v / (1 - iou + v)
return iou - (rho2 / c2 + v * alpha) # CIoU