Faster R-CNN中RPN的分析

Faster R-CNN原文地址

摘要

Faster R-CNN是object detection的里程碑之作。它提出了RPN,即一种用CNN来提取proposal的网络。

为了更好地理解RPN的代码实现细节,充分理解它用到的SmoothL1Loss是很必要的。

本文简述了RPN的作用,讨论了RPN的loss以及SmoothL1Loss的语义及其作用,最后分析了RPN的代码实现。

RPN的原理

RPN简介

RPN是一个输入global feature map,输出许多可能RoI的网络。
RoI就是所谓的感兴趣区域,相当于是物体bbox的candidate。RPN输出的RoI也被称为proposal。

RPN的anchor

RPN的基本原理就是利用有一定stride(比如16像素)的滑动窗口在原图上枚举proposal中心,对每个中心产生多个不同长宽比(例如0.5,1,2三种),不同大小(比如大中小三种)的bbox。这些产生的bbox被叫做anchor。

如果对每个中心有三种长宽比、三种大小,我们就能得到9个anchor。

RPN的minibatch

下文中你会见到minibatch这种说法。
minibatch就是RPN每次输出的proposal的数量。
如果RPN对每一张图片输出了256个proposal,那么我们就说minibatch=256。

RPN的loss及其分析

RPN的loss如下。
L ( { p i } , { t i } ) = 1 N c l s ∑ i L c l s ( p i , p i ∗ ) + λ 1 N r e g ∑ i p i ∗ L r e g ( t i , t i ∗ ) L(\{p_i\},\{t_i\}) = {1\over N_{cls}}\sum_i{L_{cls} (p_i,p_i^*)} + \lambda{1\over N_{reg}}\sum_i{p_i^*L_{reg}(t_i,t_i^*)} L({pi},{ti})=Ncls1iLcls(pi,pi)+λNreg1ipiLreg(ti,ti)

  • loss的结构。
    这个loss是一种multi-task loss。所谓多任务loss。
    这里,它是cls(proposal的分类)和reg(proposal的bbox的位置回归、微调)两个任务各自的loss之加权和。
    之所以说是加权和,主要表现在reg项乘了一个 λ \lambda λ,它一个灵活的超参数,需要人为设定。原文提到 λ = 10 \lambda=10 λ=10

  • loss的符号。
    i i i 是一个minibatch中所有anchor的索引。
    p i p_i pi是对anchor i i i的预测结果。 p i ∗ p_i^* pi是anchor i i i的ground truth。 p i ∗ = 1 p_i^*=1 pi=1则是正样本(物体,也就是前景),0则是负样本(背景)。
    t i t_i ti是一个长度为4的向量,存的是anchor的四个参数 t i ∗ t_i^* ti t i t_i ti对应的bbox的ground truth,也是存的四个参数。注意:这里的四个参数不是 ( x , y , w , h ) (x,y,w,h) (x,y,w,h)。是 ( t x , t y , t w , t h ) (t_x,t_y,t_w,t_h) (tx,ty,tw,th)。这四个参数在下文介绍。

  • 分类项的分析。
    N c l s N_{cls} Ncls的值是一个minibatch所产生的所有proposal的数量。乘上 1 N c l s 1\over N_{cls} Ncls1相当是对各个proposal产生的loss取了个平均值。
    L c l s L_{cls} Lcls是一个物体/背景二分类的log loss。通常使用softmax。
    本项语义:对所有的anchor计算loss并求和,再依照proposal数目取平均值以标准化。

  • 回归项的分析。
    N r e g N_{reg} Nreg是anchor的数量。与 N c l s N_{cls} Ncls的作用相同:取平均值以标准化。
    L r e g ( t i , t i ∗ ) = R ( t i − t i ∗ ) L_{reg}(t_i,t_i^*)=R(t_i-t_i^*) Lreg(ti,ti)=R(titi)。其中 R R R是一个鲁棒的loss函数。一般使用SmoothL1Loss,在下文详述。
    乘了一项 p i ∗ p_i^* pi意味着去掉背景bbox对回归loss的贡献——毕竟背景bbox没有必要回归、也没有ground truth可以计算loss。
    本项语义:对所有含有物体的anchor计算鲁棒loss并求和,再依照anchor数目取平均值以标准化。

这种multi-task loss的设计手法非常常见,实际上背后的思想和数学都非常简单。

SmoothL1Loss的分析

回归中的参数化

t i = ( t x , t y , t w , t h ) t_i=(t_x,t_y,t_w,t_h) ti=(tx,ty,tw,th)。存的四个参数非常特殊,是为了更好地回归而设计的。

