引用:
[1] https://www.jianshu.com/p/204d9ad9507f
[2] https://cloud.tencent.com/developer/article/1392341
1.提出原因
- 目前现有的目标检测网络为two-stage、one-stage,two-stage检测精度高速度慢;one-stage检测速度快,精度低;one-stage没有包含two-stage中提取proposal的过程。
- One-steage识别精度低原因。文章认为类别间的样本不平衡(class imbalance)造成了较低的识别精度。讲解下类别的概念:
计算loss的bbox可分为positive和nagetive。Bbox与GT之间得到IOU:
if IOU >= th:
bbox is positive example
else :
bbox is nagetive example
若一张图片上的目标相对于负样本(非label目标和背景)所占的像素点比例过小,则该图会以负样本(nagetive example为主),这会造成以下问题:
- 以CE(cross entropy)为例,负样本比例过大计算loss时,cross entropy loss会忽略正样本的loss,造成难以收敛。
- 大多negative example不在前景和背景的过渡区域上,分类很明确(这种易分类的negative称为easy negative),训练时对应的背景类score会很大,换个角度看就是单个example的loss很小,反向计算时梯度小。梯度小造成easy negative example对参数的收敛作用很有限,我们更需要loss大的对参数收敛影响也更大的example,即hard positive/negative example。
这里要注意的是前一点我们说了negative的loss很大,是因为negative的绝对数量多,所以总loss大;后一点说easy negative的loss小,是针对单个example而言。
针对以上问题,Faster Rcnn规避了以上两个问题:
- 会根据前景score的高低过滤出最有可能是前景的example (1K~2K个),因为依据前景概率的高低,就能把大量背景概率高的easy negative给过滤掉,这就解决了前面的第2个问题;
- 会根据IOU的大小来调整positive和negative example的比例,比如设置成1:3,这样防止了negative过多的情况(同时防止了easy negative和hard negative),就解决了前面的第1个问题。所以Faster RCNN的准确率高。
OHEM是近年兴起的另一种筛选example的方法,它通过对loss排序,选出loss最大的example来进行训练,这样就能保证训练的区域都是hard example。这个方法有个缺陷,它把所有的easy example都去除掉了,造成easy positive example无法进一步提升训练的精度。
图1 hard positvie、hard negative、easy positive、easy negative四种example的示意图
2.解决方法
Focal loss 是以cross entropy loss为基础,增加一个权重参数,根据样本比例调整这个权重,以达到正负样本计算loss的占比相同的目的,这也间接解决了class imbalance的问题。
CEL(cross entropy loss) = −ylog(p) - (1−y)log(1−p)
If y == 1:
CEL = -log(p)
Else :
CEL = -log(1-p)
再:
在CEL的基础上增加权重参数,最后的FL为:
FL中,Pt是不同类别的分类概率,在[0 , 5],当为0时FL=CEL,at是[0 , 1]之间的小数,和at是固定值。从表达式可以看出:
- 无论是正样本还是负样本,当Pt很大时,很小,这种情况下,easy positive/nagetive example计算loss的比重就比较小,权重更新会得到抑制。
- at用于调节前景背景比例(与CEL中的相同)前景为at,则背景为1-at。
- r和at的论文中给出r=2、at=0.25时,ResNet-101+FPN作为backbone的结构有最优的性能。且r和at成反比。
3.FL的其他关键点
- 使用sigmoid计算Pt结果较好:
2.FL的公式不是一成不变的,论文最后给出了变形式,性能差异不大。变形式如下:
测试结果:
从表中看出,FL的AP最大,改进后的FL*的AP还有一些下降?总体性能看上去没有多大提升,反而比原始的FL效果有些差。
- 模型初始化的优化:
- 在模型训练初期,样本多的类别主要影响总体的loss,这会造成模型训练的不稳定。为了提高训练的稳定性,引入一种特殊的初始化方式。
- 方法:在最后一层用于分类的conv中修改bias初始化方式,b=-log((1-π)/π) π在论文中取0.01,这样做能在训练初始阶段提高positive的分类概率。
4.RetinaNet结构
- 总体结构:
- Backbone网络:ResNet + FPN
- Regress/Classification网络:FCN
- 总体结构为:
图2 RetinaNet
上面为分类的FCN,下面为回归的FCN;其中分类结构中,K为类别数,bias的特殊初始化方式在分类的最后一层。c d结构中conv的其他bias初始化全为0,权重w初始化符合高斯分布,。
- 注意的几点:
- 训练时FPN每一级的所有example都被用于计算Focal Loss,loss值加到一起用来训练;
- 测试时FPN每一级只选取score最大的1000个example来做nms;
- 整个结构不同层的head部分(图2的c和d部分)共享参数,但分类和回归分支间的参数不共享;
- Bias初始化方式。
- 实验结果:
图3 实验结果
5.Tensorflow实现
def focal_loss(predictions , labels , alpha , gamma):
zeros = tf.zeros_like(predictions , dtype=predictions.dtype)
pos_corr = tf.where(labels > zeros , labels - predictions , zeros)
neg_corr = tf.where(labels > zeros , zeros , predictions)
# FL
fl_loss = -alpha * (pos_corr**gamma)*tf.log(predictions) - (1-alpha)*(neg_error**gamma)*tf.log(1.0 - predictions)
return tf.reduce_sum(fl_loss)