VariFocalNet | IoU-aware同V-Focal Loss全面提升密集目标检测(附YOLOV5测试代码)(一)

简介: VariFocalNet | IoU-aware同V-Focal Loss全面提升密集目标检测(附YOLOV5测试代码)(一)

1 简介


准确地对大量候选检测器进行排名是高性能密集目标检测器的关键。尽管先前的工作使用分类评分或它与基于IoU的定位评分的组合作为排名基础,但它们都不能得到可靠地排名结果,这会损害检测性能。

在本文中,作者提出学习可同时表示对象存在置信度和定位精度的IoU感知分类评分(IACS),以在密集对象检测器中产生更准确的检测等级。特别地本文还设计了一个新的损失函数,称为Varifocal损失,用于训练密集的物体检测器来预测IACS,并设计了一种新的高效星形边界框特征表示,用于估算IACS和改进粗略边界框。结合这两个新组件和边界框优化分支,作者在FCOS架构上构建了一个新的密集目标检测器,简称为VarifocalNet或VFNet

在MS COCO基准上进行的大量实验表明,VFNet超过了Baseline约2.0%AP,并且Res2Net-101-DCN最佳模型在COCO测试上达到了55.1%AP。


2 所提创新方法


本文提出学习IoU-aware classification score (IACS)用于对检测进行分级。为此在去掉中心分支的FCOS+ATSS的基础上,构建了一个新的密集目标检测器,称为VarifocalNet或VFNet。相比FCOS+ATSS融合了varifcoal loss、star-shaped bounding box特征表示和bounding box refinement 3个新组件。

2.1 IACS–IoU-Aware分类得分

IACS定义为分类得分向量的标量元素,其中ground-truth类标签位置的值为预测边界框与其ground truth之间的IoU,其他位置为0。

image.png

图1 IACS–IoU-Aware表示

如图1所示,不是学习预测一个bounding box的类标签(a),而是学习IoU-aware分类得分(IACS)作为检测分数,融合了目标存在置信度和定位精度(b)。

2.2 Varifocal Loss

本文设计了一种新的Varifocal Loss来训练密集目标检测器来预测IACS。由于它的灵感来自Focal Loss,这里也简要回顾一下Focal Loss。Focal Loss的设计是为了解决密集目标检测器训练中前景类和背景类之间极度不平衡的问题。定义为:

image.png

其中为ground-truth类,为前景类的预测概率。如公式所示,调制因子(γ为前景类和γ为背景类)可以减少简单样例的损失贡献,相对增加误分类样例的重要性。

因此,Focal Loss防止了训练过程中大量的简单负样本淹没检测器,并将检测器聚焦在稀疏的一组困难的例子上。

在训练密集目标检测器对连续IACS进行回归时借鉴了Focal Loss的加权方法来解决类别不平衡的问题。然而,不同的Focal Loss处理的正负相等,对待是不对称的。这里varifocal loss也是基于binary cross entropy loss,定义为:

image.png

其中为预测的IACS, 为目标分数。对于前景点将其ground truth类设为生成的边界框和它的ground truth(gt_IoU)之间的IoU,否则为0,而对于背景点,所有类的目标为0。

如公式所示,通过用γ的因子缩放损失,varifocal loss仅减少了负例(q=0)的损失贡献,而不以同样的方式降低正例(q>0)的权重。这是因为positive样本相对于negatives样本是非常罕见的,应该保留它们的学习信息。

另一方面,受PISA的启发将正例与训练目标q加权。如果一个正例的gt_IoU较高,那么它对损失的贡献就会比较大。这就把训练的重点放在那些高质量的正面例子上,这些例子比那些低质量的例子对获得更高的AP更重要。

