• 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    clamp
    def clamp(self, min: _float=-inf, max: _float=inf, *, out: Optional[Tensor]=None) -> Tensor: ...
    
    • 1

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

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

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

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    GIOU

    在这里插入图片描述

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

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    在yolov5使用方法

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

    请添加图片描述

  • 相关阅读:
    Redis:Feed流之Timeline的实现
    @Transactional失效场景/原因
    微信小程序报错:request:fail url not in domain list
    头歌【第2关:有序单链表中值相同的多余结点的删除操作】
    IO多路复用Selector
    Simulink脚本自动创建Autosar Parameter Port及Mapping
    IDEA操作Sharding-JDBC实战1
    输入电压转化为电流性 5~20mA方案
    【Android笔记56】Android之内容观察者Content Observer介绍及其使用
    JS问题:项目中如何区分使用防抖或节流?
  • 原文地址:https://blog.csdn.net/weixin_50862344/article/details/126613467