论文阅读笔记 | 目标检测算法——Generalized Focal Lossv1,v2

简介: 论文阅读笔记 | 目标检测算法——Generalized Focal Lossv1,v2

1. Generalized Focal Loss


Abstract

One-stage检测器基本上将目标检测定义为密集分类和定位(即边界盒回归)。该分类方法通常采用Focal loss进行优化,回归框位置通常采用狄拉克分布法进行学习。One-stage检测器的一个最新趋势是引入一个独立的预测分支来估计定位质量,预测的质量有助于分类,以提高检测性能。本文研究了质量估计、分类和定位这三个基本要素的表示。


1.1 Problem

作者发现了目前这种方法的两个问题:


  1. 质量的评估在训练与推理之使用不一致。

1)定位质量估计和分类评分通常是独立训练的,但在推理过程中会综合使用(如乘法)

image.png

2) 目前定位质量估计的监督只分配给阳性样本,这是不可靠的,因为阴性样本可能有机会获得不可控制的更高的质量预测

image.png

ps:图 (b)中的散点图表示具有预测分数的随机抽样实例,其中蓝点清楚地说明了单独表示时预测分类分数和预测IoU分数之间的弱相关性。红圈中的部分包含许多可能的负面因素,伴随着大量的质量预测,其中所蕴含的负样本,可能会排在正样本前面,削弱了检测器的性能。


这两个因素导致了训练和测试之间的差距,并可能会降低检测性能,例如,在NMS中,随机高质量分数的负实例可能排在质量预测较低的正实例前面。


  1. 边界框的不灵活表示

广泛使用的包围盒表示可以看作是目标盒坐标的Dirac delta分布,但是它没有考虑到数据集的模糊性和不确定性。作者希望用一种general的分布去建模边界框的表示。

image.png

ps:希望这一般分布的学习表示方法可以通过其形状来反映底层信息,其中平坦分布表示边界不清楚、不明确(圆形),尖锐分布表示边界清楚的情况。


1.2 Solve

为了解决上述问题,作者设计了新的边界框表示及其定位质量。


1)For localization quality representation

为了保证training和test一致,同时还能够兼顾分类score和质量预测score都能够训练到所有的正负样本,那就是将两者的表示进行联合。这个合并也非常有意思,从物理上来讲,依然还是保留分类的向量,但是对应类别位置的置信度的物理含义不再是分类的score,而是改为质量预测的score,这样就做到了两者的联合表示。 将分类分数和IoU分数统一为一个联合的单一变量(记作“分类IoU联合表征”) 。 此外,负面的将被监督为0质量分数,从而整体质量预测变得更加可靠。


2)For bounding box representation

提出通过直接学习其连续空间上的离散概率分布来表示盒位的任意分布,而不引入任何其他更强的先验(如高斯分布)。然而,对于提出的分类­IoU联合表征的情况,除了仍然存在不平衡风险外,我们还面临一个新的问题,即连续IoU标签(0~ 1)作为监管,因为原来的FL目前只支持离散的{1,0}类别标签。我们成功地解决了这个问题,将FL从{1,0}离散版本扩展到其连续变体,称为Generalized Focal Loss广义焦点损耗(GFL)。

Quality Focal Loss (QFL)专注于一组稀疏的难例子,同时对相应类别产生连续的0 ~ 1质量估计;Distribution Focal Loss(DFL)使得网络在任意、灵活分布的情况下,快速地专注于学习目标包围盒连续位置周围值的概率。


Generalized Focal Loss (GFL)带来了三个优点:

1)当One­stage与附加的质量估计想结合时,它弥补了训练和测试之间的差距,从而使分类和定位质量的表示更加简单、联合和有效

2)很好地模拟了边界框的底层分布,提供了更丰富、更准确的盒位置

3)不引入额外开销的情况下,性能持续提高


Quality Focal Loss (QFL)

为了解决上述训练阶段和测试阶段不一致的问题,我们提出了质量(即IoU分数)和分类分数(以下简称“分类­IoU”)的联合表示,其监督软化了标准one­hot类别标签,导致可能浮动相应的类别,使得targety在∈[0,1]上。具体来说,y = 0表示负样本质量分数为0,而0 < y ≤ 1表示Iou分数为y的正样本。其中,质量标签y遵循常规定义,既预测的边界框与对应的真实边界框之间的iou得分,动态值为0~1.之后,对y进行sigmoid算子运算,实现多类实现,将sigmoid的输出标记为σ。

