簡體   English   中英

如何正確地將 cv::Mat 轉換為具有完美匹配值的 torch::Tensor?

[英]How to properly convert a cv::Mat into a torch::Tensor with perfect match of values?

我正在嘗試在 C++ 中的 jit 跟蹤模型上運行推理,目前我在 Python 中獲得的輸出與我在 C++ 中獲得的輸出不同。

最初我認為這是由 jit 模型本身引起的,但現在我不這么認為,因為我發現 C++ 代碼中的輸入張量存在一些小偏差。 我相信我按照文檔的指示做了所有事情,這樣也可以在torch::from_blob顯示問題。 我不知道!

因此,為了確定是哪種情況,以下是 Python 和 C++ 中的片段以及測試它的示例輸入。

這是示例圖像:

對於 Pytorch,運行以下代碼片段:

import cv2
import torch
from PIL import Image 
import math
import numpy as np

img = Image.open('D:/Codes/imgs/profile6.jpg')
width, height = img.size
scale = 0.6
sw, sh = math.ceil(width * scale), math.ceil(height * scale)
img = img.resize((sw, sh), Image.BILINEAR)
img = np.asarray(img, 'float32')

# preprocess it 
img = img.transpose((2, 0, 1))
img = np.expand_dims(img, 0)
img = (img - 127.5) * 0.0078125
img = torch.from_numpy(img)

對於 C++:

#include <iostream>
#include <torch/torch.h>
#include <torch/script.h>
using namespace torch::indexing;

#include <opencv2/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>

void test15()
{
    std::string pnet_path = "D:/Codes//MTCNN/pnet.jit"; 
    cv::Mat img = cv::imread("D:/Codes/imgs/profile6.jpg");
    int width = img.cols;
    int height = img.rows;
    float scale = 0.6f;
    int sw = int(std::ceil(width * scale));
    int sh = int(std::ceil(height * scale));

    //cv::Mat img;
    cv::resize(img, img, cv::Size(sw, sh), 0, 0, 1);

    auto tensor_image = torch::from_blob(img.data, { img.rows, img.cols, img.channels() }, at::kByte);
    tensor_image = tensor_image.permute({ 2,0,1 });
    tensor_image.unsqueeze_(0);
    tensor_image = tensor_image.toType(c10::kFloat).sub(127.5).mul(0.0078125);
    tensor_image.to(c10::DeviceType::CPU);
}

### Input comparison : 
and here are the tensor values both in Python and C++ 
Pytorch input (`img[:, :, :10, :10]`):

