tensorflow+faster rcnn程式碼理解(四)boundingbox迴歸
1.為什麼要做Bounding-box regression?
如圖所示,綠色的框為飛機的Ground Truth,紅色的框是提取的Region Proposal。那麼即便紅色的框被分類器識別為飛機,但是由於紅色的框定位不準(IoU<0.5),那麼這張圖相當於沒有正確的檢測出飛機。如果我們能對紅色的框進行微調,使得經過微調後的視窗跟Ground Truth更接近,這樣豈不是定位會更準確。所以,Bounding-box regression 就是用來微調這個視窗的。
2. 迴歸/微調的物件是什麼?
3. Bounding-box regression(邊框迴歸)
注意:只有當Proposal和Ground Truth比較接近時(線性問題),我們才能將其作為訓練樣本訓練我們的線性迴歸模型,否則會導致訓練的迴歸模型不work(當Proposal跟GT離得較遠,就是複雜的非線性問題了,此時用線性迴歸建模顯然不合理)。這個也是G-CNN: an Iterative Grid Based Object Detector多次迭代實現目標準確定位的關鍵。
4. tensorflow faster rcnn程式碼中的實現
faster rcnn中進行邊框迴歸存在於兩個部分,第一個是在訓練RPN的過程中對anchor進行邊框迴歸,另一個是在訓練fast rcnn過程中對proposal進行邊框迴歸。
4.1 RPN訓練中的邊框迴歸
在RPN的訓練中,一方面會輸出anchor對於gt的預測的偏移量rpn_bbox_pred,同時anchor_target_layer會計算anchor與gt的實際的偏移量rpn_bbox_targets,計算的公式如下:
程式碼實現如下(該函式中anchor是經過篩選後存在於圖片大小邊界內的,對於那些篩選掉的anchor,其四個偏移引數預設全為0。)
def bbox_transform(ex_rois, gt_rois): #計算anchor的長寬以及中心 ex_widths = ex_rois[:, 2] - ex_rois[:, 0] + 1.0 ex_heights = ex_rois[:, 3] - ex_rois[:, 1] + 1.0 ex_ctr_x = ex_rois[:, 0] + 0.5 * ex_widths ex_ctr_y = ex_rois[:, 1] + 0.5 * ex_heights #計算gt的長寬以及中心 gt_widths = gt_rois[:, 2] - gt_rois[:, 0] + 1.0 gt_heights = gt_rois[:, 3] - gt_rois[:, 1] + 1.0 gt_ctr_x = gt_rois[:, 0] + 0.5 * gt_widths gt_ctr_y = gt_rois[:, 1] + 0.5 * gt_heights #anchor與gt的實際偏移量 targets_dx = (gt_ctr_x - ex_ctr_x) / ex_widths targets_dy = (gt_ctr_y - ex_ctr_y) / ex_heights targets_dw = np.log(gt_widths / ex_widths) targets_dh = np.log(gt_heights / ex_heights) targets = np.vstack( (targets_dx, targets_dy, targets_dw, targets_dh)).transpose() return targets
利用rpn_bbox_pred、rpn_bbox_targets、rpn_inside_weights和rpn_outside_weights就可以計算RPN bbox loss。
見部落格tensorflow+faster rcnn程式碼理解(三):損失函式構建
4.2 fast rcnn訓練中的邊框迴歸
在訓練fast rcnn之前要從proposal_layer從約20000個anchor中選擇出12000個proposal作為rois,從anchor->proposal的過程需要對anchor進行修正,修正的公式就是:
程式碼實現為如下,其中delas就是RPN網路輸出的預測偏移量rpn_bbox_pred.
def bbox_transform_inv(boxes, deltas):
if boxes.shape[0] == 0:
return np.zeros((0, deltas.shape[1]), dtype=deltas.dtype)
boxes = boxes.astype(deltas.dtype, copy=False)
widths = boxes[:, 2] - boxes[:, 0] + 1.0
heights = boxes[:, 3] - boxes[:, 1] + 1.0
ctr_x = boxes[:, 0] + 0.5 * widths #anchor的中心
ctr_y = boxes[:, 1] + 0.5 * heights
dx = deltas[:, 0::4]
dy = deltas[:, 1::4]
dw = deltas[:, 2::4]
dh = deltas[:, 3::4]
#修正後的中心點座標(x,y)以及w、h
pred_ctr_x = dx * widths[:, np.newaxis] + ctr_x[:, np.newaxis]
pred_ctr_y = dy * heights[:, np.newaxis] + ctr_y[:, np.newaxis]
pred_w = np.exp(dw) * widths[:, np.newaxis]
pred_h = np.exp(dh) * heights[:, np.newaxis]
pred_boxes = np.zeros(deltas.shape, dtype=deltas.dtype)
# x1
pred_boxes[:, 0::4] = pred_ctr_x - 0.5 * pred_w
# y1
pred_boxes[:, 1::4] = pred_ctr_y - 0.5 * pred_h
# x2
pred_boxes[:, 2::4] = pred_ctr_x + 0.5 * pred_w
# y2
pred_boxes[:, 3::4] = pred_ctr_y + 0.5 * pred_h
return pred_boxes
修正完畢後,在proposal_target_layer,會選擇出來的128個rois,此時就要計算這些rois與gt實際的偏移量bbox_targets,會呼叫bbox_transform函式,見4.1:
bbox_target_data = _compute_targets(
rois[:, 1:5], gt_boxes[gt_assignment[keep_inds], :4], labels)
而這些rois經過fast rcnn部分的訓練後會輸出預測的偏移量bbox_pred,因此利用bbox_targets,bbox_pred bbox_inside_weights,bbox_outside_weights就可以計算fastrcnn部分的bbox loss。