图解 MASK-RCNN

本文参考自 tensorflow model 中的 object detection ,同时实现了 FastRCNN, FasterRCNN, MaskRCNN

约定:

关于坐标

  • 绝对坐标 :表示没有除以图片的 height 和 width
  • 归一化坐标 :表示已经除以图片的 height 和 width
  • 中心化坐标 : 格式为 [y, x, h, w]
  • 对角坐标:[ymin, xmin, ymax, xmax]

以上中心化绝对坐标,中心化归一坐标,对角绝对坐标,对角归一化坐标四种组合。

关于图片大小变化

  1. 原图
  2. resize 之后的图片 true_image_shape,此时图片最短边为 600,最长边为 1200
  3. 特征提取器预处理之后的大小 image_shape,此时图片边长在 [1200],这是由于在 resize 的时候,对于不够最长边长的补 0。
  4. 特征提取网络预处理之后的图片 h, w
  5. 经过特征提取网络之后的 feature_map

预测值

RPN 网络每张图片的预测
  • rpn_box_encodings : [batch_size, num_valid_anchors, 4] 其中 4 依次为 [y, x, h, w]
  • rpn_objectness_predictions_with_bg : [batch_size, num_valid_anchors, 2],其中 2,分别为 2 元素的 one-hot,[1,0] 表示背景,[0,1] 表示包含对象

注:其中 h,w 为特征图的 height 和 width,num_valid_anchors <= h * w * 9

检测网络每张图片的预测
  • refined_box_encodings
  • class_predictions_with_background
  • proposal_boxes
  • mask_predictions

标签

RPN 网络每张图片的标签
  • reg_target : 每个元素的维度为 [num_boxes, 4] 其中 4 为 [y, x, h, w],而且都小于 [0,1]
  • reg_cls : 每个元素的维度为 [num_boxes, num_classes],其中 num_class 为分类的数量,为 one_hot 向量(只有 box 对应的分类才为 1,其余都为 0)。
  • reg_weights : 包含 box 的权重
  • reg_cls : 包含物体的权重
检测网络每张图片的标签
  • reg_targets
  • reg_weight
  • cls_targets_with_background
  • cls_weight
  • mask_targets
  • mask_targets_weight
训练

train-1

train-2

train-3

train-4

train-5

验证

inference 1

inference 2

inference 3

inference 4

inference 3 stage 1

inference  3 stage 2

注:去掉上述图片中框起来的部分,就是 Faster RCNN

训练

box_coding : [N, 4] 其中 4 依次为 [x_center, y_center, w, h]

anchor : [ymin, xmin, ymax, xmax]

注:实际在用之前都需要做处理的,参考 _format_groundtruth_data

CNN 特征提取网络:FasterRCNN 特有的术语

图片预处理

对应配置 image_resizer 部分

采用 BILINEAR 方法进行等比例的 resize, 最后图片最长 1200,最短 600。具体算法参考附录预处理部分。

特征提取器预处理

不同的 CNN 特征提取网络需要不同的预处理. 如 inception_v2 如 resnet

经过预处理之后,图片变为固定大小,如 [batch_size, 224, 224, 3]

前半部分

将 preprocessed_inputs 经过 CNN 提取网络得到 h * w * c 的特征图 rpn_features_to_crop

具体说明见附录

Anchor 生成

根据 rpn_features_to_crop 的 h, w 生成 anchors(h * w * 9 个),anchors 的维度为 [batch_size, h * w * 9]。 生成算法参考附录。

注: 生成 anchors 的个数为 h * w * 9,其中 9 为 scale 和 aspect_ratios 不同组合,在

paper 中为 scales=(0.5, 1.0, 2.0), aspect_ratios=(0.5, 1.0, 2.0) 两两共 9 种组合,anchor 为中心化绝对坐标。

box 坐标预测

  1. rpn_box_predictor_features 经过卷积核为 1 * 1, depth 为 9 * 4 的卷积,得到 rpn_box_encodings
  2. 将的输出 rpn_box_coding 维度修改为 (batch_size, h * w * 9, 4),其中 4 为 box 的坐标 [ymin, xmin, ymax, xmax] 的相对坐标。

