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
相关推荐
MediaTea1 天前
Python:实例 __dict__ 详解
java·linux·前端·数据库·python
SunnyDays10111 天前
Python Excel 打印设置全攻略(打印区域、缩放、页边距、页眉页脚等)
python·excel打印设置·excel页面设置·excel打印选项
小鸡吃米…1 天前
Python的人工智能-机器学习
人工智能·python·机器学习
傻啦嘿哟1 天前
Python上下文管理器:优雅处理资源释放的魔法工具
开发语言·python
阿方索1 天前
Python 基础简介
开发语言·python
BBB努力学习程序设计1 天前
Python异步编程完全指南:从asyncio到高性能应用
python·pycharm
deephub1 天前
机器学习时间特征处理:循环编码(Cyclical Encoding)与其在预测模型中的应用
人工智能·python·机器学习·特征工程·时间序列
追光天使1 天前
Python 连接数据库并遍历数据
python
BBB努力学习程序设计1 天前
Python迭代器与生成器深度解析:懒加载的艺术
python·pycharm
dazzle1 天前
OpenCV基础教学(二):图像的灰度化处理
python·opencv·计算机视觉