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

如何用C++读取ONNX模型中的list_classes元数据?

解决C++读取ONNX模型"list_classes"属性的问题

一、修复ONNX Runtime Session创建错误

你提供的代码报错核心原因是未初始化Ort::Env对象,std::unique_ptr<Ort::Env>默认是空指针,解引用*ort_env会触发空指针访问错误。以下是修复后的代码:

#include <onnxruntime_cxx_api.h>
#include <iostream>

int main()
{
    const wchar_t* model_path = L"model.onnx";
    // 直接初始化Ort::Env,无需使用unique_ptr(若需动态管理可后续调整)
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "ModelSession");
    Ort::SessionOptions session_options;

    try {
        Ort::Session session(env, model_path, session_options);
        std::cout << "Session创建成功!" << std::endl;
    } catch (const Ort::Exception& e) {
        std::cerr << "Session创建失败:" << e.what() << std::endl;
        return 1;
    }

    return 0;
}

二、读取ONNX模型的"list_classes"属性

OpenCV DNN库确实没有提供直接读取ONNX自定义属性的接口,推荐两种可行方案:

方案1:使用ONNX官方Protobuf库解析模型

该方法能直接读取模型中所有自定义属性(包括图层面的属性),步骤如下:

  1. 先安装ONNX库(可通过vcpkg或源码编译)
  2. 使用以下代码读取属性:
#include <onnx/onnx_pb.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <string>

bool GetListClasses(const std::string& model_path, std::vector<std::string>& class_list) {
    // 读取模型文件
    std::ifstream model_file(model_path, std::ios::binary);
    if (!model_file.is_open()) {
        std::cerr << "无法打开模型文件:" << model_path << std::endl;
        return false;
    }

    // 解析为ONNX ModelProto
    onnx::ModelProto model_proto;
    if (!model_proto.ParseFromIstream(&model_file)) {
        std::cerr << "解析ONNX模型失败" << std::endl;
        return false;
    }

    // 遍历图层面的属性,查找"list_classes"
    const auto& graph = model_proto.graph();
    for (const auto& attr : graph.attribute()) {
        if (attr.name() == "list_classes") {
            // 假设属性为字符串列表类型,根据实际类型调整
            if (attr.type() == onnx::AttributeProto_AttributeType_STRINGS) {
                for (const auto& cls_str : attr.strings()) {
                    class_list.push_back(cls_str);
                }
                return true;
            } else {
                std::cerr << "list_classes属性不是字符串列表类型" << std::endl;
                return false;
            }
        }
    }

    // 若图层面未找到,检查模型元数据(部分模型会将属性存在这里)
    for (const auto& meta : model_proto.metadata_props()) {
        if (meta.key() == "list_classes") {
            class_list.push_back(meta.value());
            return true;
        }
    }

    std::cerr << "未找到list_classes属性" << std::endl;
    return false;
}

int main() {
    std::vector<std::string> classes;
    if (GetListClasses("model.onnx", classes)) {
        std::cout << "读取到list_classes:" << std::endl;
        for (const auto& cls : classes) {
            std::cout << "- " << cls << std::endl;
        }
    }
    return 0;
}

方案2:通过ONNX Runtime读取元数据(仅适用于属性存在于模型元数据的情况)

如果"list_classes"是作为模型元数据存储的,可通过ONNX Runtime的API读取:

#include <onnxruntime_cxx_api.h>
#include <iostream>
#include <vector>
#include <string>

int main() {
    const wchar_t* model_path = L"model.onnx";
    Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "MetaReader");
    Ort::SessionOptions session_options;

    try {
        Ort::Session session(env, model_path, session_options);
        // 获取模型元数据数量
        size_t meta_count = session.GetMetadataCount();
        for (size_t i = 0; i < meta_count; ++i) {
            std::wstring key, value;
            session.GetMetadata(i, key, value);
            // 转换为窄字符串(根据需求调整编码)
            std::string key_str(key.begin(), key.end());
            std::string value_str(value.begin(), value.end());
            if (key_str == "list_classes") {
                std::cout << "list_classes: " << value_str << std::endl;
            }
        }
    } catch (const Ort::Exception& e) {
        std::cerr << "错误:" << e.what() << std::endl;
        return 1;
    }

    return 0;
}

内容的提问来源于stack exchange,提问作者Maksim Melnichuk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 12:30:51