目标检测入门:3.目标检测损失函数(IOU、GIOU、GIOU)

目录

一、IOU

二、GIOU

三、DIOU

四、DIOU_Loss实战


在前面两章里面训练模型时,损失函数都是选择L1Loss(平均绝对值误差(MAE))损失函数,L1Loss损失函数公式如下:

{Loss}_{\text {MAE }}=\frac{1}{N} \sum_{n=1}^{N}|y(n)-\hat{y}(n)|

由公式可知,L1Loss损失函数是线性函数,其梯度是恒定的,即无论预测值与真实值之间的误差大小,其梯度都是常数(+1或-1)。虽然避免了梯度爆炸的问题,但在误差很小时,梯度仍然较大,不利于梯度在接近最优解时的精细调整。同时L1Loss并不直接优化我们最关心的目标——即预测框和真实框的之间的重叠程度。L1Loss通常是分别计算预测框和真实框各个坐标点之间的L1距离,这种方法假设了坐标点之间是相互独立的,没有考虑它们之间的相关性。

预测框与真实框损失

上图中的绿框代表真实框,黑框为模型的预测框,两个预测框的大小不一,与真实框之间的重叠面积也不一致,但得到的L1Loss损失值却是一样的。说明L1Loss损失不能准确反应两个目标边界框重合的程度,因此诞生了IOU损失函数。

一、IOU

论文原文:《UnitBox: An Advanced Object Detection Network》icon-default.png?t=N7T8http://arxiv.org/pdf/1608.01471

IOU(Intersection over Union)损失函数是目标检测中常用的一种损失韩式,主要用于评估预测边界框(Bounding Box)与真实框(Ground Truth Box)之间的重叠程度,并作为优化目标来指导模型训练。

IOU即交并比,适用于衡量两个边界框的之间的重叠程度的度量指标。其计算公式为:

IoU=\frac{|A\cap B|}{|A\cup B|}

即两个框的相交的面积除以两个框相并的面积。

L1Loss与IOU

如上图所示,第一个预测框与真实框的相交的面积为(25-5)*(15-5)=200,相并的面积为15*(25-5)+(35-5)*50-200=1600,最终IOU=200/1600=0.125。而第二个预测框的IOU则为0.319。相对于两个预测框计算L1损失的结果相同,可以看出IOU能直接反映出预测框与真实框之间的重叠程度。

IOU损失计算方式如下:

Iou Loss

简单代码实现如下:
 

import cv2
import numpy as np


def IOU(RecA, RecB):
    x1 = max(RecA[0], RecB[0])
    y1 = max(RecA[1], RecB[1])
    x2 = min(RecA[2], RecB[2])
    y2 = min(RecA[3], RecB[3])
    # 计算交集部分面积
    interArea = max(0, x2 - x1 + 1) * max(0, y2 - y1 + 1)

    # 计算预测值和真实值的面积
    RecA_Area = (RecA[2] - RecA[0] + 1) * (RecA[3] - RecA[1] + 1)
    RecB_Area = (RecB[2] - RecB[0] + 1) * (RecB[3] - RecB[1] + 1)

    #计算并集部分面积
    UnionArea=float(RecA_Area + RecB_Area - interArea)

    # 计算IOU
    iou = interArea / UnionArea

    return iou


img = np.zeros((512, 512, 3), np.uint8)
img.fill(255)

RecA = [50, 50, 300, 300] #方框的左上角坐标和右上角坐标
RecB = [60, 60, 320, 320]

cv2.rectangle(img, (RecA[0], RecA[1]), (RecA[2], RecA[3]), (0, 255, 0), 5)
cv2.rectangle(img, (RecB[0], RecB[1]), (RecB[2], RecB[3]), (255, 0, 0), 5)

iou =IOU(RecA, RecB)
font = cv2.FONT_ITALIC

#展示IOU结果
cv2.putText(img, "IOU = %.2f" % iou, (130, 190), font, 0.6, (0, 0, 0), 2)
cv2.putText(img, "IOU_Loss = %.2f" % (1-iou), (80, 350), font, 0.6, (0, 0, 0), 2)

cv2.imshow("IOU",img )
cv2.waitKey()
cv2.destroyAllWindows()

IOU

最终结果如上图所示,IOU_Loss相对与L1Loss更能反映预测框与真实框之间的重叠程度。

如上图所示,IOU最大的缺点是当预测框与真实框不相交的时候,其IOU都为0,此时模型的梯度消失,导致无法进一步优化,各位可以试一下将IOU_Loss替换前两章小黄人目标检测任务中的L1_Loss,会发现模型无法收敛。

