结合NWD的Shape-IoU!助力yolo v5涨点,源码复现

331 阅读10分钟

image.png 标题:Shape-IoU: More Accurate Metric considering Bounding Box Shape and Scale 作者:Hao Zhang, Shuaijie Zhang 原文链接:arxiv.org/abs/2312.17… 代码链接:github.com/malagoutou/…

shape iou

边界框回归损失在目标检测中非常重要,典型Loss就是IoU、GIoU、CIoU、SIoU。改动方案基本上都是在IoU上添加新的几何约束(GT框和 Anchor 框的距离、形状和角度),但是都忽略了边界框自身的形状和尺寸的影响。今天笔者为大家推荐一篇最新的开源工作Shape-IoU,借助边界框本身的形状和尺度来计算损失,使边界框回归更加准确,可以有效地提高YOLO系列检测器的性能!

1、概述

作为检测器定位分支的重要组成部分,边界框回归损失在目标检测任务中发挥着重要作用。现有的边界框回归方法通常考虑GT框和预测框之间的几何关系,利用边界框的相对位置和形状来计算损失,而忽略了边界框的形状和尺度等固有属性对边界框回归的影响。为了弥补现有研究的不足,本文提出了一种关注包围盒自身形状和尺度的包围盒回归方法。首先,我们对边界框的回归特性进行了分析,发现边界框本身的形状和尺度因素会对回归结果产生影响。基于以上结论,我们提出了Shape IoU方法,该方法可以通过关注边界框本身的形状和尺度来计算损失,从而使得边界框回归更加准确。最后,我们通过大量的对比实验对我们的方法进行了验证,结果表明我们的方法可以有效地提高检测性能,并且优于现有的方法,在不同的检测任务中达到了先进的性能。 image.png

2、原理

file

如图所示,边界框回归样本A和B中GT框的尺度相同,而C和D中GT框的尺度相同。A和D中GT盒的形状相同,而B和C中GT盒的形状相同。C和D中包围盒的尺度大于A和B中包围盒的尺度,图a中所有包围盒的回归样本具有相同的偏差,形状偏差为0。图a与图b的不同之处在于,图b中所有包围盒回归样本的形状偏差相同,偏差为0。并观察到如下发现:

图a中A和B的偏差相同,但IoU值存在差异。

图a中C和D的偏差相同,但IoU值存在差异,且相比图a中的A和B,IoU值差异不显著。

图b中A和B的形状偏差相同,但IoU值存在差异。

图b中C和D的形状偏差相同,但IoU值存在差异,与图a中A和B相比,IoU值差异不显著。

图a中A和B的Io U值存在差异的原因是它们的GT盒形状不同,偏离方向分别对应它们的长边和短边方向。对于A,其GT盒沿长边方向的偏差对其影响较小。而对B而言,短边方向的偏差对其Io U值的影响更大。与大尺度包围盒相比,小尺度包围盒对Io U值的变化更敏感,GT盒形状对小尺度包围盒的Io U值影响更显著。由于A和B比C和D的尺度小,在形状和偏差相同的情况下,Io U值的变化更显著。同理,在图b中,从形状偏差的角度分析包围盒回归,发现回归样本中GT盒的形状会影响其在回归过程中的Io U值。 基于以上分析,可以得出以下结论: (1)假设GT盒不是正方形,有长边和短边,当偏差和形状偏差相同且不全为0时,回归样本中包围盒形状和尺度的不同会导致其Io U值的差异。 (2)对于相同尺度的包围盒回归样本,当回归样本的偏差和形状偏差相同且不全为0时,包围盒的形状会对回归样本的Io U值产生影响。包围盒短边方向的偏差和形状偏差对应的Io U值变化更为显著。 (3)对于具有相同形状包围盒的回归样本,当回归样本偏差和形状偏差相同且不全为0时,相比于规模较大的回归样本,规模较小的包围盒回归样本的Io U值受GT盒形状的影响更为显著。

3、shape iou 源代码

def shape_iou(box1, box2, scale1=0.5, eps=1e-7):
    (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
    w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
    b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
    b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_

    # 计算交集面积
    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 = (w1 * h1 + w2 * h2 - inter + eps)  # 添加 eps 防止除零

    # 计算 IoU
    iou = inter / union

    # 计算形状距离
    ww = 2 * torch.pow(w2, scale1) / (torch.pow(w2, scale1) + torch.pow(h2, scale1))
    hh = 2 * torch.pow(h2, scale1) / (torch.pow(w2, scale1) + torch.pow(h2, scale1))

    # 计算凸包的宽度和高度
    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)

    c2 = cw ** 2 + ch ** 2 + eps  # 凸包对角线的平方

    # 计算中心距离
    center_distance_x = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2) / 4
    center_distance_y = ((b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4
    center_distance = hh * center_distance_x + ww * center_distance_y
    distance = center_distance / (c2 + eps)  # 归一化距离,添加 eps 防止除零

    # 计算形状相似度
    omiga_w = hh * torch.abs(w1 - w2) / torch.max(w1, w2)
    omiga_h = ww * 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)

    # 最终的 Shape-IoU
    iou = iou - distance - 0.5 * shape_cost
    return iou  # 返回融合了形状和距离的 IoU

4、A Normalized Gaussian Wasserstein Distance for Tiny Object Detection(NWD)提升小目标检测能力

4.1 nwd简介

论文链接:nwd NWD是一个新的度量方法来计算框和框之间的相似度,就是把框建模成高斯分布,然后用Wasserstein距离来度量这两个分布之间的相 似度,来代替loU。这个距离的好处是,即便是2个框完全不重叠,或者重叠很少,还是可以度量出相似度出来。另外,NWD对于目标的 尺度不敏感,对于小目标的更加的稳定。 相比于loU,NWD有以下好处: 1.尺度不变性。

  1. 对于位置的差别变换平缓。 3.具有度量不想交的框的相似度的能力。 file file

4.2 nwd代码

根据shape iou论文提到的nwd撰写代码: file

def nwd(box1, box2, scale1=0.5, eps=1e-7):
    (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
    w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
    b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
    b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_

    # 计算形状距离
    ww = 2 * torch.pow(w2, scale1) / (torch.pow(w2, scale1) + torch.pow(h2, scale1))
    hh = 2 * torch.pow(h2, scale1) / (torch.pow(w2, scale1) + torch.pow(h2, scale1))

    # 计算 NWD

    B = (torch.pow(w1 - w2,2)+torch.pow(h1 - h2,2))/4
    center_distance_x1 = (b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2
    center_distance_y1 = (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2
    D =(hh*center_distance_x1+ww*center_distance_y1+B)**(1/2)
    nwd=torch.exp(-D/3)
 
    return nwd  # 返回融合了形状和距离的 IoU

5、shape iou加入yolo5复现

5.1在metrics.py中插入上述shape iou代码

def shape_iou(box1, box2, scale1=0.5, eps=1e-7):
    (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
    w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
    b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
    b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_

    # 计算交集面积
    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 = (w1 * h1 + w2 * h2 - inter + eps)  # 添加 eps 防止除零

    # 计算 IoU
    iou = inter / union

    # 计算形状距离
    ww = 2 * torch.pow(w2, scale1) / (torch.pow(w2, scale1) + torch.pow(h2, scale1))
    hh = 2 * torch.pow(h2, scale1) / (torch.pow(w2, scale1) + torch.pow(h2, scale1))

    # 计算凸包的宽度和高度
    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)

    c2 = cw ** 2 + ch ** 2 + eps  # 凸包对角线的平方

    # 计算中心距离
    center_distance_x = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2) / 4
    center_distance_y = ((b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4
    center_distance = hh * center_distance_x + ww * center_distance_y
    distance = center_distance / (c2 + eps)  # 归一化距离,添加 eps 防止除零

    # 计算形状相似度
    omiga_w = hh * torch.abs(w1 - w2) / torch.max(w1, w2)
    omiga_h = ww * 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)

    # 最终的 Shape-IoU
    iou = iou - distance - 0.5 * shape_cost
    return iou  # 返回融合了形状和距离的 IoU

5.2在metrics.py中插入上述nwd代码

def nwd(box1, box2, scale1=0.5, eps=1e-7):
    (x1, y1, w1, h1), (x2, y2, w2, h2) = box1.chunk(4, -1), box2.chunk(4, -1)
    w1_, h1_, w2_, h2_ = w1 / 2, h1 / 2, w2 / 2, h2 / 2
    b1_x1, b1_x2, b1_y1, b1_y2 = x1 - w1_, x1 + w1_, y1 - h1_, y1 + h1_
    b2_x1, b2_x2, b2_y1, b2_y2 = x2 - w2_, x2 + w2_, y2 - h2_, y2 + h2_

    # 计算形状距离
    ww = 2 * torch.pow(w2, scale1) / (torch.pow(w2, scale1) + torch.pow(h2, scale1))
    hh = 2 * torch.pow(h2, scale1) / (torch.pow(w2, scale1) + torch.pow(h2, scale1))

    # 计算 NWD

    B = (torch.pow(w1 - w2,2)+torch.pow(h1 - h2,2))/4
    center_distance_x1 = (b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2
    center_distance_y1 = (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2
    D =(hh*center_distance_x1+ww*center_distance_y1+B)**(1/2)
    nwd=torch.exp(-D/3)
    # 最终的 Shape-IoU
    # iou = iou - distance - 0.5 * shape_cost - 0.5 * nwd
    return nwd  # 返回融合了形状和距离的 IoU

5.3在loss.py中插入下面代码

首先在loss.py导入shape_iou和nwd

from utils.metrics import shape_iou,nwd

然后再computeloss函数里面将原来ciou loss改为下面代码(这里比重设置为0.8:0.2)

                iou = shape_iou(pbox, tbox[i])  # 使用 shape_iou 计算 IoU
                nwd1=nwd(pbox, tbox[i])
                lbox += 0.8*(1.0 - iou).mean()+0.2*(1.0-nwd1).mean()   # 使用 shape IoU 损失

6、总结

本文为大家推荐了一篇最新的开源工作Shape - IoU和Nwd。这篇文章指出现有Loss侧重于考虑GT框与预测框之间的几何约束,而忽略了边界框本身的形状、尺度等几何因素对回归结果的影响。然后提出了Shape - IoU方法,可以关注包围盒本身的形状和尺度来计算损失,从而提高精度,而nwd则有利于提升小目标的检测效果,最后使用SOTA单阶段检测器在不同规模的数据集上进行了一系列的对比实验,证明Shape - IoU或者结合Nwd的Shape - IoU优于现有的方法。

7、其他

可以结合一些可落地项目,在项目的基础上进行算法改进完成论文创新撰写; 相应的落地应用链接可点击:mbd.pub/o/author-aG…

本文由博客一文多发平台 OpenWrite 发布!