本文所用代碼gayhub的地址:https://github.com/chenyuntc/simple-faster-rcnn-pytorch (非本人所寫,博文只是解釋代碼)git
好長時間沒有發博客了,感受也沒啥人讀個人博客,不過我不能放棄啊,總會有人發現它的價值的,哈哈!最近一直在生啃目標檢測的幾篇論文,距離成爲我想象中的大神還有很遠的一段距離啊,剛啃完Faster-RCNN的論文的時候,以爲多是語言的關係,本身看得一直是似懂非懂的,感受沒有掌握到裏面的精髓,因而我決定擼代碼來看,聽說Ross Girshick大神的代碼很健壯,看了下是基於caffe/caffe2寫的,本身不太熟悉caffe的框架和環境,因而就心血來潮在網上找基於pytorch的Faster-RCNN的代碼,最後還真被我找到了陳雲寫的simple-faster-rcnn-pytorch-master,能從頭擼出Faster-RCNN的實現真的是十分的不容易,我光讀就讀了一個星期,真是慚愧,差距仍是很大的!simple-faster-RCNN顧名思義就是簡化版的faster-rcnn,做者說代碼除去註釋只有2000行左右,可是能達到和rgb大神差很少的精度,真的是很了不得了!爲此我還特地買了做者一本書,就當是付費看代碼吧~github
具體的實現精度和相關的環境建議你們仔細閱讀做者的README文件,上面講的很清楚,本篇博客主要負責解釋代碼,以備往後從新讀不用這麼費力氣。數據庫
本篇博客是整個Faster-rcnn系列的第四篇文章,主要解釋/simple-faster-rcnn-pytorch-master/train.py 以及/simple-faster-rcnn-pytorch-master/trainer.py網絡
前三章地址在:app
1 Faster-RCNN的數據讀取及預處理部分:(對應於代碼的/simple-faster-rcnn-pytorch-master/data文件夾)框架
2 Faster-RCNN的模型準備部分:(對應於代碼目錄/simple-faster-rcnn-pytorch-master/model/utils/文件夾)dom
3 Faster-RCNN的模型正式介紹:(對應於代碼目錄/simple-faster-rcnn-pytorch-master/model/文件夾)ide
下面正式開始介紹Faster-rcnn的訓練部分的代碼函數
一:trainer.py部分代碼:工具
首先來看trainer.py,由於trainer.py裏面實現了不少函數供train.py調用,trainer.py文件裏函數結構以下圖:
而後咱們開始一個函數一個函數的進行剖析,可能讀着讀着你就會發現原來晦澀難懂的問題忽然就變得很直覺了!
1 __init__函數 代碼以下:
1 def __init__(self, faster_rcnn): 2 super(FasterRCNNTrainer, self).__init__() 3 4 self.faster_rcnn = faster_rcnn 5 self.rpn_sigma = opt.rpn_sigma 6 self.roi_sigma = opt.roi_sigma 7 8 # target creator create gt_bbox gt_label etc as training targets. 9 self.anchor_target_creator = AnchorTargetCreator() 10 self.proposal_target_creator = ProposalTargetCreator() 11 12 self.loc_normalize_mean = faster_rcnn.loc_normalize_mean 13 self.loc_normalize_std = faster_rcnn.loc_normalize_std 14 15 self.optimizer = self.faster_rcnn.get_optimizer() 16 # visdom wrapper 17 self.vis = Visualizer(env=opt.env) 18 19 # indicators for training status 20 self.rpn_cm = ConfusionMeter(2) 21 self.roi_cm = ConfusionMeter(21) 22 self.meters = {k: AverageValueMeter() for k in LossTuple._fields}
__init__ Faster_RCNNTrainer的初始化函數,其父類是nn.module,主要是一些變量的初始化部分,定義了self.faster_rcnn = faster_rcnn,而這個rpn_sigma和roi_sigma是在_faster_rcnn_loc_loss調用用來計算位置損失函數用到的超參數,
以後定義了十分重要的兩個函數,AnchorTargetCreator()和ProposalTargetCreator(),它們一個用於從20000個候選anchor中產生256個anchor進行二分類和位置迴歸,也就是爲rpn網絡產生的預測位置和預測類別提供真正的ground_truth標準
用於rpn網絡的自我訓練,自我提升,提高產生ROIs的精度!具體的篩選過程和準則看前面幾篇文章,而ProposalTargetCreator()的做用是從2000個篩選出的ROIS中再次選出128個ROIs用於訓練,它的做用和前面的anchortargetCreator相似,不過它們服務的網絡是不一樣的,前面anchortargetCreator服務的是RPN網絡,而咱們的proposaltargetCreator服務的是ROIHearder的網絡,ROIheader的做用就是真正產生ROI__loc和ROI_cls的網絡,它完成了目標檢測最重要的預測目標位置和類別!以後定義了位置信息的均值方差,由於送入到網絡訓練的位置信息所有是歸一化處理的,須要用到相關的均值和方差數據,接下來是優化器數據,用的是faster_rcnn文件裏的get_optimizer()數據,裏面決定了是使用Adam仍是SGD等等,以及衰減率的設置之類,最後是可視化部分的一些設置,rpn_cm是混淆矩陣,就是驗證預測值與真實值精確度的矩陣ConfusionMeter(2)括號裏的參數指的是類別數,因此rpn_cm =2,而roi_cm =21由於roi的類別有21種(20個object類+1個background)
2 def forward(self,imgs,bboxes,labels,scale)函數 代碼以下:
1 def forward(self, imgs, bboxes, labels, scale): 2 """Forward Faster R-CNN and calculate losses. 3 4 Here are notations used. 5 6 * :math:`N` is the batch size. 7 * :math:`R` is the number of bounding boxes per image. 8 9 Currently, only :math:`N=1` is supported. 10 11 Args: 12 imgs (~torch.autograd.Variable): A variable with a batch of images. 13 bboxes (~torch.autograd.Variable): A batch of bounding boxes. 14 Its shape is :math:`(N, R, 4)`. 15 labels (~torch.autograd..Variable): A batch of labels. 16 Its shape is :math:`(N, R)`. The background is excluded from 17 the definition, which means that the range of the value 18 is :math:`[0, L - 1]`. :math:`L` is the number of foreground 19 classes. 20 scale (float): Amount of scaling applied to 21 the raw image during preprocessing. 22 23 Returns: 24 namedtuple of 5 losses 25 """ 26 n = bboxes.shape[0] 27 if n != 1: 28 raise ValueError('Currently only batch size 1 is supported.') 29 30 _, _, H, W = imgs.shape 31 img_size = (H, W) 32 33 features = self.faster_rcnn.extractor(imgs) 34 35 rpn_locs, rpn_scores, rois, roi_indices, anchor = \ 36 self.faster_rcnn.rpn(features, img_size, scale) 37 38 # Since batch size is one, convert variables to singular form 39 bbox = bboxes[0] 40 label = labels[0] 41 rpn_score = rpn_scores[0] 42 rpn_loc = rpn_locs[0] 43 roi = rois 44 45 # Sample RoIs and forward 46 # it's fine to break the computation graph of rois, 47 # consider them as constant input 48 sample_roi, gt_roi_loc, gt_roi_label = self.proposal_target_creator( 49 roi, 50 at.tonumpy(bbox), 51 at.tonumpy(label), 52 self.loc_normalize_mean, 53 self.loc_normalize_std) 54 # NOTE it's all zero because now it only support for batch=1 now 55 sample_roi_index = t.zeros(len(sample_roi)) 56 roi_cls_loc, roi_score = self.faster_rcnn.head( 57 features, 58 sample_roi, 59 sample_roi_index) 60 61 # ------------------ RPN losses -------------------# 62 gt_rpn_loc, gt_rpn_label = self.anchor_target_creator( 63 at.tonumpy(bbox), 64 anchor, 65 img_size) 66 gt_rpn_label = at.totensor(gt_rpn_label).long() 67 gt_rpn_loc = at.totensor(gt_rpn_loc) 68 rpn_loc_loss = _fast_rcnn_loc_loss( 69 rpn_loc, 70 gt_rpn_loc, 71 gt_rpn_label.data, #定位損失爲何加label大概是由於負例不參與定位損失吧 72 self.rpn_sigma) 73 74 # NOTE: default value of ignore_index is -100 ... 75 rpn_cls_loss = F.cross_entropy(rpn_score, gt_rpn_label.cuda(), ignore_index=-1) 76 _gt_rpn_label = gt_rpn_label[gt_rpn_label > -1] 77 _rpn_score = at.tonumpy(rpn_score)[at.tonumpy(gt_rpn_label) > -1] 78 self.rpn_cm.add(at.totensor(_rpn_score, False), _gt_rpn_label.data.long()) 79 80 # ------------------ ROI losses (fast rcnn loss) -------------------# 81 n_sample = roi_cls_loc.shape[0] 82 roi_cls_loc = roi_cls_loc.view(n_sample, -1, 4) 83 roi_loc = roi_cls_loc[t.arange(0, n_sample).long().cuda(), \ 84 at.totensor(gt_roi_label).long()] 85 gt_roi_label = at.totensor(gt_roi_label).long() 86 gt_roi_loc = at.totensor(gt_roi_loc) 87 88 roi_loc_loss = _fast_rcnn_loc_loss( 89 roi_loc.contiguous(), 90 gt_roi_loc, 91 gt_roi_label.data, 92 self.roi_sigma) 93 94 roi_cls_loss = nn.CrossEntropyLoss()(roi_score, gt_roi_label.cuda()) 95 96 self.roi_cm.add(at.totensor(roi_score, False), gt_roi_label.data.long()) 97 98 losses = [rpn_loc_loss, rpn_cls_loss, roi_loc_loss, roi_cls_loss] 99 losses = losses + [sum(losses)] 100 101 return LossTuple(*losses)
這段函數該是整個文件的精髓,畫一張流程圖出來描述整個網絡的運做過程:
整幅圖片描述在求損失以前訓練過程經歷了什麼!不許確的說是一個僞正向傳播的過程,爲啥說是僞正向傳播呢,由於過程當中調用了proposal_target_creator(),而這個函數的做用實際上是爲了訓練ROI_Header網絡而提供所謂的128張sample_roi以及它的ground_truth的位置和label用的!因此它的根本目的是爲了訓練網絡,在測試的時候是用不到的!流程圖中紅色圓框表明的是網絡運行過程當中產生的參數,而藍色框表明的是網絡定義的時候就有的參數!仔細看整個流程圖,網絡的運做結構就一目瞭然了!下面解釋下代碼:
n= bboxes.shape[0]首先獲取batch個數,若是不等於就報錯,由於本程序只支持batch_size=1,接着讀取圖片的高和寬,這裏解釋下,不論圖片仍是bbox,它們的數據格式都是形如n,c,hh,ww這種,因此H,W就能夠獲取到圖片的尺寸,緊接着用self.faster_rcnn.extractor(imgs)提取圖片的特徵,而後放到rpn網絡裏面self.faster_rcnn.rpn(feature,img_size,scale)提取出rpn_locs,rpn_scores,rois,roi_indices,anchor來,下一步就是通過proposal_target_creator網絡產生採樣事後的sample_roi,以及其對應的gt_cls_loc和gt_score,最後通過head網絡,完成整個的預測過程!流程圖中的結構是如出一轍的!
可是這個文件之因此叫trainer就是由於不只僅有正向的運做過程,確定還有反向的傳播,包括了損失計算等等,沒錯,接下來咱們看下面的損失計算部分的流程圖:
如上圖所示,其實剩下的代碼就是計算了兩部分的損失,一個是RPN_losses,一個是ROI_Losses,爲啥要這樣作呢?你們考慮一下,這個Faster-rcnn的網絡,哪些地方應用到了網絡呢?一個是提取proposal的過程,在faster-rcnn裏創造性的提出了anchor,用網絡來產生proposals,因此rpn_losses就是爲了計算這部分的損失,從而使用梯度降低的辦法來提高提取prososal的網絡的性能,另外一個使用到網絡的地方就是ROI_header,沒錯就是在利用特徵圖和ROIs來預測目標檢測的類別以及位置的偏移量的時候再一次使用到了網絡,那這部分預測網絡的性能如何保證呢?ROI_losses就是計算這部分的損失函數,從而用梯度降低的辦法來繼續提高網絡的性能啊兄弟!這樣一來,這兩部分的網絡的損失都記算出來了!forward函數也就介紹完了!這個地方須要特別注意的一點就是rpn_cm和roi_cm這兩個對象應該是Confusion matrix也就是混淆矩陣啦,做用就是用於後續的數據可視化,不是本文重點介紹的內容啦!
3 def train_step(self,imgs,bboxes,labels,scale)函數,代碼以下:
1 def train_step(self, imgs, bboxes, labels, scale): 2 self.optimizer.zero_grad() 3 losses = self.forward(imgs, bboxes, labels, scale) 4 losses.total_loss.backward() 5 self.optimizer.step()#進行一次參數優化過程 6 self.update_meters(losses) 7 return losses
整個函數實際上就是進行了一次參數的優化過程,首先self.optimizer.zero_grad()將梯度數據所有清零,而後利用剛剛介紹的self.forward(imgs,bboxes,labels,scales)函數將全部的損失計算出來,接着進行依次losses.total_loss.backward()反向傳播計算梯度,self.optimizer.step()進行一次參數更新過程,self.update_meters(losses)就是將全部損失的數據更新到可視化界面上,最後將losses返回!
4 def save() def load() def update_meters(),def reset_meters() def get_meter_data()函數
這幾個函數不想仔細展開解釋了,顧名思義,save和load就是根據傳入的參數來選擇保存model模型或者說config設置或者是other_info其餘參數vis_info可視化參數等等
而update_meters,reset_meters以及get_meter_data()就是負責將數據向可視化界面更新傳輸獲取以及重置的函數,基本上也和主要代碼沒什麼太大的關係!
5 def _smooth_l1_loss(x,t,in_weight,sigma)函數,代碼以下:
1 def _smooth_l1_loss(x, t, in_weight, sigma): 2 sigma2 = sigma ** 2 3 diff = in_weight * (x - t) 4 abs_diff = diff.abs() 5 flag = (abs_diff.data < (1. / sigma2)).float() 6 y = (flag * (sigma2 / 2.) * (diff ** 2) + 7 (1 - flag) * (abs_diff - 0.5 / sigma2)) 8 return y.sum()
這個函數其實就是寫了一個smooth_l1損失函數的計算公式,這個公式裏面的x,t就是表明預測和實際的兩個變量,in_weight表明的是權重,由於在計算損失函數的過程當中被標定爲背景的那一類實際上是不計算損失函數的,因此說能夠巧妙地將對應的權重設置爲0,這樣就完成了忽略背景類的目的,這也就是爲何計算位置的損失函數還要傳入ground_truth的label做爲參數的緣由,sigma是一個因子,在前面的__init__函數裏有定義好!
6 def _fast_rcnn_loc_loss(pred_loc,gt_loc,gt_label,sigma)函數,代碼以下:
1 def _fast_rcnn_loc_loss(pred_loc, gt_loc, gt_label, sigma): 2 in_weight = t.zeros(gt_loc.shape).cuda() 3 # Localization loss is calculated only for positive rois. 4 # NOTE: unlike origin implementation, 5 # we don't need inside_weight and outside_weight, they can calculate by gt_label 6 in_weight[(gt_label > 0).view(-1, 1).expand_as(in_weight).cuda()] = 1 7 loc_loss = _smooth_l1_loss(pred_loc, gt_loc, in_weight.detach(), sigma) 8 # Normalize by total number of negtive and positive rois. 9 loc_loss /= ((gt_label >= 0).sum().float()) # ignore gt_label==-1 for rpn_loss 10 return loc_loss
這個函數完成的任務就是我剛剛在前面說的,用in_weight來做爲權重,只將那些不是背景的anchor/ROIs的位置加入到損失函數的計算中來,方法就是隻給不是背景的anchor/ROIs的in_weight設置爲1,這樣就能夠完成loc_loss的求和計算,最後進行返回就完成了計算位置損失的任務!
二:train.py部分代碼:
接下來就是train.py部分的代碼了,一樣的先將程序框圖送上:
看這程序框圖彷彿發現這個文件好像根本沒啥東西啊,不着急咱們慢慢展開來介紹:
1 def eval(dataloader,faster_rcnn,test_num=10000)函數,代碼以下:
1 def eval(dataloader, faster_rcnn, test_num=10000): 2 pred_bboxes, pred_labels, pred_scores = list(), list(), list() 3 gt_bboxes, gt_labels, gt_difficults = list(), list(), list() 4 for ii, (imgs, sizes, gt_bboxes_, gt_labels_, gt_difficults_) in tqdm(enumerate(dataloader)): 5 sizes = [sizes[0][0].item(), sizes[1][0].item()] 6 pred_bboxes_, pred_labels_, pred_scores_ = faster_rcnn.predict(imgs, [sizes]) 7 gt_bboxes += list(gt_bboxes_.numpy()) 8 gt_labels += list(gt_labels_.numpy()) 9 gt_difficults += list(gt_difficults_.numpy()) 10 pred_bboxes += pred_bboxes_ 11 pred_labels += pred_labels_ 12 pred_scores += pred_scores_ 13 if ii == test_num: break 14 15 result = eval_detection_voc( 16 pred_bboxes, pred_labels, pred_scores, 17 gt_bboxes, gt_labels, gt_difficults, 18 use_07_metric=True) 19 return result
eval()顧名思義,就是一個評估預測結果好壞的函數,展開來看果不其然,首先pred_bboxes,pred_labels,pred_scores ,gt_bboxes,gt_labels,gt_difficults 一開始就定義了這麼多的list列表!它們分別是預測框的位置,預測框的類別和分數以及相應的真實值的類別分數等等!
接下來就是一個for循環,從 enumerate(dataloader)裏面依次讀取數據,讀取的內容是: imgs圖片,sizes尺寸,gt_boxes真實框的位置 gt_labels真實框的類別以及gt_difficults這些
而後利用faster_rcnn.predict(imgs,[sizes]) 得出預測的pred_boxes_,pred_labels_,pred_scores_預測框位置,預測框標記以及預測框的分數等等!這裏的predict是真正的前向傳播過程!完成真正的預測目的!
以後將pred_bbox,pred_label,pred_score ,gt_bbox,gt_label,gt_difficult預測和真實的值所有依次添加到開始定義好的列表裏面去,若是迭代次數等於測試test_num,那麼就跳出循環!調用 eval_detection_voc函數,接收上述的六個列表參數,完成預測水平的評估!獲得預測的結果!這個eval_detection_voc後面會解釋!
2 def train(**kwargs)函數,代碼以下:
1 def train(**kwargs): 2 opt._parse(kwargs) 3 4 dataset = Dataset(opt) 5 print('load data') 6 dataloader = data_.DataLoader(dataset, \ 7 batch_size=1, \ 8 shuffle=True, \ 9 # pin_memory=True, 10 num_workers=opt.num_workers) 11 testset = TestDataset(opt) 12 test_dataloader = data_.DataLoader(testset, 13 batch_size=1, 14 num_workers=opt.test_num_workers, 15 shuffle=False, \ 16 pin_memory=True 17 ) 18 faster_rcnn = FasterRCNNVGG16() 19 print('model construct completed') 20 trainer = FasterRCNNTrainer(faster_rcnn).cuda() 21 if opt.load_path: 22 trainer.load(opt.load_path) 23 print('load pretrained model from %s' % opt.load_path) 24 trainer.vis.text(dataset.db.label_names, win='labels') 25 best_map = 0 26 lr_ = opt.lr 27 for epoch in range(opt.epoch): 28 trainer.reset_meters() 29 for ii, (img, bbox_, label_, scale) in tqdm(enumerate(dataloader)): 30 scale = at.scalar(scale) 31 img, bbox, label = img.cuda().float(), bbox_.cuda(), label_.cuda() 32 trainer.train_step(img, bbox, label, scale)#進行一次參數優化過程 33 34 if (ii + 1) % opt.plot_every == 0: 35 if os.path.exists(opt.debug_file): 36 ipdb.set_trace() 37 38 # plot loss 39 trainer.vis.plot_many(trainer.get_meter_data()) 40 41 # plot groud truth bboxes 42 ori_img_ = inverse_normalize(at.tonumpy(img[0])) 43 gt_img = visdom_bbox(ori_img_, 44 at.tonumpy(bbox_[0]), 45 at.tonumpy(label_[0])) 46 trainer.vis.img('gt_img', gt_img) 47 48 # plot predicti bboxes 49 _bboxes, _labels, _scores = trainer.faster_rcnn.predict([ori_img_], visualize=True) 50 pred_img = visdom_bbox(ori_img_, 51 at.tonumpy(_bboxes[0]), 52 at.tonumpy(_labels[0]).reshape(-1), 53 at.tonumpy(_scores[0])) 54 trainer.vis.img('pred_img', pred_img) 55 56 # rpn confusion matrix(meter) 57 trainer.vis.text(str(trainer.rpn_cm.value().tolist()), win='rpn_cm') 58 # roi confusion matrix 59 trainer.vis.img('roi_cm', at.totensor(trainer.roi_cm.conf, False).float()) 60 eval_result = eval(test_dataloader, faster_rcnn, test_num=opt.test_num) 61 trainer.vis.plot('test_map', eval_result['map']) 62 lr_ = trainer.faster_rcnn.optimizer.param_groups[0]['lr'] 63 log_info = 'lr:{}, map:{},loss:{}'.format(str(lr_), 64 str(eval_result['map']), 65 str(trainer.get_meter_data())) 66 trainer.vis.log(log_info) 67 68 if eval_result['map'] > best_map: 69 best_map = eval_result['map'] 70 best_path = trainer.save(best_map=best_map) 71 if epoch == 9: 72 trainer.load(best_path) 73 trainer.faster_rcnn.scale_lr(opt.lr_decay) 74 lr_ = lr_ * opt.lr_decay 75 76 if epoch == 13: 77 break
這個函數是這篇文章的重點部分,也是整個網絡的訓練部分,首先來看下代碼:
首先是 opt._parse(**kwargs) + dataset = Dataset(opt) 我認爲這個地方就是將調用函數時候附加的參數用config.py文件裏面的opt._parse()進行解釋,而後獲取其數據存儲的路徑,以後放到Dataset裏面!Dataset完成的任務見第一篇博客數據預處理部分,這裏簡單解釋一下,就是用VOCBboxDataset做爲數據讀取庫,而後依次從樣例數據庫中讀取圖片出來,還調用了Transform(object)函數,完成圖像的調整和隨機反轉工做!
而後是dataloader = data_.DataLoader(dataset,batch_size=1,shuffle=True,num_workers=opt.num_workers) 將數據裝載到dataloader中,shuffle=True容許數據打亂排序,num_workers是設置數據分爲幾批處理,一樣的將測試數據集也進行一樣的處理,而後裝載到test_dataloader中!接下來定義faster_rcnn=FasterRCNNVGG16()定義好模型!FasterRCNNVGG16()的參數模型見系列博客的第三篇模型介紹,以後是設置trainer = FasterRCNNTrainer(faster_rcnn).cuda()將FasterRCNNVGG16做爲fasterrcnn的模型送入到FasterRCNNTrainer中並設置好GPU加速,接下來判斷opt.load_path是否存在,若是存在,直接從opt.load_path讀取預訓練模型,而後將訓練數據的label進行可視化操做,以後用一個for循環開始訓練過程,而訓練迭代的次數opt.epoch也在config.py文件中都預先定義好,屬於超參數,接下來看for循環體:
1首先在可視化界面重設全部數據
2而後從訓練數據中枚舉dataloader,設置好縮放範圍,將img,bbox,label,scale所有設置爲可gpu加速
3調用trainer.py中的函數trainer.train_step(img,bbox,label,scale)進行一次參數迭代優化過程!
4 判斷數據讀取次數是否可以整除plot_every(是否達到了畫圖次數),若是達到判斷debug_file是否存在,用ipdb工具設置斷點,調用trainer中的trainer.vis.plot_many(trainer.get_meter_data())將訓練數據讀取並上傳完成可視化!
5將每次迭代讀取的圖片用dataset文件裏面的inverse_normalize()函數進行預處理,將處理後的圖片調用Visdom_bbox(ori_img_,at_tonumpy(_bboxes[0]),at.tonumpy(_labels[0].reshape(-1)),at.tonumpy(_scores[0]))
6調用trainer.vis.img('pred_img',pred_img)將迭代讀取原始數據中的原圖,bboxes框架,labels標籤在可視化工具下顯示出來
7調用 _bboxes,_labels,_socres = trainer.faster_rcnn.predict([ori_img_],visualize=True)調用faster_rcnn的predict函數進行預測,預測的結果保留在以_下劃線開頭的對象裏面
8利用一樣的方法將原始圖片以及邊框類別的預測結果一樣在可視化工具中顯示出來!
9調用train.vis.text(str(trainer.rpn_cm.value().tolist),win='rpn_cm')將rpn_cm也就是RPN網絡的混淆矩陣在可視化工具中顯示出來
10調用trainer.vis.img('roi_cm', at.totensor(trainer.roi_cm.conf, False).float())將Roi_cm將roi的可視化矩陣以圖片的形式顯示出來
===============接下來是測試階段的代碼=============================================================
11 調用eval_result = eval(test_dataloader, faster_rcnn, test_num=opt.test_num)將測試數據調用eval()函數進行評價,存儲在eval_result中
12 trainer.vis.plot('test_map', eval_result['map']) 將eval_result['map']在可視化工具中進行顯示
13 lr_ = trainer.faster_rcnn.optimizer.param_groups[0]['lr'] 設置學習的learning rate
14log_info = 'lr:{}, map:{},loss:{}'.format(str(lr_),str(eval_result['map']),str(trainer.get_meter_data())) + trainer.vis.log(log_info) 將損失學習率以及map等信息及時顯示更新
15 用if判斷語句永遠保存效果最好的map!
16 if判斷語句若是學習的epoch達到了9就將學習率*0.1變成原來的十分之一
17 判斷epoch==13結束訓練驗證過程
能夠看出,其實train.py文件裏大多數都是爲可視化部分作了詳細的設置,代碼基本上都是圍繞着可視化來進行的,最後,做爲本篇博客的結束,貼一個做者運行時可視化的截圖吧!
能夠更好的方便你們理解爲何要這麼設置,代碼對應的可視化部分都有哪些:
至此,Faster-RCNN的pytorch簡化版本的整個訓練過程的代碼就解釋完了,若是對你還有點啓發的話就寫個留言鼓勵一下吧~若是以爲哪裏有問題,歡迎留言指出哦!純手打,不免有誤,多多包含謝謝你們!