zoukankan      html  css  js  c++  java
  • 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++代码应该这么写!!!!保持一致啊!!

    本来计划半天的工作量,硬是搞了两天。还是要细心耐心啊,不能偷懒,保持严谨!要不然得不偿失!

    好记性不如烂键盘---点滴、积累、进步!
  • 相关阅读:
    HDU 5213 分块 容斥
    HDU 2298 三分
    HDU 5144 三分
    HDU 5145 分块 莫队
    HDU 3938 并查集
    HDU 3926 并查集 图同构简单判断 STL
    POJ 2431 优先队列
    HDU 1811 拓扑排序 并查集
    HDU 2685 GCD推导
    HDU 4496 并查集 逆向思维
  • 原文地址:https://www.cnblogs.com/yanghailin/p/14792637.html
Copyright © 2011-2022 走看看