• 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++代码应该这么写!!!!保持一致啊!!

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

    好记性不如烂键盘---点滴、积累、进步!
  • 相关阅读:
    11个重要的数据库设计规则
    CentOS 6.8 新安装系统的网络IP配置(转载)
    WebView根据加载的内容来控制其高度
    遗传算法
    Selenium: Trying to log in with cookies and get the errorMessage
    用Tesseract训练验证码遇到的问题
    利用jTessBoxEditor工具进行Tesseract-OCR样本训练
    Tesseract处理背景渐变的图片
    XPath语法
    在Python中用Selenium执行JavaScript
  • 原文地址:https://www.cnblogs.com/yanghailin/p/14792637.html
Copyright © 2020-2023  润新知