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
相关推荐
珺毅同学9 小时前
YOLO生成预测json标签迁移问题
python·yolo·json
骑士雄师9 小时前
18.4 长期记忆可修改版
python
~小先生~9 小时前
Python从入门到放弃(一)
开发语言·python
天佑木枫9 小时前
第2天:变量与数据类型 —— 让程序记住信息
python
Dust-Chasing10 小时前
Claude Code源码剖析 - Claude Code 上下文压缩机制
人工智能·python·ai
Cloud_Shy61811 小时前
解读《Effective Python 3rd Edition》:从练气到老魔(第五章 Item 33 - 35)
开发语言·人工智能·笔记·python·学习方法
abcy07121312 小时前
python pandas csv异步后台清洗前端优先返回成功信息
前端·python·pandas
颜酱12 小时前
LangChain使用RAG 入门:让大模型读懂你的私有文档
python·langchain
天天进步201513 小时前
Python全栈项目--校园智能宿舍管理系统
开发语言·python
测试员周周13 小时前
【AI测试智能体-面试】AI测试面试60题(附回答思路)
人工智能·python·功能测试·测试工具·单元测试·自动化·测试用例