image.png


Distribution Focal Loss (DFL)

采用从位置到边界盒四周的相对偏移量作为回归目标(见图4中的回归分支)。边界盒回归模型的常规操作被标记为Dirac delta分布δ(x ­ y)。作者提出通过明确鼓励接近目标的值的高概率来优化p(x)的形状。此外,通常情况下,最合适的底层位置(如果存在的话)将离粗标签不远。

image.png

image.png


Generalized Focal Loss (GFL)

值得注意的是,QFL和DFL可以统一成一个一般形式,在本文中称为Generalized Focal Loss (GFL)。

image.png

损失函数的演化过程:

image.png


1.3 Append

about the Distributions

下图描述了狄拉克delta、高斯分布和提出的一般分布的思想:

image.png

以下表格是这几个分布的关键比较:

image.png

高斯假设的损耗目标实际上是动态加权的L2 loss,其训练权值与预测方差σ相关。当在边缘水平优化时,它在某种程度上类似于Dirac delta(标准L2损耗)。此外,还不清楚如何将高斯假设集成到基于iou-base的Loss公式中,因为它将目标表示的表达式与其优化目标紧密耦合。因此它不能享受基于iou-base的优化的好处。相比之下,作者提出的一般分布解耦了表示和损失目标,使其适用于任何类型的优化,包括边缘级和盒级。


IoU-branch superior than centerness-branch

在对比实验中,作者发现IoU作为框预测质量的度量会始终比centerness更优。具体深入分析了一些原因,发现的确从原理上来讲,IoU可能作为质量的估计更加合适。具体原因如下:


1) IoU本身就是最终metric的衡量标准,所以用来做质量估计和排序是非常自然的。


2) centerness有一些不可避免的缺陷,比如对于stride=8的FPN的特征层(也就是P3),会存在一些小物体他们的centerness label极度小甚至接近于0,而IoU就会相对好很多,如下图所示。

image.png

这里引用作者知乎的一段话:


我们也统计了一下两者作为label的分布情况,如图:

image.png

这意味着IoU的label相对都较大,而centerness的label相对都较小,同时还有非常非常小的。可以想见,如果有一些正样本的centerness的label本身就很小,那么他们最后在做NMS排序的时候,乘上一个很小的数(假设网络学到位了),那么就很容易排到很后面,那自然性能就不容易上去了。所以,综合各种实验以及上述的分析,个人认为centerness可能只是一个中间产物(当然,其在FCOS中提出时的创新性还是比较valuable的),最终历史的发展轨迹还是要收敛到IoU来。


More Examples of Distributed Bounding Boxes

以下是作者的发现:


我们发现有一些分布式表示学到了多个峰。比如伞这个物体,它的伞柄被椅子严重遮挡。如果我们不看伞柄,那么可以按照白色框(gt)来定位伞,但如果我们算上伞柄,我们又可以用绿色框(预测)来定位伞。在分布上,它也的确呈现一个双峰的模式(bottom),它的两个峰的概率会集中在底部的绿线和白线的两个位置。这个观察还是相当有趣的。这可能带来一个妙用,就是我们可以通过分布shape的情况去找哪些图片可能有界定很模糊的边界,从而再进行一些标注的refine或一致性的检查等等。颇有一种Learn From Data,再反哺Data的感觉。


例子:

image.png

image.png


2. Generalized Focal Loss V2


2.1 Problem

在GFLV1中,作者提出了对边界框进行一个一般化的分布表示建模,有了这个可以学习的表示之后,可以对物品的位置进行一个可视化。基本上那些非常清晰明确的边界,它的分布都很尖锐;而模糊定义不清的边界,它们学习到的分布基本上会平下来,而且有的时候还经常出现双峰的情况。


所以这就是GFLV1中遗漏的一个重要问题,如何让这个一般化的分布充分发挥出它的作用?


作者的想法:


这也是GFLV2的一大出发点,在GFLV2中,我们正是利用了刚才可视化观察到的这个普适的规律:既然分布的形状和真实的定位质量非常相关,那么我们为什么不好好利用一下,用能够表达分布形状的统计量去指导最终定位质量的估计


