【MMDetection 系列:三】Loss 函数详解 + Pytorch 实现

Reference

https://zhuanlan.zhihu.com/p/40284001
https://blog.csdn.net/weixin_41665360/article/details/100126744
https://github.com/open-mmlab/mmdetection
https://github.com/thangvubk/Cascade-RPN (based on mmdetection framework)
Deep Learning v1 笔记

一个函数能够作为损失函数,要符合以下两个特性:

  • 非负
  • 当实际输出接近预期,那么损失函数应该接近0

基本 loss

MSE —— 回归loss

参考KL散度

MSE 回归loss ,更适合用来预测值。而CE是衡量两个分布距离的指标

SSE

和方差

  • 该参数计算的是拟合数据和原始对应点的误差的平方和

是真实数据, 是拟合的数据, ,从这里可以看出SSE接近于0,说明模型选择和拟合更好,数据预测也越成功。

MSE

均方方差

  • 预测数据和原始数据对应点误差的平方和的均值

缺点

  • 其偏导值在输出概率值接近0或者接近1的时候非常小,这可能会造成模型刚开始训练时,偏导值几乎消失。
import torch.nn.functional as F
mse_loss = weighted_loss(F.mse_loss)

RMSE

也叫回归系统的拟合标准差,是MSE的平方根,计算公式为:

0-1 Loss

0-1损失函数直接对应分类判断错误的个数,但是它是一个非凸函数,不太适用.

hinge loss

Hinge Loss常作为 SVM 的损失函数

L1 loss

L2 Loss

L2-loss 比 L1-loss 好,因为L2-loss的收敛速度要比L1-loss要快得多。

缺点:

  • 当存在离群点(outliers)的时候,这些点会占loss的主要组成部分
    比如说真实值为1,预测10次,有一次预测值为1000,其余次的预测值为1左右,显然loss值主要由1000主宰

不管是L1损失函数,还是L2损失函数,都有两大缺陷:

  • 假定噪声的影响和图像的局部特性是独立的。然而,人类的视觉系统对噪声的感知受局部照度、对比、结构的影响。
  • 假定噪声接近高斯白噪声,然而这一假定并不总是成立。

分类 loss CE

CE

Cross - Entropy

交叉熵

表示样本, 表示预测的输出, 表示实际的输出, 表示样本总数量

  • 对数似然函数,可用于二分类和多分类任务中
  • 二分类问题中的loss函数(输入数据是softmax或者sigmoid函数的输出)
  • 多分类问题中的loss函数(输入数据是softmax或者sigmoid函数的输出)

交叉熵

def cross_entropy(pred, label, weight=None, reduction='mean', avg_factor=None):
    # element-wise losses
    loss = F.cross_entropy(pred, label, reduction='none')

    # apply weights and do the reduction
    if weight is not None:
        weight = weight.float()
    loss = weight_reduce_loss(
        loss, weight=weight, reduction=reduction, avg_factor=avg_factor)

    return loss

Binary CE loss

二分类

def binary_cross_entropy(pred,
                         label,
                         weight=None,
                         reduction='mean',
                         avg_factor=None):
    if pred.dim() != label.dim():
        label, weight = _expand_binary_labels(label, weight, pred.size(-1))

    # weighted element-wise losses
    if weight is not None:
        weight = weight.float()
    loss = F.binary_cross_entropy_with_logits(pred, label.float(), weight, reduction='none')
    # do the reduction for the weighted loss
    loss = weight_reduce_loss(loss, reduction=reduction,avg_factor=avg_factor)

    return loss

Balanced CE loss

类别不平衡问题对最终training loss的不利影响,我们自然会想到可通过在loss公式中使用与目标存在概率成反比的系数对其进行较正

Focal Loss

  • RetinaNet 提出

  • 指数式系数可对正负样本对loss的贡献自动调节
    当某样本类别比较明确些,它对整体loss的贡献就比较少;而若某样本类别不易区分,则对整体loss的贡献就相对偏大

  • 引入了一个新的 hyper parameter 即 γ γ γ
    作者有试者对其进行调节,线性搜索后得出将γ设为2时,模型检测效果最好。

  • 作者还引入了α系数,它能够使得focal loss对不同类别更加平衡

# This method is only for debugging
def py_sigmoid_focal_loss(pred,
                          target,
                          weight=None,
                          gamma=2.0,
                          alpha=0.25,
                          reduction='mean',
                          avg_factor=None):
    pred_sigmoid = pred.sigmoid()
    target = target.type_as(pred)
    pt = (1 - pred_sigmoid) * target + pred_sigmoid * (1 - target)  
    '''
    pt 平衡难易例
     (alpha * target + (1 - alpha)*(1 - target)) 平衡正负例
    '''
    focal_weight = (alpha * target + (1 - alpha)*(1 - target)) *pt.pow(gamma)
    loss = F.binary_cross_entropy_with_logits(pred, target, reduction='none') * focal_weight
    loss = weight_reduce_loss(loss, weight, reduction, avg_factor)
    return loss

