目標檢測 - 二階段檢測 - Faster-RCNN

部分內容參考:
1、https://blog.csdn.net/liuxiaoheng1992/article/details/81843363
2、mmdetection源碼(下面簡稱爲mmdet)

論文解讀

模型結構

論文中的圖
在這裏插入圖片描述
一個更詳細的圖
在這裏插入圖片描述

Faster-RCNN有兩部分組成:RPN和Fast-RCNN。兩者共享同一個backbone。具體來說,Faster-RCNN由以下幾部分組成:
1、backbone(VGG,ResNet等)
2、neck(FPN,原版的faster沒有,FPN出來之後後人才加上的)
3、rpn_head(RPNHead)
4、bbox_roi_extractor(SingleRoIExtractor > RoIAlign,RoIPool)
5、bbox_head(SharedFCBBoxHead)
上面是參考mmdet的config來分類的。backbonhe和neck無需多言,很常見的操作。下面講以下剩下的三個部分。
rpn_head
在這裏插入圖片描述上圖是論文中的圖,conv feature map是backbone出來的,或者是neck出來的特徵。在mmdet代碼中,滑動窗用一個3x3的conv來實現,獨立的分類和迴歸層分別用兩個1x1的conv來實現。代碼如下:

@HEADS.register_module
class RPNHead(AnchorHead):

    def __init__(self, in_channels, **kwargs):
        super(RPNHead, self).__init__(2, in_channels, **kwargs)

    def _init_layers(self):
        self.rpn_conv = nn.Conv2d(
            self.in_channels, self.feat_channels, 3, padding=1)  # in:256, out:256
        self.rpn_cls = nn.Conv2d(self.feat_channels,
                                 self.num_anchors * self.cls_out_channels, 1)
                                 # self.cls_out_channels = 2 前景和背景
        self.rpn_reg = nn.Conv2d(self.feat_channels, self.num_anchors * 4, 1)

    def init_weights(self):
        normal_init(self.rpn_conv, std=0.01)
        normal_init(self.rpn_cls, std=0.01)
        normal_init(self.rpn_reg, std=0.01)

    # 對單個feature map做操作,forward在AnchorHead中定義,將forward_single應用到feats上
    def forward_single(self, x):
        x = self.rpn_conv(x)
        x = F.relu(x, inplace=True)
        rpn_cls_score = self.rpn_cls(x)
        rpn_bbox_pred = self.rpn_reg(x)
        return rpn_cls_score, rpn_bbox_pred

rpn_head輸出proposal的得分+框的位置信息。

bbox_roi_extractor
從名字就可以知道,bbox_roi_extractor是對bbox_roi進行特徵提取的組件,faster-rcnn論文中用的是roi_pooling,mask-rcnn中用的是roi_align,R-FCN中的position-sensitive RoI pooling layer等。

訓練

論文中的訓練方式

論文中,給出了三種訓練方式
1、交替訓練
先訓RPN,然後將RPN得到的proposal拿去訓Fast-RCNN,接着Fast-RCNN微調後的網絡去初始化RPN,然後訓RPN,這個過程交替進行。(這裏有一個疑問,是在每一個batch進行交替,還是訓好RPN,再訓Fast-RCNN這樣進行,如果是每一個batch進行交替,那麼可以保證proposal在batch內是不變的,如果是另一種,那麼需要保證訓好RPN之後,要把RPN凍住,才能保證proposal的穩定)
2、近似聯合訓練
RPN和Fast-RCNN當成一個整體,前向過程中,RPN生成的proposal當成是預先生成好去訓練Fast-RCNN,反向傳播過程,對於共享的卷積層,計算梯度的是RPN loss和Fast RCNN的losss相加,其他獨立的部分就是各自的Loss。"approximate"體現在反向傳播階段RPN產生的置信誤差能夠獲得梯度以更新參數,但是region proposals的座標預測則直接把梯度捨棄了,也就是說box誤差不參與loss的計算(和交替訓練相比,這種方法的好處在於縮短訓練時間)。
3、非近似聯合訓練
和近似聯合訓練相比,非近似聯合訓練,把RPN生成的proposal的loss也考慮進行梯度迴歸,通過“RoI warping” 層進行梯度反傳???
四步訓練法
第一步:imagenet初始化,訓RPN,得到proposal
第二步:imagenet初始化,用RPN的proposal訓Fast-RCNN
第三步:Fast-RCNN初始化共有卷積,訓RPN(fix共有卷積)
第四步:fix共有卷積和RPN,訓Fast-RCNN

mmdetection中的訓練
RPN生成proposals->RCNN樣本匹配(FPN)
# 超參
# 1. nms_pre: 進行nms之前的數目, 2. nms_post: nms之後的輸出個數, 3. nms_thr: nms閾值
# 4. max_num: 單張圖片最終輸出proposals最多的個數, 5. nms_across_levels: 是否在跨levels進行nms操作

mlvl_proposals = []
for stride in strides:
    # 1. 在多個strides下對模型預測值進行解碼,獲取預測框
    # 2. 做一些過濾的操作
    do clip
    remove small
    nms # nms_pre和nms_post通常等於2000
    # 得到每個stride的proposals
    # 3. mlvl_proposals.append(proposals)
# 將各個strides的proposals給concat起來
if nms_across_levels:
    proposals, _ = nms(proposals, cfg.nms_thr)
    proposals = proposals[:cfg.max_num, :]
else:
    scores = proposals[:, 4]
    num = min(cfg.max_num, proposals.shape[0])
    _, topk_inds = scores.topk(num)
    proposals = proposals[topk_inds, :]
return proposals
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章