WEBKT

目标检测小目标精度提升秘籍:精选Loss函数助力!

273 0 0 0

最近在搞目标检测,小目标一直是个老大难问题。精度上不去,调参调到头秃。今天就来聊聊,有哪些 Loss 函数能让模型更关注小目标,有效提升小目标的检测精度。

为什么小目标检测难?

在深入 Loss 函数之前,先简单说说为什么小目标检测这么让人头疼:

  • 特征信息不足: 小目标在图像中占据的像素比例很小,经过多层卷积后,特征信息容易丢失或被淹没。
  • 上下文信息缺失: 小目标周围的上下文信息对于判断其类别至关重要,但小目标的上下文信息往往比较有限。
  • 正负样本比例失衡: 在目标检测任务中,负样本(背景)的数量通常远大于正样本(目标),这会导致模型更容易学习到背景的特征,而忽略小目标。

Loss 函数的选择

针对以上问题,我们可以选择一些特定的 Loss 函数来改善小目标的检测效果。

1. Focal Loss

原理: Focal Loss 是由何恺明大神提出的,主要解决的是目标检测中正负样本比例失衡的问题。它通过引入一个 modulating factor (1 - pt)γ 来降低易分类样本的权重,从而让模型更专注于难分类样本。

公式:

(FL(p_t) = - (1 - p_t)^{\gamma} log(p_t))

其中,pt 是模型预测的概率,γ 是一个可调节的参数,通常设置为 2。

优势:

  • 有效缓解正负样本比例失衡的问题,提高小目标的召回率。
  • 可以与其他 Loss 函数结合使用,例如 Cross Entropy Loss。

代码示例 (PyTorch):

import torch
import torch.nn as nn
import torch.nn.functional as F

class FocalLoss(nn.Module):
    def __init__(self, gamma=2, alpha=None, size_average=True):
        super(FocalLoss, self).__init__()
        self.gamma = gamma
        self.alpha = alpha
        if isinstance(alpha,(float,int)):
            self.alpha = torch.Tensor([alpha,1-alpha])
        if isinstance(alpha,list):
            self.alpha = torch.Tensor(alpha)
        self.size_average = size_average

    def forward(self, input, target):
        if input.dim()>2:
            input = input.view(input.size(0),input.size(1),-1)  # N,C,H,W => N,C,H*W
            input = input.transpose(1,2)    # N,C,H*W => N,H*W,C
            input = input.contiguous().view(-1,input.size(2))   # N,H*W,C => N*H*W,C
        target = target.view(-1,1)

        logpt = F.log_softmax(input, dim=1)
        logpt = logpt.gather(1,target)
        logpt = logpt.view(-1)
        pt = torch.exp(logpt)

        if self.alpha is not None:
            if self.alpha.type()!=input.data.type():
                self.alpha = self.alpha.type_as(input.data)
            at = self.alpha.gather(0, target.data.view(-1))
            logpt = logpt * at

        loss = -1 * (1-pt)**self.gamma * logpt
        if self.size_average:
            return loss.mean()
        else:
            return loss.sum()

参考资料:

2. GIoU Loss & DIoU Loss & CIoU Loss

原理: IoU (Intersection over Union) 是目标检测中常用的评价指标,但 IoU Loss 存在一些问题:

  • 当两个框没有重叠时,IoU 为 0,Loss 无法提供梯度信息。
  • 无法区分两个框的不同重叠方式。

为了解决这些问题,提出了 GIoU (Generalized IoU)、DIoU (Distance-IoU) 和 CIoU (Complete IoU) Loss。

  • GIoU Loss: 在 IoU 的基础上,考虑了两个框的最小外接矩形,可以解决两个框没有重叠时 Loss 无法提供梯度信息的问题。
  • DIoU Loss: 在 IoU 的基础上,考虑了两个框中心点的距离,可以加速收敛。
  • CIoU Loss: 在 DIoU 的基础上,进一步考虑了两个框的宽高比,可以更好地反映两个框的相似程度。