物体存在预测

  1. rpn_box_predictor_features 经过卷积核 1 * 1 ,depth 为 9 * 2 得到 rpn_objectness_predictions_with_background
  2. 将输出 rpn_objectness_predictions_with_background 维度修改为 (batch_size, h * w * 9, 2) 其中 2 代表分类,第一个列为背景,第二维为非背景

注:rpn_objectness_predictions_with_background, rpn_box_predictor_features 的第二维为 h * w * 9 与 anchors 的数量一致。即每一个 anchor 对应一个 objectness 和 box

如果当前是训练阶段

anchor 过滤

  1. 将 anchors 中四个角都在 image_shape 内的 anchors 保留,其余都删除

索引过滤

  1. 由于 anchor 与 box_encoding 和 rpn_objectness_predictions_with_background 在第二维度上相同,如果 anchors 中对应元素被删除,那么在 rpn_box_coding 和 rpn_objectness_predictions_with_background 中对应的元素也删除

如果不是训练阶段

anchor 修正

  1. 将 anchors 中每个 anchor 修改为与 input_image 的交集,去掉与预处理之后图片没有交集的 anchor

至此,第一阶段 RPN 网络预测部分完成。

rpn_box_coding : [batch_size,  num_valid_anchors, 4]  其中 4 依次代表  [y, x, h, w]

rpn_objectness_predictions_with_background : [batch_size,  num_valid_anchors,  2]

anchors_boxlist [batch_size,  num_valid_anchors]

其中 num_valid_anchors 为删除不满足条件的 anchor 之后有效 anchor 数量。

如果只运行第一阶段,求 Loss

标签预处理

  1. 将 groundtruth_boxeslist 每个 box 转为绝对坐标,即横轴乘以 true_image_shape[1], 纵轴乘以 true_image_shape[0]
  2. 将 groundtruth_classes_list 每个 box 第一列前增加一列,为背景列。 维度为 [num_boxes, 1 + 1 ]
  3. 用 NEAREST_NEIGHBOR 算法 将 groundtruth_masks_list 每个元素 resize 为 true_image_shape 的尺寸,并对齐

至此,标签和预测都准备好了,但是它们的维度不匹配,无法直接计算,因此,需要将标签映射到预测值的坐标系。也就是找到标签的每一个 box 与位于特征图的哪一个 grid cell,在该 grid cell 与哪个 anchor 匹配。

第一次 IoU 过滤

  1. 计算 groundtruth_boxeslist 与 anchors 的 IoU 矩阵 match_quality_matrix(可以理解为[num_boxes, 1] 与 [1, num_anchor] 的矩阵乘,得到 [num_boxes, num_anchor] 的矩阵。其中 row 索引为 groundtruth_boxeslist 元素索引, colum 索引为 anchors 元素索引)
  2. 记录 match_quality_matrix 每列最大值对应的行索引得到 match1。此时 match1 本身的索引为列索引,存储的值为行索引。因此,通过 match1 就能定位到 match_quality_matrix 对应的 IoU 值。
  3. 如果 match1[i] 中元素对应 IoU 大于 0.7,match1[i] 不变,如果 match1[i] 中元素对应 IoU 小于 0.7,大于 0.3,match1[i] 为 -2. 如果 match1[i] 对应 IoU 小于0.3,match1[i] 为 -1。
  4. 记录 match_quality_matrix 每行最大值对应的列索引得到 match2。此时 match2 本身的索引为行索引,存储的值为列索引。因此,通过 match1 就能定位到 match_quality_matrix 对应的 IoU 值。
  5. matches 为 num_anchor 个元素的数组,从 0 到 num_anchor 的任意值 i,如果 i 存在于 match2,matches[i] 为 i 在 match2 中的索引(假设为 k,ground_truth[k] 与 anchors[i] 的 IoU 大于其他 anchor 与 ground_truth[k] 的 IoU)。否则 matches[i] = match1[i] (备注:这是整个实现的一个非常绕的点,要仔细推敲)。至此 matches 中大于 -1 的元素为满足条件,小于 0 为不满足条件。实际上 matches 小于 0,只可能取 -1, -2,

备注:其中,大于 -1,表示对于任意 machor[i] > -1,存在 groundth truth box 与 anchors[i] 的 IoU 大于 0.7 或 groundtruth box 与 anchors[i] 的 IoU 大于其他 anchor。

