實戰 | 源碼入門之Faster RCNN

前言

學習深度學習和計算機視覺,特別是目標檢測方向的學習者,必定據說過Faster Rcnn;在目標檢測領域,Faster Rcnn表現出了極強的生命力,被大量的學習者學習,研究和工程應用。網上有不少版本的Faster RCNN的源碼,可是不少版本代碼太過於龐大,對新入門的學習者學習起來很不友好,在網上苦苦尋找了一番後終於找到了一個適合源碼學習的Faster Rcnn的pytorch版本代碼。html

根據該版本的做者講該代碼除去註釋只有兩千行左右,而且通過小編的一番學習以後,發現該版本的代碼真的是很是的精簡幹練,讀起來「朗朗上口」,而且深入的感受到做者代碼功底之深厚。在此先附上源碼的地址(https://github.com/chenyuntc/simple-faster-rcnn-pytorch) ,並對源碼做者(陳雲)表示由衷的感謝和深深地敬意。python

本文章主要的目的是對該版本代碼的主要框架進行梳理,但願可以對一些想學習源碼的讀者有必定的幫助。git

本文做者:白俊傑github

代碼的主要文件

-data文件中主要是文件的與dataset相關的文件面試

-misc中有下載caffe版本預訓練模型的文件,能夠不看算法

-model文件中主要是與構建Faster Rcnn網絡模型有關的文件markdown

-utils中主要是一些輔助可視化和驗證的文件網絡

-train.py是整個程序的運行文件,下面有一部分會作介紹app

-trainer.py文件主要是用於訓練,模型的損失函數的計算都在這個文件中框架

train

先來看一下train.py裏的主要內容:

def train(train(**kwargs)):    #訓練網絡的主要內容(位於train.py文件中)
  opt._parse(kwargs)
  dataset = Dataset(opt)      #讀取用於訓練的圖片及進行相關的預處理(在下文的dataset部分作詳細介紹)
  dataloader = data_.DataLoader(dataset, \
                                batch_size=1, \
                                shuffle=True, \
                                # pin_memory=True,
                                num_workers=opt.num_workers)
  testset = TestDataset(opt)  #讀取用於測試的圖片及進行相關的預處理
  test_dataloader = data_.DataLoader(testset,
                                     batch_size=1,
                                     num_workers=opt.test_num_workers,
                                     shuffle=False, \
                                     pin_memory=True
                                     )
  faster_rcnn = FasterRCNNVGG16()    #網絡結構,包含主要Extractor,RPN和RoIHead三部分結構。
  trainer = FasterRCNNTrainer(faster_rcnn).cuda()  #主要包含模型的訓練過程的

  for epoch in range(opt.epoch):#開始迭代訓練
        trainer.reset_meters()
        for ii, (img, bbox_, label_, scale) in tqdm(enumerate(dataloader)):
            scale = at.scalar(scale)
            img, bbox, label = img.cuda().float(), bbox_.cuda(), label_.cuda()
            trainer.train_step(img, bbox, label, scale)  #執行訓練

從train.py中的主要函數能夠看出,主要的步驟涉及訓練數據和測試數據的預處理,網絡模型的構建(Faster RCNN),而後就是迭代訓練,這也是通用的神經網絡搭建和訓練的過程。在Faster Rcnn網絡模型中主要包含Extractor、RPN和RoIhead三部分。網絡中Extractor主要是利用CNN進行特徵提取,網絡採用的VGG16;RPN是候選區網絡,爲RoIHead模塊提供可能存在目標的候選區域(rois);RoIHead主要負責rois的分類和微調。總體的框架圖以下圖所示:

圖片來源於陳雲的知乎

Dataset

在本版本的代碼中讀取的數據格式爲VOC,Dataset和TestDataset類分別負責訓練數據和測試數據的讀取及預處理。在預處理部分主要的操做就是resize圖像的大小、像素值的處理以及圖像的隨機翻轉。主要的內容以下:

class Dataset:     #訓練數據預處理(位於data/dataset.py文件中)
    def __init__(self, opt):
        self.opt = opt
        self.db = VOCBboxDataset(opt.voc_data_dir)  #讀取VOC格式的數據,包括圖像和label(.xml)
        self.tsf = Transform(opt.min_size, opt.max_size) #resize圖像的大小,在代碼中默認長邊小於等於1000,\
        #短邊小於等於600,兩個邊至少有一個等於其值,而後對圖像像素值減去均值,使得像素均值爲零,並對圖像進行隨機翻轉(具體細節代碼見**)

    def __getitem__(self, idx):
        ori_img, bbox, label, difficult = self.db.get_example(idx)
        img, bbox, label, scale = self.tsf((ori_img, bbox, label))
        return img.copy(), bbox.copy(), label.copy(), scale

    def __len__(self):
        return len(self.db)
class TestDataset:
    pass          #與class Dataset類似,沒有圖像翻轉過程(具體內容見data/dataset.py文件中TestDataset)

FasterRCNNVGG16

下面主要介紹Extractor、RPN和RoIHead三部分結構

Extractor

extractor, classifier = decom_vgg16() #該行代碼位於model/faster_rcnn_vgg16.py中的FasterRCNNVGG16類中

Extractor部分主要使用的VGG16的網絡結構,同時使用預訓練好的模型提取圖片的特徵。論文中主要使用的是Caffe的預訓練模型,根據代碼的做者講該版本的預訓練模型效果比較好。

爲了節約顯存,做者將前四層卷積層的學習率設置爲0,Conv5_3的輸入做爲圖片的特徵輸入到RPN網絡中。根據網絡結構,Conv5_3部分的感覺野爲16,也就是相較於輸入的圖片大小,feature map的尺寸爲(C,H/16,W/16).該部分網絡結構圖以下所示:

具體的decom_vgg16()代碼以下:

def decom_vgg16():    #該段落代碼位於model/faster_rcnn_vgg16.py中
    # the 30th layer of features is relu of conv5_3
    if opt.caffe_pretrain:  #使用caffe版本的預訓練模型
        model = vgg16(pretrained=False)  #使用pytorch中自帶的vgg16模型
        if not opt.load_path:
            model.load_state_dict(t.load(opt.caffe_pretrain_path)) #加載caffe版本的預訓練模型,須要本身下載。
    else:
        model = vgg16(not opt.load_path)

    features = list(model.features)[:30]    #提取特徵的網絡
    classifier = model.classifier          #classifier在RoIhead部分使用

    classifier = list(classifier)
    del classifier[6]
    if not opt.use_drop:                #是否使用dropout
        del classifier[5]
        del classifier[2]
    classifier = nn.Sequential(*classifier)  #分類器網絡

    # 凍結前四層卷積層
    for layer in features[:10]:
        for p in layer.parameters():
            p.requires_grad = False

    return nn.Sequential(*features), classifier

RPN

Faster RCNN中最突出的貢獻就是提出了Region Proposal Network(RPN),將候選區域提取的時間開銷幾乎降爲0。該模塊的主要做用提供可能存在目標的候選區域rois。模塊結構圖以下所示:

圖片來源於陳雲的知乎

class RegionProposalNetwork(nn.Module):   #代碼中實現RPN的類(代碼位於model/region_proposal_network.py中)

  def __init__():#省略,具體看先關文件
  # ......
  def forward(self, x, img_size, scale=1.):
      #x: Extractor模塊處理後的特徵圖,形狀爲(N, C, H, W)
      #img_size : 輸入圖像的大小
      #scale : 網絡下采樣的尺寸大小
      n, _, hh, ww = x.shape
      anchor = _enumerate_shifted_anchor(   #枚舉全部anchor
          np.array(self.anchor_base),
          self.feat_stride, hh, ww)

      n_anchor = anchor.shape[0] // (hh * ww)  #一個anchor產生的錨點框
      h = F.relu(self.conv1(x))  #激活函數

      rpn_locs = self.loc(h)     #卷積產生每一個錨點框的位置
      rpn_locs = rpn_locs.permute(0, 2, 3, 1).contiguous().view(n, -1, 4)
      rpn_scores = self.score(h)  #卷積產生每一個錨點框的評分
      rpn_scores = rpn_scores.permute(0, 2, 3, 1).contiguous()
      rpn_softmax_scores = F.softmax(rpn_scores.view(n, hh, ww, n_anchor, 2), dim=4) #softmax操做
      rpn_fg_scores = rpn_softmax_scores[:, :, :, :, 1].contiguous()
      rpn_fg_scores = rpn_fg_scores.view(n, -1)
      rpn_scores = rpn_scores.view(n, -1, 2)

      rois = list()
      roi_indices = list()
      for i in range(n):
          roi = self.proposal_layer(            #根據每一個錨點的評分選出對應的候選區域
              rpn_locs[i].cpu().data.numpy(),
              rpn_fg_scores[i].cpu().data.numpy(),
              anchor, img_size,
              scale=scale)
          batch_index = i * np.ones((len(roi),), dtype=np.int32)
          rois.append(roi)
          roi_indices.append(batch_index)

      rois = np.concatenate(rois, axis=0)
      roi_indices = np.concatenate(roi_indices, axis=0)
      return rpn_locs, rpn_scores, rois, roi_indices, anchor

RoIHead

RoIhead主要任務是對RPN網絡選出的候選框進行分類和迴歸,在RoIhead中做者提出了RolPooling方法將不一樣尺度的候選區域所有pooling到一個尺度上。模塊結構圖以下所示:

圖片來源於陳雲的知乎
class VGG16RoIHead(nn.Module):                         #代碼位於model/faster_rcnn_vgg16.py中
    def __init__(self, n_class, roi_size, spatial_scale,
                 classifier):
        # n_class includes the background
        super(VGG16RoIHead, self).__init__()

        self.classifier = classifier                   #vgg16的兩層全鏈接,可見文中的Extractor部分VGG16的結構圖
        self.cls_loc = nn.Linear(4096, n_class * 4)    #輸出目標區域位置
        self.score = nn.Linear(4096, n_class)          #輸出預測類別

        normal_init(self.cls_loc, 0, 0.001)            #正則化
        normal_init(self.score, 0, 0.01)

        self.n_class = n_class                         #類別
        self.roi_size = roi_size                       #roi大小
        self.spatial_scale = spatial_scale             #空間尺度
        self.roi = RoIPooling2D(self.roi_size, self.roi_size, self.spatial_scale)

    def forward(self, x, rois, roi_indices):
        #......省略
        pool = self.roi(x, indices_and_rois)     #RoI池化部分
        pool = pool.view(pool.size(0), -1)       #降維
        fc7 = self.classifier(pool)              #VGG16的兩層全鏈接
        roi_cls_locs = self.cls_loc(fc7)         #預測出位置
        roi_scores = self.score(fc7)             #分類
        return roi_cls_locs, roi_scores

運行代碼

總體來講該版本的代碼環境至關簡單,配置起來至關容易,沒有什麼坑,認真閱讀做者的readme就好。在utils文件中有一個config.py文件,在裏邊能夠修改文件讀取的路徑,學習率等參數,本身運行時根據本身的狀況進行修改便可。小編運行本身的數據(非VOC2007)結果以下圖:

總結

本篇文章主要的目的是推薦一個適合源碼學習的Faster rcnn版本給你們,並對代碼框架作了初步的介紹,但願對你們的源碼學習有必定的幫助,因爲整個算法實現的代碼較爲複雜,且細節比較多,很難經過一篇文章進行詳細的說明,若是你們對本版本的代碼感興趣,能夠本身閱讀源碼學習。在學習源碼的時候我我的是有不少感想的,做爲一個小白,經過源碼的學習真的學習到了不少,以前論文閱讀過幾遍,別的版本的代碼也拿來訓練過數據,可是讀了這個的源碼,又如發現了新大陸,不少算法的細節和精髓纔算有了深入的理解,真的是紙上得來終覺淺,絕知此事要coding。除了算法自己,在一些代碼的實現上也有不少的學習,真的感覺到代碼做者的功力深厚,再次對做者表示深深地敬意.最後留個問題,在閱讀源碼的時候,發現做者使用了visdom進行可視化,如運行的截圖,小編還知道pytorch中一個可視化工具tensorboardX,但都不是很熟悉,還請知情人士在下方留言,詳細的講解一下兩種可視化工具的優劣。因爲小編是一個剛入門(入坑)的學習者,文章中的不當之處還請你們諒解和提出,很但願能與你們一塊兒討論學習。

最後再次放上源碼連接:https://github.com/chenyuntc/simple-faster-rcnn-pytorch

參考:

https://zhuanlan.zhihu.com/p/32404424

http://www.javashuo.com/article/p-ugokejbr-gp.html

****推薦閱讀****

實戰 | 相機標定
實戰 | 圖像矯正技術
實戰 | Unity下ARKit與OpenCV的結晶
實戰 | 基於SegNet和U-Net的遙感圖像語義分割
實戰 | 文字定位與切割
我用MATLAB擼了一個2D LiDAR SLAM
原來CNN是這樣提取圖像特徵的。。。
最佳機器/深度學習課程 Top 5 ,吳恩達佔了倆
機器學習必學十大算法
語義分割如何「拉關係」?
YOLO簡史
這多是「多模態機器學習」最通俗易懂的介紹
算力限制場景下的目標檢測實戰淺談
開源 | 用深度學習讓你的照片變得美麗
面試時讓你手推公式不在懼怕 | 線性迴歸
面試時讓你手推公式不在懼怕 | 梯度降低
深度學習在計算機視覺各項任務中的應用
乾貨 | 深刻理解深度學習中的激活函數

相關文章
相關標籤/搜索