此前观察得出的“分布的形状与真实的定位质量具有较强的相关性”这个假设是基本成立的。基于这个分析,我们即决定采用学习到的分布的形状来帮助(协助指导)定位质量估计,从而提升检测的整体性能。


2.2 Solve

那么如何来刻画分布的形状呢?我们采用了一个非常简单的做法,就是直接取我们学习到的分布(分布是用离散化的多个和为1的回归数值表示的)的Topk数值。其实理解起来也不难,因为所有数值和为1,如果分布非常尖锐的话,Topk这几个数通常就会很大;反之Topk就会比较小。选择Topk还有一个重要的原因就是它可以使得我们的特征与对象的scale尽可能无关,如下图所示:

image.png

简单来说就是长得差不多形状的分布要出差不多结果的数值,不管它峰值时落在小scale还是大scale。我们把4条边的分布的Topk

concat在一起形成一个维度非常低的输入特征向量(可能只有10+或20+),用这个向量再接一个非常小的fc层(通常维度为32、64),最后再变成一个Sigmoid之后的scalar乘到原来的分类表征中,就完事啦~具体model参考下图,其中红色框就是比GFLV1多出来的Distribution-Guided

Quality Predictor部分,也就是本文的核心。


结构如图所示:

image.png


要说GFLV2最大的亮点其实是从思考角度上的。如下图所示,此前有很多工作都在尝试用不同空间维度的卷积特征去增强分类表示(或者是分类-质量联合表示),但鲜有工作落脚于找到一个更加相关的、复杂度非常低的统计特征来指导质量的估计。用一张图可以体现出GFLV2和现有工作的最大区别(同时,如果我没有miss掉一些工作的话,GFLV2也是检测历史上第一个用学习到的分布的统计特征去指导质量估计的)

image.png


2.3 Append

最后,我们还可视化了一下GFLV2是如何利用好更好的定位质量估计来保障更精准的结果的(我们给出了NMS前后的所有框,并列出了NMS

score排前4的框和它们的分数):

image.png

大家可以看到,其他算法里面也有非常准的预测框,但是它们的score通常都排到了第3第4的位置,而score排第一的框质量都比较欠佳。相反,GFLV2也有预测不太好的框,但是质量较高的框都排的非常靠前,性能就是这么的给提上来。


3. Code


参考代码:https://github.com/RangiLyu/nanodet


import torch
import torch.nn as nn
import torch.nn.functional as F
from .utils import weighted_loss
@weighted_loss
def quality_focal_loss(pred, target, beta=2.0):
    r"""Quality Focal Loss (QFL) is from `Generalized Focal Loss: Learning
    Qualified and Distributed Bounding Boxes for Dense Object Detection
    <https://arxiv.org/abs/2006.04388>`_.
    Args:
        pred (torch.Tensor): Predicted joint representation of classification
            and quality (IoU) estimation with shape (N, C), C is the number of
            classes.
        target (tuple([torch.Tensor])): Target category label with shape (N,)
            and target quality label with shape (N,).
        beta (float): The beta parameter for calculating the modulating factor.
            Defaults to 2.0.
    Returns:
        torch.Tensor: Loss tensor with shape (N,).
    """
    assert (
        len(target) == 2
    ), """target for QFL must be a tuple of two elements,
        including category label and quality label, respectively"""
    # label denotes the category id, score denotes the quality score
    label, score = target
    # negatives are supervised by 0 quality score
    pred_sigmoid = pred.sigmoid()
    scale_factor = pred_sigmoid
    zerolabel = scale_factor.new_zeros(pred.shape)
    loss = F.binary_cross_entropy_with_logits(
        pred, zerolabel, reduction="none"
    ) * scale_factor.pow(beta)
    # FG cat_id: [0, num_classes -1], BG cat_id: num_classes
    bg_class_ind = pred.size(1)
    pos = torch.nonzero((label >= 0) & (label < bg_class_ind), as_tuple=False).squeeze(
        1
    )
    pos_label = label[pos].long()
    # positives are supervised by bbox quality (IoU) score
    scale_factor = score[pos] - pred_sigmoid[pos, pos_label]
    loss[pos, pos_label] = F.binary_cross_entropy_with_logits(
        pred[pos, pos_label], score[pos], reduction="none"
    ) * scale_factor.abs().pow(beta)
    loss = loss.sum(dim=1, keepdim=False)
    return loss
@weighted_loss
def distribution_focal_loss(pred, label):
    r"""Distribution Focal Loss (DFL) is from `Generalized Focal Loss: Learning
    Qualified and Distributed Bounding Boxes for Dense Object Detection
    <https://arxiv.org/abs/2006.04388>`_.
    Args:
        pred (torch.Tensor): Predicted general distribution of bounding boxes
            (before softmax) with shape (N, n+1), n is the max value of the
            integral set `{0, ..., n}` in paper.
        label (torch.Tensor): Target distance label for bounding boxes with
            shape (N,).
    Returns:
        torch.Tensor: Loss tensor with shape (N,).
    """
    dis_left = label.long()
    dis_right = dis_left + 1
    weight_left = dis_right.float() - label
    weight_right = label - dis_left.float()
    loss = (
        F.cross_entropy(pred, dis_left, reduction="none") * weight_left
        + F.cross_entropy(pred, dis_right, reduction="none") * weight_right
    )
    return loss
class QualityFocalLoss(nn.Module):
    r"""Quality Focal Loss (QFL) is a variant of `Generalized Focal Loss:
    Learning Qualified and Distributed Bounding Boxes for Dense Object
    Detection <https://arxiv.org/abs/2006.04388>`_.
    Args:
        use_sigmoid (bool): Whether sigmoid operation is conducted in QFL.
            Defaults to True.
        beta (float): The beta parameter for calculating the modulating factor.
            Defaults to 2.0.
        reduction (str): Options are "none", "mean" and "sum".
        loss_weight (float): Loss weight of current loss.
    """
    def __init__(self, use_sigmoid=True, beta=2.0, reduction="mean", loss_weight=1.0):
        super(QualityFocalLoss, self).__init__()
        assert use_sigmoid is True, "Only sigmoid in QFL supported now."
        self.use_sigmoid = use_sigmoid
        self.beta = beta
        self.reduction = reduction
        self.loss_weight = loss_weight
    def forward(
        self, pred, target, weight=None, avg_factor=None, reduction_override=None
    ):
        """Forward function.
        Args:
            pred (torch.Tensor): Predicted joint representation of
                classification and quality (IoU) estimation with shape (N, C),
                C is the number of classes.
            target (tuple([torch.Tensor])): Target category label with shape
                (N,) and target quality label with shape (N,).
            weight (torch.Tensor, optional): The weight of loss for each
                prediction. Defaults to None.
            avg_factor (int, optional): Average factor that is used to average
                the loss. Defaults to None.
            reduction_override (str, optional): The reduction method used to
                override the original reduction method of the loss.
                Defaults to None.
        """
        assert reduction_override in (None, "none", "mean", "sum")
        reduction = reduction_override if reduction_override else self.reduction
        if self.use_sigmoid:
            loss_cls = self.loss_weight * quality_focal_loss(
                pred,
                target,
                weight,
                beta=self.beta,
                reduction=reduction,
                avg_factor=avg_factor,
            )
        else:
            raise NotImplementedError
        return loss_cls
class DistributionFocalLoss(nn.Module):
    r"""Distribution Focal Loss (DFL) is a variant of `Generalized Focal Loss:
    Learning Qualified and Distributed Bounding Boxes for Dense Object
    Detection <https://arxiv.org/abs/2006.04388>`_.
    Args:
        reduction (str): Options are `'none'`, `'mean'` and `'sum'`.
        loss_weight (float): Loss weight of current loss.
    """
    def __init__(self, reduction="mean", loss_weight=1.0):
        super(DistributionFocalLoss, self).__init__()
        self.reduction = reduction
        self.loss_weight = loss_weight
    def forward(
        self, pred, target, weight=None, avg_factor=None, reduction_override=None
    ):
        """Forward function.
        Args:
            pred (torch.Tensor): Predicted general distribution of bounding
                boxes (before softmax) with shape (N, n+1), n is the max value
                of the integral set `{0, ..., n}` in paper.
            target (torch.Tensor): Target distance label for bounding boxes
                with shape (N,).
            weight (torch.Tensor, optional): The weight of loss for each
                prediction. Defaults to None.
            avg_factor (int, optional): Average factor that is used to average
                the loss. Defaults to None.
            reduction_override (str, optional): The reduction method used to
                override the original reduction method of the loss.
                Defaults to None.
        """
        assert reduction_override in (None, "none", "mean", "sum")
        reduction = reduction_override if reduction_override else self.reduction
        loss_cls = self.loss_weight * distribution_focal_loss(
            pred, target, weight, reduction=reduction, avg_factor=avg_factor
        )
        return loss_cls



