如何用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库解析模型
该方法能直接读取模型中所有自定义属性(包括图层面的属性),步骤如下:
- 先安装ONNX库(可通过vcpkg或源码编译)
- 使用以下代码读取属性:
#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
相关产品推荐
相关产品推荐

