Focal Loss for Dense Object Detection论文详解

《Focal Loss for Dense Object Detection》发表于ICCV2017

代码地址:
caffe2实现:https://github.com/facebookresearch/Detectron
keras实现:https://github.com/fizyr/keras-retinanet

文章思路:作者思考,目前two-stage的检测方法能够达到较高的精度,而one-stage虽然速度快,但是精度却达不到two-stage的效果。作者认为原因是在one-stage的训练过程中正负样本的不平衡造成的。对于一幅图像来说,一般有10^4 - 10^5个候选区域,但是至少非常少的候选区域包含待检测物体。这种正负样本极度不平衡的情况下会导致两个问题:

  • 训练效率低,大部分易于分类的负样本对模型的训练没有很大的指导意义
  • 大量的易分类负样本加入训练,导致训练出来的效果不好,容易收到这部分样本的影响
    因此,本文提出focal loss这种改进的交叉熵loss来解决样本不均衡带来的问题,又因为本文小改了一下网络结构,将新的网络结构称为retinanet,所以本文有人也称为retinanet。但是文章说明,本文的重点是提出一个有效的loss,而不是网络。

下面将按照本人一贯的解读习惯,先介绍一下网络结构,然后介绍focal loss

一、网络结构

简单来说本文采用的网络是resnet作为主干网络,网络框架采用的是FPN的结构,最后将FPN得到的各层feature map(P3-P7)都加上两个分支,一个用于回归框一个用于得到物体的类别。基本的网络结构如下图所示:


1.png

这里还要多解释两句P3-P7这几个feature map的来源。因为采用的backbone为resnet,对于resnet几个阶段的feature,重复利用C3-C5这几个feature。P6就是C5通过3\times 3 stride-2的卷积得到,P7为P6经过ReLU函数后在经过3\times 3 stride-2的卷积得到。其它几层类似于FPN。

1.1 Anchors
虽然是one-stage,但还是使用anchor的方式都物体进行检测的,所以还有一些关于anchor的参数设置。
因为使用了FPN中的P3-P7层的featuremap,每层feature的大小不一致,所以anchors的大小也不一致,对应的大小为32^2, 64^2, 128^2, 256^2, 512^2。而对于每一层的anchor,每个anchor的长宽比为{1:2, 1:1, 2:1},每个anchor大小在上述的基础大小上进行缩放,缩放比例为{2^0, 2^{1/3}, 2^{2/3}}。所以在每个featuremap上每个点都对应9个不同的anchor,而每个不同的featuremap对应的anchor面积大小也是不一样的。这部分类似与fasterrcnn
的设计,不太理解的看看fasterrcnn详解

至于正负训练样本的选择,anchor与gt框的IoU大于0.5定为正样本,IoU在[0,0.4)之间的定为负样本,其他的anchor则忽略不参与训练。

1.2 输出分支(Classification Subnet 和 Box Regression Subnet)

分类分支(Classification Subnet)
对于上述得到的P3-P7的feature,每个feature都经过4个3\times 3的卷积层,每个卷积之后都进行relu的激活,最后在经过一个3\times 3的卷积得到9×K个通道,对应每个anchor对应的类别。

回归分支(Box Regression Subnet)
这个分支和上面的分类分支是平行的,也就是他们是独立的。结构和上面分支基本一样,只是输出维度不同,这个分支输出9*4个通道,对应每个anchor的四个回归值。

二、Focal Loss

这个是本文的一大创新,也是重点内容,它是对cross entropy loss的一种改进。
下面先看看一个二分类的交叉熵表示
CE(p,y)=\left\{\begin{aligned}-log(p) \quad if \quad y=1 \\ -log(1-p) \quad otherwise \end{aligned}\right.

为了方便定义p_t:
p_t=\left\{\begin{aligned} p \quad if \quad y=1 \\ 1-p \quad otherwise, \end{aligned}\right.

这样可以得到CE(p,y)=CE(p_t)=-log(p_t)

这种loss的计算方法在有大量易分类的样本中,难分类的样本容易本起不到决定性的作用。

为了平衡正负样本的作用,将上述loss改为:
CE(p_t)=-\alpha_t log(p_t)
上式中的\alpha_t为一个0-1之间的数,一般取于类别频率成反比的数。

上面改进能够起到平衡样本的作用,但是并没有对一些容易分类的样本做处理,我们不仅希望平衡样本,而且希望将易分类的样本提供的loss比重减小,所以提出下面的式子:
FL(p_t)=-(1-p_t)^\gamma log(p_t)
其中\gamma为大于等于0的一个超参数,下图为将\gamma取值为[0,5]的一个可视化曲线。

2.png

对于上面的式子我们可以看出两点:

  • 当一个样本被错分类后,且p_t较小,则前面因子接近于1,loss几乎没影响
  • 当一个样本p_t接近于1,因子接近0,这样导致易分类样本loss权重减小,从而达到给易分类样本loss降权的目的。

最后为了平衡样本在上面的loss前加上平衡因子,最终focalloss形式如下:
FL(p_t)=-\alpha_t(1-p_t)^\gamma log(p_t)
在文章的实验中,\gamma=2, \alpha=0.25达到最好的效果。

到这里这篇文章就介绍完了。

三、关于focalloss的实现

上述公式看起来挺简单的,其实细心一点,实现也不难,但是不细心的话容易出错,先来看看下面两种实现

def com_focal_loss1(
      features: tf.Tensor, 
      labels: tf.Tensor, 
      alpha: float,
      gamma: float):
      """
      features 为网络的输出特征,该特征求sigmoid就是对样本是否为正样本的预测
      labels 为输入的标签,0表示正样本1表示负样本
      alpha: 上述的平衡因子
      gamma: 同公式
      """
      p = tf.nn.sigmoid(features)
      focal = alpha * tf.pow(tf.abs(labels - p), gamma)
      ce_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels = labels, logits = features)
      focal_loss = focal * ce_loss
      return focal_loss
def com_focal_loss2(
      features: tf.Tensor, 
      labels: tf.Tensor, 
      alpha: float,
      gamma: float):
      """
      features 为网络的输出特征,该特征求sigmoid就是对样本是否为正样本的预测
      labels 为输入的标签,0表示正样本1表示负样本
      alpha: 上述的平衡因子
      gamma: 同公式
      """
      p = tf.nn.sigmoid(features)
      ce_loss = tf.nn.sigmoid_cross_entropy_with_logits(labels = labels,  logits = features)
      p_t = p * labels + (1 - p) * (1 - labels)
      alpha_t = alpha * labels + (1 - alpha) * (1 - labels)
      focal_loss = alpha_t * tf.pow((1 - p_t), gamma) * ce_loss
      return focal_loss

第一种实现看起来跟公式很像,但是会有些问题,p_t的计算简化一下和第二种是一样的,但是\alpha_t却与文章中的不一样,没有起到平衡正负样本的作用,第二种实现是有的。

欢迎加入Object Detection交流,群聊号码:910457072

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,924评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,902评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,716评论 0 239
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,783评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,166评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,510评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,784评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,476评论 0 196
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,196评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,459评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,978评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,321评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,964评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,046评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,803评论 0 193
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,530评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,420评论 2 265

推荐阅读更多精彩内容