C++读取MATLAB二进制5D矩阵并基于ONNX Runtime推理遇问题求助
解决MATLAB 5D矩阵转C++ ONNX Runtime推理的维度与数据读写问题
问题背景
拥有MATLAB中形状为[1, 1, 512, 320, 2]的5D矩阵,写入二进制文件后在C++中通过ONNX Runtime推理时,因维度重塑、MATLAB列优先扁平化导致数据顺序错误,推理结果与预期差异大。
核心问题分析
- MATLAB采用列优先(column-major)存储,而C++/ONNX Runtime默认是行优先(row-major),直接读写会导致维度顺序和数据排列错位。
- 原始MATLAB操作中对矩阵的重塑和写入逻辑未匹配ONNX模型的输入要求。
步骤1:修正MATLAB端的二进制写入逻辑
无需额外reshape,直接按原始5D矩阵的列优先顺序写入,同时可保存维度信息方便C++端核对:
originalMatrix = rand(1, 1, 512, 320, 2, 'single'); % 示例矩阵 disp(size(originalMatrix)); % 输出: 1 1 512 320 2 % 直接写入原始5D矩阵,无需提前reshape fileID = fopen('inputMatrix.bin', 'wb'); fwrite(fileID, originalMatrix, 'single'); fclose(fileID); % 可选:保存维度信息到文本文件,方便C++端参考 dlmwrite('input_dims.txt', size(originalMatrix));
步骤2:C++端的正确数据读取与维度转换
2.1 修正读取逻辑的文件名错误
原代码中文件名多了单引号,需改为:std::string fileName = "inputMatrix.bin";
2.2 处理列优先到行优先的维度转换
ONNX模型输入维度为[1,1,dynamic_size,dynamic_size,2],对应原始MATLAB的[1,1,512,320,2],需对空间维度(512和320)进行转置并调整数据排列:
#include<iostream> #include<fstream> #include <onnxruntime_cxx_api.h> std::vector<float> readBinaryFile(const std::string& filename) { std::ifstream file(filename, std::ios::binary | std::ios::ate); if (!file.is_open()) { std::cerr << "Error opening file: " << filename << std::endl; return {}; } std::streamsize size = file.tellg(); file.seekg(0, std::ios::beg); std::vector<char> buffer(size); if (!file.read(buffer.data(), size)) { std::cerr << "Error reading file: " << filename << std::endl; return {}; } file.close(); const float* dataArray = reinterpret_cast<const float*>(buffer.data()); size_t numElements = size / sizeof(float); std::cout << "Number of elements: " << numElements << std::endl; return std::vector<float>(dataArray, dataArray + numElements); } int main() { std::vector<float> input_data; std::string fileName = "inputMatrix.bin"; input_data = readBinaryFile(fileName); // 加载ONNX模型 Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "ONNX_Runtime_Logs"); Ort::SessionOptions session_options; Ort::Session session(env, "model.onnx", session_options); // 获取输入输出名称 Ort::AllocatorWithDefaultOptions allocator; const char* input_name = session.GetInputName(0, allocator); const char* output_name = session.GetOutputName(0, allocator); // 原始MATLAB维度:[1,1,512,320,2](列优先) // ONNX模型期望行优先输入,保持逻辑维度,转置空间维度的数据排列 std::vector<int64_t> inputDims = {1, 1, 512, 320, 2}; size_t total_elements = 1 * 1 * 512 * 320 * 2; // 转换列优先数据为行优先:针对空间维度(512,320)转置 std::vector<float> transposed_data(total_elements); for (int c = 0; c < 2; ++c) { // 通道维度 for (int y = 0; y < 320; ++y) { // MATLAB的列维度 for (int x = 0; x < 512; ++x) { // MATLAB的行维度 size_t matlab_idx = c * 512 * 320 + y * 512 + x; size_t row_major_idx = c * 512 * 320 + x * 320 + y; transposed_data[row_major_idx] = input_data[matlab_idx]; } } } // 创建输入张量 Ort::MemoryInfo mem_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault); Ort::Value input_tensor = Ort::Value::CreateTensor<float>( mem_info, transposed_data.data(), total_elements, inputDims.data(), inputDims.size() ); // 执行推理 std::vector<Ort::Value> output_tensors = session.Run( Ort::RunOptions{nullptr}, &input_name, &input_tensor, 1, &output_name, 1 ); // 处理输出并转为MATLAB可读的列优先格式 if (!output_tensors.empty()) { float* output_data = output_tensors[0].GetTensorMutableData<float>(); size_t output_elements = 1 * 1 * 512 * 320 * 2; std::vector<float> matlab_output(output_elements); for (int c = 0; c < 2; ++c) { for (int x = 0; x < 512; ++x) { for (int y = 0; y < 320; ++y) { size_t row_major_idx = c * 512 * 320 + x * 320 + y; size_t matlab_idx = c * 512 * 320 + y * 512 + x; matlab_output[matlab_idx] = output_data[row_major_idx]; } } } // 写入二进制文件 std::ofstream outFile("outputMatrix.bin", std::ios::binary); if (outFile.is_open()) { outFile.write(reinterpret_cast<const char*>(matlab_output.data()), output_elements * sizeof(float)); outFile.close(); } } else { std::cout << "No output tensors returned." << std::endl; return 1; } return 0; }
步骤3:验证与调试要点
- 核对元素数量:读取二进制文件后,确认
numElements等于327680(即1*1*512*320*2),确保数据未丢失。 - 小矩阵测试:先用小维度矩阵(如
[1,1,2,2,2])测试,分别在MATLAB和C++中打印数据值,验证转置逻辑正确性。 - 模型维度确认:用Netron工具打开ONNX模型,确认输入张量的维度顺序与C++中设置的
inputDims一致。 - 输出对比:将C++生成的
outputMatrix.bin在MATLAB中读取,对比与MATLAB直接运行模型的结果:fileID = fopen('outputMatrix.bin', 'rb'); output_mat = fread(fileID, [1,1,512,320,2], 'single'); fclose(fileID); % 与MATLAB本地推理结果对比
内容的提问来源于stack exchange,提问作者Ebin
相关产品推荐
相关产品推荐

