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
相关推荐
开源技术12 小时前
Python Pillow 优化,打开和保存速度最快提高14倍
开发语言·python·pillow
Li emily12 小时前
解决港股实时行情数据 API 接入难题
人工智能·python·fastapi
wfeqhfxz258878213 小时前
农田杂草检测与识别系统基于YOLO11实现六种杂草自动识别_1
python
mftang13 小时前
Python 字符串拼接成字节详解
开发语言·python
0思必得013 小时前
[Web自动化] Selenium设置相关执行文件路径
前端·爬虫·python·selenium·自动化
石去皿13 小时前
大模型面试通关指南:28道高频考题深度解析与实战要点
人工智能·python·面试·职场和发展
jasligea14 小时前
构建个人智能助手
开发语言·python·自然语言处理
测试秃头怪14 小时前
面试大厂就靠这份软件测试八股文了【含答案】
自动化测试·软件测试·python·功能测试·面试·职场和发展·单元测试
测试杂货铺14 小时前
软件测试面试题大全,你要的都在这。。
自动化测试·软件测试·python·功能测试·面试·职场和发展·测试用例
测试大圣14 小时前
软件测试基础知识总结(超全的)
软件测试·python·功能测试·测试工具·职场和发展·单元测试·测试用例