您的位置:首页 > 其它

Faster R-CNN 训练源码学习笔记

2018-01-07 20:47 411 查看
Faster R-CNN训练脚本:.\experiments\script_faster_rcnn_VOC2007_ZF.m文件

function script_faster_rcnn_VOC2007_ZF()
% script_faster_rcnn_VOC2007_ZF()
% Faster rcnn training and testing with Zeiler & Fergus model
% --------------------------------------------------------
% Faster R-CNN
% Copyright (c) 2015, Shaoqing Ren
% Licensed under The MIT License [see LICENSE for details]
% --------------------------------------------------------

clc;
clear mex;
clear is_valid_handle; % to clear init_key
run(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'startup'));
%% -------------------- CONFIG --------------------
opts.caffe_version          = 'caffe_faster_rcnn';
opts.gpu_id                 = auto_select_gpu;
active_caffe_mex(opts.gpu_id, opts.caffe_version);

% do validation, or not
opts.do_val                 = true;
% model
model                       = Model.ZF_for_Faster_RCNN_VOC2007;
% cache base
cache_base_proposal         = 'faster_rcnn_VOC2007_ZF';
cache_base_fast_rcnn        = '';
% train/test data
dataset                     = [];
use_flipped                 = true;
dataset                     = Dataset.voc2007_trainval(dataset, 'train', use_flipped);
dataset                     = Dataset.voc2007_test(dataset, 'test', false);

%% -------------------- TRAIN --------------------
% conf
conf_proposal               = proposal_config('image_means', model.mean_image, 'feat_stride', model.feat_stride);
conf_fast_rcnn              = fast_rcnn_config('image_means', model.mean_image);
% set cache folder for each stage
model                       = Faster_RCNN_Train.set_cache_folder(cache_base_proposal, cache_base_fast_rcnn, model);
% generate anchors and pre-calculate output size of rpn network
[conf_proposal.anchors, conf_proposal.output_width_map, conf_proposal.output_height_map] ...
= proposal_prepare_anchors(conf_proposal, model.stage1_rpn.cache_name, model.stage1_rpn.test_net_def_file);

%%  stage one proposal
fprintf('\n***************\nstage one proposal \n***************\n');
% train
model.stage1_rpn            = Faster_RCNN_Train.do_proposal_train(conf_proposal, dataset, model.stage1_rpn, opts.do_val);
% test
dataset.roidb_train        	= cellfun(@(x, y) Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage1_rpn, x, y), dataset.imdb_train, dataset.roidb_train, 'UniformOutput', false);
dataset.roidb_test        	= Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage1_rpn, dataset.imdb_test, dataset.roidb_test);

%%  stage one fast rcnn
fprintf('\n***************\nstage one fast rcnn\n***************\n');
% train
model.stage1_fast_rcnn      = Faster_RCNN_Train.do_fast_rcnn_train(conf_fast_rcnn, dataset, model.stage1_fast_rcnn, opts.do_val);
% test
opts.mAP                    = Faster_RCNN_Train.do_fast_rcnn_test(conf_fast_rcnn, model.stage1_fast_rcnn, dataset.imdb_test, dataset.roidb_test);

%%  stage two proposal
% net proposal
fprintf('\n***************\nstage two proposal\n***************\n');
% train
model.stage2_rpn.init_net_file = model.stage1_fast_rcnn.output_model_file;
model.stage2_rpn            = Faster_RCNN_Train.do_proposal_train(conf_proposal, dataset, model.stage2_rpn, opts.do_val);
% test
dataset.roidb_train       	= cellfun(@(x, y) Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage2_rpn, x, y), dataset.imdb_train, dataset.roidb_train, 'UniformOutput', false);
dataset.roidb_test       	= Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage2_rpn, dataset.imdb_test, dataset.roidb_test);