二、GIOU

原文论文:《Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression》icon-default.png?t=N7T8http://arxiv.org/pdf/1902.09630GIOU(Generalized Intersection over Union),即广义交并比,这是一种在目标检测领域中用来评估预测框与真实框之间重叠度的指标,传统IOU在两个框无重叠时无法反映他们之间的远近关系,在模型训练时会出现梯度消失的情况。为了解决这个问题,GIOU被提出。公式如下:

GIOU=IoU-\frac{|C-(A\cup B)|}{|C|}

GIOU引入了一个最小闭包区域(即能同事包含预测框与真实框的最小矩形框),如上图中的红框C,并引入了一个额外的惩罚项来反映两个框的远近程度。

代码实现如下:

import cv2
import numpy as np


def GIOU(RecA, RecB):
    x1 = max(RecA[0], RecB[0])
    y1 = max(RecA[1], RecB[1])
    x2 = min(RecA[2], RecB[2])
    y2 = min(RecA[3], RecB[3])
    # 计算交集部分面积
    interArea = max(0, x2 - x1 + 1) * max(0, y2 - y1 + 1)

    # 计算预测值和真实值的面积
    RecA_Area = (RecA[2] - RecA[0] + 1) * (RecA[3] - RecA[1] + 1)
    RecB_Area = (RecB[2] - RecB[0] + 1) * (RecB[3] - RecB[1] + 1)

    #计算并集部分面积
    UnionArea=float(RecA_Area + RecB_Area - interArea)

    # 计算IOU
    iou = interArea / UnionArea

    C_x1 = min(RecA[0], RecB[0])
    C_y1 = min(RecA[1], RecB[1])
    C_x2 = max(RecA[2], RecB[2])
    C_y2 = max(RecA[3], RecB[3])
    #计算最小闭包矩形面积
    C_area = (C_x2 - C_x1) * (C_y2 - C_y1)

    IOU = interArea / UnionArea
    GIOU = IOU - abs((C_area - UnionArea) / C_area)
    return GIOU


img = np.zeros((512, 512, 3), np.uint8)
img.fill(255)

RecA = [50, 50, 80,80] #方框的左上角坐标和右上角坐标
RecB = [100, 160, 320, 320]

cv2.rectangle(img, (RecA[0], RecA[1]), (RecA[2], RecA[3]), (0, 255, 0), 5)
cv2.rectangle(img, (RecB[0], RecB[1]), (RecB[2], RecB[3]), (255, 0, 0), 5)

iou =GIOU(RecA, RecB)
font = cv2.FONT_ITALIC

#展示IOU结果
cv2.putText(img, "GIOU = %.2f" % iou, (200, 450), font, 0.6, (0, 0, 0), 2)

cv2.imshow("IOU",img)
cv2.waitKey()
cv2.destroyAllWindows()

GIOU在计算预测框与真实框之间的重叠程度时,即使两框之间无重叠区域,其结果也不会为0,有效的解决了模型在预测框也真实框之间无交集时出现的梯度消失问题。

GIOU缺点

当真实框内含预测框时,如上图所示,IOU和GIOU的值相同,无法反映出哪个预测框更好。

三、DIOU

论文原文:《Distance-IoU Loss: Faster and Better Learning for Bounding Box Regression》icon-default.png?t=N7T8http://arxiv.org/pdf/1911.08287

DIOU(Distance Intersection over Union)是一种改进的交并比,DIOU既考虑到了IOU的缺点,又考虑到了GIOU的缺点。DIOU也是增加了最小闭包区域(即能同事包含预测框与真实框的最小矩形框),但不再计算闭包区域与预测框真实框之间的交并比,而是计算它们之间的欧氏距离。公式如下:

IoU-\mathrm{DIoU}=\frac{\rho^2(\mathrm{A},\mathrm{B})}{\mathrm{c}^2}

其中c代表最小闭包区域矩形的对角线距离,d代表预测框中心点和真实框中心点距离。DIOU等于d的平方除以c的平方。

代码实现如下

import cv2
import numpy as np


