Detectron2學習五:build_backbone_model配置及實現流程
- 2019 年 12 月 16 日
- 筆記
本文主要講build_backbone_model的配置及創建流程,目的則是希望大家看完本章節後能夠對detectron2中模型創建及使用有清晰的認識,便於後續自定義網路層。若有需要補充希望大家在評論中提出。
build_model調用位置如下:

調用順序:—–>表示調用該文件夾下相應的函數,即:函數調用路徑。
class DefaultTrainer(SimpleTrainer): model = self.build_model(cfg) ------->##/detectron2/engine/defaults.py def build_model(cls,cfg): model = build_model(cfg) ---------->##detectron2/modeling/meta_arch/build.py def build_model(cfg): meta_arch = cfg.MODEL.META_ARCHITECTURE return META_ARCH_REGISTRY.get(meta_arch)(cfg)
接下來則是基於配置文件夾中相應的模型配置參數進行相應模組的調用。所有的網路配置基本都是可以通過配置文件進行完成,個人認為,這是學習Detectron2框架過程中最需要學習和掌握的一個重要的環節。
一、基本參數配置
其他默認參數配置可參見/detectron2/config/defaults.py文件
本章節以/configs/PascalVOC-Detection/faster_rcnn_R_50_FPN.yaml為例進行闡述。
####faster_rcnn_R_50_FPN.yaml _BASE_: "../Base-RCNN-FPN.yaml" MODEL: WEIGHTS: "detectron2://ImageNetPretrained/MSRA/R-50.pkl" MASK_ON: False RESNETS: DEPTH: 50 ROI_HEADS: NUM_CLASSES: 20 ...
###../Base-RCNN-FPN.yaml MODEL: META_ARCHITECTURE: "GeneralizedRCNN" BACKBONE: NAME: "build_resnet_fpn_backbone" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"] ANCHOR_GENERATOR: SIZES: [[32], [64], [128], [256], [512]] # One size for each in feature map ASPECT_RATIOS: [[0.5, 1.0, 2.0]] # Three aspect ratios (same for all in feature maps) ...
基於配置資訊可知該網路的註冊名稱為:GeneralizedRCNN (在搭建網路之前,首先要註冊一個META_ARCH_REGISTRY,方便在配置文件中使用,如果要進行檢測任務的話,可在GeneralizedRCNN機制下進行修改)
(利用全局搜索,定位到該類所在的文件為/detectron2/modeling/meta_arch/rcnn.py 。該文件中主要包含兩類,GeneralizedRCNN和ProposalNetwork。
__all__ = ["GeneralizedRCNN", "ProposalNetwork"] @META_ARCH_REGISTRY.register() class GeneralizedRCNN(nn.Module): """ Generalized R-CNN. Any models that contains the following three components: 1. Per-image feature extraction (aka backbone) 影像特徵提取主要是影像數據、通道、均值、方差的處理。 2. Region proposal generation ##候選區域的生成 3. Per-region feature extraction and prediction ##特徵提取及預測 """ @META_ARCH_REGISTRY.register() class ProposalNetwork(nn.Module):
)
從該配置資訊中能獲取到什麼資訊呢?配置的網路結構是怎樣的呢?
- 基網路為resnet50的結構,對res2,res3,res4,res5四層進行FPN操作。
而其中階段名稱'res2','res3'從哪獲取的呢?與之關聯設置的參數又是怎樣的呢?
在文件/detectron2/modeling/backbone/resnet.py中設置默認的每個階段的配置參數和輸出名稱如下:
##depth為配置文件中配置的MODEL.RESNETS.DEPTH ##當前默認支援res50,res101,res152三種網路結構,分為4個階段,,每個階段的配置blocks的個數如下 num_blocks_per_stage = {50: [3, 4, 6, 3], 101: [3, 4, 23, 3], 152: [3, 8, 36, 3]}[depth] ##4個階段的輸出名稱配置如下:注意的是該名稱與外面網路配置參數的名稱要保持一致,否則找不到 ##out_features為配置文件中的MODEL.RESNETS.OUT_FEATURES stages = [] out_stage_idx = [{"res2": 2, "res3": 3, "res4": 4, "res5": 5}[f] for f in out_features] #########題外延伸############# resnet的配置不一定要配置為4個階段,可根據需求進行適當修改。任意舉例如: num_blocks_per_stage={50,[2,3,4,3,4]} ##5個階段,意味著可以有5個特徵層的輸出 out_stage_idx=[{"res2": 2, "res3": 3, "res4": 4, "res5": 5,「res6」:6}[f] for f in out_features]

- anchor計算:每個特徵層產生anchor的aspect_ratio都是一樣的[0.5,1.0,2.0],該情況可根據自己需要進行配置參數。
MODEL: ANCHOR_GENERATOR: SIZES: [[32], [64], [128], [256], [512]] # One size for each in feature map ASPECT_RATIOS: [[0.5, 1.0, 2.0],[0.5, 1.0, 2.0,0.33,3.0],[0.5, 1.0, 2.0,0.33,3.0],[0.5, 1.0, 2.0],[0.5, 1.0, 2.0]] ##此處的aspect_ratio為實際運算時需要的比例值。與caffe裡面實現的不同。 ##caffe裡面則是外部設置aspect_ratio=2,3,flip=True,實際內部計算時的值為:1,1,2,3,1/2,1/3.具體計算可自行百度 ##個人認為caffe的這種實現方式比較方便。可修改相應源程式碼實現該操作。
二、GeneralizedRCNN中網路結構創建順序和調用介面。