```python
img: tensor([[
    [[0.3555,  0.3555,  0.3477,  0.3555,  0.3711,  0.3945,  0.3945,  0.3867,  0.3789,  0.3789],
    [ 0.3477,  0.3555,  0.3555,  0.3555,  0.3555,  0.3555,  0.3555,  0.3477,  0.3398,  0.3398],
    [ 0.3320,  0.3242,  0.3320,  0.3242,  0.3320,  0.3398,  0.3398,  0.3242,  0.3164,  0.3242],
    [ 0.2852,  0.2930,  0.2852,  0.2852,  0.2930,  0.2930,  0.2930,  0.2852,  0.2773,  0.2773],
    [ 0.2539,  0.2617,  0.2539,  0.2617,  0.2539,  0.2148,  0.2148,  0.2148,  0.2070,  0.2070],
    [ 0.1914,  0.1914,  0.1836,  0.1836,  0.1758,  0.1523,  0.1367,  0.1211,  0.0977,  0.0898],
    [ 0.1367,  0.1211,  0.0977,  0.0820,  0.0742,  0.0586,  0.0273,  -0.0195, -0.0742, -0.0820],
    [-0.0039, -0.0273, -0.0508, -0.0664, -0.0898, -0.1211, -0.1367, -0.1523, -0.1758, -0.1758],
    [-0.2070, -0.2070, -0.2148, -0.2227, -0.2148, -0.1992, -0.1992, -0.1836, -0.1680, -0.1680],
    [-0.2539, -0.2461, -0.2383, -0.2305, -0.2227, -0.1914, -0.1836, -0.1758, -0.1680, -0.1602]],

    [[0.8398,  0.8398,  0.8320,  0.8242,  0.8320,  0.8477,  0.8398, 0.8320,  0.8164,  0.8164],
    [ 0.8320,  0.8242,  0.8164,  0.8164,  0.8086,  0.8008,  0.7930, 0.7852,  0.7695,  0.7695],
    [ 0.7852,  0.7852,  0.7773,  0.7695,  0.7695,  0.7617,  0.7539, 0.7383,  0.7305,  0.7148],
    [ 0.7227,  0.7070,  0.7070,  0.6992,  0.6914,  0.6836,  0.6836, 0.6680,  0.6523,  0.6367],
    [ 0.6289,  0.6211,  0.6211,  0.6211,  0.6055,  0.5586,  0.5508, 0.5352,  0.5273,  0.5039],
    [ 0.4805,  0.4727,  0.4648,  0.4648,  0.4570,  0.4180,  0.3945, 0.3633,  0.3477,  0.3164],
    [ 0.3555,  0.3398,  0.3086,  0.2930,  0.2695,  0.2461,  0.2070, 0.1523,  0.1055,  0.0820],
    [ 0.1367,  0.1133,  0.0820,  0.0508,  0.0273, -0.0117, -0.0352, -0.0508, -0.0820, -0.0898],
    [-0.1211, -0.1289, -0.1445, -0.1602, -0.1602, -0.1523, -0.1523, -0.1367, -0.1367, -0.1289],
    [-0.2070, -0.1992, -0.1992, -0.1992, -0.1992, -0.1680, -0.1680, -0.1602, -0.1523, -0.1445]],

    [[0.9492,  0.9414,  0.9336,  0.9180,  0.9180,  0.9336,  0.9258, 0.9023,  0.8867,  0.9023],
    [ 0.9258,  0.9258,  0.9102,  0.9023,  0.8945,  0.8789,  0.8633, 0.8477,  0.8320,  0.8398],
    [ 0.8711,  0.8633,  0.8555,  0.8477,  0.8320,  0.8242,  0.8086, 0.7930,  0.7852,  0.7773],
    [ 0.7852,  0.7773,  0.7617,  0.7539,  0.7461,  0.7305,  0.7148, 0.6992,  0.6914,  0.6836],
    [ 0.6758,  0.6680,  0.6602,  0.6602,  0.6367,  0.5820,  0.5742, 0.5508,  0.5430,  0.5273],
    [ 0.5117,  0.5117,  0.4961,  0.4883,  0.4727,  0.4336,  0.4102, 0.3711,  0.3477,  0.3242],
    [ 0.3867,  0.3711,  0.3398,  0.3164,  0.2930,  0.2539,  0.2148, 0.1523,  0.1055,  0.0820],
    [ 0.1680,  0.1445,  0.1055,  0.0742,  0.0352, -0.0039, -0.0273, -0.0586, -0.0820, -0.0898],
    [-0.0898, -0.0977, -0.1211, -0.1367, -0.1445, -0.1445, -0.1445, -0.1445, -0.1445, -0.1445],
    [-0.1758, -0.1680, -0.1680, -0.1680, -0.1680, -0.1523, -0.1523, -0.1602, -0.1602, -0.1523]]]])

C++/Libtorch 張量值( img.index({Slice(), Slice(), Slice(None, 10), Slice(None, 10)}); ):

img: (1,1,.,.) =
  0.3555  0.3555  0.3555  0.3555  0.3555  0.4023  0.3945  0.3867  0.3789  0.3789
  0.3633  0.3633  0.3555  0.3555  0.3555  0.3555  0.3477  0.3555  0.3398  0.3398
  0.3398  0.3320  0.3320  0.3242  0.3398  0.3320  0.3398  0.3242  0.3242  0.3242
  0.2930  0.2930  0.2852  0.2773  0.2852  0.2930  0.2852  0.2852  0.2773  0.2852
  0.2695  0.2695  0.2617  0.2773  0.2695  0.2227  0.2227  0.2227  0.2148  0.2148
  0.1914  0.1914  0.1914  0.1914  0.1914  0.1602  0.1445  0.1289  0.1055  0.0977
  0.1289  0.1133  0.0820  0.0742  0.0586  0.0586  0.0195 -0.0273 -0.0820 -0.0898
  0.0039 -0.0195 -0.0508 -0.0664 -0.0820 -0.1289 -0.1445 -0.1602 -0.1836 -0.1836
 -0.2070 -0.2148 -0.2227 -0.2383 -0.2305 -0.2070 -0.2070 -0.1914 -0.1836 -0.1758
 -0.2539 -0.2461 -0.2461 -0.2383 -0.2305 -0.1914 -0.1914 -0.1758 -0.1680 -0.1602

(1,2,.,.) =
  0.8398  0.8398  0.8242  0.8164  0.8242  0.8555  0.8398  0.8320  0.8242  0.8242
  0.8320  0.8320  0.8242  0.8242  0.8086  0.8008  0.7930  0.7773  0.7695  0.7617
  0.7930  0.7852  0.7773  0.7695  0.7695  0.7695  0.7539  0.7461  0.7305  0.7227
  0.7070  0.7070  0.6992  0.6992  0.6914  0.6836  0.6758  0.6602  0.6523  0.6367
  0.6367  0.6367  0.6289  0.6289  0.6211  0.5664  0.5586  0.5430  0.5352  0.5117
  0.4805  0.4805  0.4805  0.4648  0.4727  0.4258  0.4023  0.3711  0.3555  0.3320
  0.3398  0.3320  0.3008  0.2773  0.2617  0.2461  0.1992  0.1445  0.0898  0.0586
  0.1367  0.1211  0.0898  0.0508  0.0273 -0.0195 -0.0352 -0.0664 -0.0898 -0.1055
 -0.1211 -0.1289 -0.1367 -0.1602 -0.1602 -0.1523 -0.1523 -0.1445 -0.1445 -0.1367
 -0.2148 -0.2070 -0.2070 -0.2070 -0.1992 -0.1680 -0.1680 -0.1602 -0.1523 -0.1445

(1,3,.,.) =
  0.9414  0.9414  0.9336  0.9180  0.9102  0.9336  0.9258  0.9023  0.8945  0.9023
  0.9180  0.9180  0.9102  0.9102  0.8945  0.8711  0.8633  0.8555  0.8242  0.8477
  0.8711  0.8711  0.8633  0.8477  0.8320  0.8164  0.8164  0.7930  0.7852  0.7852
  0.7773  0.7773  0.7539  0.7461  0.7305  0.7148  0.7070  0.6992  0.6836  0.6758
  0.6836  0.6836  0.6758  0.6680  0.6445  0.5898  0.5820  0.5586  0.5508  0.5352
  0.5273  0.5195  0.5117  0.4883  0.4883  0.4414  0.4102  0.3789  0.3633  0.3398
  0.3867  0.3633  0.3320  0.3008  0.2695  0.2539  0.2070  0.1445  0.0898  0.0664
  0.1836  0.1523  0.1133  0.0742  0.0352 -0.0117 -0.0352 -0.0664 -0.0898 -0.1055
 -0.0820 -0.0977 -0.1211 -0.1367 -0.1445 -0.1445 -0.1445 -0.1367 -0.1445 -0.1445
 -0.1758 -0.1758 -0.1758 -0.1758 -0.1758 -0.1602 -0.1523 -0.1680 -0.1602 -0.1602

[ CPUFloatType{1,3,10,10} ]

順便說一下,這些是歸一化/預處理之前的張量值:

Python:

img.shape: (3, 101, 180)
img: [
 [[173. 173. 172. 173. 175.]
  [172. 173. 173. 173. 173.]
  [170. 169. 170. 169. 170.]
  [164. 165. 164. 164. 165.]
  [160. 161. 160. 161. 160.]]

 [[235. 235. 234. 233. 234.]
  [234. 233. 232. 232. 231.]
  [228. 228. 227. 226. 226.]
  [220. 218. 218. 217. 216.]
  [208. 207. 207. 207. 205.]]

 [[249. 248. 247. 245. 245.]
  [246. 246. 244. 243. 242.]
  [239. 238. 237. 236. 234.]
  [228. 227. 225. 224. 223.]
  [214. 213. 212. 212. 209.]]]

CPP:

img.shape: [1, 3, 101, 180]
img: (1,1,.,.) =
  173  173  173  173  173
  174  174  173  173  173
  171  170  170  169  171
  165  165  164  163  164
  162  162  161  163  162

(1,2,.,.) =
  235  235  233  232  233
  234  234  233  233  231
  229  228  227  226  226
  218  218  217  217  216
  209  209  208  208  207

(1,3,.,.) =
  248  248  247  245  244
  245  245  244  244  242
  239  239  238  236  234
  227  227  224  223  221
  215  215  214  213  210
[ CPUByteType{1,3,5,5} ]

如您所見,乍一看,它們可能看起來相同,但仔細觀察時,您會發現輸入中有許多小偏差! 如何避免這些更改,並獲得 C++ 中的確切值?

我想知道是什么導致了這種奇怪的現象發生!

很明顯,這確實是一個輸入問題,更具體地說,這是因為圖像首先由 Python 中的PIL.Image.open讀取,然后更改為一個numpy數組。 如果使用OpenCV讀取圖像,那么在輸入方面,Python 和 C++ 中的所有內容都是相同的。

更多解釋

但是,在我的特定情況下,使用 OpenCV 圖像會導致最終結果發生微小變化。 最小化這種變化/差異的唯一方法是,當我制作 Opencv 圖像灰度並將其提供給網絡時,在這種情況下,PIL 輸入和 opencv 輸入具有幾乎相同的輸出。

這是兩個示例,pil圖像是bgr,opencv處於灰度模式:您需要將它們保存在磁盤上並看到它們幾乎相同(左側是cv_image,右側是pil_image):

img62_cvimg62_pil

但是,如果我只是不將 opencv 圖像轉換為灰度模式(並返回到 bgr 以獲得 3 個通道),則它的外觀是這樣的(左側是 cv_image,右側是 pil_image):

img62_cvimg62_pil

更新

結果證明這又與輸入相關。 我們有輕微差異的原因是由於模型是在 rgb 圖像上訓練的,因此通道順序很重要。 在使用 PIL 圖像時,不同的方法會發生一些來回轉換,因此它導致整個事情變得一團糟,你之前在上面讀到過。

長話短說,從cv::Mattorch::Tensor的轉換沒有任何問題,反之亦然,問題在於在 Python 和 C++ 中創建圖像和饋送到網絡的方式不同. 當 Python 和 C++ 后端都使用 OpenCV 處理圖像時,它們的輸出和結果匹配 100%。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM