GIOU (Generalized Intersection over Union) 详解

  1. GIOU 概述

    GIOU(Generalized IoU)是目标检测领域中用于评估边界框相似度的度量指标,也是对传统IoU的改进。它解决了IoU在零重叠情况下的问题,并为边界框回归提供了更好的损失函数。

  2. IoU 的局限性

    传统 IoU 公式

python 复制代码
IoU = Area of Intersection / Area of Union

IoU 的缺点:

1.零重叠时梯度为零:当两个框不重叠时,IoU=0,梯度也为0,无法优化

2.无法区分不同分离情况:当IoU=0时,无法知道两个框有多远

3.对尺度敏感:相同的偏移量,对小目标影响更大

  1. GIOU 的定义
    GIOU 在 IoU 的基础上引入了最小闭合区域的概念:
python 复制代码
GIOU = IoU - (C - U) / C

其中:

C:包含预测框A和真实框B的最小闭合凸区域(通常是矩形)的面积

U:A和B的并集面积

(C - U):最小闭合区域中不属于A∪B的部分

  1. GIOU 的数学公式

具体计算步骤:

1.计算两个框的交集面积:I = Area(A ∩ B)

2.计算两个框的并集面积:U = Area(A) + Area(B) - I

3.计算IoU:IoU = I / U

4.找到包含A和B的最小闭合矩形C

5.计算GIOU:GIOU = IoU - (Area© - U) / Area©

公式表达:

python 复制代码
GIOU = IoU - |C \ (A ∪ B)| / |C|
  1. GIOU 的特性
    值域范围:
    最佳情况:A和B完全重合时,GIOU = IoU = 1

最差情况:当A和B相距无限远时,GIOU趋近于 -1

取值范围:GIOU ∈ [-1, 1]

优点:

保持尺度不变性

非重叠时有梯度:即使两个框不重叠,GIOU也能提供有效的梯度

对称性:GIOU(A,B) = GIOU(B,A)

三角不等式不敏感:更符合实际需求

  1. GIOU Loss
    GIOU Loss 通常定义为:
python 复制代码
L_GIOU = 1 - GIOU

这样:

当两个框完全重合时,Loss = 0

当两个框完全不重合且距离很远时,Loss ≈ 2

  1. 代码实现

Python 实现示例:

python 复制代码
import numpy as np
import torch

def calculate_giou(box1, box2):
    """
    计算GIOU
    box1, box2: [x1, y1, x2, y2] 格式
    """
    # 确保x2 > x1, y2 > y1
    box1 = [min(box1[0], box1[2]), min(box1[1], box1[3]),
            max(box1[0], box1[2]), max(box1[1], box1[3])]
    box2 = [min(box2[0], box2[2]), min(box2[1], box2[3]),
            max(box2[0], box2[2]), max(box2[1], box2[3])]
    
    # 计算交集
    x1_inter = max(box1[0], box2[0])
    y1_inter = max(box1[1], box2[1])
    x2_inter = min(box1[2], box2[2])
    y2_inter = min(box1[3], box2[3])
    
    width_inter = max(0, x2_inter - x1_inter)
    height_inter = max(0, y2_inter - y1_inter)
    area_inter = width_inter * height_inter
    
    # 计算各自面积
    area_box1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
    area_box2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
    
    # 计算并集
    area_union = area_box1 + area_box2 - area_inter
    
    # 计算IoU
    iou = area_inter / area_union if area_union > 0 else 0
    
    # 计算最小闭合区域C
    x1_c = min(box1[0], box2[0])
    y1_c = min(box1[1], box2[1])
    x2_c = max(box1[2], box2[2])
    y2_c = max(box1[3], box2[3])
    
    area_c = (x2_c - x1_c) * (y2_c - y1_c)
    
    # 计算GIOU
    giou = iou - (area_c - area_union) / area_c if area_c > 0 else -1
    
    return giou

def giou_loss(pred_boxes, target_boxes):
    """计算GIOU损失"""
    giou = calculate_giou(pred_boxes, target_boxes)
    return 1 - giou

PyTorch 实现:

python 复制代码
import torch
import torch.nn as nn

class GIoULoss(nn.Module):
    def __init__(self, reduction='mean'):
        super(GIoULoss, self).__init__()
        self.reduction = reduction
    
    def forward(self, pred, target):
        """
        pred, target: [N, 4] 格式,坐标形式为 [x1, y1, x2, y2]
        """
        # 确保坐标顺序正确
        pred_x1 = torch.min(pred[:, 0], pred[:, 2])
        pred_y1 = torch.min(pred[:, 1], pred[:, 3])
        pred_x2 = torch.max(pred[:, 0], pred[:, 2])
        pred_y2 = torch.max(pred[:, 1], pred[:, 3])
        
        target_x1 = torch.min(target[:, 0], target[:, 2])
        target_y1 = torch.min(target[:, 1], target[:, 3])
        target_x2 = torch.max(target[:, 0], target[:, 2])
        target_y2 = torch.max(target[:, 1], target[:, 3])
        
        # 计算交集
        inter_x1 = torch.max(pred_x1, target_x1)
        inter_y1 = torch.max(pred_y1, target_y1)
        inter_x2 = torch.min(pred_x2, target_x2)
        inter_y2 = torch.min(pred_y2, target_y2)
        
        inter_area = torch.clamp(inter_x2 - inter_x1, min=0) * \
                    torch.clamp(inter_y2 - inter_y1, min=0)
        
        # 计算各自面积
        pred_area = (pred_x2 - pred_x1) * (pred_y2 - pred_y1)
        target_area = (target_x2 - target_x1) * (target_y2 - target_y1)
        
        # 计算并集
        union_area = pred_area + target_area - inter_area
        
        # 计算IoU
        iou = inter_area / (union_area + 1e-6)
        
        # 计算最小闭合区域
        c_x1 = torch.min(pred_x1, target_x1)
        c_y1 = torch.min(pred_y1, target_y1)
        c_x2 = torch.max(pred_x2, target_x2)
        c_y2 = torch.max(pred_y2, target_y2)
        
        c_area = (c_x2 - c_x1) * (c_y2 - c_y1) + 1e-6
        
        # 计算GIOU
        giou = iou - (c_area - union_area) / c_area
        
        # 计算损失
        loss = 1 - giou
        
        if self.reduction == 'mean':
            return loss.mean()
        elif self.reduction == 'sum':
            return loss.sum()
        else:
            return loss
相关推荐
汐ya~41 分钟前
Cursor连接异常问题“Model not available/connection failed”解决:IDE内置代理配置,无需全局流量代理与虚拟网卡
python·编辑器·cursor
海市公约1 小时前
Python操作SQLite数据库:从基础语法到完整项目实战
数据库·ide·python·程序人生·架构·pycharm·sqlite
轻竹办公PPT1 小时前
学校要求开题报告 PPT,有没有模板?
人工智能·python·powerpoint
大雾的小屋1 小时前
【1-1】基于深度学习的滚动轴承故障诊断系统:从数据处理到交互式界面全流程解析
人工智能·pytorch·深度学习·系统架构·人机交互·pyqt·用户界面
神奇的代码在哪里1 小时前
C++的演进与我的编程学习之旅:从底层基础到AI应用
c++·人工智能·python·学习·程序人生·个人开发
lanbo_ai1 小时前
基于深度学习的宠物猫品种识别系统,resnet50,alexnet,mobilenet【pytorch框架,python代码】
人工智能·pytorch·python·深度学习·cnn
Kyln.Wu1 小时前
【python实用小脚本-315】跨界应用 | 烹饪爱好者如何用Python改造传统选菜流程?自然语言处理×美食推荐的化学反应,轻松实现AI菜谱生成
人工智能·python·自然语言处理
起来_敲代码1 小时前
super()调用和父类名调用的区别
python
YuSun_WK1 小时前
检索增强VS知识蒸馏VS伪标签扩展
人工智能·python