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

news2024/12/23 5:50:03

目录

一、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))
测试结果

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA学习笔记2

一、加号使用 二、数据类型 bit:计算机中的最小存储单位 byte(字节):计算机中基本存储单元,1byte8bit 浮点数符号位指数位尾数位 浮点数默认为double类型

Truenas scale入坑

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

Android 10.0 关于定制自适应AdaptiveIconDrawable类型的动态时钟图标的功能实现系列一

1.前言 在10.0的系统rom定制化开发中,在关于定制动态时钟图标中,原系统是不支持动态时钟图标的功能,所以就需要从新 定制动态时钟图标关于自适应AdaptiveIconDrawable类型的样式,就是可以支持当改变系统图标样式变化时,动态时钟 图标的背景图形也跟着改变,所以接下来就来…

揭开北斗系统和物联网的神秘面纱:探索未来技术的无限可能性

北斗系统和物联网是现代科技领域的两个重要概念。随着科学技术的快速发展和应用的深化,这两个术语逐渐进入人们的视野。本文将深入探讨北斗系统和物联网的原理、应用和未来发展前景,带您充分了解科技革命的幕后故事。北斗系统:引领全球导航新…

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

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

[单master节点部署]14.deamonSet和配置管理中心

Deamonset deamonSet可以保证集群的每一个物理节点上都可以运行某些服务的一个pod,就是说集群增加一个node,他自动在这个node上部署该服务。这适合监控、日志收集等服务。 部署deamonset: apiVsersion: apps/v1 kind: DeamonSet metadata:…

ThinkPHP定时任务是怎样实现的?

接到一个需求:定时检查设备信息,2分钟没有心跳的机器,推送消息给相关人员,用thinkphp5框架,利用框架自带的任务功能与crontab配合来完成定时任务。 第一步:分析需求 先写获取设备信息,2分钟之…

华为5288 V5服务器安装BCLinux8U4手记

本文记录了华为5288 V5服务器安装BCLinux8U4操作系统的过程。 一、系统环境 1、服务器 华为FusionServer Pro 5288 V5服务器 2、操作系统 BCLinux-R8-U4-Server-x86_64-220725.iso 官网下载地址 sha256sum:1d31d3b8e02279e89965bd3bea61f14c65b9d32ad2ab6d4eb…

基于Java的壁纸网站设计与实现

💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

JavaFx基础知识

1.Stage 舞台 如此这样的一个框框,舞台只是这个框框,并不管里面的内容 public void start(Stage primaryStage) throws Exception {primaryStage.setScene(new Scene(new Group()));primaryStage.getIcons().add(new Image("/icon/img.png"))…

HQ-SAM

不建议复现

腾讯云COS分布式对象存储

腾讯云COS分布式对象存储 腾讯云对象存储(Cloud Object Storage,COS)是腾讯云提供的一种用于存储海量文件的分布式存储服务。 腾讯云 COS 适用于多种场景,如静态网站托管、大规模数据备份和归档、多媒体存储和处理、移动应用数据存…

电脑彻底删除的文件还能恢复吗怎么弄 电脑删除的文件怎么恢复 回收站也删了

实测可行的文件恢复方法,无论是彻底删除的文件,还是被清空的回收站文件,使用该方法都可以轻松找回。整个恢复过程操作简单,并且绝不会损伤电脑硬件。这意味着,您再也不用为误删文件而焦虑了。有关电脑彻底删除的文件还…

在windows上安装objection

安装命令pip install objection -i https://mirrors.aliyun.com/pypi/simple hook指定进程 objection -g 测试 explore 进程名不定是包名,也可能是app名字,如“测试”就是app的名字 若出现如下错误,说明python 缺少setuptools 直接安装setu…

编程语言中浅拷贝(Shallow Copy)和深拷贝(Deep Copy)

编程语言中浅拷贝(Shallow Copy)和深拷贝(Deep Copy) 编程语言中浅拷贝(Shallow Copy)和深拷贝(Deep Copy)概念及JavaScript、Python、C、Java深拷贝和浅拷贝情况介绍。 浅拷贝和深拷…

【Redis】三大Redis内存分析工具介绍(Redisinsight、RDR、RMA)

目录 一、RedisInsight工具介绍 1、工具概述 2、关键特性 3、版本与服务 4、实际应用 二、Redis Data Reveal工具介绍 1、简介 2、主要特性 3、使用方法 4、注意事项 5、总结 三、Redis Memory Analyzer (RMA)工具介绍 1、工具概述 2、技术特点 3、应用场景 4、…

day02-统计数据

numpy统计学 1.求平均值[数组名.mean()/np.mean(数组名)] m1 np.arange(20).reshape((4,5))m1.mean() #9.5若想要求某一维的平均值,设置axis参数,多维数组元素指定: axis 0,将从上往下计算。axis 1,将从左往右计算…

使用getline()从文件中读取一行字符串

我们知道,getline() 方法定义在 istream 类中,而 fstream 和 ifstream 类继承自 istream 类,因此 fstream 和 ifstream 的类对象可以调用 getline() 成员方法。 当文件流对象调用 getline() 方法时,该方法的功能就变成了从指定文件…

最新抖音极速版双红包雨掘金助手

项目介绍: 抖音极速版目前小说里有双红包雨,单广告2000,金币1万比1,脚本自动看广告 设备需求: 安卓手机(最高支持安卓13.0版本) 购买后包含月卡脚本详细使用教程 百度网盘 请输入提取码百度…

SpringMVC 的工作流程和详细解释

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