将FPN中的一些层改成C++

因为需要用C++的代码跑测试,因而需要将prototxt中一些原来用python写的层改成c++格式。

之前跑faster rcnn的时候,将rpn层参考博客修改过,但是因为对源码不了解,这次改三个层无从下手,下面记录一下过程。需要修改的三个层分别为rpn-data,roi-data和proposal层。

rpn-data:

layer {
  name: 'rpn-data'
  type: 'Module'
  bottom: 'rpn_cls_score/p2'
  bottom: 'rpn_cls_score/p3'
  bottom: 'rpn_cls_score/p4'
  bottom: 'rpn_cls_score/p5'
  bottom: 'rpn_cls_score/p6'
  bottom: 'gt_boxes'
  bottom: 'im_info'
  top: 'rpn_labels'
  top: 'rpn_bbox_targets'
  top: 'rpn_bbox_inside_weights'
  top: 'rpn_bbox_outside_weights'
  module_param {
    module: "modules"
    type: "FPNAnchorTarget"
    param_str: "{ 'feat_strides': [4,8,16,32,64] }"
  }
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
}

roi-data:

layer {
  name: 'roi-data'
  type: 'Module'
  bottom: 'rpn_rois'
  bottom: 'gt_boxes'
  top: 'rois/h2'
  top: 'rois/h3'
  top: 'rois/h4'
  top: 'rois/h5'
#  top: 'rois/h6'
  top: 'labels'
  top: 'bbox_targets'
  top: 'bbox_inside_weights'
  top: 'bbox_outside_weights'
  propagate_down: 0
  propagate_down: 0
  module_param {
    module: 'modules'
    type: 'FPNProposalTarget'
  }
}

proposal:

layer {
  name: 'proposal'
  type: 'Module'
  bottom: 'fpn_out_reshape/p2'
  bottom: 'rpn_bbox_pred/p2'
  bottom: 'fpn_out_reshape/p3'
  bottom: 'rpn_bbox_pred/p3'
  bottom: 'fpn_out_reshape/p4'
  bottom: 'rpn_bbox_pred/p4'
  bottom: 'fpn_out_reshape/p5'
  bottom: 'rpn_bbox_pred/p5'
  bottom: 'fpn_out_reshape/p6'
  bottom: 'rpn_bbox_pred/p6'
  bottom: 'im_info'
  top: 'rpn_rois'
  module_param {
    module: 'modules'
    type: 'FPNProposal'
    param_str: "{'feat_strides': [4,8,16,32,64]}"
  }
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  propagate_down: 0
  include { phase: TRAIN }
}

注意到其中的module_param和model的'modules'都是需要根据实际情况改掉的。在调用module_param的地方,调用方法为this->layer_param_.module_param(),而直接编译caffe的时候是无法通过编译的,会报找不到module_param()的error。分析了源码,发现代码中使用YAML解析结构(在faster rcnn中为用LayerParameter直接定义解析参数,之后也可以尝试用这种方法),因此需要在caffe.proto里添加Moduleparameter。

(虽然yaml-cpp安装成功了,但是还是报错undefined yaml,所以打算尝试上面的方法:

  1.   (备份后)将train和test的pt里的module_param更改成fpn_param
  2. 在caffe.proto里添加parameter,FPNParameter fpn_param;然后发现,根据caffe.proto中,参数的类型不同,会在caafe.pb.h和.cc中自动生成不同的参数。对于optional变量,会生成has_xx,对于repeated变量,会生成xx.size(),可以对比dummy_data_layer.cpp和pooling_layer.cpp两个文件,而生成参数的主要作用是用来在.cpp中取值的时候做判断)

事实上尝试失败了,因为没有搞清楚层与层之间的关系

 

该prototxt在roi_pooling层只写了一个feat_strides,而实际上在Faster Rcnn中,还需要anchor_scales和anchor_ratios。因此查看了fpn_proposal_layer.cpp,发现其中的结构是,如果pt中为空,则自动设置。(可以在后期加在prototxt中修改试一试)

 

另外可以看到,在roi-data层中,c++版本是没有另外传入参数的,而python版本是添加了num_class参数。然后发现该n_class参数是在frcnn_param里传入的,而里面的参数是从脚本中parse出来的,因此不需要在这里设置了。

 

另外,在fpn_proposal_layer.cu里,有cub/cub.cuh,找不到文件,所以先注释掉了。

 

================分界线======================

11.07 我又回来了,并搞明白了几个问题,为:

  1. cub.cub.cuh为cuda的一个头文件。

  2. c++版本中的另外添加参数,是在输入层用window_data这个层传入进来的。而我之前的思路是要把train的pt文件中python层也改成c++,于是我一开始的思路是把所需要的参数全部传进来,而现在思路更改为只需要改test的pt文件中的python层为c++格式,这种情况下只需要把cfg中在此调用的参数重新传进来就行了。

 

那么,在此重新分析一下逻辑:

1.首先要找到需要更改的python层,并简要分析

test的prototxt里,Python层为「input-data」,「rpn-data」,「proposal」,「roi-data」

test的prototxt里,Python层为「proposal」,「as-rois」

