记一次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