You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++读取MATLAB二进制5D矩阵并基于ONNX Runtime推理遇问题求助

解决MATLAB 5D矩阵转C++ ONNX Runtime推理的维度与数据读写问题

问题背景

拥有MATLAB中形状为[1, 1, 512, 320, 2]的5D矩阵,写入二进制文件后在C++中通过ONNX Runtime推理时,因维度重塑、MATLAB列优先扁平化导致数据顺序错误,推理结果与预期差异大。

核心问题分析

  1. MATLAB采用列优先(column-major)存储,而C++/ONNX Runtime默认是行优先(row-major),直接读写会导致维度顺序和数据排列错位。
  2. 原始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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 17:10:54