faster-rcnn 源碼運行流程(理解)

第一步,準備

從train_faster_rcnn_alt_opt.py入:

初始化參數:args = parse_args() 采用的是Python的argparse

主要有–net_name,–gpu,–cfg等(在cfg中只是修改了幾個參數,其他大部分參數在congig.py中,涉及到訓練整個網絡)。

cfg_from_file(args.cfg_file) 這里便是代用config中的函數cfg_from_file來讀取前面cfg文件中的參數,同時調用_merge_a_into_b函數把所有的參數整合,其中__C = edict() cfg = __C cfg是一個詞典(edict)數據結構。

faster rcnn采用的是多進程,mp_queue是進程間用于通訊的數據結構

????????import multiprocessing as mp

????????mp_queue = mp.Queue()

同時solvers, max_iters, rpn_test_prototxt = get_solvers(args.net_name)得到solver參數

接下來便進入了訓練的各個階段。

第二步,Stage 1 RPN, init from ImageNet model

????????????cfg.TRAIN.SNAPSHOT_INFIX ='stage1'

????????????mp_kwargs = dict(? ? ? ??

????????????????????????????????????????????queue=mp_queue,? ? ? ??

????????????????????????????????????????????imdb_name=args.imdb_name,? ? ? ??

????????????????????????????????????????????init_model=args.pretrained_model,? ? ? ??

????????????????????????????????????????????solver=solvers[0],? ? ? ??

????????????????????????????????????????????max_iters=max_iters[0],

? ? ? ? ????????????????????????????????????cfg=cfg)

????????????p = mp.Process(target=train_rpn, kwargs=mp_kwargs)

????????????p.start()

? ? ? ? ? ? rpn_stage1_out = mp_queue.get()

????????????p.join()

可以看到第一個步驟是用ImageNet的模型M0來Finetuning RPN網絡得到模型M1。以訓練為例,這里的args參數都在腳本 experiments/scrips/faster_rcnn_alt_opt.sh中找到。主要關注train_rpn函數。

對于train_rpn函數,主要分一下幾步:

1.在config參數的基礎上改動參數,以適合當前任務,主要有

????????????cfg.TRAIN.HAS_RPN =True

????????????cfg.TRAIN.BBOX_REG =False# applies only to Fast R-CNN bbox regression?

????????????cfg.TRAIN.PROPOSAL_METHOD ='gt'

這里,關注proposal method 使用的是gt,后面會使用到gt_roidb函數,重要。

2. 初始化化caffe

3. 準備roidb和imdb

????????????imdb, roidb = combined_roidb(args.imdb_name)

里面主要涉及到的函數get_roidb

在get_roidb函數中調用factory中的get_imdb根據__sets[name]中的key(一個lambda表達式)轉到pascol_voc類。class pascal_voc(imdb)在初始化自己的時候,先調用父類的初始化方法,例如:

{? ??

????????????year:’2007’? ??

????????????image _set:’trainval’? ??

????????????devkit _path:’data/VOCdevkit2007’? ??

????????????data _path:’data /VOCdevkit2007/VOC2007’? ??

????????????classes:(…)_如果想要訓練自己的數據,需要修改這里

????????????_class_to_ind:{…} _一個將類名轉換成下標的字典 _? 建立索引0,1,2....? ??

? ? ? ? ? ? ?image _ext:’.jpg’? ? image _index: [‘000001’,’000003’,……]_根據trainval.txt獲取到的image索引_

? ? ? ? ? ? ?roidb _handler: < method gt_roidb >

? ? ? ? ? ? ?salt : <Object uuid>

? ? ? ? ? ? ?comp _id:’comp4’

? ? ? ? ? ? ?config:{…}

}

注意,在這里,并沒有讀入任何數據,只是建立了圖片的索引。

????????????imdb.set_proposal_method(cfg.TRAIN.PROPOSAL_METHOD)

