天天看點

rpn産生proposals_一文讀懂RPN和ROI Align

rpn和roi align是two-stage detector中比較關鍵的兩個操作,這兩個操作将two-stage detector中的兩個stage連接配接起來,變成end-to-end(端到端)的網絡,同時也給整個檢測方法的性能帶來提升。rpn為roi align提供高品質的候選框,即proposal,關系如圖1所示:

rpn産生proposals_一文讀懂RPN和ROI Align

下面詳細說明一下各個過程,并且配合了代碼的說明,其中代碼來自facebook的detectron2,其中相關參數的配置檔案可以參考detectron2/config/defaults.py

一、RPN

rpn全稱是region proposal network,作用是為第二階段提供高品質的目标候選框,如圖1所示,包括了anchor generator、anchor target generator、rpn loss、proposal generator幾個關鍵的步驟,下面分别詳細說明。

1,anchor generator

Anchor是根據scale和ratio預先設定的,這些參數在全特征圖中共享,如下圖所示。左邊表示使用stride=16的feature map作為目标檢測的特征圖,對于輸入大小為800*600的圖像,該特征圖大小為50*38。其中anchor的scale包括為(8,16,32),ratio參數包括(0.5,1,2),故産生9種anchor;右圖表示對于50*38大小的特征圖,共産生17100個anchor,平鋪到原圖時,有一部分框會超出圖像邊界。

rpn産生proposals_一文讀懂RPN和ROI Align

步驟及代碼實作:

detectron2/modeling/anchor_generator.py:

grid_anchors(self, grid_sizes)

1)根據scale和ratio産生,預先生成n種anchor,這n種anchor所在坐标系為以anchor中心為原點的圖像坐标系。

generate_cell_anchors(self, sizes=(32, 64, 128, 256, 512), aspect_ratios=(0.5, 1, 2))

2)在特征圖中的每個坐标點處,計算anchor中心與該坐标的偏移

_create_grid_offsets(size, stride, offset, device)

3)通過anchor與生成的相對偏移,計算每張特征圖中的所有anchor

anchors.append((shifts.view(-1, 1, 4) + base_anchors.view(1, -1, 4)).reshape(-1, 4))

2,anchor target generator

有了anchor,這些anchor是均勻地平鋪在特征圖的每個像素處,但是我們不知道哪些anchor是包括真實目标的,是以anchor target layer就完成區分哪些anchor是為正樣本(包括真實目标),哪些anchor為負樣本(隻包括背景)的任務,具體方法是計算anchor與ground truth的IoU,評判标準有3條:對于每一個ground truth,選取一個與之有最大IoU的anchor作為正樣

對于每一個anchor,與ground truth的IoU大于某一個門檻值t1的anchor,作為正樣本。

并不是除了以上兩條的anchor為負樣本,而是與ground truth的IoU小于某一個門檻值t2的anchor為負樣本,[t2,t1]之間的樣本為“don’t care”樣本,既不是正樣本也不是負樣本,不參與模型優化,即:不計算rpn loss

第一條保證了每個ground truth都有一個anchor與之相對應,第二條保證了在衆多的anchor中,可以篩選出一定資料量的anchor作為正樣本,保證正負樣本的平衡。

步驟及代碼實作:

detectron2/modeling/proposal_generator/rpn_outputs.py

detectron2/modeling/matcher.py

_get_ground_truth(self)

1)生成anchor與ground truth的IoU矩陣

match_quality_matrix=retry_if_cuda_oom(pairwise_iou)(gt_boxes_i,anchors_i)

2)根據評判标準,生成2組向量:anchor與ground truth比對ID,用于bbox(bounding box回歸);anchor的label:正樣本、負樣本、don’t care。

matched_idxs, gt_objectness_logits_i =retry_if_cuda_oom(self.anchor_matcher)(match_quality_matrix )

3)是否删除超過圖像大小的anchor

if self.boundary_threshold>= 0:

# Discard anchors that go outof the boundaries of the image

# NOTE: This is legacyfunctionality that is turned off by default in Detectron2

anchors_inside_image =anchors_i.inside_box(image_size_i, self.boundary_threshold)

gt_objectness_logits_i[~anchors_inside_image] = -1

3,RPN Loss

rpn有兩個任務:從衆多anchor中,判斷哪些anchor是正樣本,哪些是負樣本,即分類任務;對于正樣本的anchor,回歸獲得真正的目标,即回歸任務。是以loss由兩部分組成,即:

rpn産生proposals_一文讀懂RPN和ROI Align

其中分類任務,使用交叉熵loss:

rpn産生proposals_一文讀懂RPN和ROI Align

回歸任務使用smooth_l1 loss:

rpn産生proposals_一文讀懂RPN和ROI Align

代碼實作:

detectron2/modeling/proposal_generator/rpn_outputs.py

detectron2/modeling/box_regression.py

losses(self)

1)分類loss

objectness_loss =F.binary_cross_entropy_with_logits(

pred_objectness_logits[valid_masks],

gt_objectness_logits[valid_masks].to(torch.float32),

reduction="sum",

)

2)回歸loss

localization_loss =smooth_l1_loss(

pred_anchor_deltas[pos_masks],gt_anchor_deltas[pos_masks], smooth_l1_beta, reduction="sum"

)

4,proposal generator

獲得候選框的目的是為了給第二階段提供優質的roi框,首先通過rpn_cls_prob篩選出topk_rpn_pre_nms個框,然後再經過nms得到topk_rpn_post_nms個框,最終輸出給roi align。主要流程如下圖。

rpn産生proposals_一文讀懂RPN和ROI Align

主要步驟和相應代碼實作如下:

detectron2/modeling/proposal_generator/rpn_outputs.py

find_top_rpn_proposals(

proposals,

pred_objectness_logits,

images,

nms_thresh,

pre_nms_topk,

post_nms_topk,

min_box_side_len,

training,

)

1)擷取top_k_pre_nms個候選框

logits_i, idx =logits_i.sort(descending=True, dim=1)

topk_scores_i = logits_i[batch_idx,:num_proposals_i]

topk_idx = idx[batch_idx,:num_proposals_i]

# each is N x topk

topk_proposals_i =proposals_i[batch_idx[:, None], topk_idx] # N x topk x 4

2)對候選框做一些後處理,如:截斷超出圖像範圍的框;删除非常小的框。

boxes.clip(image_size)

# filter empty boxes

keep =boxes.nonempty(threshold=min_box_side_len)

3)nms篩選得到更可信的top_k_post_nms個候選框作為roi

keep = batched_nms(boxes.tensor, scores_per_img, lvl, nms_thresh)

keep = keep[:post_nms_topk]

二、ROI Align

這個階段是在rpn提供的proposal的基礎上,篩選出第二階段的訓練樣本,并提取相應的特征,用于組建第二階段的訓練網絡,主要包括兩個部分:proposal target generator、feature crop and pooling

1,proposal target generator

這個操作的主要目的是: 在rpn産生的proposal的基礎上,選擇一定量(min_batch: 一般每張圖選擇256個proposal,或者512個proposal)的roi,作為訓練第二階段的樣本,并且要設定該min_batch中正負樣本的比例,如正:負=1:3。

主要步驟與代碼實作如下:

detectron2/modeling/roi_heads/roi_heads.py

detectron2/modeling/sampling.py

label_and_sample_proposals(

self, proposals: List[Instances], targets: List[Instances]

) -> List[Instances]:

1)判斷proposal中,哪些是正樣本,哪些是負樣本

match_quality_matrix =pairwise_iou(

targets_per_image.gt_boxes,proposals_per_image.proposal_boxes

)

matched_idxs, matched_labels =self.proposal_matcher(match_quality_matrix)

2)篩選min_batch的樣本,并給正樣本賦予正确的目标類别

sampled_idxs, gt_classes =self._sample_proposals(

matched_idxs, matched_labels,targets_per_image.gt_classes

)

# Set target attributes of thesampled proposals:

proposals_per_image =proposals_per_image[sampled_idxs]

proposals_per_image.gt_classes =gt_classes

gt_boxes = Boxes(

targets_per_image.gt_boxes.tensor.new_zeros((len(sampled_idxs), 4))

)

proposals_per_image.gt_boxes =gt_boxes

2,feature crop and pooling

得到roi之後,根據roi大小,需要選擇合适的特征層crop并pooling得到固定大小的feature map,這個過程稱為roi align。原始的roi pooling也可以完成這個操作,但是由于計算過程使用取整操作,造成特征粗糙,對小目标檢測效果不好,取整操作主要展現在以下兩步:将roi邊界量化為整數點坐标值,然後再選擇合适feature map進行crop。

将crop得到的區域平均分割成 k x k 個單元(bin),在擷取每個單元的左右邊界時取整

Roi align的步驟及相應代碼如下,其中所有操作均為浮點數操作:

detectron2/modeling/roi_heads/roi_heads.py

detectron2/modeling/poolers.py

detectron2/layers/roi_align.py

1)計算rpn得到的ro­i­([x1, y1, x2, y2])在相應的特征層box,即:[x1, y1, x2, y2]/stride。stride為特征圖相對輸入圖像縮小的倍數。

pooler_fmt_boxes= convert_boxes_to_pooler_format(box_lists)

2)特征crop并pooling得到目标大小輸出的特征圖。

output[inds] =pooler(x_level, pooler_fmt_boxes_level)

rpn産生proposals_一文讀懂RPN和ROI Align