ghm loss

https://arxiv.org/abs/1811.05181
https://www.cnblogs.com/xxxxxxxxx/p/11602248.html
https://blog.csdn.net/u013841196/article/details/88650784

  • focal loss 的改进

    • focal loss 缺点
      • 如果让模型过多关注 难分样本 会引发一些问题,比如样本中的离群点(outliers),已经收敛的模型可能会因为这些离群点还是被判别错误,总而言之,我们不应该过多关注易分样本,但也不应该过多关注难分样本;
      • α 与 γ 的取值全从实验得出,且两者要联合一起实验,因为它们的取值会相互影响。
  • 为了解决特别难分样本的问题

  • 抑制方法之梯度密度 G(D)

    因为易分样本和特别难分样本数量都要比一般样本多一些,而我们要做的就是衰减 单位区间数量多的那类样本,也就是物理学上的密度概念

    在这里插入图片描述

    在这里插入图片描述

  • 分类问题的GHM损失

在这里插入图片描述

  • 回归问题的GHM损失

    在这里插入图片描述

    在这里插入图片描述为修正的 smooth L1 Loss

回归 loss —— L1

Smooth L1 loss (回归常用)

  • faster rcnn 提出

优点

  • 相比于L2损失函数,其对离群点、异常值(outlier)不敏感,梯度变化相对更小,训练时不容易跑飞
def smooth_l1_loss(pred, target, beta=1.0):
    assert beta > 0
    assert pred.size() == target.size() and target.numel() > 0
    diff = torch.abs(pred - target)
    loss = torch.where(diff < beta, 0.5 * diff * diff / beta,diff - 0.5 * beta)    
    '''
    torch.where  判断
    如果 diff<beta ,loss就是 0.5 * diff * diff / beta (diff 相当于上面公式里的 x,/ beta是改变梯度)
    如果 diff不<beta ,loss就是 diff - 0.5 * beta
    '''
    return loss


Balance L1 loss

  • libra RCNN 提出

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

$α = 0.5$ and $γ = 1.5$
  • C
    求解利用函数连续性,当x=beta(一般为1)时,公式 L b ( x ) L_b(x) Lb(x) 相等:
    在这里插入图片描述
def balanced_l1_loss(pred,
                     target,
                     beta=1.0,
                     alpha=0.5,
                     gamma=1.5,
                     reduction='mean'):
    assert beta > 0
    assert pred.size() == target.size() and target.numel() > 0

    diff = torch.abs(pred - target)
    b = np.e**(gamma / alpha) - 1
    loss = torch.where(diff < beta, alpha / b *(b * diff + 1) * torch.log(b * diff / beta + 1) - alpha * diff,gamma * diff + gamma / b - alpha * beta)
    '''
    torch.where  判断
    如果 diff<beta ,loss就是 alpha / b *(b * diff + 1) * torch.log(b * diff / beta + 1) - alpha * diff  (/beta 为了改变梯度)
    如果 diff不<beta ,loss就是 gamma * diff + gamma / b - alpha * beta ( 按照公式 c= gamma / b - alpha * beta,是利用了函数连续性 )
    '''
    return loss

Bounded IOU loss

在这里插入图片描述

  • GARPN 中使用

  • 和 IOU loss 一样是 尺度不敏感

  • 是 smooth L1 的改进,和IOU loss 没啥关系