%%  stage two fast rcnn
fprintf('\n***************\nstage two fast rcnn\n***************\n');
% train
model.stage2_fast_rcnn.init_net_file = model.stage1_fast_rcnn.output_model_file;
model.stage2_fast_rcnn      = Faster_RCNN_Train.do_fast_rcnn_train(conf_fast_rcnn, dataset, model.stage2_fast_rcnn, opts.do_val);

%% final test
fprintf('\n***************\nfinal test\n***************\n');

model.stage2_rpn.nms        = model.final_test.nms;
dataset.roidb_test       	= Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage2_rpn, dataset.imdb_test, dataset.roidb_test);
opts.final_mAP              = Faster_RCNN_Train.do_fast_rcnn_test(conf_fast_rcnn, model.stage2_fast_rcnn, dataset.imdb_test, dataset.roidb_test);

% save final models, for outside tester
Faster_RCNN_Train.gather_rpn_fast_rcnn_models(conf_proposal, conf_fast_rcnn, model, dataset);
end

function [anchors, output_width_map, output_height_map] = proposal_prepare_anchors(conf, cache_name, test_net_def_file)
[output_width_map, output_height_map] ...
= proposal_calc_output_size(conf, test_net_def_file);
anchors                = proposal_generate_anchors(cache_name, ...
'scales',  2.^[3:5]);
end


1、初始准备

clc;
clear mex; %清理mex文件
clear is_valid_handle; % to clear init_key
run(fullfile(fileparts(fileparts(mfilename('fullpath'))), 'startup'));%运行根目录下的startup.m文件,添加搜索路径,创建目录。


2、配置

%% -------------------- CONFIG --------------------
opts.caffe_version          = 'caffe_faster_rcnn';%caffe路径:external\caffe\matlab\caffe_faster_rcnn
opts.gpu_id                 = auto_select_gpu;  %自动选择显存最大的一个显卡,返回其显卡索引号
active_caffe_mex(opts.gpu_id, opts.caffe_version); %激活caffe

% do validation, or not
opts.do_val                 = true; %使用验证。就是在训练过程中通过验证集测评模型的表现
% model
model                       = Model.ZF_for_Faster_RCNN_VOC2007;%模型配置,这个在experiments\+Model目录下
% cache base
cache_base_proposal         = 'faster_rcnn_VOC2007_ZF';%与缓存文件的文件名有关
cache_base_fast_rcnn        = '';
% train/test data
dataset                     = [];
use_flipped                 = true; 	%使用“翻转”,就是将训练集通过水平翻转图像以实现数据增强。
dataset                     = Dataset.voc2007_trainval(dataset, 'train', use_flipped);%训练集和测试集信息
dataset                     = Dataset.voc2007_test(dataset, 'test', false);

  在这里,dataset包含train和test两部分,其中每部分又包括imdb和roidb两部分。这些会保存在目录:imdb\cache



以imdb_train为例,其包括的主要信息(这里面没有图像的实际数据,更多是一些索引和路径):



3、训练准备

%% -------------------- TRAIN --------------------
% conf
conf_proposal               = proposal_config('image_means', model.mean_image, 'feat_stride', model.feat_stride);
conf_fast_rcnn              = fast_rcnn_config('image_means', model.mean_image);
% set cache folder for each stage
model                       = Faster_RCNN_Train.set_cache_folder(cache_base_proposal, cache_base_fast_rcnn, model);
% generate anchors and pre-calculate output size of rpn network
[conf_proposal.anchors, conf_proposal.output_width_map, conf_proposal.output_height_map] ...
= proposal_prepare_anchors(conf_proposal, model.stage1_rpn.cache_name, model.stage1_rpn.test_net_def_file);

conf_proposal函数是proposal的配置文件,详见faster_rcnn\functions\rpn\proposal_config.m文件。conf_fast_rcnn同理。所谓set_cache_folder是只设置模型训练过程中的缓存目录,详见experiments\+Faster_RCNN_Train\set_cache_folder.m。比如output\rpn_cachedir\faster_rcnn_VOC2007_ZF_stage1_rpn这种目录。

proposal_prepare_chahors函数是训练脚本文件内部定义的函数(如下),它调用了两个函数:一个是proposal_calc_output_size函数,详见functions\rpn\proposal_calc_output_size.m,是建立网络输入图像的尺度(宽高)与其输出数据的尺度之间的映射关系,比如,输入一个600*800图像,conv_5层输出39*51的特征图,那么一对数据就是一条映射。proposal_generate_anchors函数详见functions\rpn\proposal_generate_anchors.m,是生成9(三种尺度,三种比例)个anchors的。

function [anchors, output_width_map, output_height_map] = proposal_prepare_anchors(conf, cache_name, test_net_def_file)
[output_width_map, output_height_map] ...
= proposal_calc_output_size(conf, test_net_def_file);
anchors                = proposal_generate_anchors(cache_name, ...
'scales',  2.^[3:5]);
end


4、训练: stage one proposal

训练分为两个阶段(stage),每个阶段又分为训练rpn和训练fast rcnn,因此总共四块。这里介绍第一阶段的rpn训练。该网络用ImageNet预训练的模型初始化,并端到端微调用于区域建议任务。

%%  stage one proposal
fprintf('\n***************\nstage one proposal \n***************\n');
% train
model.stage1_rpn            = Faster_RCNN_Train.do_proposal_train(conf_proposal, dataset, model.stage1_rpn, opts.do_val);
% test
dataset.roidb_train        	= cellfun(@(x, y) Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage1_rpn, x, y), dataset.imdb_train, dataset.roidb_train, 'UniformOutput', false);
dataset.roidb_test        	= Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage1_rpn, dataset.imdb_test, dataset.roidb_test);

训练通过Faster_RCNN_Train的类函数do_proposal_train进行,该函数详见experiments\+Faster_RCNN_Train\do_proposal_train.m,该函数进一步调用functions\rpn目录下的proposal_train函数。proposal_train函数代码很长,这里不直接引用。按照作者的注解,该函数首先是配置,然后尝试寻找已经训练好的模型,之后进行初始化(包括打开日志,和caffe的相关初始化),然后准备训练数据和验证数据的信息(尚未开始读入图像),之后检查GPU显存是不是足够,最后就是训练(在迭代次数达到之前,一直进行训练。每次训练前,先根据索引读入minibatch的数据,然后执行训练步骤。而且还要检查是否执行验证,是否打印快照(保存中间模型))。最终,保存模型,关闭日志,重置caffe。

下面调用do_proposal_test函数执行两个测试,一是对训练集,二是对测试集。函数运行的结果是:dataset.roidb_train和dataset.roidb_test得到更新(更新后的数据集用于下一步训练fast rcnn):



这里附录do_proposal_test函数的部分(通过test过程生成的anchors,作为训练fast rcnn的输入数据):

function roidb_new = do_proposal_test(conf, model_stage, imdb, roidb)
aboxes                      = proposal_test(conf, imdb, ...
'net_def_file',     model_stage.test_net_def_file, ...
'net_file',         model_stage.output_model_file, ...
'cache_name',       model_stage.cache_name); %每张图像生成约20000个数量级的anchors。

aboxes                      = boxes_filter(aboxes, model_stage.nms.per_nms_topN, model_stage.nms.nms_overlap_thres, model_stage.nms.after_nms_topN, conf.use_gpu);    %过滤box,其数目降为2000数量级。

roidb_regions               = make_roidb_regions(aboxes, imdb.image_ids);

roidb_new                   = roidb_from_proposal(imdb, roidb, roidb_regions, ...
'keep_raw_proposal', false);
end


5、训练:stage one fast rcnn

利用第一步的RPN生成的建议框,由Fast R-CNN训练一个单独的检测网络,这个检测网络同样是由ImageNet预训练的模型初始化的,这时候两个网络还没有共享卷积层。

%%  stage one fast rcnn
fprintf('\n***************\nstage one fast rcnn\n***************\n');
% train
model.stage1_fast_rcnn      = Faster_RCNN_Train.do_fast_rcnn_train(conf_fast_rcnn, dataset, model.stage1_fast_rcnn, opts.do_val);
% test
opts.mAP                    = Faster_RCNN_Train.do_fast_rcnn_test(conf_fast_rcnn, model.stage1_fast_rcnn, dataset.imdb_test, dataset.roidb_test);

训练fast rcnn的代码与训练rpn的代码相似。这里do_fast_rcnn_train用于训练,do_fast_rcnn_test用于测试,返回mAP(mean average precision)。参考models\fast_rcnn_prototxts\ZF\train_val.prototxt,可知训练时网络
b278
的输入数据有5个,分别是:data(输入图像数据),rois(输入包围盒坐标及其类别数据),labels(类别的标签),bbox_targets(包围盒的标签),bbox_loss_weights(包围盒损失权重)。在这里,其维度分别是:800*600*3*2(2代表每批包含两张图像),1*1*5*128,1*1*1*128,1*1*8*128,1*1*8*128。后两个维度里面的“8”是随着类别数量变化的,如果类别是k,则这里的维度为4*(k+1)。我这里k=1,因此维度为8。

6、训练:stage two proposal

开始第二阶段的训练。

%%  stage two proposal
% net proposal
fprintf('\n***************\nstage two proposal\n***************\n');
% train
model.stage2_rpn.init_net_file = model.stage1_fast_rcnn.output_model_file;
model.stage2_rpn            = Faster_RCNN_Train.do_proposal_train(conf_proposal, dataset, model.stage2_rpn, opts.do_val);
% test
dataset.roidb_train       	= cellfun(@(x, y) Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage2_rpn, x, y), dataset.imdb_train, dataset.roidb_train, 'UniformOutput', false);
dataset.roidb_test       	= Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage2_rpn, dataset.imdb_test, dataset.roidb_test);


与stage one proposal 不同的主要有两个地方:一是用stage one fast rcnn训练后的模型参数来初始化stage two proposal的模型;二是将训练时模型文件换成models\fast_rcnn_prototxts\ZF_fc6\train_val.prototxt,目的是固定卷积层,只微调RPN独有的层。ZF_fc6目录下的模型与ZF目录下的模型的区别在于:前者将前面的卷积层的学习率设置为0(如下图),那么在训练网络时,这里的参数就不会更新了。



之后,同样用这一步训练好的RPN生成一些建议框,用于下一步训练fast rcnn

7、训练:stage two fast rcnn

第二阶段的fast rcnn训练。

%%  stage two fast rcnn
fprintf('\n***************\nstage two fast rcnn\n***************\n');
% train
model.stage2_fast_rcnn.init_net_file = model.stage1_fast_rcnn.output_model_file;
model.stage2_fast_rcnn      = Faster_RCNN_Train.do_fast_rcnn_train(conf_fast_rcnn, dataset, model.stage2_fast_rcnn, opts.do_val);

类似地,它也是用stage one fast rcnn的训练好的模型参数初始化自己的网络模型,也是固定卷积层,只微调其全连接层。

8、最终测试

最终测试,用于评估本次训练的模型的表现。

%% final test
fprintf('\n***************\nfinal test\n***************\n');

model.stage2_rpn.nms        = model.final_test.nms;
dataset.roidb_test       	= Faster_RCNN_Train.do_proposal_test(conf_proposal, model.stage2_rpn, dataset.imdb_test, dataset.roidb_test);
opts.final_mAP              = Faster_RCNN_Train.do_fast_rcnn_test(conf_fast_rcnn, model.stage2_fast_rcnn, dataset.imdb_test, dataset.roidb_test);


9、保存最终模型

% save final models, for outside tester
Faster_RCNN_Train.gather_rpn_fast_rcnn_models(conf_proposal, conf_fast_rcnn, model, dataset);
end

比如,最终模型保存在:output\faster_rcnn_final\faster_rcnn_VOC2007_ZF\,内容如图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: