[英]How to convert cv::Mat to torch::Tensor and feed it to libtorch model?
[英]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):
但是,如果我只是不將 opencv 圖像轉換為灰度模式(並返回到 bgr 以獲得 3 個通道),則它的外觀是這樣的(左側是 cv_image,右側是 pil_image):
結果證明這又與輸入相關。 我們有輕微差異的原因是由於模型是在 rgb 圖像上訓練的,因此通道順序很重要。 在使用 PIL 圖像時,不同的方法會發生一些來回轉換,因此它導致整個事情變得一團糟,你之前在上面讀到過。
長話短說,從cv::Mat
到torch::Tensor
的轉換沒有任何問題,反之亦然,問題在於在 Python 和 C++ 中創建圖像和饋送到網絡的方式不同. 當 Python 和 C++ 后端都使用 OpenCV 處理圖像時,它們的輸出和結果匹配 100%。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.