設置proposal方法,接上面,設置為gt,這里只是設置了生成的方法,第一次調用發(fā)生在下一句,roidb = get_training_roidb(imdb) –> append_flipped_images()時的這行代碼:“boxes = self.roidb[i][‘boxes’].copy()”,其中get_training_roidb位于train.py,主要實現(xiàn)圖片的水平翻轉,并添加回去。實際是該函數調用了imdb. append_flipped_images也就是在這個函數,調用了pascal_voc中的gt_roidb,轉而調用了同一個文件中的_load_pascal_annotation,該函數根據圖片的索引,到Annotations這個文件夾下去找相應的xml標注數據,然后加載所有的bounding box對象,xml的解析到此結束,接下來是roidb中的幾個類成員的賦值:

????????boxes 一個二維數組,每一行存儲 xmin ymin xmax ymax

????????gt _classes存儲了每個box所對應的類索引(類數組在初始化函數中聲明)

????????gt _overlap是一個二維數組,共有num _classes(即類的個數)行,每一行對應的box的類索引處值為1,其余皆為0,后來被轉成了稀疏矩陣

????????seg _areas存儲著某個box的面積

????????flipped 為false 代表該圖片還未被翻轉(后來在train.py里會將翻轉的圖片加進去,用該變量用于區(qū)分

最后將這些成員變量組裝成roidb返回。

這里要貼幾個連接了,信息量太大(像貼上來的,但是代碼太多了,不貼怕之后就沒了,默默儲存html):

faster-rcnn 之訓練數據是如何準備的:imdb和roidb的產生

https://blog.csdn.net/sloanqin/article/details/51537713

py-faster-rcnn代碼閱讀3-roidb.py

https://www.cnblogs.com/alanma/p/6803713.html

https://blog.csdn.net/xiamentingtao/article/details/78450654

在get_training_roidb函數中還調用了roidb中的prepare_roidb函數,這個函數就是用來準備imdb 的roidb,給roidb中的字典添加一些屬性,比如image(圖像的索引),width,height,通過前面的gt _overla屬性,得到max_classes和max_overlaps.

至此 ? ? ? ? ? ? ? return roidb,imdb

4. 設置輸出路徑,output_dir = get_output_dir(imdb),函數在config中,用來保存中間生成的caffemodule等

5.正式開始訓練

????????????train_net(solver, roidb, output_dir,

? ? ? ? ? ? ? ? ? ? ? ? ? ?pretrained_model=init_model,

? ? ? ? ? ? ? ? ? ? ? ? ? ?max_iters=max_iters)

調用train中的train_net函數,其中,首先filter_roidb,判斷roidb中的每個entry是否合理,合理定義為至少有一個前景box或背景box,roidb全是groudtruth時,因為box與對應的類的重合度(overlaps)顯然為1,也就是說roidb起碼要有一個標記類。如果roidb包含了一些proposal,overlaps在[BG_THRESH_LO, BG_THRESH_HI]之間的都將被認為是背景,大于FG_THRESH才被認為是前景,roidb 至少要有一個前景或背景,否則將被過濾掉。將沒用的roidb過濾掉以后,返回的就是filtered_roidb。在train文件中,需要關注的是SolverWrapper類。詳細見train.py,在這個類里面,引入了caffe SGDSlover,最后一句self.solver.net.layers[0].set_roidb(roidb)將roidb設置進layer(0)(在這里就是ROILayer)調用ayer.py中的set_roidb方法,為layer(0)設置roidb,同時打亂順序。最后train_model。在這里,就需要去實例化每個層,在這個階段,首先就會實現(xiàn)ROIlayer,詳細參考layer中的setup,在訓練時roilayer的forward函數,在第一個層,只需要進行數據拷貝,在不同的階段根據prototxt文件定義的網絡結構拷貝數據,blobs = self._get_next_minibatch()這個函數讀取圖片數據(調用get_minibatch函數,這個函數在minibatch中,主要作用是為faster rcnn做實際的數據準備,在讀取數據的時候,分出了boxes,gt_boxes,im_info(寬高縮放)等)。

第一個層,對于stage1_rpn_train.pt文件中,該layer只有3個top blob:’data’、’im_info’、’gt_boxes’。

對于stage1_fast_rcnn_train.pt文件中,該layer有6個top blob:top: ‘data’、’rois’、’labels’、’bbox_targets’、’bbox_inside_weights’、’bbox_outside_weights’,這些數據準備都在minibatch中。至此后數據便在caffe中流動了,直到訓練結束。


http://ethereon.github.io/netscope/#/editor

網絡的結構只截取了一部分:

值得注意的是在rpn-data層使用的是AnchorTargetLayer,該層使用python實現(xiàn)的,往后再介紹。

6.保存最后得到的權重參數

????????????rpn_stage1_out = mp_queue.get()

至此,第一階段完成,在后面的任務開始時,如果有需要,會在這個輸出的地址找這一階段得到的權重文件。

第三步,Stage 1 RPN, generate proposals

這一步就是調用上一步訓練得到的模型M1來生成proposal P1,在這一步只產生proposal,參數:

mp_kwargs = dict(? ? ? ? queue=mp_queue,? ? ? ? imdb_name=args.imdb_name,? ? ? ? rpn_model_path=str(rpn_stage1_out['model_path']),? ? ? ? cfg=cfg,? ? ? ? rpn_test_prototxt=rpn_test_prototxt)p = mp.Process(target=rpn_generate, kwargs=mp_kwargs)p.start()rpn_stage1_out['proposal_path'] = mp_queue.get()['proposal_path']

p.join()

1.關注rpn_generate函數

前面和上面講到的train_rpn基本相同,從rpn_proposals = imdb_proposals(rpn_net, imdb)開始,imdb_proposals函數在rpn.generate.py文件中,rpn_proposals是一個列表的列表,每個子列表。對于imdb_proposals,使用im = cv2.imread(imdb.image_path_at(i))讀入圖片數據,調用 im_proposals生成單張圖片的rpn proposals,以及得分。這里,im_proposals函數會調用網絡的forward,從而得到想要的boxes和scores,這里需要好好理解blobs_out = net.forward(data,im_info)中net forward和layer forward間的調用關系。

在這里,也會有proposal,同樣會使用python實現(xiàn)的ProposalLayer,這個函數也在rpn文件夾內,后面再補充。

boxes = blobs_out['rois'][:,1:].copy() / scale? ? scores = blobs_out['scores'].copy()return boxes, scores

至此,得到imdb proposal

2.保存得到的proposal文件

queue.put({'proposal_path': rpn_proposals_path})rpn_stage1_out['proposal_path'] = mp_queue.get()['proposal_path']

至此,Stage 1 RPN, generate proposals結束

第四步,Stage 1 Fast R-CNN using RPN proposals, init from ImageNet model

參數:

cfg.TRAIN.SNAPSHOT_INFIX ='stage1'mp_kwargs = dict(? ? ? ? queue=mp_queue,? ? ? ? imdb_name=args.imdb_name,? ? ? ? init_model=args.pretrained_model,? ? ? ? solver=solvers[1],? ? ? ? max_iters=max_iters[1],? ? ? ? cfg=cfg,? ? ? ? rpn_file=rpn_stage1_out['proposal_path'])

p = mp.Process(target=train_fast_rcnn, kwargs=mp_kwargs)

p.start()

fast_rcnn_stage1_out = mp_queue.get()

p.join()

這一步,用上一步生成的proposal,以及imagenet模型M0來訓練fast-rcnn模型M2。

關注train_fast_rcnn

同樣地,會設置參數,這里注意cfg.TRAIN.PROPOSAL_METHOD = ‘rpn’ 不同于前面,后面調用的將是rpn_roidb。cfg.TRAIN.IMS_PER_BATCH = 2,每個mini-batch包含兩張圖片,以及它們proposal的roi區(qū)域。且在這一步是有rpn_file的(后面和rpn_roidb函數使用有關)。其他的和前面差不多。提一下,這里在train_net的時候,會調用add_bbox_regression_targets位于roidb中,主要是添加bbox回歸目標,即添加roidb的‘bbox_targets’屬性,同時根據cfg中的參數設定,求取bbox_targets的mean和std,因為需要訓練class-specific regressors在這里就會涉及到bbox_overlaps函數,放在util.bbox中。

要注意的是在這一步get_roidb時,如前所說,使用的是rpn_roidb,會調用imdb. create_roidb_from_box_list該方法功能是從box_list中讀取每張圖的boxes,而這個box_list就是從上一步保存的proposal文件中讀取出來的,然后做一定的處理,詳細見代碼,重點是在最后會返回roidb,rpn_roidb中的gt_overlaps是rpn_file中的box與gt_roidb中box的gt_overlaps等計算IoU等處理后得到的,而不像gt_roidb()方法生成的gt_roidb中的gt_overlaps全部為1.0。同時使用了imdb.merge_roidb,類imdb的靜態(tài)方法【這里不太懂,需要再學習下】,把rpn_roidb和gt_roidb歸并為一個roidb,在這里,需要具體去了解合并的基本原理。


第五步,Stage 2 RPN, init from stage 1 Fast R-CNN model

參數:

cfg.TRAIN.SNAPSHOT_INFIX ='stage2'mp_kwargs = dict(? ? ? ? queue=mp_queue,? ? ? ? imdb_name=args.imdb_name,? ? ? ? init_model=str(fast_rcnn_stage1_out['model_path']),? ? ? ? solver=solvers[2],? ? ? ? max_iters=max_iters[2],

? ? ? ? cfg=cfg)

p = mp.Process(target=train_rpn, kwargs=mp_kwargs)

rpn_stage2_out = mp_queue.get()

這部分就是利用模型M2練rpn網絡,這一次與stage1的rpn網絡不通,這一次conv層的參數都是不動的,只做前向計算,訓練得到模型M3,這屬于微調了rpn網絡。


第六步,Stage 2 RPN, generate proposals

參數:

mp_kwargs = dict(? ? ? ? queue=mp_queue,? ? ? ? imdb_name=args.imdb_name,? ? ? ? rpn_model_path=str(rpn_stage2_out['model_path']),? ? ? ? cfg=cfg,? ? ? ? rpn_test_prototxt=rpn_test_prototxt)p = mp.Process(target=rpn_generate, kwargs=mp_kwargs)p.start()rpn_stage2_out['proposal_path'] = mp_queue.get()['proposal_path']

p.join()

這一步,基于上一步得到的M3模型,產生proposal P2,網絡結構和前面產生proposal P1的一樣。


第七步,Stage 2 Fast R-CNN, init from stage 2 RPN R-CNN model

參數:

cfg.TRAIN.SNAPSHOT_INFIX ='stage2'mp_kwargs = dict(? ? ? ? queue=mp_queue,? ? ? ? imdb_name=args.imdb_name,? ? ? ? init_model=str(rpn_stage2_out['model_path']),? ? ? ? solver=solvers[3],? ? ? ? max_iters=max_iters[3],? ? ? ? cfg=cfg,? ? ? ? rpn_file=rpn_stage2_out['proposal_path'])

p = mp.Process(target=train_fast_rcnn, kwargs=mp_kwargs)

p.start()

fast_rcnn_stage2_out = mp_queue.get()

p.join()

這一步基于模型M3和P2訓練fast rcnn得到最終模型M4,這一步,conv層和rpn都是參數固定,只是訓練了rcnn層(也就是全連接層),與stage1不同,stage1只是固定了rpn層,其他層還是有訓練。模型結構與stage1相同:


第八步,輸出最后模型

final_path = os.path.join(? ? ? ? os.path.dirname(fast_rcnn_stage2_out['model_path']),? ? ? ? args.net_name +'_faster_rcnn_final.caffemodel')print'cp {} -> {}'.format(? ? ? ? fast_rcnn_stage2_out['model_path'], final_path)shutil.copy(fast_rcnn_stage2_out['model_path'], final_path)print'Final model: {}'.format(final_path)


只是對上一步模型輸出的一個拷貝。

至此,整個faster-rcnn的訓練過程就結束了。


AnchorTargetLayer和ProposalLayer

前面說過還有這兩個層沒有說明,一個是anchortarget layer一個是proposal layer,下面逐一簡要分析。

classAnchorTargetLayer(caffe.Layer)

首先是讀取參數,在prototxt,實際上只讀取了param_str: “‘feat_stride’: 16”,這是個很重要的參數,目前我的理解是滑塊滑動的大小,對于識別物體的大小很有用,比如小物體的識別,需要把這個參數減小等。

首先 setup部分,

anchor_scales = layer_params.get('scales', (8,16,32))

self._anchors = generate_anchors(scales=np.array(anchor_scales))

調用generate_anchors方法生成最初始的9個anchor該函數位于generate_anchors.py 主要功能是生成多尺度,多寬高比的anchors,8,16,32其實就是scales:[2^3 2^4 2^5],base_size為16,具體是怎么實現(xiàn)的可以查閱源代碼。_ratio_enum()部分生成三種寬高比 1:2,1:1,2:1的anchor如下圖所示:(以下參考 另外一篇博客)


_scale_enum()部分,生成三種尺寸的anchor,以_ratio_enum()部分生成的anchor[0 0 15 15]為例,擴展了三種尺度 128*128,256*256,512*512,如下圖所示:


另外一個函數就是forward()。

在faster rcnn中會根據不同圖的輸入,得到不同的feature map,height, width = bottom[0].data.shape[-2:]首先得到conv5的高寬,以及gt box gt_boxes = bottom[1].data,圖片信息im_info = bottom[2].data[0, :],然后計算偏移量,shift_x = np.arange(0, width) * self._feat_stride,在這里,你會發(fā)現(xiàn),例如你得到的fm是H=61,W=36,然后你乘以16,得到的圖形大概就是1000*600,其實這個16大概就是網絡的縮放比例。接下來就是生成anchor,以及對anchor做一定的篩選,詳見代碼。

另外一個需要理解的就是proposal layer,這個只是在測試的時候用,許多東西和AnchorTargetLayer類似,不詳細介紹,可以查看代碼。主要看看forward函數,函數算法介紹在注釋部分寫的很詳細:


4 Faster RCNN

Faster R-CNN統(tǒng)一的網絡結構如下圖所示,可以簡單看作RPN網絡+Fast R-CNN網絡。

原理步驟如下:

首先向CNN網絡【ZF或VGG-16】輸入任意大小圖片;

經過CNN網絡前向傳播至最后共享的卷積層,一方面得到供RPN網絡輸入的特征圖,另一方面繼續(xù)前向傳播至特有卷積層,產生更高維特征圖;

供RPN網絡輸入的特征圖經過RPN網絡得到區(qū)域建議和區(qū)域得分,并對區(qū)域得分采用非極大值抑制【閾值為0.7】,輸出其Top-N【文中為300】得分的區(qū)域建議給RoI池化層;

第2步得到的高維特征圖和第3步輸出的區(qū)域建議同時輸入RoI池化層,提取對應區(qū)域建議的特征;

第4步得到的區(qū)域建議特征通過全連接層后,輸出該區(qū)域的分類得分以及回歸后的bounding-box。

4.1 單個RPN網絡結構

單個RPN網絡結構如下:

注意:上圖中卷積層/全連接層表示卷積層或者全連接層,作者在論文中表示這兩層實際上是全連接層,但是網絡在所有滑窗位置共享全連接層,可以很自然地用n×n卷積核【論文中設計為3×3】跟隨兩個并行的1×1卷積核實現(xiàn)

RPN的作用:RPN在CNN卷積層后增加滑動窗口操作以及兩個卷積層完成區(qū)域建議功能,第一個卷積層將特征圖每個滑窗位置編碼成一個特征向量,第二個卷積層對應每個滑窗位置輸出k個區(qū)域得分和k個回歸后的區(qū)域建議,并對得分區(qū)域進行非極大值抑制后輸出得分Top-N【文中為300】區(qū)域,告訴檢測網絡應該注意哪些區(qū)域,本質上實現(xiàn)了Selective Search、EdgeBoxes等方法的功能。

4.2 RPN層的具體流程

首先套用ImageNet上常用的圖像分類網絡,本文中試驗了兩種網絡:ZF或VGG-16,利用這兩種網絡的部分卷積層產生原始圖像的特征圖;

對于1中特征圖,用n×n【論文中設計為3×3,n=3看起來很小,但是要考慮到這是非常高層的feature map,其size本身也沒有多大,因此9個矩形中,每個矩形窗框都是可以感知到很大范圍的】的滑動窗口在特征圖上滑動掃描【代替了從原始圖滑窗獲取特征】,每個滑窗位置通過卷積層1映射到一個低維的特征向量【ZF網絡:256維;VGG-16網絡:512維,低維是相對于特征圖大小W×H,typically~60×40=2400】后采用ReLU,并為每個滑窗位置考慮k種【論文中k=9】可能的參考窗口【論文中稱為anchors,見下解釋】,這就意味著每個滑窗位置會同時預測最多9個區(qū)域建議【超出邊界的不考慮】,對于一個W×H的特征圖,就會產生W×H×k個區(qū)域建議;

步驟2中的低維特征向量輸入兩個并行連接的卷積層2:reg窗口回歸層【位置精修】和cls窗口分類層,分別用于回歸區(qū)域建議產生bounding-box【超出圖像邊界的裁剪到圖像邊緣位置】和對區(qū)域建議是否為前景或背景打分,這里由于每個滑窗位置產生k個區(qū)域建議,所以reg層有4k個輸出來編碼【平移縮放參數】k個區(qū)域建議的坐標,cls層有2k個得分估計k個區(qū)域建議為前景或者背景的概率。

4.3 Anchor

Anchors是一組大小固定的參考窗口:三種尺度{1282,2562,51221282,2562,5122?}×三種長寬比{1:1,1:2,2:1},如下圖所示,表示RPN網絡中對特征圖滑窗時每個滑窗位置所對應的原圖區(qū)域中9種可能的大小,相當于模板,對任意圖像任意滑窗位置都是這9中模板。繼而根據圖像大小計算滑窗中心點對應原圖區(qū)域的中心點,通過中心點和size就可以得到滑窗位置和原圖位置的映射關系,由此原圖位置并根據與Ground Truth重復率貼上正負標簽,讓RPN學習該Anchors是否有物體即可。對于每個滑窗位置,產生k=9個anchor對于一個大小為W*H的卷積feature map,總共會產生WHk個anchor。

平移不變性

Anchors這種方法具有平移不變性,就是說在圖像中平移了物體,窗口建議也會跟著平移。同時這種方式也減少了整個模型的size,輸出層512×(4+2)×9=2.8×104512×(4+2)×9=2.8×104?個參數【512是前一層特征維度,(4+2)×9是9個Anchors的前景背景得分和平移縮放參數】,而MultiBox有1536×(4+1)×800=6.1×106個1536×(4+1)×800=6.1×106個?參數,而較小的參數可以在小數據集上減少過擬合風險。

當然,在RPN網絡中我們只需要找到大致的地方,無論是位置還是尺寸,后面的工作都可以完成,這樣的話采用小網絡進行簡單的學習【估計和猜差不多,反正有50%概率】,還不如用深度網絡【還可以實現(xiàn)卷積共享】,固定尺度變化,固定長寬比變化,固定采樣方式來大致判斷是否是物體以及所對應的位置并降低任務復雜度。

4.4 多尺度多長寬比率

有兩種方法解決多尺度多長寬比問題:

圖像金字塔:對伸縮到不同size的輸入圖像進行特征提取,雖然有效但是費時.

feature map上使用多尺度(和/或長寬比)的滑窗:例如,DPM分別使用不同大小的filter來訓練不同長寬比的模型。若這種方法用來解決多尺度問題,可以認為是“filter金字塔(pyramid of filters)”

4.5 訓練過程

4.5.1 RPN網絡訓練過程

RPN網絡被ImageNet網絡【ZF或VGG-16】進行了有監(jiān)督預訓練,利用其訓練好的網絡參數初始化; 用標準差0.01均值為0的高斯分布對新增的層隨機初始化。

4.5.2 Fast R-CNN網絡預訓練

同樣使用mageNet網絡【ZF或VGG-16】進行了有監(jiān)督預訓練,利用其訓練好的網絡參數初始化。

4.5.3 RPN網絡微調訓練

PASCAL VOC 數據集中既有物體類別標簽,也有物體位置標簽; 正樣本僅表示前景,負樣本僅表示背景; 回歸操作僅針對正樣本進行; 訓練時棄用所有超出圖像邊界的anchors,否則在訓練過程中會產生較大難以處理的修正誤差項,導致訓練過程無法收斂; 對去掉超出邊界后的anchors集采用非極大值抑制,最終一張圖有2000個anchors用于訓練【詳細見下】; 對于ZF網絡微調所有層,對VGG-16網絡僅微調conv3_1及conv3_1以上的層,以便節(jié)省內存。

SGD mini-batch采樣方式:同F(xiàn)ast R-CNN網絡,采取image-centric方式采樣,即采用層次采樣,先對圖像取樣,再對anchors取樣,同一圖像的anchors共享計算和內存。每個mini-batch包含從一張圖中隨機提取的256個anchors,正負樣本比例為1:1【當然可以對一張圖所有anchors進行優(yōu)化,但由于負樣本過多最終模型會對正樣本預測準確率很低】來計算一個mini-batch的損失函數,如果一張圖中不夠128個正樣本,拿負樣本補湊齊。

訓練超參數選擇:在PASCAL VOC數據集上前60k次迭代學習率為0.001,后20k次迭代學習率為0.0001;動量設置為0.9,權重衰減設置為0.0005。

多任務目標函數【分類損失+回歸損失】具體如下:

L({pi},{ti})=1Ncls∑iLcls(pi,p?i)+λ1Nreg∑ip?iLreg(ti,t?i)L({pi},{ti})=1Ncls∑iLcls(pi,pi?)+λ1Nreg∑ipi?Lreg(ti,ti?)

i為一個anchor在一個mini-batch中的下標

pipi?是anchor i為一個object的預測可能性

p?ipi??為ground-truth標簽。如果這個anchor是positive的,則ground-truth標簽p?ipi??為1,否則為0。

titi?表示表示正樣本anchor到預測區(qū)域bounding box的4個參數化坐標,【以anchor為基準的變換

t?iti??是這個positive anchor對應的ground-truth box。【以anchor為基準的變換

LclsLcls?分類的損失(classification loss),是一個二值分類器(是object或者不是)的softmax loss。其公式為Lcls(pi,p?i)=?log[pi?p?i+(1?p?i)(1?pi)]Lcls(pi,pi?)=?log[pi?pi?+(1?pi?)(1?pi)]

LregLreg?回歸損失(regression loss),Lreg(ti,t?i)=R(ti?t?i)Lreg(ti,ti?)=R(ti?ti?)?【兩種變換之差越小越好】,其中R是Fast R-CNN中定義的robust ross function (smooth L1)。p?iLregpi?Lreg表示回歸損失只有在positive anchor(p?i=1pi?=1?)的時候才會被激活。cls與reg層的輸出分別包含{pipi}和{titi?}。R函數的定義為:smoothL1(x)=0.5x2if∣x∣<1otherwise∣x∣?0.5smoothL1(x)=0.5x2if∣x∣<1otherwise∣x∣?0.5

λ參數用來權衡分類損失LclsLcls?和回歸損失LregLreg?,默認值λ=10【文中實驗表明 λ從1變化到100對mAP影響不超過1%】;

NclsNcls?和NregNreg?分別用來標準化分類損失項LclsLcls?和回歸損失項LregLreg,默認用mini-batch size=256設置NclsNcls,用anchor位置數目~2400初始化NregNreg,文中也說明標準化操作并不是必須的,可以簡化省略。

4.5.4 RPN網絡、Fast R-CNN網絡聯(lián)合訓練

訓練網絡結構示意圖如下所示:

如上圖所示,RPN網絡、Fast R-CNN網絡聯(lián)合訓練是為了讓兩個網絡共享卷積層,降低計算量

文中通過4步訓練算法,交替優(yōu)化學習至共享特征:

進行上面RPN網絡預訓練,和以區(qū)域建議為目的的RPN網絡end-to-end微調訓練。

進行上面Fast R-CNN網絡預訓練,用第①步中得到的區(qū)域建議進行以檢測為目的的Fast R-CNN網絡end-to-end微調訓練【此時無共享卷積層】。

使用第2步中微調后的Fast R-CNN網絡重新初始化RPN網絡,固定共享卷積層【即設置學習率為0,不更新】,僅微調RPN網絡獨有的層【此時共享卷積層】。

固定第3步中共享卷積層,利用第③步中得到的區(qū)域建議,僅微調Fast R-CNN獨有的層,至此形成統(tǒng)一網絡如上圖所示。

4.6 相關解釋

**RPN網絡中bounding-box回歸怎么理解?同F(xiàn)ast R-CNN中的bounding-box回歸相比有什么區(qū)別? **

對于bounding-box回歸,采用以下公式:

t

tx=(x?xa)waty=(y?ya)hatw=logwwath=loghhatx=(x?xa)waty=(y?ya)hatw=logwwath=loghha

t?t?

t?x=(x??xa)wat?y=(y??ya)hat?w=logw?wat?h=logh?hatx?=(x??xa)waty?=(y??ya)hatw?=logw?wath?=logh?ha

其中,x,y,w,h表示窗口中心坐標和窗口的寬度和高度,變量x,xaxa?和x?x??分別表示預測窗口、anchor窗口和Ground Truth的坐標【y,w,h同理】,因此這可以被認為是一個從anchor窗口到附近Ground Truth的bounding-box 回歸;

RPN網絡中bounding-box回歸的實質其實就是計算出預測窗口。這里以anchor窗口為基準,計算Ground Truth對其的平移縮放變化參數,以及預測窗口【可能第一次迭代就是anchor】對其的平移縮放參數,因為是以anchor窗口為基準,所以只要使這兩組參數越接近,以此構建目標函數求最小值,那預測窗口就越接近Ground Truth,達到回歸的目的;

文中提到, Fast R-CNN中基于RoI的bounding-box回歸所輸入的特征是在特征圖上對任意size的RoIs進行Pool操作提取的,所有size RoI共享回歸參數,而在Faster R-CNN中,用來bounding-box回歸所輸入的特征是在特征圖上相同的空間size【3×3】上提取的,為了解決不同尺度變化的問題,同時訓練和學習了k個不同的回歸器,依次對應為上述9種anchors,這k個回歸量并不分享權重。因此盡管特征提取上空間是固定的【3×3】,但由于anchors的設計,仍能夠預測不同size的窗口。



文中提到了三種共享特征網絡的訓練方式?

交替訓練,訓練RPN,得到的區(qū)域建議來訓練Fast R-CNN網絡進行微調;此時網絡用來初始化RPN網絡,迭代此過程【文中所有實驗采用】;

近似聯(lián)合訓練:如上圖所示,合并兩個網絡進行訓練,前向計算產生的區(qū)域建議被固定以訓練Fast R-CNN;反向計算到共享卷積層時RPN網絡損失和Fast R-CNN網絡損失疊加進行優(yōu)化,但此時把區(qū)域建議【Fast R-CNN輸入,需要計算梯度并更新】當成固定值看待,忽視了Fast R-CNN一個輸入:區(qū)域建議的導數,則無法更新訓練,所以稱之為近似聯(lián)合訓練。實驗發(fā)現(xiàn),這種方法得到和交替訓練相近的結果,還能減少20%~25%的訓練時間,公開的python代碼中使用這種方法;

聯(lián)合訓練需要RoI池化層對區(qū)域建議可微,需要RoI變形層實現(xiàn),具體請參考這片paper:Instance-aware Semantic Segmentation via Multi-task Network Cascades。

圖像Scale細節(jié)問題?

文中提到訓練和檢測RPN、Fast R-CNN都使用單一尺度,統(tǒng)一縮放圖像短邊至600像素; 在縮放的圖像上,對于ZF網絡和VGG-16網絡的最后卷積層總共的步長是16像素,因此在縮放前典型的PASCAL圖像上大約是10像素【~500×375;600/16=375/10】。

Faster R-CNN中三種尺度怎么解釋:

原始尺度:原始輸入的大小,不受任何限制,不影響性能;

歸一化尺度:輸入特征提取網絡的大小,在測試時設置,源碼中opts.test_scale=600。anchor在這個尺度上設定,這個參數和anchor的相對大小決定了想要檢測的目標范圍;

網絡輸入尺度:輸入特征檢測網絡的大小,在訓練時設置,源碼中為224×224。

理清文中anchors的數目

文中提到對于1000×600的一張圖像,大約有20000(~60×40×9)個anchors,忽略超出邊界的anchors剩下6000個anchors,利用非極大值抑制去掉重疊區(qū)域,剩2000個區(qū)域建議用于訓練; 測試時在2000個區(qū)域建議中選擇Top-N【文中為300】個區(qū)域建議用于Fast R-CNN檢測。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容