记一次faster-rcnn debug记录

问题描述

一年debug 三次faster rcnn,每次都有新感觉(不

接到一个bug report,现象为某人脸模型,转换成trt模型,当batch size为1时结果完全正确,但是batch size大于1时结果不正确。 具体的现象是,如果跑多张不同的图,只有第一张图有结果,后面的图都没有结果。 如果跑的图中有相同的,那么和第一张相同的图都会有结果,其余的图没有结果。

 1layer {
 2  name: "POD_proposal"
 3  type: "RPRoIFused"
 4  bottom: "Reshape_105"
 5  bottom: "Conv_100"
 6  bottom: "Add_95"
 7  bottom: "im_info"
 8  top: "rois"
 9  top: "tmp_pooling"
10  rpn_proposal_param{
11    feat_stride: 16
12    anchor_ratios: 1
13    anchor_scales: 1
14    anchor_scales: 2
15    anchor_scales: 4
16    anchor_scales: 8
17    anchor_scales: 16
18    anchor_scales: 32
19    test_desc_param {
20        rpn_pre_nms_top_n: 2000
21        rpn_post_nms_top_n: 50
22        rpn_min_size: 16
23        rpn_nms_thresh: 0.7
24    }
25  }
26
27  roi_pooling_param{
28    pooled_h: 7
29    pooled_w: 7
30    spatial_scale: 0.0625
31
32  }
33}
34
35

特别地,proposal layer中 rpn_post_nms_top_n的参数值如果使用默认的300,那么结果都是对的。把这个值改小(只要小于300),结果就像上面所述。

debug 经过

首先根据rpn_post_nms_top_n的值一修改,结果就是错的来看,怀疑是哪里参数写死了。 然而很快就排除了这个问题。因为faster rcnn的模型已经在另一个产品中经过长期验证了。 而且proposal layer是tensorrt自己实现的,有bug早就有人发现了。

然后根据batch size为1时结果正确,但是batch size大于1时结果错误来看,怀疑是proposal layer前面rpn做的softmax的维度 不太对。 因为rpn前景和背景的得分有两种不同的排列方式 可能是

1+ + + + + +
2- - - - - -

也可能是

1+ - + - + -
2+ - + - + -

其中‘+’代表前景,‘-’代表背景。

前者的排列方式在softmax前的维度应该是 N×2×A×H×W

后者的排列方式在softmax前的维度应该是 N×A×2×H×W

其中N为batch size,A为anchor的个数。

排查发现pytorch模型的输出是后者的排列方式,而tensorrt proposal layer期望的排列方式是前者,也就是N×2×A×H×W

所以在做softmax之前要先permute 一下

 1
 2layer {
 3  name: "tmp_add_for_continue"
 4  type: "Permute"
 5  bottom:"Reshape_102"
 6  top:"tmp_add_for_continue"
 7  permute_param {
 8    order: 0
 9    order: 2
10    order: 1
11    order: 3
12  }
13}
14
15layer {
16  name: "Softmax_103"
17  type: "Softmax"
18  bottom: "tmp_add_for_continue"
19  top: "Softmax_103"
20  softmax_param {
21    axis:1
22  }
23}
24

但是。。这里,之前已经做了啊。。。 就是说其实已经考虑到前景背景排列不一致的问题了。。。

然后根据一个batch中,和第一张图片相同的图片也是有结果的。。 怀疑是nms或者哪里做sort的时候,交换没写对。。

按照之前debug faster rcnn 的经验,看一下roi的输出吧。 结果发现把同一张图,分别放在一个batch的不同位置,roi的输出是一致的。 。。。这说明proposal 似乎是没问题的?

尝试将roi_align换成roi_pooling... 发现结果似乎也是没问题的。。。

所以是roi_align 的实现有问题?

于是看了下caffe cuda的实现 发现里面有个叫num_roi_per_image的东西。。。

?????

 1template <typename T>
 2__global__ void RoIAlignForwardKernel(
 3    const int nthreads,
 4    const T* bottom_data,
 5    const T spatial_scale,
 6    const bool position_sensitive,
 7    const int channels,
 8    const int height,
 9    const int width,
10    const int pooled_height,
11    const int pooled_width,
12    const int sampling_ratio,
13    const int num_roi_per_image,
14    const T* bottom_rois,
15    T* top_data) {
16  CUDA_KERNEL_LOOP(index, nthreads) {
17    // (n, c, ph, pw) is an element in the pooled output
18    int pw = index % pooled_width;
19    int ph = (index / pooled_width) % pooled_height;
20    int c = (index / pooled_width / pooled_height) % channels;
21    int n = index / pooled_width / pooled_height / channels;
22
23//    const T* offset_bottom_rois = bottom_rois + n * 5;
24    const T* offset_bottom_rois = bottom_rois + n * 4;
25    int roi_batch_ind = n / num_roi_per_image;

int roi_batch_ind = n / num_roi_per_image;

这什么鬼了。。 于是跑去看caffe.proto。。。。 果然。。。

1message RoIAlignParameter {
2  optional uint32 pooled_h = 1 [default = 0];
3  optional uint32 pooled_w = 2 [default = 0];
4  optional float spatial_scale = 3 [default = 1];
5  optional int32 sample_ratio = 4 [default = -1];
6  optional bool position_sensitive = 5 [default = false];
7  optional uint32 num_roi_per_image = 6 [default = 300];
8}

这个num_roi_per_image有个默认值。。。跪了。。

所以当修改 rpn_post_nms_top_n 的时候,由于这个默认值一直是300 所以就会把后面若干图片的roi都当成第一张图的roi来处理。。

经验总结

caffe的源码还是要看的。。。

希望2020年可以看完orz