@weighted_loss
def bounded_iou_loss(pred, target, beta=0.2, eps=1e-3):
    """Improving Object Localization with Fitness NMS and Bounded IoU Loss,
    https://arxiv.org/abs/1711.00164.
    Args:
        pred (tensor): Predicted bboxes.
        target (tensor): Target bboxes.
        beta (float): beta parameter in smoothl1.
        eps (float): eps to avoid NaN.
    """
    pred_ctrx = (pred[:, 0] + pred[:, 2]) * 0.5
    pred_ctry = (pred[:, 1] + pred[:, 3]) * 0.5
    pred_w = pred[:, 2] - pred[:, 0] + 1
    pred_h = pred[:, 3] - pred[:, 1] + 1
    with torch.no_grad():
        target_ctrx = (target[:, 0] + target[:, 2]) * 0.5
        target_ctry = (target[:, 1] + target[:, 3]) * 0.5
        target_w = target[:, 2] - target[:, 0] + 1
        target_h = target[:, 3] - target[:, 1] + 1

    dx = target_ctrx - pred_ctrx
    dy = target_ctry - pred_ctry

    loss_dx = 1 - torch.max(
        (target_w - 2 * dx.abs()) /
        (target_w + 2 * dx.abs() + eps), torch.zeros_like(dx))
    loss_dy = 1 - torch.max(
        (target_h - 2 * dy.abs()) /
        (target_h + 2 * dy.abs() + eps), torch.zeros_like(dy))
    loss_dw = 1 - torch.min(target_w / (pred_w + eps), pred_w /
                            (target_w + eps))
    loss_dh = 1 - torch.min(target_h / (pred_h + eps), pred_h /
                            (target_h + eps))
    loss_comb = torch.stack([loss_dx, loss_dy, loss_dw, loss_dh],
                            dim=-1).view(loss_dx.size(0), -1)

    loss = torch.where(loss_comb < beta, 0.5 * loss_comb * loss_comb / beta,
                       loss_comb - 0.5 * beta)
    return loss

回归 loss —— IoU

IOU Loss

  • UnitBox 提出(做人脸)
    在这里插入图片描述

  • FCOS 等 anchor free 基本都用

  • 求 IOU ,IOU 越大 loss 越小,IOU 越小 loss 越大

  • 但是 他和 smooth L1 区别是 IOU loss 对尺寸大小不敏感

    在这里插入图片描述

在这里插入图片描述

def iou_loss(pred, target, eps=1e-6):
    """IoU loss.
    Computing the IoU loss between a set of predicted bboxes and target bboxes.
    The loss is calculated as negative log of IoU.
    Args:
        pred (Tensor): Predicted bboxes of format (x1, y1, x2, y2),
            shape (n, 4).
        target (Tensor): Corresponding gt bboxes, shape (n, 4).
        eps (float): Eps to avoid log(0).
    Return:
        Tensor: Loss tensor.
    """
    ious = bbox_overlaps(pred, target, is_aligned=True).clamp(min=eps)
    loss = -ious.log()
    return loss

GIOU-loss

Generalized Intersection over Union: A Metric and A Loss for Bounding Box Regression

IOU Loss 缺点:

  • 如果两个框没有相交,根据定义,IoU=0,不能反映两者的距离大小(重合度)。同时因为loss=0,没有梯度回传,无法进行学习训练。
  • IoU无法精确的反映两者的重合度大小。 GIOU是更严格的指标。
    以上几种情况下均有 IoU=0.33 IoU=0.33IoU=0.33 但是显然从左到右定位效果越来越差

GIoU

  • 想法很好,效果一般,1-iou (Linear IOU loss) 基本可以达到1-giou(GIoU loss)相同的效果
  • 成本高还不讨好,现在最广泛的基本就是线性IOUloss
  • 闭包:包含两个框的最小框

Linear IOU Loss

l o s s = 1 − i o u s loss = 1 - ious loss=1ious

def iou_loss(pred, target, linear=False, eps=1e-6):
    """IoU loss.
    Computing the IoU loss between a set of predicted bboxes and target bboxes.
   """
    ious = bbox_overlaps(pred, target, is_aligned=True).clamp(min=eps)
    if linear:
        loss = 1 - ious
    else:
        loss = -ious.log()
    return loss

分类概率

softmax (多分类)

https://zhuanlan.zhihu.com/p/25723112
https://www.zhihu.com/question/23765351/answer/240869755

softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类!

假设我们有一个数组 V,Vi表示V中的第i个元素,那么这个元素的Softmax值就是

Sigmoid (二分类)

h ( x ) = 1 1 + e − x h(x) = \frac{\mathrm{1} }{\mathrm{1} + e^{-x} } h(x)=1+ex1

Sigmoid 因其在 logistic 回归中的重要地位而被人熟知,值域在 0 到 1 之间。Logistic Sigmoid(或者按通常的叫法,Sigmoid)激活函数给神经网络引进了概率的概念。它的导数是非零的,并且很容易计算(是其初始输出的函数)。然而,在分类任务中,sigmoid 正逐渐被 Tanh 函数取代作为标准的激活函数,因为后者为奇函数(关于原点对称)。

sigmoid函数缺点

  • Sigmoid函数饱和使梯度消失。sigmoid神经元有一个不好的特性,就是当神经元的激活在接近0或1处时会饱和:在这些区域,梯度几乎为0。如果初始化权重过大,那么大多数神经元将会饱和,导致网络就几乎不学习了。

  • Sigmoid函数的输出不是零中心的
    将影响梯度下降的运作

猜你喜欢

转载自blog.csdn.net/qq_31622015/article/details/103364467
今日推荐