参考链接:


1. 大白话 Generalized Focal Loss

2. 大白话 Generalized Focal Loss V2

3. Nanodet


目录
相关文章
|
2月前
|
机器学习/深度学习 运维 算法
大模型开发:描述一种用于异常检测的技术或算法。
LOF算法是一种无监督异常检测技术,通过比较数据点局部密度识别离群点。它计算每个点的局部离群因子得分,得分高则异常可能性大。主要步骤包括:距离度量、k近邻搜索、计算局部可达密度和LOF得分,然后设定阈值识别异常点。适用于入侵检测、故障检测等场景,Python中可使用scikit-learn库实现。
22 1
|
2月前
|
传感器 算法 计算机视觉
基于肤色模型和中值滤波的手部检测算法FPGA实现,包括tb测试文件和MATLAB辅助验证
该内容是关于一个基于肤色模型和中值滤波的手部检测算法的描述,包括算法的运行效果图和所使用的软件版本(matlab2022a, vivado2019.2)。算法分为肤色分割和中值滤波两步,其中肤色模型在YCbCr色彩空间定义,中值滤波用于去除噪声。提供了一段核心程序代码,用于处理图像数据并在FPGA上实现。最终,检测结果输出到&quot;hand.txt&quot;文件。
|
1天前
|
机器学习/深度学习 人工智能 算法
【图像版权】论文阅读:CRMW 图像隐写术+压缩算法
【图像版权】论文阅读:CRMW 图像隐写术+压缩算法
7 0
|
7天前
|
人工智能 算法 测试技术
论文介绍:进化算法优化模型融合策略
【5月更文挑战第3天】《进化算法优化模型融合策略》论文提出使用进化算法自动化创建和优化大型语言模型,通过模型融合提升性能并减少资源消耗。实验显示,这种方法在多种基准测试中取得先进性能,尤其在无特定任务训练情况下仍能超越参数更多模型。同时,该技术成功应用于创建具有文化意识的日语视觉-语言模型。然而,模型融合可能产生逻辑不连贯响应和准确性问题,未来工作将聚焦于图像扩散模型、自动源模型选择及生成自我改进的模型群体。[论文链接: https://arxiv.org/pdf/2403.13187.pdf]
111 1
|
11天前
|
机器学习/深度学习 运维 算法
【Python机器学习专栏】异常检测算法在Python中的实践
【4月更文挑战第30天】本文介绍了异常检测的重要性和在不同领域的应用,如欺诈检测和网络安全。文章概述了四种常见异常检测算法:基于统计、距离、密度和模型的方法。在Python实践中,使用scikit-learn库展示了如何实现这些算法,包括正态分布拟合、K-means聚类、局部异常因子(LOF)和孤立森林(Isolation Forest)。通过计算概率密度、距离、LOF值和数据点的平均路径长度来识别异常值。
|
11天前
|
算法 数据可视化 数据挖掘
R语言平滑算法LOESS局部加权回归、三次样条、变化点检测拟合电视节目《白宫风云》在线收视率
R语言平滑算法LOESS局部加权回归、三次样条、变化点检测拟合电视节目《白宫风云》在线收视率
|
17天前
|
算法 数据可视化 数据挖掘
R语言社区发现算法检测心理学复杂网络:spinglass、探索性图分析walktrap算法与可视化
R语言社区发现算法检测心理学复杂网络:spinglass、探索性图分析walktrap算法与可视化
|
23天前
|
算法 数据可视化
R语言社区检测算法可视化网络图:ggplot2绘制igraph对象分析物种相对丰度
R语言社区检测算法可视化网络图:ggplot2绘制igraph对象分析物种相对丰度
|
24天前
|
文字识别 算法 计算机视觉
图像倾斜校正算法的MATLAB实现:图像倾斜角检测及校正
图像倾斜校正算法的MATLAB实现:图像倾斜角检测及校正
|
25天前
|
算法 数据可视化 数据挖掘
R语言社区主题检测算法应用案例
R语言社区主题检测算法应用案例