三、 build_backbone參數設置及實現流程
##參數設置 MODEL: BACKBONE: NAME: "build_resnet_fpn_backbone" RESNETS: OUT_FEATURES: ["res2", "res3", "res4", "res5"] FPN: IN_FEATURES: ["res2", "res3", "res4", "res5"]
(相同道理,全局搜索build_resnet_fpn_backbone,如果有能運行起來demo的話,那就單步跟進最方便)
改環節主要包含兩個部分:
- 創建基網路模型build_resnet_backbone,基於配置參數MODEL.RESNETS建立網路結構,設置輸出層、凍結層、可變性卷積層、層的stride、kernel_size、dilation、in_channles、out_channels等的操作。具體實現見程式碼,實現起來比較清晰。
主要的網路結果如下:
resnet基本網路結構–BottleneckBlock如下:

帶有deformable-conv的網路結構–DeformBottleneckBlock如下:(deformable conv的具體實現後續有時間在深入了解)

當前該框架支援deformV1和deformV2兩個版本,相應參數設置如下:
# Apply Deformable Convolution in stages # Specify if apply deform_conv on Res2, Res3, Res4, Res5 _C.MODEL.RESNETS.DEFORM_ON_PER_STAGE = [False, False, False, False] # Use True to use modulated deform_conv (DeformableV2, https://arxiv.org/abs/1811.11168); # Use False for DeformableV1. _C.MODEL.RESNETS.DEFORM_MODULATED = False # Number of groups in deformable conv. _C.MODEL.RESNETS.DEFORM_NUM_GROUPS = 1
- FPN操作
現在先來回顧下FPN論文中的主要結構如下:
(a)影像金字塔,即將影像做成不同的scale,然後不同scale的影像生成對應的不同scale的特徵。這種方法的缺點在於增加了時間成本。有些演算法會在測試時候採用影像金字塔。
(b)像SPP net,Fast RCNN,Faster RCNN是採用這種方式,即僅採用網路最後一層的特徵。
(c)像SSD(Single Shot Detector)採用這種多尺度特徵融合的方式,沒有上取樣過程,即從網路不同層抽取不同尺度的特徵做預測,這種方式不會增加額外的計算量。作者認為SSD演算法中沒有用到足夠低層的特徵(在SSD中,最低層的特徵是VGG網路的conv4_3),而在作者看來足夠低層的特徵對於檢測小物體是很有幫助的。
(d)FPN中的網路結構,頂層特徵通過上取樣和低層特徵做融合,而且每層都是獨立預測的。

在FPN中特徵融合的方式,先對當前特徵的維度進行操作,然後與上取樣得到的特徵進行融合(橫向連接),對融合後的特徵再接一個3*3的卷積網路,目的則是消除上取樣的混疊效應(aliasing effect).

先看下該函數的官方定義說明:
class FPN(Backbone): """ This module implements Feature Pyramid Network. It creates pyramid features built on top of some input feature maps. """ 返回的結果dict[str->Tensor] 與輸入特徵層in_features名稱對應,輸出的名稱:['p2','p3','p4','p5','p6'] 其中最底層的特徵輸出'p6',該層是通過對'p5'層進行下取樣操作(max_pool(stride=2,kernel=1,padding=0))得到的。 def __init__( self, bottom_up, in_features, out_channels, norm="", top_block=None, fuse_type="sum" ): """ Args: bottom_up (Backbone): 輸入的基網路, in_features (list[str]): 進行特徵融合的層['res2','res3','res4','res5']] out_channels (int): number of channels in the output feature maps. norm (str): the normalization to use. top_block (nn.Module or None): 最後輸出的層 fuse_type (str): 特徵融合時的計算方式,'sum','avg' #####其中,'avg':上取樣後的feature map與當前融合的feature map 進行element_wise求平均操作((value1+value2/2)) 'sum':上取樣後的feature map與當前融合的feature map 進行element_wise求和操作 """
程式碼中上取樣操作採用插值操作,默認使用最近鄰,除此之外,還支援其他很多類型,可自由選擇。
top_down_features = F.interpolate(prev_features, scale_factor=2, mode="nearest") ###### def interpolate(input, size=None, scale_factor=None, mode='nearest', align_corners=None): The modes available for resizing are: `nearest`, `linear` (3D-only), `bilinear` (4D-only), `trilinear` (5D-only), `area` Args: input (Tensor): the input tensor,4D(N*C*H*W),5D(N*C*D*H*W) size (int or Tuple[int] or Tuple[int, int] or Tuple[int, int, int]): output spatial size. scale_factor (float or Tuple[float]): multiplier for spatial size. Has to match input size if it is a tuple. mode (string): algorithm used for upsampling: 'nearest' | 'linear' | 'bilinear' | 'trilinear' | 'area'. Default: 'nearest' align_corners (bool, optional): if True, the corner pixels of the input and output tensors are aligned, and thus preserving the values at those pixels. This only has effect when :attr:`mode` is `linear`, `bilinear`, or `trilinear`. Default: False .. warning:: With ``align_corners = True``, the linearly interpolating modes (`linear`, `bilinear`, and `trilinear`) don't proportionally align the output and input pixels, and thus the output values can depend on the input size. This was the default behavior for these modes up to version 0.3.1. Since then, the default behavior is ``align_corners = False``. See :class:`~torch.nn.Upsample` for concrete examples on how this affects the outputs. .. include:: cuda_deterministic_backward.rst """
理解通FPN實現流程,再看程式碼就相對比較簡單了,此處就不上傳程式碼,想看請直接移步文件/detectron2/modeling/backbone/fpn.py文件中