crnn pytorch转libtorch转trt问题记录--------libtorch的data_ptr()方法不同版本变化了
大坑!!!
首先发现这个问题的时候是在libtorch1.1版本上面没有问题的代码,移植到高版本libtorch1.7,发现同样的代码在高版本上面精度不一样。然后查找原因的时候发现的。
运行代码发现没有显存累加情况但是精度不对,不能出效果图。之前的环境虽然存在显存累加问题但是精度是对的可以出效果图。查找问题,先查找trt推理出来的结果发现对不上,再查找输入发现对的上。这里我都是对比的libtorch的tensor里面数值。
然后我再对比之前一开始写的测试代码,没有用libtorch的,就只用全1的矩阵输入作为输入给trt推理,对比pytorch和trt结果,发现是可以对的上的。说明trt只要输入和pytorch一致输出就一致,在这个配置环境下是没有问题的。但是为啥加了libtorch就不一样了。然后再去libtorch代码找原因。
在数据预处理之后是
void* input = tensor_image.data_ptr();
用libtorch的tensor类型的提供的数据指针data_ptr()给trt的。然后我对这个指针取出前100个,和之前libtorch1.1,cuda10.0上面的工程对比,发现取出来的前100个数据居然不一样。但是tensor_image这个里面的数值两者是一样的。
就是打印tensor_image两边发现是一样的数据。但是用指针方式访问发现是不一样的!!
本能的认为可能是数据类型的问题。tensor_image = tensor_image.to(torch::kFloat16);这么试float16,32,64都试了还是不一致。
在jiamin提醒下是不是高版本通道变化了,我发现打印出来的前100个数有些数值确实是和之前低版本打印的是一样的。然后在低版本的代码如下打印:
tensor_image[0][0][0],tensor_image[1][0][0],tensor_image[2][0][0]
发现这样的打印,低版本的这么打印是和高版本的用data_ptr打印的是一致的。说明高版本的data_ptr确实是有改动了。然后就是
tensor_image = tensor_image.permute({2, 0, 1});把6种可能的顺序都颠倒试了一下还是没有和之前低版本打印的一样。
最后没有办法,tensor_image = tensor_image.reshape({-1});用这句话把数据压成一维度,在调用data_ptr打印,这回发现数据一致了。然后跑整个工程可以出效果图。
然后的然后,我又用libtorch来转trt的crnn,本来已经写好的代码调试可以出效果。然后整理代码,把申请显存释放显存的操作放在循环外面,然后一波修改。改完之后发现出来的结果都是乱七八糟的。
气死,本来都弄好的,咋就不一样了呢,可是代码都被我保存,不好回退了。哎。。。
搞了一个晚上,实在是不想从头再搞。。。。查找了好久还是找不出问题,甚至从头开始就对不第一层卷积出来的效果发现结果是不一样的。然而我还是不知道哪里问题。我对比了输入给网络的输入是一样的。!!!
这里注意,用的是libtorch tensor和pytorch的tensor是一样的!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
隔了好久,没有办法,我找了个一开始的版本,然后重新来,弄着弄着的时候发现漏了一句话,然后我恍然大悟!原来又是之前的坑啊!!
整理代码的时候把这句话给删了
input = input.reshape({-1});///import for torch1.7//////////////////////////////
一开始查找输入的时候发现tensor一致,是因为tensor本来就是一致的,只是用指针访问才不一致!!!
这里还得吐槽一下,一个巨坑!
就是就是我一开始把crnn转trt的时候,先搭好了基网络,然后验证精度。发现精度对不上,按照我之前的经验torch和trt应该转出来是一摸一样的。然后找原因,然后找到layer2发现精度也不一样,然后找第一个pool发现也不一样,然后第一个卷积层,发现也不一样!!!然后我迷茫了。这种情况就是两种可能,第一种可能就是输入不一样,还有就是提取的权重有问题。
打印出输入的前几个数值发现是一样的,那么输入就是没有问题了,难不成还是权重提取的有问题的吗?
我看了代码不就是那几行代码,之前也是这么整的,这能有什么问题!!?
我又陷入迷茫加无助!!放弃的边缘。。。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~分割线~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
然后,痛定思痛。
转libtorch验证精度小程序 https://www.cnblogs.com/yanghailin/p/13669046.html
耐心核查每一步。不偷懒了,虽然前面几个数值一样,还是把tensor都保存在本地txt,两个txt用脚本统计精度。
惊奇的发现输入误差很大!!!虽然前几个数值是一样的,但是中间有数值是不一样的,而且很多!!!
然后我就去找原因。定位问题在如下:
python代码
def LstmImgStandardization(img, ratio, stand_w, stand_h):
img_h, img_w, _ = img.shape
if img_h < 2 or img_w < 2:
return
if 32 == img_h and 320 == img_w:
return img
ratio_now = img_w * 1.0 / img_h
if ratio_now <= ratio:
mask = np.ones((img_h, int(img_h * ratio), 3), dtype=np.uint8) * 255
mask[0:img_h,0:img_w,:] = img
else:
mask = np.ones((int(img_w*1.0/ratio), img_w, 3), dtype=np.uint8) * 255
mask[0:img_h, 0:img_w, :] = img
mask_stand = cv2.resize(mask,(stand_w, stand_h),interpolation=cv2.INTER_AREA)
return mask_stand
c++代码
bool LstmImgStandardization(const cv::Mat &src, const float &ratio, int standard_w, int standard_h, cv::Mat &dst)
{
if(src.empty()) {return false;}
if(src.cols<2 || src.rows<2) { return false;}
if(32 == src.rows && 320 == src.rows) { dst = src.clone(); return true;}
float width=src.cols;
float height=src.rows;
float a=width/ height;
if(a <=ratio)
{
cv::Mat mask(height, ratio*height, CV_8UC3, cv::Scalar(255, 255, 255));
cv::Mat imageROI = mask(cv::Rect(0, 0, width, height));
src.copyTo(imageROI);
dst=mask.clone();
}
else
{
cv::Mat mask(width/ratio, width, CV_8UC3, cv::Scalar(255, 255, 255));
cv::Mat imageROI = mask(cv::Rect(0, 0, width, height));
src.copyTo(imageROI);
dst=mask.clone();
}
cv::resize(dst, dst, cv::Size(standard_w,standard_h));
return true;
}
两者功能是一样的。但是细心的同学会发现最后的resize不一样!!!!
cv::resize(dst, dst, cv::Size(standard_w,standard_h),0,0,cv::INTER_AREA);
c++代码应该这么写!!!!保持一致啊!!
本来计划半天的工作量,硬是搞了两天。还是要细心耐心啊,不能偷懒,保持严谨!要不然得不偿失!