生成标签

  1. reg_targets : 对满足条件的 anchors 和 groundtruth_boxlists 进行编码,不满足的设置为 [0, 0, 0, 0]。维度为 [num_valid_anchors, 4 ], 4 依次代表 [y, x, h, w]
    输入:Anchors 与  gt_box 编码
    #anchors 表示为 [ycenter_a, xcenter_a, ha, wa]
    #gt_box 表示为  [ycenter, xcenter, h, w]

    tx = (xcenter - xcenter_a) / wa
    ty = (ycenter - ycenter_a) / ha
    tw = tf.log(w / wa)
    th = tf.log(h / ha)

    输出 [tx, ty, tw, th]
  1. cls_targets : 对满足条件的 groundtruth_boxlists 保留,不满足条件的设置为 [0]。 [num_valid_anchors, 1]
  2. reg_weights : 满足条件 1,不满足条件 0。 [num_anchors]
  3. cls_weights : 如果 matches[i] = -2,cls_weights[i] = 0,其余 cls_weight 置为 1。 [num_anchors]

注:num_anchors <= num_valid_anchors

采样

  1. 按照 BalancedPositiveNegativeSampler 方法,从 cls_targets 中随机采样 256 个样本,正负比例为 0.5,得到数据中采用数据的索引(这里显然是一个优化点,对于不同的数据集,显然不能无脑 1:1 采样,还与正负样本权重有关)。
  2. 将 cls_targets 变为 one-hot 矩阵。两列,第一列表示背景,第二列表示存在物体
  3. 计算分类和位置的 loss,回归用 Smooth L1,分类用 softmax,之后取均值。

注:

  1. 以上 reg_targets, cls_targets 是针对 一张图片而言,实际是批量操作。
  2. 实际总的表示数量为 num_valid_anchors,通过第一次 IoU 过滤和采样,使得计算 loss 的时候,又有一部分不参与计算 loss。这块部分多次看才理解了,因此需要注意。
    比如 
    每列 IoU 最大依次为 [0.6, 0.8, 0.3, 0.7, 0.3, 0.8] 其中阈值为 0.5
    match [3, 2, -1, 4, -1, 8]   

    cls_targets
    [1, 1, 0, 1, 0, 1]

    cls_weights
    [1, 1, 0, 1, 0, 1]

    reg_targets
    [0.1, 0.2, 0.3, 0.4]
    [0.1, 0.2, 0.3, 0.4]
    [0, 0, 0, 0]
    [0.1, 0.2, 0.3, 0.4]
    [0, 0, 0, 0]
    [0.1, 0.2, 0.3, 0.4]
    reg_weights
    [1, 1, 0, 1, 0, 1]

第二阶段

解码

  1. rpn_box_encodings 和 anchors 解码,得到 proposal_boxes
    输入 Anchors 与  box_encoding 编码
    #anchors 表示为 [ycenter_a, xcenter_a, ha, wa]
    #box_encoding 表示为  [ty, tx, th, tw]

    w = tf.exp(tw) * wa
    h = tf.exp(th) * ha
    ycenter = ty * ha + ycenter_a
    xcenter = tx * wa + xcenter_a
    ymin = ycenter - h / 2.
    xmin = xcenter - w / 2.
    ymax = ycenter + h / 2
    xmax = xcenter + w / 2 

    输出 [ymin, xmin, ymax, xmax]

NMS

  1. 对 proposal_boxes 计算 NMS 得到 proposal_boxes,proposal_scores,num_proposals(其中 scores 为rpn_objectness_softmax_without_background,score_threshold 为 0.0, iou_threshold 为 0.7, max_proposals 为 300)

如果当前是训练

标签预处理

  1. 将 groundtruth_boxeslist 每个 box 转为绝对坐标,即横轴乘以 true_image_shape[1], 纵轴乘以 true_image_shape[0]
  2. 将 groundtruth_classes_list 每个 box 第一列前增加一列,为背景列。 维度为 [num_boxes, 1 + num_classes ]
  3. 用 NEAREST_NEIGHBOR 算法 将 groundtruth_masks_list 每个元素 resize 为 true_image_shape 的尺寸,并对齐

第二次过滤与采样

