### 优化从OpenCV Mat/Array到OnnxRuntime Tensor的转换?

我在使用ONNXRuntime进行UNet模型的推理,作为预处理的一部分,我需要将EMGU OpenCV矩阵转换为OnnxRuntime.Tensor。

我通过使用两个嵌套的for循环实现了这一点,但遗憾的是速度相当慢:

            var data = new DenseTensor<float>(new[] { 1, 3, WIDTH, HEIGHT});            for (int y = 0; y < HEIGHT; y++)            {                for (int x = 0; x < WIDTH; x++)                {                    data[0, 0, x, y] = image.GetValue(2, y, x)/255.0;                    data[0, 1, x, y] = image.GetValue(1, y, x)/255.0;                    data[0, 2, x, y] = image.GetValue(0, y, x)/255.0;                }            } 

然后我发现有一个方法可以将Array转换为DenseTensor。我想按如下方式使用这个方法:

        var imgToPredictFloat = new Mat(image.Height, image.Width, DepthType.Cv32F, 3);        image.ConvertTo(imgToPredictFloat, DepthType.Cv32F, 1/255.0);        CvInvoke.CvtColor(imgToPredictFloat, imgToPredictFloat, ColorConversion.Bgra2Rgb);        var data = image.GetData().ToTensor<float>;        var reshaped = data.Reshape(new int[] { 1, 3, WIDTH, HEIGHT});

这将大大提高性能,但是输出张量的布局不正确(与for循环中的布局相同),显然模型不会工作。有什么建议可以将数组重塑为正确的布局吗?

代码中还进行了从0-255的整数转换为0-1的浮点数,以及从BGR布局转换为RGB布局的操作。


回答:

这是我在ONNX Runtime(C++)中使用cv::Mat的方式:

const wchar_t* model_path = L"C:/data/DNN/ONNX/ResNet/resnet152v2/resnet152-v2-7.onnx";printf("Using Onnxruntime C++ API\n");Ort::Session session(env, model_path, session_options);//*************************************************************************// print model input layer (node names, types, shape etc.)Ort::AllocatorWithDefaultOptions allocator;size_t num_output_nodes = session.GetOutputCount();std::vector<char*> outputNames;for (size_t i = 0; i < num_output_nodes; ++i){    char* name = session.GetOutputName(i, allocator);    std::cout << "output: " << name << std::endl;    outputNames.push_back(name);}// print number of model input nodessize_t num_input_nodes = session.GetInputCount();std::vector<const char*> input_node_names(num_input_nodes);std::vector<int64_t> input_node_dims;  // simplify... this model has only 1 input node {1, 3, 224, 224}.                                       // Otherwise need vector<vector<>>printf("Number of inputs = %zu\n", num_input_nodes);// iterate over all input nodesfor (int i = 0; i < num_input_nodes; i++) {    // print input node names    char* input_name = session.GetInputName(i, allocator);    printf("Input %d : name=%s\n", i, input_name);    input_node_names[i] = input_name;    // print input node types    Ort::TypeInfo type_info = session.GetInputTypeInfo(i);    auto tensor_info = type_info.GetTensorTypeAndShapeInfo();    ONNXTensorElementDataType type = tensor_info.GetElementType();    printf("Input %d : type=%d\n", i, type);    // print input shapes/dims    input_node_dims = tensor_info.GetShape();    printf("Input %d : num_dims=%zu\n", i, input_node_dims.size());    for (int j = 0; j < input_node_dims.size(); j++)        printf("Input %d : dim %d=%jd\n", i, j, input_node_dims[j]);}cv::Size dnnInputSize;cv::Scalar mean;cv::Scalar std;bool rgb = true;//cv::Mat inputImage = cv::imread("C:/TestImages/kitten_01.jpg");cv::Mat inputImage = cv::imread("C:/TestImages/slug_01.jpg");rgb = true;dnnInputSize = cv::Size(224, 224);mean[0] = 0.485;mean[1] = 0.456;mean[2] = 0.406;std[0] = 0.229;std[1] = 0.224;std[2] = 0.225;cv::Mat blob;// ONNX: (N x 3 x H x W)cv::dnn::blobFromImage(inputImage, blob, 1.0 / 255.0, dnnInputSize, mean, rgb, false);size_t input_tensor_size = blob.total();std::vector<float> input_tensor_values(input_tensor_size);for (size_t i = 0; i < input_tensor_size; ++i){    input_tensor_values[i] = blob.at<float>(i);}std::vector<const char*> output_node_names = { outputNames.front() };// create input tensor object from data valuesauto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info, input_tensor_values.data(), input_tensor_size, input_node_dims.data(), 4);assert(input_tensor.IsTensor());// score model & input tensor, get back output tensorauto output_tensors = session.Run(Ort::RunOptions{ nullptr }, input_node_names.data(), &input_tensor, 1, output_node_names.data(), 1);assert(output_tensors.size() == 1 && output_tensors.front().IsTensor());// Get pointer to output tensor float valuesfloat* floatarr = output_tensors.front().GetTensorMutableData<float>();assert(abs(floatarr[0] - 0.000045) < 1e-6);cv::Mat1f result = cv::Mat1f(1000, 1, floatarr);cv::Point classIdPoint;double confidence = 0;minMaxLoc(result, 0, &confidence, 0, &classIdPoint);int classId = classIdPoint.y;std::cout << "confidence: " << confidence << std::endl;std::cout << "class: " << classId << std::endl;

我认为您需要的实际转换部分是(根据您的网络调整大小和均值/标准差):

cv::Mat inputImage = cv::imread("C:/TestImages/slug_01.jpg");rgb = true;dnnInputSize = cv::Size(224, 224);mean[0] = 0.485;mean[1] = 0.456;mean[2] = 0.406;std[0] = 0.229;std[1] = 0.224;std[2] = 0.225;cv::Mat blob;// ONNX: (N x 3 x H x W)cv::dnn::blobFromImage(inputImage, blob, 1.0 / 255.0, dnnInputSize, mean, rgb, false);

Related Posts

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注