Focal Loss/RetinaNet

论文Focal Loss for Dense Object Detection(CVPR 2017) 速达>>
代码fizyr/keras-retinanet

针对问题

多阶段检测器虽然有较高的精度,但是速度与单阶段检测器有相当大的差距,实用价值大打折扣。单阶段网络的最大劣势就是精度不够高

那么为什么one-stage detector的准确率不够高?

  • 样本的类别不均衡导致的,负样本数量太大,占总的loss的大部分(主导Loss),不利于真正目标的学习
  • 多数为简单样本(目标少,大量背景当做负样本),容易使模型的优化方向跑偏(变成预测背景而不是前景)

两阶段检测器通常可以较好地上述两个问题,如:Faster RCNN :

  • 减少简单样本:根据RPN预测的正负样本得分取前N个(训练:12000)预测框,经过NMS得到大约2000个建议框
  • 平衡正负样本:从根据与gt_box 的IoU 挑选出n(128,正负样本比例:1:3)个rois 训练RCNN部分

OHEM算法也可以用来处理类别不均衡的问题,但只取Loss高的前N个样本训练,忽略了容易分类的样本,这种方式显然过于 Hard。简单样本学习得很好需要保持住,应该赋予其较低的权重(简单样本loss虽然小,但数量大),减小其loss的贡献

所以单阶段对于上述两个问题的解决方向为

  • 减少简单样本的权重,使得模型在训练时更专注于困难样本
  • 平衡正负样本

Focal Loss

交叉熵损失

下式为普通的二分类交叉熵损失, p p p 表示预测概率, y = 1 y=1 y=1表示正样本。当 y = 1 y=1 y=1时,预测概率 p p p越接近1,预测得越准,损失越小
在这里插入图片描述
p t p_t pt 代替 p p p,则可以将损失表达形式简化:
在这里插入图片描述
一般可以通过权重来平衡损失,如:简单地添加一个系数 α t \alpha_t αt y = 1 y=1 y=1 时, α t = a \alpha_t=a αt=a y = − 1 y=-1 y=1 时, α t = 1 − a \alpha_t=1-a αt=1a a ∈ [ 0 − 1 ] a\in[0-1] a[01]。通过改变 a a a的值来控制正负样本Loss权重

在这里插入图片描述

Focal Loss

而上面的形式相当于一刀砍的形式,没有区别对待难分类样本和易分类样本,因为易分类样本占样本的绝大部分,一刀砍的形式并不能让网络专注于困难样本

为其加上调制系数(modulating factor),就是Focal Loss的形式

在这里插入图片描述

预测越准, p t p_t pt越趋于1时(分类正确且为易分类样本),调制系数趋于0,loss贡献小

调制系数让网络更专注于困难样本,加上 α t \alpha_t αt系数(如式3)控制正负样本权重(注意不是比例), γ = 2 , α = 0.25 γ=2,α=0.25 γ=2α=0.25 的取值组合效果较好(原文:as easy negatives are downweighted, less emphasis needs to be placed on the positives), α \alpha α取0.25意味着还要减小正样本权重!!

在这里插入图片描述
Focal Loss形式简单,但体现作者对目标检测中样本不平衡问题的深刻认识

# https://github.com/fizyr/keras-retinanet/blob/master/keras_retinanet/losses.py
def focal(alpha=0.25, gamma=2.0, cutoff=0.5):
    """ Create a functor for computing the focal loss.
    Args
        alpha: Scale the focal weight with alpha.
        gamma: Take the power of the focal weight with gamma.
        cutoff: Positive prediction cutoff for soft targets
    Returns
        A functor that computes the focal loss using the alpha and gamma.
    """
    def _focal(y_true, y_pred):
        """ Compute the focal loss given the target tensor and the predicted tensor.
        As defined in https://arxiv.org/abs/1708.02002
        Args
            y_true: Tensor of target data from the generator with shape (B, N, num_classes).
            y_pred: Tensor of predicted data from the network with shape (B, N, num_classes).
        Returns
            The focal loss of y_pred w.r.t. y_true.
        """
        labels         = y_true[:, :, :-1]
        anchor_state   = y_true[:, :, -1]  # -1 for ignore, 0 for background, 1 for object
        classification = y_pred

        # filter out "ignore" anchors
        indices        = tensorflow.where(keras.backend.not_equal(anchor_state, -1))
        labels         = tensorflow.gather_nd(labels, indices)
        classification = tensorflow.gather_nd(classification, indices)

        # compute the focal loss
        alpha_factor = keras.backend.ones_like(labels) * alpha
        # 预测为正样本alpha_factor=0.25,预测为负样本alpha_factor=0.75
        alpha_factor = tensorflow.where(keras.backend.greater(labels, cutoff), alpha_factor, 1 - alpha_factor)
        focal_weight = tensorflow.where(keras.backend.greater(labels, cutoff), 1 - classification, classification)
        focal_weight = alpha_factor * focal_weight ** gamma

        cls_loss = focal_weight * keras.backend.binary_crossentropy(labels, classification)

        # compute the normalizer: the number of positive anchors
        normalizer = tensorflow.where(keras.backend.equal(anchor_state, 1))
        normalizer = keras.backend.cast(keras.backend.shape(normalizer)[0], keras.backend.floatx())
        normalizer = keras.backend.maximum(keras.backend.cast_to_floatx(1.0), normalizer)

        return keras.backend.sum(cls_loss) / normalizer

    return _focal

RetinaNet

结构上主要是Resnet+FPN 【 7 】 ^{【7】} 7
在这里插入图片描述

初始化问题

对 classification subnet 的最后一层 conv 初始化其偏置 b b b − log ⁡ ( ( 1 − π ) / π ) -\log((1-\pi)/\pi) log((1π)/π) π \pi π 代表先验概率,即正样本占比(正样本少),这里代表正样本框占所有框的比重,文中设为0.01

最后一层的激活函数为 Sigmoid 函数,其实就是最后的预测:
p = 1 1 + e − ( W x + b ) p= \frac{1}{1+e^{-(Wx+b)}} p=1+e(Wx+b)1

假定损失只是简单的交叉损失:
L o s s = − log ⁡ ( p t ) \mathcal Loss =-\log(p_t) Loss=log(pt)

如果初始化 b b b 为 0,由于 W W W 初始化值是一个很小的数(趋近于 0),而且由于前面层的初始化均很小,中间还有 BN 层,所以 x x x 值也不会太大, W x + b Wx+b Wx+b 的值可以认为趋近于 0,则有:
1 1 + e − ( W x + b ) ≈ 0.5 ⟹ L o s s = − log ⁡ ( 0.5 ) \frac{1}{1+e^{-(Wx+b)}}\approx 0.5\Longrightarrow Loss =-\log(0.5) 1+e(Wx+b)10.5Loss=log(0.5)

这个时候可以认为网络第一次向前传播得到的预测就是瞎蒙,虽然正负样本预测错了惩罚均为 L o s s = − log ⁡ ( 0.5 ) Loss =-\log(0.5) Loss=log(0.5) ,但由于负样本数量远远多于正样本,这样负样本的损失占主导地位,不利于收敛。

如果希望一开始就针对正样本学习,那就让预测偏向负样本,即让预测 p p p 大概率为一个较小的数 π \color{blue}\pi π(小于 0.5 即预测为负样本,文中取的是正样本占比 0.1),对于负样本来说,大部分都预测正确(不容易把负样本预测为正样本),这样一开始就是正样本的损失占据主导地位了,所以有:
1 1 + e − ( W x + b ) ≈ 1 1 + e − b = π ⟹ b = − log ⁡ ( ( 1 − π ) / π ) \frac{1}{1+e^{-(Wx+b)}}\approx \frac{1}{1+e^{-b}}= \pi\Longrightarrow \color{blue}b =-\log((1-\pi)/\pi) 1+e(Wx+b)11+eb1=πb=log((1π)/π)

实验

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

参考文献

【1】focal loss理解与初始化偏置b设置解释
【2】论文阅读: RetinaNet
【3】RetinaNet(Focal Loss)
【4】何恺明大神的「Focal Loss」,如何更好地理解?
【5】目标检测 | 比 Focal Loss 更强的:Gradient Harmonized Mechanism
【6】堪比Focal Loss!解决目标检测中样本不平衡的无采样方法
【7】FPN

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值