公式:

  • GIoU = IoU - (C - A ∪ B) / C,其中 C 是包含 A 和 B 的最小外接矩形。
  • DIoU = IoU - (ρ2(b, bgt) / c2),其中 b 和 bgt 分别是预测框和真实框的中心点,ρ 是欧氏距离,c 是包含预测框和真实框的最小外接矩形的对角线长度。
  • CIoU = DIoU - αv,其中 α 是一个权重系数,v = (4 / π2) * (arctan(wgt / hgt) - arctan(w / h))2,用于衡量宽高比的差异。

优势:

  • 可以有效提高目标检测的精度,尤其是在目标重叠或遮挡的情况下。
  • 可以加速模型收敛。

代码示例 (PyTorch):

可以使用 torchvision 库中的 ops.box_iou 函数计算 IoU,然后根据公式计算 GIoU、DIoU 或 CIoU Loss。这里给出一个简单的 GIoU Loss 的示例:

import torch
from torchvision.ops import box_iou

def giou_loss(boxes1, boxes2):
    iou = box_iou(boxes1, boxes2)
    union = (boxes1[:, 2] - boxes1[:, 0]) * (boxes1[:, 3] - boxes1[:, 1]) + \
            (boxes2[:, 2] - boxes2[:, 0]) * (boxes2[:, 3] - boxes2[:, 1]) - \
            iou.diag()
    giou = iou.diag() - ( (boxes1[:, 2].max(boxes2[:, 2], dim=1)[0] - boxes1[:, 0].min(boxes2[:, 0], dim=1)[0]) * \
                           (boxes1[:, 3].max(boxes2[:, 3], dim=1)[0] - boxes1[:, 1].min(boxes2[:, 1], dim=1)[0]) - union ) / \
                  (boxes1[:, 2].max(boxes2[:, 2], dim=1)[0] - boxes1[:, 0].min(boxes2[:, 0], dim=1)[0]) * \
                  (boxes1[:, 3].max(boxes2[:, 3], dim=1)[0] - boxes1[:, 1].min(boxes2[:, 1], dim=1)[0]

    return 1 - giou

参考资料:

3. Square IoU Loss

原理: Square IoU Loss 是一种简单有效的 IoU Loss 变体。其核心思想是将 IoU 值进行平方,从而放大 IoU 的差异,使得模型更加关注 IoU 较高的样本,从而提高检测精度。

公式:

(Loss_{SquareIoU} = 1 - IoU^2)

优势:

  • 实现简单,易于集成到现有模型中。
  • 在一些情况下,可以获得比传统 IoU Loss 更好的性能,尤其是在小目标检测方面。

代码示例 (PyTorch):

import torch
from torchvision.ops import box_iou

def square_iou_loss(boxes1, boxes2):
    iou = box_iou(boxes1, boxes2)
    return 1 - iou.diag()**2

参考资料:

  • 虽然 Square IoU Loss 没有正式的论文发表,但它在一些开源目标检测项目中被广泛使用,例如 YOLOv5

4. 其他技巧

除了选择合适的 Loss 函数,还可以尝试以下技巧来提高小目标的检测精度:

  • 数据增强: 使用 Mosaic、MixUp 等数据增强方法,增加小目标的数量和多样性。
  • 多尺度训练: 在训练过程中使用不同尺度的图像,让模型学习到不同尺度下的目标特征。
  • 特征金字塔网络 (FPN): FPN 可以将不同层级的特征进行融合,提高小目标的特征表达能力。
  • 更强的 Backbone: 使用更强大的 Backbone 网络,例如 ResNet101、ResNeXt101 等,提高特征提取能力。

总结

提高小目标的检测精度是一个具有挑战性的任务,需要综合考虑 Loss 函数的选择、数据增强、模型结构等因素。希望本文介绍的 Loss 函数能对你有所帮助。记住,没有万能的 Loss 函数,需要根据实际情况进行尝试和调整。祝你早日攻克小目标检测难题!

算法小菜鸡 目标检测小目标检测Loss函数

评论点评