第一阶段生成的 proposal 是第一阶段 groundtruth box 和  anchor 的近似拟合,因此,在第二阶段,再次与 groundtruth box 进行 IoU 计算(经过第一阶段,proposal box 以及很
接近 groundtruth box 啦,所以,第二阶段 IoU 阈值 0.5 就够了)可以认为第一阶段生成的 
proposal 可以认为是扮演了第二阶段 anchor 的角色。可以理解为 proposal box 是优化版的 
anchor。在 Yolo 中 anchor 用 k-mean 方法获取,而在 faster RCNN 中, 用  RPN 网
络对一个粗糙版本的 anchor 进行调优。
  1. 计算 groundtruth_boxeslist 与 proposal_boxes 的 IoU 矩阵 match_quality_matrix(可以理解为[num_boxes, 1] 与 [1, num_anchor] 的矩阵乘,得到 [num_boxes, num_anchor] 的矩阵。其中 row 索引为 groundtruth_boxeslist 元素索引, colum 索引为 anchors 元素索引)
  2. 记录 match_quality_matrix 每列最大值对应的行索引得到 match。此时 match 本身的索引为列索引,存储的值为行索引。因此,通过 match 就能定位到 match_quality_matrix 对应的 IoU 值。
  3. 如果 match[i] 中元素对应 IoU 大于 0.5,match[i] 不变,如果 match[i] 中元素对应 IoU 小于 0.5 为 -1。
  4. 找到 match 中所有正样本和负样本中随机采样 64 (正:负 =1:4) 个,当然正样本也许不够 16 个,那么,有多少就采多少,剩余都为负样本。 proposal_boxes 中选择采样的元素,如果不够就用 0 补足。并设置 proposal_scores,num_proposals

这次 IoU 过滤主要的目的在于采样。

归一化

  1. 对 proposal_boxes 归一化得到 normalized_proposal_boxes(宽除以 image_shape[1], 高除以 image_shape[0])

RoI Pooling

  1. proposal_boxes_normalized 和 rpn_features_to_crop 经过 crop_and_resize 得到 cropped_regions

后半部分

  1. flattened_proposal_feature_maps 经过网络的后半部分得到 box_classifier_features

具体说明见附录

绝对化

将 proposal_boxes_normalized 变为绝对值 absolute_proposal_boxes

后半部分经过两个全连接层得到 refined_box_encodings,class_predictions_with_background,至此,第二阶段预测部分完成

  1. refined_box_encodings: [batch_size, num_boxes, 4]
  2. class_predictions_with_background 维度为 [batch_size, num_classes + 1]
  3. absolute_proposal_boxes

第三阶段

如果是训练

  1. box_classifier_features 经 resize_bilinear 和两个 conv2d 得到 mask_predictions([total_num_proposals, num_classes, mask_height, mask_width])
    1. S = 2 ** (round(log(image_features.channel)*2 + 3*log(num_class) / (2 + 3)))
    2. 需要注意的这里就是 MASK-RCNN 中提到的 RoI Align。在实现上就是一个参数,即设置tf.image.resize_bilinear 的参数 align_corners=True 即可。
    3. Mask RCNN 与 Faster RCNN 在训练阶段的唯一区别就在于是否包含  Mask 预测部分。

如果是验证

解码

  1. refined_box_encodings 与 absolute_proposal_boxes 解码得到 refined_decoded_boxes_batch
  2. mask_predict 经过 sigmoid 得到 mask_predictions_batch

NMS

  1. 对 refined_decoded_boxes_batch 应用 NMS,其中 score 为 class_predictions_batch,score_threshold 为 0.0,iou_threshold 为 0.6, max_detections_per_class 为 100,max_total_detections 为 300 得到 nmsed_boxes,nmsed_scores,nmsed_classes,nmsed_masks, num_detections

RoIPooling

  1. nmsed_boxes 与 rpn_features_to_crop 经过 crop_and_resize,再经过 max_pool 得到 flattened_detected_feature_maps

后半部分

  1. flattened_detected_feature_maps 经过基础网络后半部分得到 curr_box_classifier_features

  2. curr_box_classifier_features 经过 reduce_mean, flatten, resize_bilinear, conv2d (3x3) 的 mask_predictions