def DIOU(RecA, RecB):
    x1 = max(RecA[0], RecB[0])
    y1 = max(RecA[1], RecB[1])
    x2 = min(RecA[2], RecB[2])
    y2 = min(RecA[3], RecB[3])
    # 计算交集部分面积
    interArea = max(0, x2 - x1 + 1) * max(0, y2 - y1 + 1)

    # 计算预测值和真实值的面积
    RecA_Area = (RecA[2] - RecA[0] + 1) * (RecA[3] - RecA[1] + 1)
    RecB_Area = (RecB[2] - RecB[0] + 1) * (RecB[3] - RecB[1] + 1)

    #计算并集部分面积
    UnionArea=float(RecA_Area + RecB_Area - interArea)

    # 计算IOU
    iou = interArea / UnionArea

    # DISTANCE
    C_x1 = min(RecA[0], RecB[0])
    C_y1 = min(RecA[1], RecB[1])
    C_x2 = max(RecA[2], RecB[2])
    C_y2 = max(RecA[3], RecB[3])

    center_x1 = (RecA[0]+RecA[2]) / 2
    center_y1 = (RecA[1]+RecA[3]) / 2
    center_x2 = (RecB[0] + RecB[2]) / 2
    center_y2 = (RecB[1] + RecB[3]) / 2

    center_distance = (center_x2 - center_x1) ** 2 + (center_y2 - center_y1) ** 2
    c_distance = (C_x2 - C_x1) ** 2 + (C_y2 - C_y1) ** 2

    DIOU = iou - center_distance / c_distance

    return DIOU



img = np.zeros((512, 512, 3), np.uint8)
img.fill(255)

RecA = [0, 0, 30,50] #方框的左上角坐标和右上角坐标
RecB = [5, 5, 25, 45]

cv2.rectangle(img, (RecA[0], RecA[1]), (RecA[2], RecA[3]), (0, 255, 0), 5)
cv2.rectangle(img, (RecB[0], RecB[1]), (RecB[2], RecB[3]), (255, 0, 0), 5)

iou =DIOU(RecA, RecB)
font = cv2.FONT_ITALIC

#展示IOU结果
cv2.putText(img, "DIOU = %.2f" % iou, (200, 450), font, 0.6, (0, 0, 0), 2)


cv2.imshow("IOU",img)
cv2.waitKey()
cv2.destroyAllWindows()

当真实框内含预测框时,DIOU也能反映出不同的预测框之间的差距,有效的解决了GIOU的缺点。

现在还有各种改进的交并比,如CIOU、EIOU、Focal-EIOU、SIOU、WIOU等,如果大家有兴趣可以去学习一下这些改进的IOU。

四、DIOU_Loss实战

在这一节我们用学习到的DIOU替换前两章中的小黄人目标检测的L1Loss损失函数。

DIOU_Loss代码如下

class DIou_Loss(nn.Module):
    def __init__(self):
        super(DIou_Loss, self).__init__()

    def box_iou(self, b1, b2):
        """
        输入为:
        ----------
        b1: tensor, shape=(batch,[x1,y1,x2,y2]) x1,y1 左上角坐标,x2,y2右下角坐标
        b2: tensor, shape=(batch, [x1,y1,x2,y2])
        返回为:
        -------
        iou: tensor, shape=(batch, 1)
        """
        b1_wh = b1[:, 2:4] - b1[:, :2]
        b2_wh = b2[:, 2:4] - b2[:, :2]
        inter_x1 = torch.max(b1[:, 0], b2[:, 0])
        inter_y1 = torch.max(b1[:, 1], b2[:, 1])
        inter_x2 = torch.min(b1[:, 2], b2[:, 2])
        inter_y2 = torch.min(b1[:, 3], b2[:, 3])


        # ----------------------------------------------------#
        #   求真实框和预测框所有的iou
        # ----------------------------------------------------#
        intersect_area =  (torch.clamp(inter_x2 - inter_x1, min=0)+1) * (torch.clamp(inter_y2 - inter_y1, min=0)+1)
        b1_area = (b1_wh[:, 0]+1) * (b1_wh[:, 1]+1)
        b2_area = (b2_wh[:, 0]+1) * (b2_wh[:, 1]+1)
        union_area = b1_area + b2_area - intersect_area
        iou = intersect_area / union_area

        # DISTANCE
        C_x1 = torch.min(b1[...,0], b2[...,0])
        C_y1 = torch.min(b1[...,1], b2[...,1])
        C_x2 = torch.max(b1[...,2], b2[...,2])
        C_y2 = torch.max(b1[...,3], b2[...,3])

        center_x1 = (b1[...,0] + b1[...,2]) / 2
        center_y1 = (b1[...,1] + b1[...,3]) / 2
        center_x2 = (b2[...,0] + b2[...,2]) / 2
        center_y2 = (b2[...,1] + b2[...,3]) / 2

        center_distance = (center_x2 - center_x1) ** 2 + (center_y2 - center_y1) ** 2
        c_distance = (C_x2 - C_x1) ** 2 + (C_y2 - C_y1) ** 2

        DIOU = iou - center_distance / c_distance


        return DIOU

    def forward(self, input, targets=None):
        iou = self.box_iou(input, targets)  # 计算交互比
        loss = torch.mean((1 - iou))
        return loss

