yolov5 优化方法(四)修改bbox损失函数(补充EIOU,SIOU)

【参考文档】江大白的yolo解析
后面会给出我的完整代码,先来分段看看!

转化格式

 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

转换成这种格式:
在这里插入图片描述

IOU

这个应该都很熟了

 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)                                                    
            #.clamp:将小于0的元素修改为0,截断元素的取值空
    # Union Area
    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 + ep
    iou = inter / union

clamp

def clamp(self, min: _float=-inf, max: _float=inf, *, out: Optional[Tensor]=None) -> Tensor: ...

inf:无穷大
-inf:负无穷
out:输出,默认即可,不用设定

在 yolov5的使用中,应该是截断掉小于0的部分

(torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0)

torch.clamp

DIOU

在正式进入各种iou之前

		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)  # 最小包裹矩形高度

cw :最小外包矩形宽度
ch :最小外包矩形高度

在这里插入图片描述
分子部分的一次项代表:GT框和bbox框中心点的距离
c:两个框对角线的距离
在这里插入图片描述

考虑了重叠面积和中心点距离

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  # DIoU

c2: 勾股定理,使用两边的平方和来代替斜边的平方

扫描二维码关注公众号,回复: 15187862 查看本文章

GIOU

在这里插入图片描述

 	c_area = cw * ch + eps  # convex area
 	return iou - (c_area - union) / c_area  # GIoU

CIoU

CIOU_Loss和DIOU_Loss前面的公式都是一样的,不过在此基础上还增加了一个影响因子,将预测框和目标框的长宽比都考虑了进去。
在这里插入图片描述

其中v是衡量长宽比一致性的参数,我们也可以定义为:
在这里插入图片描述

这样CIOU_Loss就将目标框回归函数应该考虑三个重要几何因素:重叠面积、中心点距离,长宽比全都考虑进去了。

            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 / (v - iou + (1 + eps))
                return iou - (rho2 / c2 + v * alpha)  # CIoU

EIOU

【参考博文】IOU、GIOU、DIOU、CIOU、EIOU、Focal EIOU、alpha IOU损失函数
前两部分延续CIOU中的方法,但是宽高损失直接使目标盒与锚盒的宽度和高度之差最小,使得收敛速度更快。
在这里插入图片描述

该损失函数包含三个部分:重叠损失,中心距离损失,宽高损失

            rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 +
                    (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4  # center distance squared
 		elif EIoU:
                w=(w1-w2)*(w1-w2)
                h=(h1-h2)*(h1-h2)
                return iou-(rho2/c2+w/(cw**2)+h/(ch**2))

w:宽度差的平方
h:高度差的平方

SIOU

直接看这篇的解析吧。就不重复写了

然后上一下完整代码

def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, SIoU=False, EIoU = False, eps=1e-7):
    # 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 + 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 or SIoU or EIoU:
        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 SIoU:    # SIoU Loss 2022.08.01
            sigma = torch.pow(cw ** 2 + ch ** 2, 0.5)
            sin_alpha_1 = ch / sigma
            sin_alpha_2 = cw / sigma
            threshold = pow(2, 0.5) / 2
            sin_alpha = torch.where(sin_alpha_1 > threshold, sin_alpha_2, sin_alpha_1)
            # angle_cost = 1 - 2 * torch.pow( torch.sin(torch.arcsin(sin_alpha) - np.pi/4), 2)
            angle_cost = torch.cos(torch.arcsin(sin_alpha) * 2 - np.pi / 2)
            rho_x = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) / cw) ** 2
            rho_y = ((b2_y1 + b2_y2 - b1_y1 - b1_y2) / ch) ** 2
            gamma = 2 - angle_cost
            distance_cost = 2 - torch.exp(-1 * gamma * rho_x) - torch.exp(-1 * gamma * rho_y)
            omiga_w = torch.abs(w1 - w2) / torch.max(w1, w2)
            omiga_h = torch.abs(h1 - h2) / torch.max(h1, h2)
            shape_cost = torch.pow(1 - torch.exp(-1 * omiga_w), 4) + torch.pow(1 - torch.exp(-1 * omiga_h), 4)
            return iou - 0.5 * (distance_cost + shape_cost)

        elif CIoU or DIoU or EIoU:  # 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 distance squared
            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 / (v - iou + (1 + eps))
                return iou - (rho2 / c2 + v * alpha)  # CIoU
            elif EIoU:
                w=(w1-w2)*(w1-w2)
                h=(h1-h2)*(h1-h2)
                return iou-(rho2/c2+w/(cw**2)+h/(ch**2))#EIOU
        else:  # GIoU https://arxiv.org/pdf/1902.09630.pdf
            c_area = cw * ch + eps  # convex area
            return iou - (c_area - union) / c_area  # GIoU
    else:
        return iou  # IoU

在yolov5使用方法

1.metrics.py修改一下注释掉原来的bbox_iou,复制上面的完整代码
2.loss.py中把想要使用的iou设置为True(下图以EIOU为例)

请添加图片描述

猜你喜欢

转载自blog.csdn.net/weixin_50862344/article/details/126613467