第三次 IoU 过滤

  1. 计算 groundtruth_boxeslist 与 proposal_boxes 的 IoU 矩阵 match_quality_matrix(可以理解为[num_boxes, 1] 与 [1, num_anchor] 的矩阵乘,得到 [num_boxes, num_anchor] 的矩阵。其中 row 索引为 groundtruth_boxeslist 元素索引, colum 索引为 anchors 元素索引)
  2. 记录 match_quality_matrix 每列最大值对应的行索引得到 match。此时 match 本身的索引为列索引,存储的值为行索引。因此,通过 match 就能定位到 match_quality_matrix 对应的 IoU 值。
  3. 如果 match[i] 中元素对应 IoU 大于 0.5,match[i] 不变,如果 match[i] 中元素对应 IoU 小于 0.5 为 -1。
  4. 根据 absolute_proposal_boxes, groundtruth_boxlist,match 创建 reg_target, reg_weight, cls_target, cls_weight

这次 IoU 的过滤就是为了生成标签。

分类过滤1

refined_box_encodings 增加背景分类得到 refined_box_encodings_with_background,并用 cls_target 进行过滤得到 refined_box_encodings_masked_by_class_targets

分类过滤2

prediction_masks 增加背景分类得到 prediction_masks_with_background,并用 cls_target 进行过滤得到 prediction_masks_masked_by_class_targets

第四次 IoU 过滤

  1. 计算 groundtruth_boxeslist 与 proposal_boxes 的 IoU 矩阵 match_quality_matrix(可以理解为[num_boxes, 1] 与 [1, num_anchor] 的矩阵乘,得到 [num_boxes, num_anchor] 的矩阵。其中 row 索引为 groundtruth_boxeslist 元素索引, colum 索引为 anchors 元素索引)
  2. 记录 match_quality_matrix 每列最大值对应的行索引得到 match。此时 match 本身的索引为列索引,存储的值为行索引。因此,通过 match 就能定位到 match_quality_matrix 对应的 IoU 值。
  3. 如果 match[i] 中元素对应 IoU 大于 0.5,match[i] 不变,如果 match[i] 中元素对应 IoU 小于 0.5 为 -1。
  4. 根据 absolute_proposal_boxes, groundtruth_boxlist,match 创建 reg_target, reg_weight, cls_target, cls_weight

这次 IoU 的过滤就是为了生成标签。

附录

图片预处理

原图片:[orig_height, orig_width, num_channels]

large_scale_factor = min_dimension / float(min(orig_height, orig_width))
large_size = [int(round(orig_height * large_scale_factor)), int(round(orig_width * large_scale_factor)), num_channels]
small_scale_factor = max_dimension / float(max(orig_height, orig_width))
small_size = [int(round(orig_height * small_scale_factor)), int(round(orig_width * small_scale_factor)), num_channels]

如果 max(large_size) > max_dimension,新图片的 shape 为 [small_size]
否则,new_shape  为 [large_size]

例 1:输入图片为 [600, 800],min_dimension 为 600,max_dimension 为 1200。

此时

large_scale_factor = 1.0 large_size 为 [600,800]

small_scale_factor 为 1.5 small_size 为 [900, 1200]

因此,new_shape 为 [600, 800]

例2:

输入图片为 [300, 800],min_dimension 为 600,max_dimension 为 1200。

此时

large_scale_factor = 2.0 large_size 为 [600,1600]

small_scale_factor 为 1.5 small_size 为 [450, 1200]

因此,new_shape 为 [450, 1200]

总结:

  1. width, height 同比例放缩
  2. 最后图片尺寸,较小值不低于 min_dimension,较大值不高于 max_dimension

前半部分与后半部分

由于 Faster RCNN 是典型的两阶段网络,因此,将整个网络分为前半部分和后半部分

(支持 inception_v2, resnet_v1, nasnet, inception_resnet_v2)

对于 InceptionV2,前部分为 Mixed4e 之前, 后半部分为 Mixed4e 之后部分

对于 InceptionResnetV2,前部分为 PreAuxLogits 之前, 后半部分为 PreAuxLogits 之后部分

对于 MobilenetV1,前部分为 Conv2d_11_pointwise 之前, 后半部分为 Conv2d_11_pointwise 之后部分

对于 resnet_v1_50、resnet_v1_101、resnet_v1_152,前部分为 block3 之前, 后半部分为 block3 之后部分

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值