其余代码可以去github下载

GitHub - 1578630119/Single_Object_Detection

再将损失函数换成DIOU_Loss,同时我们还可以利用IOU计算模型的准确率,设置一个阈值,即交并比值,当大于这个值,则这个预测框是正确的,小于则是错误的,最终可以得到模型准确率。代码如下

def iou(b1, b2):
    b1_wh = b1[:, 2:4] - b1[:, :2]
    b2_wh = b2[:, 2:4] - b2[:, :2]
    inter_x1 = torch.max(b1[:, 0], b2[:, 0])
    inter_y1 = torch.max(b1[:, 1], b2[:, 1])
    inter_x2 = torch.min(b1[:, 2], b2[:, 2])
    inter_y2 = torch.min(b1[:, 3], b2[:, 3])

    # ----------------------------------------------------#
    #   求真实框和预测框所有的iou
    # ----------------------------------------------------#
    intersect_area = (torch.clamp(inter_x2 - inter_x1, min=0) + 1) * (torch.clamp(inter_y2 - inter_y1, min=0) + 1)
    b1_area = (b1_wh[:, 0] + 1) * (b1_wh[:, 1] + 1)
    b2_area = (b2_wh[:, 0] + 1) * (b2_wh[:, 1] + 1)
    union_area = b1_area + b2_area - intersect_area
    iou = intersect_area / union_area
    return iou

def test():
    #如果已经训练好了权重,模型直接加载权重文件进行测试#
    model_test=Net_res()
    model_test.load_state_dict(torch.load('model.pth',map_location=device))
    model_test.eval()
    model_test=model_test.to(device)
    test_loss = 0
    correct=0
    with torch.no_grad():  # 仅测试模型,禁用梯度计算
        for batch_idx, (data, target) in enumerate(eval_loader):
            data = data.to(device)
            target = target.to(device)
            output = model_test(data)
            test_loss += criterion(output, target).item()
            result = iou(output, target)
            result = torch.where(result > 0.3, 1, 0)
            correct = correct + result.sum()
    print('Accuracy:{:.2f}%'.format((correct / ((batch_idx+1)*test_batch_size)).to('cpu').detach().numpy()*100))
    print('Test Loss:',test_loss/(batch_idx+1))
测试结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/771654.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Midway Serverless 发布 2

可以看看优化后的开发情况,不仅和应用一样,速度还比较快,也不会生成临时目录,修改实时生效。 这是 v2.0 和 v1.0 的根本性变化,也是整体架构升级带来的巨大优势。 当然,这一块并不是功能的新增&#xff0c…

【C++】类和对象(中)--上篇

个人主页~ 类和对象上 类和对象 一、类的六个默认成员函数二、构造函数1、构造函数基本概念2、构造函数的特性 三、析构函数1、析构函数的概念2、特性 四、拷贝构造函数1、拷贝构造函数的概念2、特征 一、类的六个默认成员函数 如果有个类中什么成员都没有,那么被称…

Python从0到100(三十六):字符和字符集基础知识及其在Python中的应用

1. 字符和字符集概述 字符(Character)是构成书面语言的基本元素,它包括但不限于各国家的文字、标点符号、图形符号和数字。字符集(Character set)则是一个包含多个字符的系统,用于统一管理和编码不同的字符。 常见字符集 ASCII:最早的字符…

Truenas scale入坑

家里有一台刚上大学时配的电脑,看着无用武之地,又还能用,于是想那它来搞个私有云nas。 一、选择想要入的坑 一开始对这块没什么了解和概念,最早是在旧主机上安装了个Ubuntu,然后再安装CassOS小尝试了下。可能CassOS里…

【Apache Doris】周FAQ集锦:第 9 期

【Apache Doris】周FAQ集锦:第 9 期 SQL问题数据操作问题运维常见问题其它问题关于社区 欢迎查阅本周的 Apache Doris 社区 FAQ 栏目! 在这个栏目中,每周将筛选社区反馈的热门问题和话题,重点回答并进行深入探讨。旨在为广大用户和…

eNSP-VLAN虚拟局域网

一、出现Vlan的原因 同一个局域网,使用交换机连接,虽然比集线器相连,降低了广播风暴,但是局域网主机数量够多的时候,正常的广播数据(arp、dhcp)也很影响网络性能,所以还需要进一步降低广播风暴——VLAN (图…

双指针算法:快速排序模拟实现

目录 1.思路解析 2:代码展示 1.思路解析 使用双指针pre和cur 指针cur用于检测符合条件的数据 cur和pre数据发生交换用于将符合条件的数据(比key小)向左扔 一轮循环结束时,以pre为分界点,除去key,pre左边的…

SpringMVC 的工作流程和详细解释

Spring MVC(Model-View-Controller)框架是基于经典的 MVC 设计模式构建的,用于开发 Web 应用程序。下面是 Spring Boot MVC 的工作流程和详细解释: 1.客户端发起请求 1.客户端(通常是浏览器)发起 HTTP 请求…

VUE Pinia状态持久化

效果 实现方法 插件:pinia-plugin-persistedstate 链接地址 具体操作 安装 npm i pinia-plugin-persistedstate 添加到 pinia 实例上 import { createPinia } from pinia import piniaPluginPersistedstate from pinia-plugin-persistedstateconst pinia cre…

自动化设备上位机设计 一

目录 一 设计原型 二 后台代码 一 设计原型 二 后台代码 namespace 自动化上位机设计 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){}} }namespace 自动化上位机设计 {partial class Fo…

PDM与ERP物料编码技术在产品设计中的区别与应用

01 概 述 产品是企业赖以生存的基础,产品数据是企业最基本的也是最重要的数据,产品数据存在于产品设计、采购、生产、销售、服务、库存管理等全过程中。通过对产品设计数据进行编码,并增加采购、库存、生产、制造等属性信息,可以…

2.5 C#视觉程序开发实例1----设计一个IO_Manager

2.5 C#视觉程序开发实例1----设计一个IO_Manager 第一步目标: 1 实现获取IO触发信号Trig0 2 能够实现程序切换 3 图像处理后能够输出一个脉冲 1 IO 引脚定义 1.1 输入信号定义 1.2 输出信号定义 2 IO时序图 2.1 触发时序 2.2 切换程序时序图 3 IO_Manager.cs …

Android系统集成和使用FFmpeg

文章目录 前言FFmpeg源码下载交叉编译NDK下载x264编译源码下载编译 FFmpeg编译脚本 AOSP继承FFmpeg 前言 原生AOSP中并未继承FFmpeg,所以要想在android上使用,需要自己编译集成。 FFmpeg源码下载 git clone https://git.ffmpeg.org/ffmpeg.git目前最新…

云桌面运维工程师

一 深信服驻场工程师 1 深信服AC、AF、AD、NGAF、WOC Atrust、WAF项目实施经验者优先考虑。 负责云桌面POC测试 部署和配置:设置云桌面基础设施,包括虚拟化平台、云桌面管理软件和相关组件。确保正确配置网络、存储和安全设置。 用户体验&#xff1…

oracle用户过期/设置无限期用户/ORA-28001:the password has expired

oracle默认情况下,新建的账户只有180天的有效期,在有效期到期前一周就会报警。而一旦过了有效期,账户就会被锁定无法登录。所以为了方便起见,要修改oracle用户的有效期为无限。 1.查看用户密码的有效期设置,一般默认的…

如何解决滑块验证码 | 最佳滑块拼图验证码解决方案

你是否曾经在遇到滑块验证码时感觉像一个拼图大师?那种需要将拼图块完美地匹配到槽位中以证明你是人类的验证码?我也曾多次遇到过这些棘手的测试,虽然有点挑战性,但它们也是网络安全世界的一个迷人一瞥。在本指南中,我…

能保存到相册的风景视频在哪下载?下载风景视频网站分享

在当今以视觉为核心的时代,高清美丽的风景视频不仅能够丰富我们的日常生活,还能提供心灵上的慰藉。无论是为了制作视频项目,还是仅仅想要珍藏一些精美的风景画面,获取高质量的风景视频素材显得尤为重要。许多人可能会问&#xff1…

班迪录屏(Bandicam)7.0下载以及安装教程

最近有小伙伴私信我,问我有没有好用的录屏工具,今天给大家分享一个我一直在使用的录屏工具,也是解锁了V1P版本,绿色版打开就可以使用~ Bandicam录屏(PC) Bandicam录屏是一款专为捕捉屏幕精彩瞬间而设计的…

使用 iconfont.ttf文件保存多个图标文件,并且像文字一样使用代码绘制出来

先看演示效果 这里的多个图标其实是存储在 iconfont.ttf文件中 这个文件里面的图标对应的编码 显示代码 void CMFCApplication3Dlg::OnBnClickedOk() {// 加载字体文件CString fontPath = _T("C:\\Users\\35497\\Desktop\\test\\MFCApplication3\\font\\iconfont.ttf&qu…