关键词: 方针检测、IoU、GIoU、DIoU、CIoU、EIoU、SIoU、WIoU

前语

   在方针检测网络中,IoU(Intersection over Union)函数的作用是衡量检测框和实在框之间的堆叠程度。具体来说,IoU函数核算检测框和实在框的交集面积和并集面积之间的份额,一般表示为IoU分数。

  经过比较检测框和实在框之间的IoU分数,能够判别检测框是否正确地定位了方针,并进一步优化方针检测网络的猜测成果。在练习过程中,一般会使用IoU函数作为丢失函数的一部分,来衡量猜测框和实在框之间的间隔,然后引导网络学习更准确的方针检测。

IoU宗族函数简介

GIoU

  GIoU能够更准确地衡量检测成果的准确度,并且在练习中能够帮助模型更好地收敛。GIoU函数的核算方法在IoU的基础上增加了对检测框和实在标示框之间间隔的考虑,以减小框的堆叠部分面积的核算差错。具体来说,GIoU使用了检测框和实在标示框的最小闭合矩形(minimum enclosing rectangle)来核算间隔,并将间隔的贡献参加到核算中,然后得到更准确的评价成果。

【基础回顾&DIYIoU】尝试撸一份属于自己的IoU函数

CIoU

  相较于GIoU函数,能够更全面地考虑框的形状和尺度信息,以取得更准确的检测成果。CIoU函数的核算方法在GIoU的基础上增加了对框的长宽份额和中心点间隔的赏罚项,以减小框的形状和尺度差异对检测成果的影响。具体来说,CIoU首先核算出GIoU值,然后在核算过程中参加长宽份额和中心点间隔的赏罚项,最终得到一个更全面的评价成果。

【基础回顾&DIYIoU】尝试撸一份属于自己的IoU函数

DIoU

  DIoU 能够更好地考虑框的方位信息和不同尺寸之间的联系,以取得更准确的检测成果。 DIoU函数的核算方法在CIoU的基础上增加了对框之间间隔的赏罚项,以减小框的方位差异对检测成果的影响。具体来说,DIoU核算出CIoU值,然后在核算过程中参加间隔的赏罚项,将框之间的间隔纳入到评价中,然后得到更准确的成果。

【基础回顾&DIYIoU】尝试撸一份属于自己的IoU函数

EIoU

  EIoU能够更好地考虑框之间的联系,EIoU函数的核算方法在DIoU的基础上增加了对框之间嵌入embedding)联系的考虑,以减小框之间的堆叠部分的核算差错。具体来说,EIoU将框之间的嵌入联系表示为一个向量,然后经过向量的相似度来衡量框之间的堆叠程度,然后得到更准确的评价成果。

【基础回顾&DIYIoU】尝试撸一份属于自己的IoU函数

SIOU

  SIoU能够更准确地衡量检在方针的鸿沟模糊或堆叠的状况下的准确度。SIoU函数的核算方法类似于IoU,但不同之处在于它使用了一种“软化”的方法来核算交集和并集面积。具体来说,SIoU使用了高斯函数对交集和并集区域进行平滑,以减小鸿沟差错的影响,然后得到更准确的评价成果。

【基础回顾&DIYIoU】尝试撸一份属于自己的IoU函数
【基础回顾&DIYIoU】尝试撸一份属于自己的IoU函数

WIOU

  WIoU能够更好地考虑不同类别之间的重要性差异,以取得更准确的检测成果。WIoU函数的核算方法在传统的IoU的基础上引入了类别权重的概念,以减小不同类别之间的重要性差异对检测成果的影响。具体来说,WIoU为每个类别分配一个权重,然后在核算IoU时对不同类别之间的堆叠部分使用不同的权重进行加权,然后得到更准确的评价成果。

【基础回顾&DIYIoU】尝试撸一份属于自己的IoU函数

代码示例

import math
import torch
def my_ious(pred_x1, pred_y1, pred_x2, pred_y2, target_x1, target_y1, target_x2, target_y2, eps=1e-7, MyIoU=0):
    """
    MyIoU 的值代表不同的IoU
    0 ----> IoU
    1 ----> CIoU
    2 ----> DIoU
    3 ----> EIoU
    4 ----> GIoU
    5 ----> SIoU
    6 ----> WIoU
    """
    # The overlapping region 堆叠区域 求交集
    inter_x = (torch.min(pred_x2, target_x2) - torch.max(pred_x1, target_x1)).clamp(0)
    inter_y = (torch.min(pred_y2, target_y2) - torch.max(pred_y1, target_y1)).clamp(0)
    s_inter = inter_x * inter_y
    # The area covered  求并集
    w1, h1 = pred_x2 - pred_x1, pred_y2 - pred_y1 + eps
    w2, h2 = target_x2 - target_x1, target_y2 - target_y1 + eps
    s_union = w1 * h1 + w2 * h2 - s_inter + eps
    # IoU
    iou = s_inter / s_union
    ptx_min = torch.min(pred_x1, target_x1)
    pty_min = torch.min(pred_y1, target_y1)
    ptx_max = torch.max(pred_x2, target_x2)
    pty_max = torch.max(pred_y2, target_y2)
    cw = ptx_max - ptx_min
    ch = pty_max - pty_min
    cds = cw ** 2 + ch ** 2 + eps
    tpx2 = (target_x1 + target_x2 - pred_x1 - pred_x2) ** 2
    tpy2 = (target_y1 + target_y2 - pred_y1 - pred_y2) ** 2
    rho2 = (tpx2 + tpy2) / 4
    focaleiou = False
    if MyIoU != 0:
        # CIoU
        if MyIoU == 1:
            anat = torch.atan(w2 / h2) - torch.atan(w1 / h1)
            v = (4 / math.pi ** 2) * torch.pow(anat + eps, 2)
            alpha = v / (iou - v + (1 + eps))
            ciou = iou - (rho2 / cds + alpha * v)
            return ciou
        # DIoU
        if MyIoU == 2:
            diou = (iou - rho2 + eps) / cds
            return diou
        # EIoU
        if MyIoU == 3:
            diou_term = (rho2 + eps) / (cds + eps)
            c2_w = cw ** 2 + eps
            c2_h = ch ** 2 + eps
            rho2_w = (w1 - w2) ** 2
            rho2_h = (h1 - h2) ** 2
            eiou_term = (rho2_w / c2_w) + (rho2_h / c2_h)
            eiou = (1 - iou + diou_term + eiou_term) * 1.
            if focaleiou:
                eiou = iou ** 0.5 * eiou
            return eiou
        # GIoU
        if MyIoU == 4:
            s_box = cw * ch + eps
            giou = iou - (s_box - s_union) / s_box
            return giou
        # SIoU
        if MyIoU == 5:
            s_cw = (target_x1 + target_x2 - pred_x1 - pred_x2) * 0.5
            s_ch = (target_y1 + target_y2 - pred_y1 - pred_y2) * 0.5
            sigma = torch.pow(s_cw ** 2 + s_ch ** 2, 0.5)
            sin_alpha_1 = torch.abs(s_cw) / sigma
            sin_alpha_2 = torch.abs(s_ch) / 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 - math.pi / 2)
            rho_x = (s_cw / cw) ** 2
            rho_y = (s_ch / ch) ** 2
            gamma = angle_cost - 2
            distance_cost = 2 - torch.exp(gamma * rho_x) - torch.exp(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)
            siou = iou - 0.5 * (distance_cost + shape_cost)
            return siou
        # WIoU
        if MyIoU == 6:
            exp_num = rho2 / cds
            dist = torch.exp(exp_num)
            wiou = dist * iou
            return wiou
    else:
        return iou

优化

  IoU函数的核算方法是,首先将检测框(bounding box)与实在标示框(ground truth box)进行交集(intersection)运算,然后将交集的面积除以两个框的并集(union)面积,得到一个介于0和1之间的值。当IoU值越大,表示检测成果越挨近实在标示。

  一般来说,IoU值大于阈值(一般为0.5或0.75)时才以为检测成果是正确的。然而在实际使用中IoU函数往往满足不了需求,因此进行优化。

IoU函数的优化思路

  在方针检测网络中,IoU函数的优化思路一般能够从以下两个方面入手:

  1. 进步检测框的准确度:由于IoU函数的核算依赖于检测框和实在框的交集和并集面积,因此进步检测框的准确度是进步IoU函数体现的重要手法。这能够经过调整网络结构、参加更多的特征信息、优化方针函数等方式完成。

  2. 进步IoU函数自身的体现:除了经过进步检测框的准确度来进步IoU函数的体现之外,也能够直接优化IoU函数自身。一种常见的做法是使用一些基于IoU函数的丢失函数,例如SmoothL1Loss、GIoULoss、DIoULoss等,来代替传统的L2Loss或穿插熵丢失函数。这些丢失函数能够更好地衡量猜测框和实在框之间的相似度,然后进步方针检测网络的功能。 综上所述,进步检测框的准确度和优化IoU函数自身是进步方针检测网络功能的两个重要方面。

完成优化

  例如咱们对检测框和实在标示框之间的包括联系:红色为实在标示框,绿色为检测框,这个时分能够发现有“外包”和“内包”这两种状况,在内外包之间有一层面积,咱们需要对这一层面积单独设定,当面积越大的时分iou值就越小,反之iou值越大。

  断定“内外包” 的条件能够将检测框和实在标示框之间的并集面积等于检测框或实在标示框。

  1. 当并集的面积等于【检测框】的面积时阐明【检测框】将【实在标示框】“包括”在里面了;
  2. 当并集的面积等于【实在标示框】的面积时阐明【实在标示框】将【检测框】“包括”在里面了;

咱们能够根据上述的特殊状况对IoU系列的函数进行更改。

def Punish(x, t=True):
    """ 赏罚函数:经过面积核算LOSS值。 这个阶段至少是包括的状态,因从y的值域为[0-1]"""
    if t:
        y = 1 - (x ** 6) / 1e+12
    else:
        y = 1 - (x ** 3) / 1e+6
    return y
def yiou(w1, h1, w2, h2, s_union, s_inter, eps):
    S_pred = w1 * h1 + eps
    S_target = w2 * h2 + eps
    # 相离状态
    if s_inter == 0:
        print("无交集")
        return eps  #
# --------------存在包括状态----------------------------
    if torch.equal(s_union, S_pred):
        S = S_pred - S_target
        return Punish(S, t=False)
    if torch.equal(s_union, S_target):
        S = S_target - S_pred
        return Punish(S, t=True)

【基础回顾&DIYIoU】尝试撸一份属于自己的IoU函数