前言
在目标检测网络中,IoU(Intersection over Union)函数的作用是衡量检测框和真实框之间的重叠程度。具体来说,IoU函数计算检测框和真实框的交集面积和并集面积之间的比例,通常表示为IoU分数。
通过比较检测框和真实框之间的IoU分数,可以判断检测框是否正确地定位了目标,并进一步优化目标检测网络的预测结果。在训练过程中,通常会使用IoU函数作为损失函数的一部分,来衡量预测框和真实框之间的差距,从而引导网络学习更准确的目标检测。
IoU家族函数简介
GIoU
GIoU可以更准确地衡量检测结果的准确度,并且在训练中可以帮助模型更好地收敛。GIoU函数的计算方法在IoU的基础上增加了对检测框和真实标注框之间距离的考虑,以减小框的重叠部分面积的计算误差。具体来说,GIoU使用了检测框和真实标注框的最小闭合矩形(minimum enclosing rectangle)来计算距离,并将距离的贡献加入到计算中,从而得到更准确的评估结果。
CIoU
相较于GIoU函数,可以更全面地考虑框的形状和尺度信息,以获得更准确的检测结果。CIoU函数的计算方法在GIoU的基础上增加了对框的长宽比例和中心点距离的惩罚项,以减小框的形状和尺度差异对检测结果的影响。具体来说,CIoU首先计算出GIoU值,然后在计算过程中加入长宽比例和中心点距离的惩罚项,最终得到一个更全面的评估结果。
DIoU
DIoU 可以更好地考虑框的位置信息和不同尺寸之间的关系,以获得更准确的检测结果。 DIoU函数的计算方法在CIoU的基础上增加了对框之间距离的惩罚项,以减小框的位置差异对检测结果的影响。具体来说,DIoU计算出CIoU值,然后在计算过程中加入距离的惩罚项,将框之间的距离纳入到评估中,从而得到更准确的结果。
EIoU
EIoU可以更好地考虑框之间的关系,EIoU函数的计算方法在DIoU的基础上增加了对框之间嵌入embedding)关系的考虑,以减小框之间的重叠部分的计算误差。具体来说,EIoU将框之间的嵌入关系表示为一个向量,然后通过向量的相似度来衡量框之间的重叠程度,从而得到更准确的评估结果。
SIOU
SIoU可以更准确地衡量检在目标的边界模糊或重叠的情况下的准确度。SIoU函数的计算方法类似于IoU,但不同之处在于它使用了一种“软化”的方法来计算交集和并集面积。具体来说,SIoU使用了高斯函数对交集和并集区域进行平滑,以减小边界误差的影响,从而得到更精确的评估结果。
WIOU
WIoU可以更好地考虑不同类别之间的重要性差异,以获得更准确的检测结果。WIoU函数的计算方法在传统的IoU的基础上引入了类别权重的概念,以减小不同类别之间的重要性差异对检测结果的影响。具体来说,WIoU为每个类别分配一个权重,然后在计算IoU时对不同类别之间的重叠部分使用不同的权重进行加权,从而得到更准确的评估结果。
代码示例
ini
复制代码
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函数的优化思路通常可以从以下两个方面入手:
- 提高检测框的准确度:由于IoU函数的计算依赖于检测框和真实框的交集和并集面积,因此提高检测框的准确度是提高IoU函数表现的重要手段。这可以通过调整网络结构、加入更多的特征信息、优化目标函数等方式实现。
- 提高IoU函数本身的表现:除了通过提高检测框的准确度来提高IoU函数的表现之外,也可以直接优化IoU函数本身。一种常见的做法是使用一些基于IoU函数的损失函数,例如SmoothL1Loss、GIoULoss、DIoULoss等,来替代传统的L2Loss或交叉熵损失函数。这些损失函数可以更好地衡量预测框和真实框之间的相似度,从而提高目标检测网络的性能。 综上所述,提高检测框的准确度和优化IoU函数本身是提高目标检测网络性能的两个重要方面。
实现优化
例如我们对检测框和真实标注框之间的包含关系:红色为真实标注框,绿色为检测框,这个时候可以发现有“外包”和“内包”这两种情况,在内外包之间有一层面积,我们需要对这一层面积单独设定,当面积越大的时候iou值就越小,反之iou值越大。
判定“内外包” 的条件可以将检测框和真实标注框之间的并集面积等于检测框或真实标注框。
- 当并集的面积等于【检测框】的面积时说明【检测框】将【真实标注框】“包含”在里面了;
- 当并集的面积等于【真实标注框】的面积时说明【真实标注框】将【检测框】“包含”在里面了;
我们可以根据上述的特殊情况对IoU系列的函数进行更改。
ini
复制代码
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