import mmcv
import torch.nn as nn
import torch.nn.functional as F
from ..builder import LOSSES
from .utils import weight_reduce_loss
@mmcv.jit(derivate=True, coderize=True)
def varifocal_loss(pred,
                   target,
                   weight=None,
                   alpha=0.75,
                   gamma=2.0,
                   iou_weighted=True,
                   reduction='mean',
                   avg_factor=None):
    """`Varifocal Loss <https://arxiv.org/abs/2008.13367>`_
    Args:
        pred (torch.Tensor): The prediction with shape (N, C), C is the
            number of classes
        target (torch.Tensor): The learning target of the iou-aware
            classification score with shape (N, C), C is the number of classes.
        weight (torch.Tensor, optional): The weight of loss for each
            prediction. Defaults to None.
        alpha (float, optional): A balance factor for the negative part of
            Varifocal Loss, which is different from the alpha of Focal Loss.
            Defaults to 0.75.
        gamma (float, optional): The gamma for calculating the modulating
            factor. Defaults to 2.0.
        iou_weighted (bool, optional): Whether to weight the loss of the
            positive example with the iou target. Defaults to True.
        reduction (str, optional): The method used to reduce the loss into
            a scalar. Defaults to 'mean'. Options are "none", "mean" and
            "sum".
        avg_factor (int, optional): Average factor that is used to average
            the loss. Defaults to None.
    """
    # pred and target should be of the same size
    assert pred.size() == target.size()
    pred_sigmoid = pred.sigmoid()
    target = target.type_as(pred)
    if iou_weighted:
        focal_weight = target * (target > 0.0).float() + \
            alpha * (pred_sigmoid - target).abs().pow(gamma) * \
            (target <= 0.0).float()
    else:
        focal_weight = (target > 0.0).float() + \
            alpha * (pred_sigmoid - target).abs().pow(gamma) * \
            (target <= 0.0).float()
    loss = F.binary_cross_entropy_with_logits(
        pred, target, reduction='none') * focal_weight
    loss = weight_reduce_loss(loss, weight, reduction, avg_factor)
    return loss
@LOSSES.register_module()
class VarifocalLoss(nn.Module):
    def __init__(self,
                 use_sigmoid=True,
                 alpha=0.75,
                 gamma=2.0,
                 iou_weighted=True,
                 reduction='mean',
                 loss_weight=1.0):
        """`Varifocal Loss <https://arxiv.org/abs/2008.13367>`_
        Args:
            use_sigmoid (bool, optional): Whether the prediction is
                used for sigmoid or softmax. Defaults to True.
            alpha (float, optional): A balance factor for the negative part of
                Varifocal Loss, which is different from the alpha of Focal
                Loss. Defaults to 0.75.
            gamma (float, optional): The gamma for calculating the modulating
                factor. Defaults to 2.0.
            iou_weighted (bool, optional): Whether to weight the loss of the
                positive examples with the iou target. Defaults to True.
            reduction (str, optional): The method used to reduce the loss into
                a scalar. Defaults to 'mean'. Options are "none", "mean" and
                "sum".
            loss_weight (float, optional): Weight of loss. Defaults to 1.0.
        """
        super(VarifocalLoss, self).__init__()
        assert use_sigmoid is True, \
            'Only sigmoid varifocal loss supported now.'
        assert alpha >= 0.0
        self.use_sigmoid = use_sigmoid
        self.alpha = alpha
        self.gamma = gamma
        self.iou_weighted = iou_weighted
        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): The prediction.
            target (torch.Tensor): The learning target of the prediction.
            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.
                Options are "none", "mean" and "sum".
        Returns:
            torch.Tensor: The calculated loss
        """
        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 * varifocal_loss(
                pred,
                target,
                weight,
                alpha=self.alpha,
                gamma=self.gamma,
                iou_weighted=self.iou_weighted,
                reduction=reduction,
                avg_factor=avg_factor)
        else:
            raise NotImplementedError
        return loss_cls

2.3 Star-Shaped Box特征表示

图2 Star-Shaped Box示意

本文设计了一种用于IACS预测的Star-Shaped Box特征表示方法。它利用9个固定采样点的特征(图2中的黄色圆圈)表示一个具有可变形卷积的bounding box。这种新的表示方法可以捕获bounding box的几何形状及其附近的上下文信息,这对于编码预测的bounding box和ground-truth之间的不对齐是至关重要的。

具体来说:

  • 首先,给定图像平面上的一个采样位置(或feature map上的一个投影点),首先用卷积从它回归一个初始bounding box;
  • 然后,在FCOS之后,这个bounding box由一个4D向量编码,这意味着位置分别到bounding box的左、上、右和下侧的距离。利用这个距离向量启发式地选取,,,,,,,和9个采样点,然后将它们映射到feature map上。它们与(x, y)投影点的相对偏移量作为可变形卷积的偏移量;
  • 最后,将这9个投影点上的特征使用可变形卷积卷积表示一个bounding box。由于这些点是人工选择的,没有额外的预测负担。

2.4 Bounding Box细化

通过bounding box细化步骤进一步提高了目标定位的精度。bounding box细化是目标检测中常用的一种技术,但由于缺乏有效的、有判别性的目标描述符,在密集的目标检测器中并未得到广泛应用。有了Star-Shaped Box特征表示现在可以在高密度物体探测器中采用它,而不会损失效率。

这里将bounding box细化建模为一个残差学习问题。对于初始回归的bounding box:

  • 首先,提取Star-Shaped Box特征表示并对其进行编码;
  • 然后,根据表示学习4个距离缩放因子来缩放初始距离向量,使表示的细化bounding box更接近ground-truth。

3 VarifocalNet


将上述3个组件附加到FCOS网络体系结构并删除原来的centerness分支就得到了VarifocalNet

image.png

图3 VFNet架构

图3说明了VFNet的网络架构。VFNet的骨干网和FPN网部分与FCOS相同。区别在于头部结构。VFNet的Head是由2个子网组成:localization subnet执行bounding box回归Bounding Box细化

一个分支将FPN各层的特征图作为输入,首先应用ReLU激活的3个的conv层。这将产生256个通道的特征映射。localization subnet的一个分支再次卷积Feature Map,然后在每个空间位置输出一个4D距离向量,表示初始bounding box。考虑到最初的bounding box和特征映射,另一个分支应用卷积的Star-Shaped得到9个功能采样点和距离比例因子,然后距离变换因子乘以初始距离矢量便可以得到细化后的bounding box。

另一个分支用于预测IACS。它具有与localization subnet(细化分支)类似的结构,只是每个空间位置输出一个由C(类别)组成的向量,其中每个元素联合表示对象存在置信度和定位精度。

相关文章
|
20天前
|
测试技术 API 数据库
Django测试入门:打造坚实代码基础的钥匙
Django测试入门:打造坚实代码基础的钥匙
31 3
|
7天前
|
测试技术 持续交付
软件测试的艺术:追求卓越的代码之旅
在软件的世界中,测试不仅仅是一项任务,它是一场精心编排的舞蹈,旨在确保每一个步伐都准确无误。本文将带您踏上一场探索软件测试之美的旅程,从基础理论到实践技巧,我们将一同揭开高效测试的秘密,并分享那些能让代码更健壮、更可靠的智慧精华。
15 2
|
12天前
|
测试技术 Go
写出高质量代码的秘诀:Golang中的测试驱动开发(TDD)
写出高质量代码的秘诀:Golang中的测试驱动开发(TDD)
|
4天前
|
自动驾驶 测试技术 持续交付
软件测试的艺术:追求卓越的代码之旅
在软件开发的海洋中,测试是那艘不可或缺的航船,它带领我们驶向质量的彼岸。本文将带你领略软件测试的重要性,探讨如何通过创造性思维和系统方法提升测试效率与效果。我们将从测试基础出发,逐步深入到高级策略,最终实现测试的艺术化,确保软件产品能在复杂多变的环境中稳健航行。
|
4天前
|
Java 测试技术
单元测试问题之想通过单元测试来驱动代码的设计与重构,如何实现
单元测试问题之想通过单元测试来驱动代码的设计与重构,如何实现
|
5天前
分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了
分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了
|
5天前
|
存储 Kubernetes 测试技术
阿里云块存储问题之生产代码与测试代码需要同步原子提交如何解决
阿里云块存储问题之生产代码与测试代码需要同步原子提交如何解决
16 0
|
5天前
|
敏捷开发 安全 测试技术
软件测试的艺术:从代码到信心
在数字世界的舞台上,软件如同演员,而测试则是它们精彩表演的彩排。本文将带您穿梭于软件测试的幕后,揭示那些让软件从笨拙的初稿变成流畅的终演的魔法。我们将探索测试的多面性,从基础的单元测试到复杂的集成测试,再到用户面前的系统测试,每一步都旨在确保软件的优雅舞步不会因缺陷而绊倒。文章还将点亮持续集成的灯塔,指引船只安全航行,并展示自动化测试如何像忠实的伙伴一样,不断给予支持。最后,我们将探讨测试策略的选择艺术,如何在多变的需求与资源之间找到平衡点。让我们一起走进软件测试的世界,体验这场从代码到信心的旅程。
|
26天前
|
监控 搜索推荐 机器人
开发与运维数据问题之LangChain帮助提升GPT-4的实用性的如何解决
开发与运维数据问题之LangChain帮助提升GPT-4的实用性的如何解决
27 1
|
1月前
|
Devops jenkins 测试技术
如何在Visual Basic项目中实施单元测试以确保代码健壮性
【7月更文挑战第2天】本文探讨了如何在Visual Basic项目中实施单元测试以确保代码健壮性。单元测试基础包括验证代码单元的功能,促进重构和提高代码质量。MSTest、NUnit和xUnit是VB.NET的单元测试工具。遵循TDD原则,保持测试独立,关注单一功能,并确保快速执行。示例展示了如何为`Calculator`类的加法方法编写MSTest。持续集成与自动化测试工具如Jenkins和Azure DevOps辅助测试运行和代码质量检查。单元测试是提升软件质量和开发效率的关键实践,反映了良好的开发文化。
33 2

热门文章

最新文章