Faster rcnn代码理解(2)
接着上篇的博客,咱们继续看一下Faster RCNN的代码~
上次大致讲完了Faster rcnn在训练时是如何获取imdb和roidb文件的,主要都在train_rpn()的get_roidb()函数中,train_rpn()函数后面的部分基本没什么需要讲的了,那我们再回到训练流程中来:
这一步训练的网络结构见下图:
训练的第一步就这么完成了(RPN网络使用gt_roidb训练完成),还有,这里的train_rpn()函数中有涉及到train_net()函数,即用来训练得到网络模型,我会在训练fast rcnn时给出讲解;之后再进行第二步:
产生proposal的网络结构如下:
这一步是利用上一步训练好的RPN网络来生成proposals供下一步中的fast rcnn训练,这里补充一下,字典mp_kwargs中的参数solver,是使用get_solvers()函数得到的,见下:
由上图可知,四步训练时的网络结构都在相应的四个solver文件有解释。好了回到训练流程中,产生proposal的函数是rpn_generate()函数,那我们进入这个函数:
首先设置了什么预NMS(不太懂),还有就是经过NMS后产生2000个proposals,然后初始化caffe,再用get_imdb()函数得到imdb数据,方法和前面一样,再用caffe.NET()加载RPN网络,再使用imdb_proposals()得到proposal,那我们就进入这个函数:
该函数的作用就是在所有的图片上生成proposal,不过作者又嵌套了一个im_proposals()函数,即在一张图片上产生proposals(这个嵌套看似多余,但是为后面再添一些测试脚本提供了方便,我猜rgb大神可能有这个目的),进入im_proposals()函数中:
见上图,首先用_get_image_blob()函数将图片数据转换为caffe的blob格式,进入该函数:
最终得到的blob格式为(batch elem , channel , height , width),im_info格式为[M,N,im_scale],其中im_scale是缩放比例,原始图片输入faster rcnn中进行训练时都需要先缩放成统一的规格;再回到im_proposals()函数中,使用net.forward()函数进行一次前向传播,获得proposals,ok。之后再回到imdb_proposals()函数中,最后返回得到的imdb_boxes,即我们从RPN上产生的proposals。再回到rpn_generate()函数中,接着就是将生成的proposals保存并传输到多线程中去供下一步训练使用,这个函数使命就暂时完成了;
再到第三步,训练fast rcnn网络,见下:
这一步训练的网络结构如下图:
注意这时候训练fast rcnn的roi就是前面训练好的RPN网络生成的proposals了(训练RPN网络用的是gt框),相关配置都在mp_kwargs字典中,很明显,我们要进入train_fast_rcnn()中一探究竟:
这里首先设置了训练使用的rpn_roidb方法(RPN用的是gt_roidb方法),由于这时候的cfg.TRAIN.PROPOSAL_METHOD变成了rpn_roidb,所以相应的使用的get_roidb()也相应地改变,此时使用rpn_roidb()方法,进入该函数:
该方法首先先获得gt_roidb,然后再用_load_rpn_roidb()获得由RPN产生的roidb,进入该函数:
接着进入create_roidb_from_box_list()函数中:
这个函数凸显了数据结构的重要性,我们需要重点关注一下这其中'gt_overlaps'、'argmaxes'、'maxes'、'overlaps'、'I'的结构,对于理解这个函数费仲重要,最好在纸上写出来~将RPN产生的proposal制作成roidb后,再回到rpn_roidb()中,使用merge_roidbs()将gt_roidb和rpn_roidb进行组合,见该函数:
这样子就得到了最终训练fast rcnn所需要的roidb数据,ok~再回到train_fast_rcnn()中,接着我们就来看看train_net()这个函数,进入该函数:
首先是使用filter_roidb()对之前产生的用于训练fast_rcnn的roidb再进行一次筛选,具体过程参见该筛选函数:
筛选过之后,再回到train_net()函数中,创建一个solverWrapper对象,其中就是训练得到的网络模型,进入这个类中:
上图是它的类定义中的一部分,我们先来看看它的初始化函数,这里需要注意的是add_bbox_regression_targets()这个函数,它的作用是为RPN产生的proposal提供回归属性,该函数向roidb中再添加一个key:'bbox_targets',它的格式如:targets[][5]:第一个元素是label,后面四个元素就是论文中谈及的tx,ty,tw,th;好的,我们进入这个函数:
上图是改函数的前半部分,主要看_compute_targets()函数,它产生了回归属性,进入该函数:
产生了回归属性,OK,再回到add_bbox_regression_targets()函数中,看后面剩下的部分:
这部分主要得到rpn_roidb的坐标的均值和方差,可以用来进行坐标归一化;OK,再回到SolverWrapper类中,剩下的则是snapshot快照方法,和train_model方法,回到train_net()函数中,接着再调用train_model()方法,进入该函数:
上图的函数就是使用SGD得到训练模型也就是我们需要的fast_rcnn网络模型,好了,train_net()函数就介绍到这儿了~
再回到train_fast_rcnn()函数中,剩下的都是保存之类的,那我们再回到训练流程中,剩下的几步训练流程就如法炮制了,见下:
这两步训练的网络结构见下图:
这一步训练的网络结构见下图:
这样子,就通过分步训练得到了最终的网络模型,最后就是一些收尾工作了:
好了,终于全部弄完,接下来我们就来看作者在网络结构中添加的那几层了~
(转载请注明出处)