Faster RCNN源码解读5-损失函数

Faster RCNN复现

Faster RCNN源码解读1-整体流程和各个子流程梳理

Faster RCNN源码解读2-_anchor_component()为图像建立anchors(核心和关键1)

Faster RCNN源码解读3.1-_region_proposal() 筛选anchors-_proposal_layer()(核心和关键2)

Faster RCNN源码解读3.2-_region_proposal()筛选anchors-_anchor_target_layer()(核心和关键2)

Faster RCNN源码解读3.3-_region_proposal() 筛选anchors-_proposal_target_layer()(核心和关键2)

Faster RCNN源码解读4-其他收尾工作:ROI_pooling、分类、回归等

Faster RCNN源码解读5-损失函数

 

理论介绍:有关Faster RCNN理论介绍的文章,可以自行搜索,这里就不多说理论部分了。

复现过程:代码配置过程没有记录,具体怎么把源码跑起来需要自己搜索一下。

faster rcnn源码确实挺复杂的,虽然一步步解析了,但是觉得还是没有领会其中的精髓,只能算是略知皮毛。在这里将代码解析的过程给大家分享一下,希望对大家有帮助。先是解析了代码的整体结构,然后对各个子结构进行了分析。代码中的注释,有的是原来就有的注释,有的是参考网上别人的,有的是自己理解的,里面或多或少会有些错误,如果发现,欢迎指正!

本文解析的源码地址:https://github.com/lijianaiml/tf-faster-rcnn-windows

知乎:FasterRCNN损失函数理论

CSDN:FasterRCNN损失函数理论 

上面链接里的文章,自己手动抄了一份,加深理解。

Faster RCNN源码解读5-损失函数_第1张图片

Faster RCNN源码解读5-损失函数_第2张图片

rcnn包括两个损失:rpn网络的损失+rcnn网络的损失,其中每个损失又包括分类损失回归损失分类损失使用的是交叉熵回归损失使用的是smooth L1 loss

程序通过**_add_losses**增加对应的损失函数。其中:
rpn_cross_entropyrpn_loss_boxRPN网络的两个损失,这两个损失用于判断archor是否是ground truth(二分类);
cls_scorebbox_predrcnn网络的两个损失。这两个损失的batchsize是256。

  1. 将rpn_label(1,?,?,2)中不是-1的index取出来,之后将rpn_cls_score(1,?,?,2)及rpn_label中对应于index的取出,计算sparse_softmax_cross_entropy_with_logits,得到rpn_cross_entropy。
  2. 计算rpn_bbox_pred(1,?,?,36)和rpn_bbox_targets(1,?,?,36)的_smooth_l1_loss,得到rpn_loss_box。
  3. 计算cls_score(256*21)和label(256)的sparse_softmax_cross_entropy_with_logits:cross_entropy。
  4. 计算bbox_pred(256*84)和bbox_targets(256*84)的_smooth_l1_loss:loss_box。

最终将上面四个loss相加,得到总的loss(还需要加上regularization_loss),至此,损失构造完毕。

_add_losses()

  '''
  faster rcnn包括两个损失:rpn网络的损失+rcnn网络的损失。其中每个损失又包括分类损失和回归损失。
  分类损失使用的是交叉熵,回归损失使用的是smooth L1 loss。
  
  程序通过**_add_losses**增加对应的损失函数。其中
  rpn_cross_entropy和rpn_loss_box是RPN网络的两个损失,这两个损失用于判断archor是否是ground truth(二分类);
  cls_score和bbox_pred是rcnn网络的两个损失。这两个损失的batchsize是256。
  
  将rpn_label(1,?,?,2)中不是-1的index取出来,之后将rpn_cls_score(1,?,?,2)及rpn_label中对应于index的取出,
  计算sparse_softmax_cross_entropy_with_logits,得到rpn_cross_entropy。
  计算rpn_bbox_pred(1,?,?,36)和rpn_bbox_targets(1,?,?,36)的_smooth_l1_loss,得到rpn_loss_box。
  计算cls_score(256*21)和label(256)的sparse_softmax_cross_entropy_with_logits:cross_entropy。 
  计算bbox_pred(256*84)和bbox_targets(256*84)的_smooth_l1_loss:loss_box。
  最终将上面四个loss相加,得到总的loss(还需要加上regularization_loss)。
  至此,损失构造完毕。
  '''
  def _add_losses(self, sigma_rpn=3.0):
    with tf.variable_scope('LOSS_' + self._tag) as scope:
      # (1)RPN, class loss 分类损失
      # 每个anchors是正样本还是负样本
      rpn_cls_score = tf.reshape(self._predictions['rpn_cls_score_reshape'], [-1, 2])
      # 特征图中每个位置对应的是正样本、负样本还是不关注(去除了边界框在图像外面的anchors)
      rpn_label = tf.reshape(self._anchor_targets['rpn_labels'], [-1])
      rpn_select = tf.where(tf.not_equal(rpn_label, -1)) #不关注的anchors的索引
      rpn_cls_score = tf.reshape(tf.gather(rpn_cls_score, rpn_select), [-1, 2]) #去除不关注的anchors
      rpn_label = tf.reshape(tf.gather(rpn_label, rpn_select), [-1]) #去除不关注的label
      rpn_cross_entropy = tf.reduce_mean(
        tf.nn.sparse_softmax_cross_entropy_with_logits(logits=rpn_cls_score, labels=rpn_label)) #rpn二分类的损失

      # (2)RPN, bbox loss 回归损失
      rpn_bbox_pred = self._predictions['rpn_bbox_pred'] #每个位置的9个anchors回归位置偏移
      rpn_bbox_targets = self._anchor_targets['rpn_bbox_targets'] #特征图中每个位置和对应的正样本的坐标偏移(很多为0)
      rpn_bbox_inside_weights = self._anchor_targets['rpn_bbox_inside_weights'] #正样本的权重为1(去除负样本和不关注的样本,均为0)
      rpn_bbox_outside_weights = self._anchor_targets['rpn_bbox_outside_weights'] #正样本和负样本(不包括不关注的样本)归一化的权重
      rpn_loss_box = self._smooth_l1_loss(rpn_bbox_pred, rpn_bbox_targets, rpn_bbox_inside_weights,
                                          rpn_bbox_outside_weights, sigma=sigma_rpn, dim=[1, 2, 3])

      # (3)RCNN, class loss 分类损失
      cls_score = self._predictions["cls_score"] #用于rcnn分类的256个anchors的特征
      label = tf.reshape(self._proposal_targets["labels"], [-1]) #正样本和负样本对应的真实的类别
      cross_entropy = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(logits=cls_score, labels=label))

      # (4)RCNN, bbox loss 回归损失
      bbox_pred = self._predictions['bbox_pred']  #RCNN ,bbox loss
      bbox_targets = self._proposal_targets['bbox_targets'] #256*(4*21)的矩阵,只有为正样本时,对应类别的坐标才不为0,其他类别的坐标全为0
      bbox_inside_weights = self._proposal_targets['bbox_inside_weights']
      bbox_outside_weights = self._proposal_targets['bbox_outside_weights']
      loss_box = self._smooth_l1_loss(bbox_pred, bbox_targets, bbox_inside_weights, bbox_outside_weights)

      self._losses['cross_entropy'] = cross_entropy
      self._losses['loss_box'] = loss_box
      self._losses['rpn_cross_entropy'] = rpn_cross_entropy
      self._losses['rpn_loss_box'] = rpn_loss_box

      loss = cross_entropy + loss_box + rpn_cross_entropy + rpn_loss_box   #总的损失
      regularization_loss = tf.add_n(tf.losses.get_regularization_losses(), 'regu')  #获取总正则化loss.
      self._losses['total_loss'] = loss + regularization_loss

      self._event_summaries.update(self._losses)

    return loss

 _smooth_l1_loss()

  '''
  程序中先计算pred和target的差box_diff,而后得到正样本的差in_box_diff
  (通过乘以权重bbox_inside_weights将负样本设置为0)及绝对值abs_in_box_diff,之后计算上式(3)
  中的符号smoothL1_sign,并得到的smooth L1 loss:in_loss_box,乘以bbox_outside_weights权重,
  并得到最终的loss:loss_box。
  '''
  def _smooth_l1_loss(self, bbox_pred, bbox_targets, bbox_inside_weights, bbox_outside_weights, sigma=1.0, dim=[1]):
    sigma_2 = sigma ** 2
    box_diff = bbox_pred - bbox_targets   # 预测的和真实的相减   x
    in_box_diff = bbox_inside_weights * box_diff  # 乘以正样本的权重1(rpn:去除负样本和不关注的样本,rcnn:去除负样本)
    abs_in_box_diff = tf.abs(in_box_diff)  # 绝对值  |x|
    smoothL1_sign = tf.stop_gradient(tf.to_float(tf.less(abs_in_box_diff, 1. / sigma_2)))   # 小于阈值的截断的标志位
    in_loss_box = tf.pow(in_box_diff, 2) * (sigma_2 / 2.) * smoothL1_sign \
                  + (abs_in_box_diff - (0.5 / sigma_2)) * (1. - smoothL1_sign)  # smooth l1 loss
    out_loss_box = bbox_outside_weights * in_loss_box  # rpn:除以有效样本总数(不考虑不关注的样本),进行归一化;rcnn:正样本四个坐标权重为1,负样本为0
    loss_box = tf.reduce_mean(tf.reduce_sum(
      out_loss_box,
      axis=dim
    ))
    return loss_box

终于更新完了,写完后自己对FasterRCNN也有了更深的理解,送人玫瑰,手有余香。感谢你一直以来的关注!一起努力一起加油!

你可能感兴趣的:(#,目标检测算法)