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
相关推荐
AC赳赳老秦19 小时前
企业工商公开信息采集分析:OpenClaw 批量查询企业工商信息,生成企业画像报告
大数据·开发语言·python·自动化·php·deepseek·openclaw
FoldWinCard20 小时前
D6 Python 基础语法 --- 保留关键字
开发语言·python
暮暮祈安20 小时前
Celery 新手入门指南
java·数据库·python·flask·httpx
风吹心凉21 小时前
python3基础2026.7.22
开发语言·python
小猴子爱上树1 天前
一站式解决图片视频翻译难题的高效AI工具
人工智能·python·音视频
weixin_538601971 天前
智能体测开Day31
开发语言·python
lbb 小魔仙1 天前
Git + Python 项目工作流最佳实践:pre-commit、CI、CHANGELOG 自动化
git·python·ci/cd
dyxal1 天前
最长公共子序列(LCS)
python·算法
你驴我1 天前
WhatsApp Cloud API 速率限制下的令牌桶与退避策略实践
网络·后端·python
AC赳赳老秦1 天前
司法公开数据采集应用:OpenClaw 抓取裁判文书公开信息,批量整理同类参考案例
java·大数据·python·数据挖掘·数据分析·php·openclaw