t x = ( x − x a ) / w a , t y = ( y − t a ) / h a , t w = l o g ( w / w a ) , t h = l o g ( h / h a ) . t_x = (x-x_a)/w_a,\\ t_y = (y-t_a)/h_a,\\ t_w = log(w/w_a),\\ t_h = log(h/h_a). tx=(xxa)/wa,ty=(yta)/ha,tw=log(w/wa),th=log(h/ha).
t i t_i ti对应的bbox的ground truth记作 t i ∗ = ( t x ∗ , t y ∗ , t w ∗ , t h ∗ ) t_i^*=(t_x^*,t_y^*,t_w^*,t_h^*) ti=(tx,ty,tw,th)

类似地,
t x ∗ = ( x ∗ − x a ) / w a , t y ∗ = ( y ∗ − t a ) / h a , t w ∗ = l o g ( w ∗ / w a ) , t h ∗ = l o g ( h ∗ / h a ) . t_x^* = (x^*-x_a)/w_a,\\ t_y^* = (y^*-t_a)/h_a,\\ t_w^* = log(w^*/w_a),\\ t_h^* = log(h^*/h_a). tx=(xxa)/wa,ty=(yta)/ha,tw=log(w/wa),th=log(h/ha).
其中, x , y , w , h x,y,w,h x,y,w,h表示bbox的横纵坐标和宽高。带*的则表示对应的ground truth.

SmoothL1Loss

下式就是SmoothL1Loss。
smooth L 1 ( x ) = { 0.5 x 2 if |x|<1 ∣ x ∣ − 0.5 otherwise \text{smooth}_{L1}(x) = \begin{cases} 0.5x^2& \text{if |x|<1}\\ |x|-0.5& \text{otherwise} \end{cases} smoothL1(x)={0.5x2x0.5if |x|<1otherwise
本质上来说,它基于L1 loss。L1 loss,是指用真实值和预测值之差的绝对值——也就是差值(或者差向量)的L1范数作为loss值。
L1 loss有一个问题,它在零点处不可微。
而SmoothL1Loss改善了这个问题:在 ∣ x ∣ < 1 |x|<1 x<1的时候,用具有相同导数的 0.5 x 2 0.5x^2 0.5x2代替L1范数,这让loss更加smooth。

现在再看reg loss的式子: L r e g ( t i , t i ∗ ) = smooth L 1 ( t i − t i ∗ ) L_{reg}(t_i,t_i^*)=\text{smooth}_{L_1}(t_i-t_i^*) Lreg(ti,ti)=smoothL1(titi),已经非常明显了。求出位置bbox的真实值和预测值的差向量,然后求loss。

Detectron的RPN代码实现分析

网络结构图

日后再补。

bbox_inside_weights

bbox_inside_weights 中每个长度为4的向量对应回归loss中的 p i ∗ p_i^* pi。它乘入anchor的4个坐标参数,将所有非物体的anchor的4个坐标参数都置为零或不变。只有(0,0,0,0)和(1,1,1,1)两种取值。

    # 摘自rpn.py
    # Bbox regression loss has the form:
    # loss(x) = weight_outside * L(weight_inside * x)
    # Inside weights allow us to set zero loss on an element-wise basis
    # Bbox regression is only trained on positive examples so we set their
    # weights to 1.0 (or otherwise if config is different) and 0 otherwise
    bbox_inside_weights = np.zeros((num_inside, 4), dtype=np.float32)
    bbox_inside_weights[labels == 1, :] = (1.0, 1.0, 1.0, 1.0)

bbox_outside_weights

bbox_outside_weights 相当于回归loss中的 1 N r e g 1\over {N_{reg}} Nreg1

	# 摘自rpn.py
    # The bbox regression loss only averages by the number of images in the
    # mini-batch, whereas we need to average by the total number of example
    # anchors selected
    # Outside weights are used to scale each element-wise loss so the final
    # average over the mini-batch is correct
    bbox_outside_weights = np.zeros((num_inside, 4), dtype=np.float32)
    # uniform weighting of examples (given non-uniform sampling)
    num_examples = np.sum(labels >= 0)
    bbox_outside_weights[labels == 1, :] = 1.0 / num_examples
    bbox_outside_weights[labels == 0, :] = 1.0 / num_examples

含wide的blobs的解释

		# 摘自rpn.py
        blobs_out.append(
            dict(
                rpn_labels_int32_wide=_labels,
                rpn_bbox_targets_wide=_bbox_targets,
                rpn_bbox_inside_weights_wide=_bbox_inside_weights,
                rpn_bbox_outside_weights_wide=_bbox_outside_weights
            )
        )

SpatialNarrowAs的意义

裁剪稠密的label。

待回答的疑问

  • fast head中计算loss_bbox为何需要bbox_inside_weights和bbox_outside_weights?这里的两个weights又是什么?
  • CollectAndDistributeFpnRpnProposalsOp有何用处?
  • GenerateProposalsOp有何用处?
  • 还有吗?

References

  • rcnn ->fast rcnn->faster rcnn物体检测论文 http://www.cnblogs.com/wuxiangli/p/7066707.html
  • Detectron总结(二)
    https://blog.csdn.net/u013548568/article/details/79470938

你可能感兴趣的:(CV,知識總結)