在这里的proposal层在python中调用的是(rpn.proposal_layer),roi-data是(rpn.proposal_target_layer),as-rois是(rpn.as_rois)。

自此可以看出,需要更改的只有propsal层和as-rois层。那么我们去看python文件。

2.分析as-rois层

打开python的这个文件,可以看到该层调用的外部函数只有config.py函数,并只用了其中的「cfg.TEST.RPN_POST_NMS_TOP_N」这一个参数变量,而该层的作用是将proposal和gt对比,并分类,那么该层应该还是挺好改的,因为只涉及了自己一个脚本文件。

3.分析propsal

这个文件调用的函数比较多,而python中把调用的函数写在了多个文件中,画个表表示:

调用的脚本及其函数
fast_rcnn.configcfg
generate_anchorsgenerate_anchors
fast_rcnn.bbox_transformbbox_transform_inv , clip_boxes
fast_rcnn.nms_wrappernms

参照之前修改的rpn的c++文件,其将这些函数写在了一个c++文件中。

4.分析Faster Rcnn和FPN的python脚本文件

主要去看了proposal_layer这个文件,其中区别最大的是FPN是有多个feat_stride,而Faster Rcnn只有一个,其他的函数基本一样。

 

分析完需要修改的文件后,整理一下需要了解的背景知识:

1.Python层的逻辑

Python中每个class需要有四个层,分别为『setup』、『forward』、『backward』、『reshape』。如果有其他需要的函数,可以在class外面定义。

其中backward的参数为(self,top,propagate_down,bottom),其他三个为(self,top,bottom)。

bottom和top的参数顺序根据prototxt中顺序决定。

2.C++层的逻辑

c++中逻辑比较麻烦,因为要头文件定义很多参数。

3.Python层的一些参数解释

im_info:bottom[0].data[0,:],存放的是(height , width , scale)

4.caffe层的一些参数解释

blob中的一些函数

常用的math函数

caffe_set:用参数alpha对参数Y进行初始化

template <typename Dtype>
void caffe_set(const int N, const Dtype alpha, Dtype* Y) {
  if (alpha == 0) {
    memset(Y, 0, sizeof(Dtype) * N);  // NOLINT(caffe/alt_fn)
    return;
  }
  for (int i = 0; i < N; ++i) {
    Y[i] = alpha; 
  }
}

caffe_axpy:Y=alpha*X+Y ,N为X和Y中element个数

template <>
void caffe_axpy<float>(const int N, const float alpha, const float* X,
    float* Y) { cblas_saxpy(N, alpha, X, 1, Y, 1); }

CopyFrom()

template <typename Dtype>
void Blob<Dtype>::CopyFrom(const Blob& source, bool copy_diff, bool reshape) {
}
//从source 拷贝数据 , copy_diff控制是拷贝diff还是data

 _axpy:

 

================分界线======================

11.08 我又回来了,出现了一些问题:

我测试了之前该rpn的faster rcnn,发现直接跑测试是无法跑的,但是直接detect是可以的,问题出在blob的尺寸问题上,目前还没有解决。

猜测原因是config脚本设置的问题

解决思路

1.查看rpn的top格式

2.查看roipooling的bottom格式

 

================分界线======================

11.09 我又回来了,解决问题了!!!哭了哭了

昨天确定出错的位置在于,c++版本用blob传递信息(虽然python也是),但是很坑很关键的一点是,python中很多地方是用numpy计算的,而as we all know,blob是四维的,于是在我使用的环境下,就是在test.py脚本中,根据rois得到的boxes,调用了bbox_transform_inv函数,由于用到了其本身的数据类型和blob的类型,四维和二维不匹配于是出错了。

在test脚本中,net.blob['rois'].data.shape可以查看rois的维度,查到是四维。而实际上没改C++版本之前,传递的该参数维度是二维,很巧和的是,前者shape为[1,5,1,1],后者为[1,5],于是我就分别去看c++和python的rpn层文件,发现c++层在最后reshape成了4维。于是经我不缜密的猜测,最后两位数据其实只是为了对其的,其实没有用,也就是说,只需要在python文件中需要rois的地方,把原数据的前两维拷贝就好了

解决方法也很简单,在test.py中用到rois的地方(boxes)的shape改掉:

rois = net.blobs['rois'].data.copy()
boxes = rois[:,1:5] / im_scales[0]
box_min_resize = min(cfg.TEST.RPN_POST_NMS_TOP_N,boxes.shape[0])
boxes.resize([box_min_resize,4])

 

接下来就开始搞as_rois.py了,github上没有对应的层真的哭了!!本来计划周日稍微改改就能跑的c++模型,没想到搞到了今天,低估了工作量但是对caffe 的这几个层的了解更深刻了。。。

 

================分界线======================

11.13 我又回来了,全部改好并且能跑了,问题就是结果不对- -

记录一些问题

1.一开始把vector的变量定义在.hpp中,然后在cpp中操作,这造成一个问题,就是运行速度会越来越慢,可能造成了内存泄漏没有清理空间。于是我用了一个简单的方法就是把hpp中定义的变量放cpp中定义了,这样就相当于他在程序运行结束后就自动销毁了。

2.如果添加cpp层需要make clean,如果只是修改cpp层,不需要make clean

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值