From 0dc1e6ee61e5a354a916c8e1fefc5b79739afb31 Mon Sep 17 00:00:00 2001 From: Scott McKay Date: Mon, 30 Dec 2024 09:42:34 +1000 Subject: [PATCH] Add Constant test --- onnxruntime/core/graph/graph.cc | 1 - onnxruntime/core/session/utils.cc | 1 + .../test/shared_lib/test_model_builder_api.cc | 77 +++++++++++-------- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/onnxruntime/core/graph/graph.cc b/onnxruntime/core/graph/graph.cc index 802ea5029b..9b7dfb5071 100644 --- a/onnxruntime/core/graph/graph.cc +++ b/onnxruntime/core/graph/graph.cc @@ -5833,7 +5833,6 @@ Status Graph::LoadFromModelBuilderApiModel(const OrtGraph& api_graph, bool updat NodeProto node_proto; // 'Constant' node has no inputs or attributes - assert(node.input_names.empty() && node.attributes.empty()); ORT_RETURN_IF_NOT(node.input_names.empty() && node.attributes.size() == 1 && node.output_names.size() == 1, node.node_name, " is an invalid 'Constant' node. " diff --git a/onnxruntime/core/session/utils.cc b/onnxruntime/core/session/utils.cc index 7f6d3f040c..afb1ed2696 100644 --- a/onnxruntime/core/session/utils.cc +++ b/onnxruntime/core/session/utils.cc @@ -10,6 +10,7 @@ #include "core/session/inference_session.h" #include "core/session/inference_session_utils.h" #include "core/session/onnxruntime_c_api.h" +#include "core/session/ort_apis.h" #include "core/session/ort_env.h" using namespace onnxruntime; diff --git a/onnxruntime/test/shared_lib/test_model_builder_api.cc b/onnxruntime/test/shared_lib/test_model_builder_api.cc index 417e1b564f..48d5c91f7a 100644 --- a/onnxruntime/test/shared_lib/test_model_builder_api.cc +++ b/onnxruntime/test/shared_lib/test_model_builder_api.cc @@ -197,7 +197,8 @@ TEST(ModelBuilderAPITest, Basic_CApi) { Ort::ThrowOnError(api.CreateOpAttr("alpha", &alpha_value, 1, OrtOpAttrType::ORT_OP_ATTR_FLOAT, &alpha_attr)); std::vector node_input_names = {"X", "Y"}; - std::vector node_output_names = {"Z"}; + const std::string gemm_output_name = use_constant_node ? "Z_temp" : "Z"; + std::vector node_output_names = {gemm_output_name.c_str()}; std::vector node_attributes{alpha_attr}; OrtNode* node = CreateNode(graph_api, "Gemm", "Gemm1", node_input_names, node_output_names, node_attributes); @@ -213,41 +214,44 @@ TEST(ModelBuilderAPITest, Basic_CApi) { 4.0f, 5.0f, 6.0f})); auto& y_values = *deleter.weights.back(); + // create an initializer for the Y input. add to `weights` so the memory remains valid + OrtValue* y_tensor = nullptr; + auto info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault); + + // if you use this API the initializer data MUST remain valid for the lifetime of the InferenceSession + Ort::ThrowOnError( + api.CreateTensorWithDataAndDeleterAsOrtValue(&deleter, + y_values.data(), y_values.size() * sizeof(y_values[0]), + y_dims.data(), y_dims.size(), + ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, + &y_tensor)); + + Ort::ThrowOnError(graph_api.AddInitializerToGraph(graph, "Y", y_tensor, /*data is external*/ true)); + y_tensor = nullptr; // graph now owns + if (use_constant_node) { // Test that a Constant node is converted to an intializer - // create an attribute for the Y input - // create Constant node that produces "Y" output with the value_floats attribute + // create Constant node that is used as the Max in a Clip to limit the output OrtOpAttr* value_attr = nullptr; - int bytes = onnxruntime::narrow(y_values.size() * sizeof(y_values[0])); - Ort::ThrowOnError(api.CreateOpAttr("value", y_values.data(), bytes, ORT_OP_ATTR_FLOAT, &value_attr)); + float max = 60.0f; + Ort::ThrowOnError(api.CreateOpAttr("value", &max, sizeof(max), ORT_OP_ATTR_FLOAT, &value_attr)); - node = CreateNode(graph_api, "Constant", "Y_constant", {}, {"Y"}, {value_attr}); + node = CreateNode(graph_api, "Constant", "clip_max", {}, {"max"}, {value_attr}); Ort::ThrowOnError(graph_api.AddNodeToGraph(graph, node)); node = nullptr; // graph now owns node - } else { - // create an initializer for the Y input. add to `weights` so the memory remains valid - OrtValue* y_tensor = nullptr; - auto info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeDefault); - // if you use this API the initializer data MUST remain valid for the lifetime of the InferenceSession - Ort::ThrowOnError( - api.CreateTensorWithDataAndDeleterAsOrtValue(&deleter, - y_values.data(), y_values.size() * sizeof(y_values[0]), - y_dims.data(), y_dims.size(), - ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, - &y_tensor)); - - Ort::ThrowOnError(graph_api.AddInitializerToGraph(graph, "Y", y_tensor, /*data is external*/ true)); - y_tensor = nullptr; // graph now owns - - std::vector domain_names = {onnxruntime::kOnnxDomain}; - std::vector opset_versions = {18}; - Ort::ThrowOnError(graph_api.CreateModel(domain_names.data(), opset_versions.data(), domain_names.size(), - &model)); - Ort::ThrowOnError(graph_api.AddGraphToModel(model, graph)); - graph = nullptr; // model now owns + node = CreateNode(graph_api, "Clip", "Clip1", {gemm_output_name.c_str(), "", "max"}, {"Z"}); + Ort::ThrowOnError(graph_api.AddNodeToGraph(graph, node)); + node = nullptr; // graph now owns node } + + std::vector domain_names = {onnxruntime::kOnnxDomain}; + std::vector opset_versions = {18}; + Ort::ThrowOnError(graph_api.CreateModel(domain_names.data(), opset_versions.data(), domain_names.size(), + &model)); + Ort::ThrowOnError(graph_api.AddGraphToModel(model, graph)); + graph = nullptr; // model now owns }; auto run_test = [&](bool use_constant_node) -> void { @@ -266,15 +270,26 @@ TEST(ModelBuilderAPITest, Basic_CApi) { ModelBuilderAPI::Model cxx_model(model); auto session = CreateSession(*ort_env, cxx_model); - TestInference(session, inputs, "Z", expected_dims, - {18.0f, 24.0f, 30.0f, - 38.0f, 52.0f, 66.0f, - 58.0f, 80.0f, 102.0f}); + std::vector expected_output; + if (use_constant_node) { + expected_output = {18.0f, 24.0f, 30.0f, + 38.0f, 52.0f, 60.0f, // clipped + 58.0f, 60.0f, 60.0f}; // clipped + } else { + expected_output = {18.0f, 24.0f, 30.0f, + 38.0f, 52.0f, 66.0f, + 58.0f, 80.0f, 102.0f}; + } + + TestInference(session, inputs, "Z", expected_dims, expected_output); api.ReleaseSession(session.release()); ASSERT_EQ(deleter.weights.size(), 0) << "All weights should have been freed"; }; + + run_test(false); + run_test(true); // use Constant node for initializer } TEST(ModelBuilderAPITest, Basic_CxxApi) {