diff --git a/include/onnxruntime/core/graph/graph.h b/include/onnxruntime/core/graph/graph.h index 8b38797745..c4c1e71356 100644 --- a/include/onnxruntime/core/graph/graph.h +++ b/include/onnxruntime/core/graph/graph.h @@ -1009,6 +1009,9 @@ class Graph { // Model IR version. Version ir_version_{ONNX_NAMESPACE::Version::IR_VERSION}; + // Is model using latest ONNX opset + bool using_latest_onnx_opset_{false}; + int name_generator_ = 0; ResolveContext resolve_context_; diff --git a/include/onnxruntime/core/graph/node_arg.h b/include/onnxruntime/core/graph/node_arg.h index c2bd144fbf..f1f111c27e 100644 --- a/include/onnxruntime/core/graph/node_arg.h +++ b/include/onnxruntime/core/graph/node_arg.h @@ -59,13 +59,21 @@ class NodeArg { as the shape information is stored as part of TypeProto. */ void SetShape(const ONNX_NAMESPACE::TensorShapeProto& shape); + /** Clears shape info. + @remarks If there is a mismatch during shape inferencing that can't be resolved the shape info may be removed. */ + void ClearShape(); + /** Validate and merge type [and shape] info from input_type. - @returns Success unless there is existing type or shape info that can't be cleanly updated. */ - common::Status UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& input_type); + @param strict If true, the shape update will fail if there are incompatible values. + If false, will be lenient and merge only shape info that can be validly processed. + @returns Success unless there is existing type or shape info that can't be successfully updated. */ + common::Status UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& input_type, bool strict = true); /** Validate and merge type [and shape] info from node_arg. - @returns Success unless there is existing type or shape info that can't be cleanly updated. */ - common::Status UpdateTypeAndShape(const NodeArg& node_arg); + @param strict If true, the shape update will fail if there are incompatible values. + If false, will be lenient and merge only shape info that can be validly processed. + @returns Success unless there is existing type or shape info that can't be successfully updated. */ + common::Status UpdateTypeAndShape(const NodeArg& node_arg, bool strict = true); /** Gets this NodeArg as a ValueInfoProto. */ const NodeArgInfo& ToProto() const noexcept { return node_arg_info_; } diff --git a/onnxruntime/core/graph/graph.cc b/onnxruntime/core/graph/graph.cc index 6ef83fecf4..e70faff417 100644 --- a/onnxruntime/core/graph/graph.cc +++ b/onnxruntime/core/graph/graph.cc @@ -40,12 +40,42 @@ namespace onnxruntime { GraphProtoSyncNeeded(sync_needed); \ } while (0) +static bool UsingLatestOnnxOpset(const DomainToVersionMap& opset_versions) { + bool is_latest_opset = false; + auto onnx_opset = opset_versions.find(kOnnxDomain); + + if (onnx_opset != opset_versions.cend()) { + static int latest_onnx_version = + ONNX_NAMESPACE::OpSchemaRegistry::DomainToVersionRange().Map().at(ONNX_NAMESPACE::ONNX_DOMAIN).second; + + if (onnx_opset->second == latest_onnx_version) { + is_latest_opset = true; + } + } + + return is_latest_opset; +} + static Status MergeShapeInfo(const std::string& output_name, - const TypeProto_Tensor& source, TypeProto_Tensor& target) { + const TypeProto_Tensor& source, TypeProto_Tensor& target, + bool strict) { try { ONNX_NAMESPACE::mergeInShapeInfo(source, target); } catch (const ONNX_NAMESPACE::InferenceError& ex) { - return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Output:", output_name, " ", ex.what()); + // if this model was not created with the latest onnx version, allow the shape inferencing failure (strict == false). + // we do this to have strict testing of the latest inferencing to detect bugs, but lenient shape inferencing for + // older models in case later changes to the ONNX shape inferencing or ORT break them. + if (!strict) { + // mergeInShapeInfo does nothing unless source.shape() is not null, and there would be no conflict if + // target.shape() was empty. 'assert' just in case that ever changes. + assert(utils::HasShape(source) && utils::HasShape(target)); + LOGS_DEFAULT(WARNING) << "Error merging shape info for output. '" << output_name + << "' source:" << source.shape() << " target:" << target.shape() + << ". Falling back to lenient merge."; + ONNX_NAMESPACE::UnionShapeInfo(source.shape(), target); + } else { + return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Output:", output_name, " ", ex.what()); + } } return Status::OK(); @@ -158,7 +188,25 @@ void NodeArg::SetShape(const TensorShapeProto& shape) { } } -common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& input_type) { +void NodeArg::ClearShape() { + const auto type_case = node_arg_info_.type().value_case(); + switch (type_case) { + case TypeProto::kTensorType: + node_arg_info_.mutable_type()->mutable_tensor_type()->clear_shape(); + break; + case TypeProto::kSparseTensorType: + node_arg_info_.mutable_type()->mutable_sparse_tensor_type()->clear_shape(); + break; + case TypeProto::kSequenceType: + case TypeProto::kMapType: + case TypeProto::kOpaqueType: + case TypeProto::VALUE_NOT_SET: + default: + return; + } +} + +common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& input_type, bool strict) { if (!utils::HasType(node_arg_info_)) { *node_arg_info_.mutable_type() = input_type; type_ = DataTypeUtils::ToType(node_arg_info_.type()); @@ -187,7 +235,7 @@ common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& inpu if (utils::HasShape(input_tensor_type)) { auto& current_tensor_type = *current_type.mutable_tensor_type(); if (utils::HasShape(current_tensor_type)) { - ORT_RETURN_IF_ERROR(MergeShapeInfo(Name(), input_tensor_type, current_tensor_type)); + ORT_RETURN_IF_ERROR(MergeShapeInfo(Name(), input_tensor_type, current_tensor_type, strict)); } else { current_tensor_type = input_tensor_type; } @@ -225,11 +273,11 @@ common::Status NodeArg::UpdateTypeAndShape(const ONNX_NAMESPACE::TypeProto& inpu return Status::OK(); } -common::Status NodeArg::UpdateTypeAndShape(const NodeArg& node_arg) { +common::Status NodeArg::UpdateTypeAndShape(const NodeArg& node_arg, bool strict) { auto status = Status::OK(); if (utils::HasType(node_arg.node_arg_info_)) - status = UpdateTypeAndShape(node_arg.node_arg_info_.type()); + status = UpdateTypeAndShape(node_arg.node_arg_info_.type(), strict); return status; } @@ -657,6 +705,7 @@ Graph::Graph(GraphProto* graph_proto, const std::unordered_map domain_to_version_(domain_to_version), model_functions_(model_functions), ir_version_(ir_version), + using_latest_onnx_opset_(UsingLatestOnnxOpset(domain_to_version)), parent_graph_(parent_graph), parent_node_(parent_node) { ORT_ENFORCE(graph_proto != nullptr, "graph_proto cannot be null"); @@ -1612,12 +1661,16 @@ Status Graph::InferAndVerifyTypeMatch(Node& node, const OpSchema& op) { // that have no values. TypeProto_Tensor merge_target; (*merge_target.mutable_shape()) = *output_def->Shape(); - auto status = MergeShapeInfo(output_def->Name(), tensor_type, merge_target); + auto status = MergeShapeInfo(output_def->Name(), tensor_type, merge_target, using_latest_onnx_opset_); if (!status.IsOK()) { return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "Node:", node_name, " ", status.ErrorMessage()); } - output_def->SetShape(merge_target.shape()); + // we may have cleared the shape if there was a mismatch so handle that + if (utils::HasShape(merge_target)) + output_def->SetShape(merge_target.shape()); + else + output_def->ClearShape(); } } } diff --git a/onnxruntime/test/contrib_ops/element_wise_ops_test.cc b/onnxruntime/test/contrib_ops/element_wise_ops_test.cc index 434b2f89e7..45be5182b6 100644 --- a/onnxruntime/test/contrib_ops/element_wise_ops_test.cc +++ b/onnxruntime/test/contrib_ops/element_wise_ops_test.cc @@ -13,7 +13,7 @@ namespace onnxruntime { namespace test { TEST(MathOpTest, AffineDefaultAttributes) { - OpTester test("Affine"); + OpTester test("Affine", 7); std::vector dims{2, 2}; test.AddInput("A", dims, {0.0f, 1.0f, 2.0f, 3.0f}); test.AddOutput("B", dims, {0.0f, 1.0f, 2.0f, 3.0f}); @@ -21,7 +21,7 @@ TEST(MathOpTest, AffineDefaultAttributes) { } TEST(MathOpTest, Affine) { - OpTester test("Affine"); + OpTester test("Affine", 7); std::vector dims{2, 2}; test.AddAttribute("alpha", 2.0f); test.AddAttribute("beta", 1.0f); @@ -31,7 +31,7 @@ TEST(MathOpTest, Affine) { } TEST(MathOpTest, Scale) { - OpTester test("Scale"); + OpTester test("Scale", 7); std::vector dims{2, 2}; test.AddAttribute("scale", 2.0f); test.AddInput("A", dims, {0.0f, 1.0f, 2.0f, 3.0f}); @@ -40,7 +40,7 @@ TEST(MathOpTest, Scale) { } TEST(MathOpTest, Scale_Default) { - OpTester test("Scale"); + OpTester test("Scale", 7); std::vector dims{2, 2}; test.AddInput("A", dims, {0.0f, 1.0f, 2.0f, 3.0f}); test.AddOutput("B", dims, {0.0f, 1.0f, 2.0f, 3.0f}); diff --git a/onnxruntime/test/contrib_ops/tensor_op_test.cc b/onnxruntime/test/contrib_ops/tensor_op_test.cc index e611b5d41e..2a0920e345 100644 --- a/onnxruntime/test/contrib_ops/tensor_op_test.cc +++ b/onnxruntime/test/contrib_ops/tensor_op_test.cc @@ -5,7 +5,6 @@ #include "test/common/tensor_op_test_utils.h" #include "contrib_ops/cpu/crop.h" - using namespace ONNX_NAMESPACE; using namespace onnxruntime::test; namespace onnxruntime { @@ -29,7 +28,7 @@ TEST(CropContribOpTest, CropBorderOnly) { 5.0f, 6.0f}; - OpTester test("Crop"); + OpTester test("Crop", 7); test.AddAttribute("border", border); test.AddInput("input", {N, C, H, W}, X); test.AddOutput("output", {N, C, (H - border[2] - border[0]), (W - border[3] - border[1])}, output); @@ -56,7 +55,7 @@ TEST(CropContribOpTest, CropBorderAndScale) { 4.0f, 5.0f, 5.0f, 6.0f}; - OpTester test("Crop"); + OpTester test("Crop", 7); test.AddAttribute("border", border); test.AddAttribute("scale", scale); test.AddInput("input", {N, C, H, W}, X); @@ -83,7 +82,7 @@ TEST(ImageScalerContribOpTest, ImageScalerTest) { 8.0f, 12.0f, 16.0f, 20.0f}; - OpTester test("ImageScaler"); + OpTester test("ImageScaler", 7); test.AddAttribute("scale", scale); test.AddAttribute("bias", bias); test.AddInput("input", {N, C, H, W}, X); diff --git a/onnxruntime/test/framework/inference_session_test.cc b/onnxruntime/test/framework/inference_session_test.cc index 2f5b5193e8..0ff4ae63ec 100644 --- a/onnxruntime/test/framework/inference_session_test.cc +++ b/onnxruntime/test/framework/inference_session_test.cc @@ -1471,6 +1471,56 @@ TEST(InferenceSessionTests, TestL1AndL2Transformers) { } } +// fallback to lenient merging of shape info if model opset is not the latest +TEST(InferenceSessionTests, TestLenientShapeInferencing) { + // latest opset should fail + std::vector input_shape{2, 2}; + std::vector input_data{0.f, 1.f, 2.f, 3.f}; + std::vector invalid_output_shape{1, 2}; // valid shape is {2} as output data is input_shape + std::vector output_data{2, 2}; + + OpTester latest_opset("Shape"); + latest_opset.AddInput("data", input_shape, input_data); + latest_opset.AddOutput("output", invalid_output_shape, output_data); + latest_opset.Run(OpTester::ExpectResult::kExpectFailure, + "Mismatch between number of source and target dimensions. Source=1 Target=2"); + + // older opset should allow the mismatch with a warning. + // we also need for the output to be valid so OpTester doesn't throw so add an Unsqueeze after the Shape. + // This should result in a warning log message but successful run. + class OpTesterWithReshape : public OpTester { + public: + OpTesterWithReshape() : OpTester("Shape", 7) { + } + + protected: + void AddNodes(onnxruntime::Graph& graph, + std::vector& graph_input_defs, + std::vector& graph_output_defs, + std::vector>& add_attribute_funcs) override { + // we need to create an intermediate output with a different name + auto tmp_output_defs = graph_output_defs; + auto type_info = *tmp_output_defs[0]->TypeAsProto(); // copy + auto& shape_output = graph.GetOrCreateNodeArg("shape_output", &type_info); + tmp_output_defs[0] = &shape_output; + + // call base implementation to add the Shape node with invalid output shape + OpTester::AddNodes(graph, graph_input_defs, tmp_output_defs, add_attribute_funcs); + + // add Unsqueeze node to fix the output shape + + auto& unsqueeze = graph.AddNode("unsqueeze", "Unsqueeze", "Fix output shape", tmp_output_defs, graph_output_defs); + unsqueeze.AddAttribute("axes", std::vector{0}); + } + }; + + OpTesterWithReshape old_opset; + + old_opset.AddInput("data", input_shape, input_data); + old_opset.AddOutput("output", invalid_output_shape, output_data); + old_opset.Run(); +} + #ifdef USE_CUDA TEST(InferenceSessionTests, TestParallelExecutionWithCudaProvider) { diff --git a/onnxruntime/test/providers/cpu/controlflow/scan_test.cc b/onnxruntime/test/providers/cpu/controlflow/scan_test.cc index 10d350f478..9b40aff358 100644 --- a/onnxruntime/test/providers/cpu/controlflow/scan_test.cc +++ b/onnxruntime/test/providers/cpu/controlflow/scan_test.cc @@ -335,7 +335,7 @@ static void RunTest_v9(const std::string test_name, int64_t sequence_len, int64_ CreateSubgraph(graph, options, options.add_bad_shape ? failure_message : ""); auto& proto = graph.ToGraphProto(); - ScanOpTester test{9}; + ScanOpTester test{11}; // use latest version - no significant change over 9 test.AddAttribute("body", proto); test.AddAttribute("num_scan_inputs", 2); @@ -553,9 +553,10 @@ static void OuterScopeAccess_NoShapeInMainGraph_NoTypeAndShapeInSubgraph(bool is TEST_8_AND_9(OuterScopeAccess_NoShapeInMainGraph_NoTypeAndShapeInSubgraph); -static void BadShape(bool is_v8) { +// shape inferencing is only strict for the latest version so only test BadShape with that +TEST(Scan9, BadShape) { RunOptions options{}; - options.is_v8 = is_v8; + options.is_v8 = false; options.include_dim_values_in_main_graph = false; options.include_types_in_subgraph = true; options.include_dim_values_in_subgraph = true; @@ -566,9 +567,6 @@ static void BadShape(bool is_v8) { "Node:concat Output:concat_out_1 [ShapeInferenceError] Mismatch between number of source and target dimensions. " "Source=2 Target=1"); } - -TEST_8_AND_9(BadShape); - TEST(Scan8, ShortSequenceTwoInBatchOneLoopStateVar) { const int64_t batch_size = 2; const int64_t sequence_len = 2; diff --git a/onnxruntime/test/providers/cpu/math/logsoftmax_test.cc b/onnxruntime/test/providers/cpu/math/logsoftmax_test.cc index 32f44174c5..a4ed40c805 100644 --- a/onnxruntime/test/providers/cpu/math/logsoftmax_test.cc +++ b/onnxruntime/test/providers/cpu/math/logsoftmax_test.cc @@ -101,7 +101,7 @@ TEST(LogSoftmaxOperator, ThreeDimsAxis0) { -4.042971f, -4.2982683f, -3.5933442f, -4.538994f, -5.307373f, -4.2677402f, -4.44635f, -3.5821702f, -3.8414123f, -4.267664f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*axis*/ 0, false);// axis=0 is not supported by TensorRT + RunTest(x_vals_3dims, expected_vals, three_dimensions, /*axis*/ 0, false); // axis=0 is not supported by TensorRT } TEST(LogSoftmaxOperator, ThreeDimsAxis1) { @@ -127,7 +127,7 @@ TEST(LogSoftmaxOperator, ThreeDimsAxis1) { -2.9822054f, -3.2375026f, -2.5325785f, -3.4782279f, -4.246608f, -3.2069747f, -3.3855844f, -2.5214045f, -2.7806466f, -3.206898f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*axis*/ 1, false);// This test failed on TensorRT + RunTest(x_vals_3dims, expected_vals, three_dimensions, /*axis*/ 1, false); // This test failed on TensorRT } TEST(LogSoftmaxOperator, ThreeDimsAxis2) { @@ -194,7 +194,9 @@ TEST(LogSoftmaxOperator, InvalidAxis) { /* invalid axis */ -7, false, OpTester::ExpectResult::kExpectFailure, - "-7 is not in valid range [-2,1]");//TensorRT parser: Assertion failed: axis >= 0 && axis < nbDims + // ONNX has a bug in the error message generation so this is somewhat cryptic until it's fixed. Message should be: + // "[ShapeInferenceError] 'axis' must be in [-2 , 1]. Its actual value is: -7" + ", 1]. Its actual value is: -7"); //TensorRT parser: Assertion failed: axis >= 0 && axis < nbDims } } // namespace test diff --git a/onnxruntime/test/providers/cpu/math/softmax_test.cc b/onnxruntime/test/providers/cpu/math/softmax_test.cc index 48ea1bdbf1..08a8b89c44 100644 --- a/onnxruntime/test/providers/cpu/math/softmax_test.cc +++ b/onnxruntime/test/providers/cpu/math/softmax_test.cc @@ -96,7 +96,7 @@ TEST(SoftmaxOperator, ThreeDimsAxis0) { 0.017545262f, 0.0135920765f, 0.027506188f, 0.010684152f, 0.0049549243f, 0.01401341f, 0.011721271f, 0.027815264f, 0.021463264f, 0.014014485f}; - RunTest(x_vals_3dims, expected_vals, three_dimensions, /*axis*/ 0, false);// Axis=0 is not supported by TensorRT + RunTest(x_vals_3dims, expected_vals, three_dimensions, /*axis*/ 0, false); // Axis=0 is not supported by TensorRT } TEST(SoftmaxOperator, ThreeDimsAxis1) { @@ -188,7 +188,9 @@ TEST(SoftmaxOperator, InvalidAxis) { dimensions, /* invalid axis */ -10, false, OpTester::ExpectResult::kExpectFailure, - "-10 is not in valid range [-2,1]"); + // bug in ONNX error message currently. Message should be + // "[ShapeInferenceError] 'axis' must be in [-2 , 1]. Its actual value is: -10" + ", 1]. Its actual value is: -10"); } } // namespace test diff --git a/onnxruntime/test/providers/cpu/nn/tfidfvectorizer_test.cc b/onnxruntime/test/providers/cpu/nn/tfidfvectorizer_test.cc index a11675caaf..c424323c11 100644 --- a/onnxruntime/test/providers/cpu/nn/tfidfvectorizer_test.cc +++ b/onnxruntime/test/providers/cpu/nn/tfidfvectorizer_test.cc @@ -10,9 +10,6 @@ namespace onnxruntime { namespace test { namespace tfidfvectorizer_test { -constexpr const char* domain = kOnnxDomain; -const int opset_ver = 9; - void InitTestAttr(OpTester& test, const std::string& mode, int64_t min_gram_length, int64_t max_gram_length, int64_t max_skip_count, const std::vector& ngram_counts, @@ -49,7 +46,7 @@ using namespace tfidfvectorizer_test; // into consideration or not.With all = false, we only consider N - grams. TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -71,7 +68,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0) { } TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim1Fail) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -89,11 +86,13 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim1Fail) { std::vector output = {}; test.AddOutput("Y", out_dims, output); - test.Run(OpTester::ExpectResult::kExpectFailure); + test.Run(OpTester::ExpectResult::kExpectFailure, + "Can't merge shape info. " + "Both source and target dimension have values but they differ. Source=7 Target=0 Dimension=0"); } TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim1Success) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -115,7 +114,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim1Success) { } TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim2) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -133,11 +132,12 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim2) { std::vector output = {0, 0, 0, 0, 0, 0, 0}; test.AddOutput("Y", out_dims, output); - test.Run(OpTester::ExpectResult::kExpectFailure); + test.Run(OpTester::ExpectResult::kExpectFailure, + "Mismatch between number of source and target dimensions. Source=2 Target=1"); } TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip01_Empty_Dim2) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -155,11 +155,12 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip01_Empty_Dim2) { std::vector output = {0, 0, 0, 0, 0, 0, 0}; test.AddOutput("Y", out_dims, output); - test.Run(OpTester::ExpectResult::kExpectFailure); + test.Run(OpTester::ExpectResult::kExpectFailure, + "Mismatch between number of source and target dimensions. Source=2 Target=1"); } TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim2N) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -174,7 +175,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim2N) { test.AddInput("T", dims, input); std::vector out_dims{2, 7}; - std::vector output = {0, 0, 0, 0, 0, 0, 0, + std::vector output = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; test.AddOutput("Y", out_dims, output); @@ -182,7 +183,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip0_Empty_Dim2N) { } TEST(TfIdfVectorizerTest, Int32_TF_BatchOnlyBigrams_Skip0) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -207,7 +208,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_BatchOnlyBigrams_Skip0) { } TEST(TfIdfVectorizerTest, String_TF_OnlyBigrams_Skip0) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, string InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -230,7 +231,7 @@ TEST(TfIdfVectorizerTest, String_TF_OnlyBigrams_Skip0) { } TEST(TfIdfVectorizerTest, String_TF_BatchOnlyBigrams_Skip0) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, string InitTestAttr(test, "TF", 2, 2, 0, {0, 4}, @@ -257,7 +258,7 @@ TEST(TfIdfVectorizerTest, String_TF_BatchOnlyBigrams_Skip0) { } TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_LevelEmpty) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=0, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 0, {0, 0}, // no unigrams, bi-grams start immediately @@ -283,7 +284,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_LevelEmpty) { } TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 5, {0, 4}, @@ -307,7 +308,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, Int32_TF_BatchOnlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, , Min=Max=2, weights empty, int32 InitTestAttr(test, "TF", 2, 2, 5, {0, 4}, @@ -333,7 +334,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_BatchOnlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, String_TF_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, , Min=Max=2, weights empty, string InitTestAttr(test, "TF", 2, 2, 5, {0, 4}, @@ -358,7 +359,7 @@ TEST(TfIdfVectorizerTest, String_TF_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, String_TF_BatchOnlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, , Min=Max=2, weights empty, string InitTestAttr(test, "TF", 2, 2, 5, {0, 4}, @@ -382,7 +383,7 @@ TEST(TfIdfVectorizerTest, String_TF_BatchOnlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, Int32_TF_UniAndBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, , Min=1, Max=2, weights empty, int32 InitTestAttr(test, "TF", 1, 2, 5, {0, 4}, @@ -405,7 +406,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_UniAndBigrams_Skip5) { } TEST(TfIdfVectorizerTest, Int32_TF_BatchUniAndBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=1, Max=2, weights empty, int32 InitTestAttr(test, "TF", 1, 2, 5, {0, 4}, @@ -430,7 +431,7 @@ TEST(TfIdfVectorizerTest, Int32_TF_BatchUniAndBigrams_Skip5) { } TEST(TfIdfVectorizerTest, String_TF_UniAndBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=1, Max=2, weights empty, string InitTestAttr(test, "TF", 1, 2, 5, {0, 4}, @@ -453,7 +454,7 @@ TEST(TfIdfVectorizerTest, String_TF_UniAndBigrams_Skip5) { } TEST(TfIdfVectorizerTest, String_TF_BatchUniAndBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=1, Max=2, weights empty, string InitTestAttr(test, "TF", 1, 2, 5, {0, 4}, @@ -478,7 +479,7 @@ TEST(TfIdfVectorizerTest, String_TF_BatchUniAndBigrams_Skip5) { } TEST(TfIdfVectorizerTest, Int32_IDF_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights empty, int32 // We change to IDF but do not supply weights so // we should get all 1.0f where count is not zero @@ -502,7 +503,7 @@ TEST(TfIdfVectorizerTest, Int32_IDF_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, String_IDF_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights empty, string InitTestAttr(test, "IDF", 2, 2, 5, {0, 4}, @@ -525,7 +526,7 @@ TEST(TfIdfVectorizerTest, String_IDF_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, Int32_TFIDF_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights empty, int32 // We change to TFIDF but do not supply weights so // we should all get the original values as weights are 1.0f by @@ -550,7 +551,7 @@ TEST(TfIdfVectorizerTest, Int32_TFIDF_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, String_TFIDF_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights empty, string InitTestAttr(test, "TFIDF", 2, 2, 5, {0, 4}, @@ -573,7 +574,7 @@ TEST(TfIdfVectorizerTest, String_TFIDF_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, Int32_IDFWeights_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights specified, int32 // We change to IDF with supplied weights. All // with non-zero counts must be replaced with the supplied weights @@ -597,7 +598,7 @@ TEST(TfIdfVectorizerTest, Int32_IDFWeights_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, String_IDFWeights_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights specified, string InitTestAttr(test, "IDF", 2, 2, 5, {0, 4}, @@ -620,7 +621,7 @@ TEST(TfIdfVectorizerTest, String_IDFWeights_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, Int32_TFIDFWeights_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights specified, int32 // We change to TFIDF with supplied weights. // We should have all counts scaled by weights @@ -644,7 +645,7 @@ TEST(TfIdfVectorizerTest, Int32_TFIDFWeights_onlyBigrams_Skip5) { } TEST(TfIdfVectorizerTest, String_TFIDFWeights_onlyBigrams_Skip5) { - OpTester test("TfIdfVectorizer", opset_ver, domain); + OpTester test("TfIdfVectorizer"); // s=5, Min=Max=2, weights specified, string InitTestAttr(test, "TFIDF", 2, 2, 5, {0, 4}, diff --git a/onnxruntime/test/providers/cpu/tensor/gather_op_test.cc b/onnxruntime/test/providers/cpu/tensor/gather_op_test.cc index 0e563d1a81..78884dfd4b 100644 --- a/onnxruntime/test/providers/cpu/tensor/gather_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/gather_op_test.cc @@ -81,7 +81,7 @@ TEST(GatherOpTest, Gather_invalid_index_cpu) { #ifdef USE_CUDA TEST(GatherOpTest, Gather_invalid_index_gpu) { - OpTester test("Gather"); + OpTester test("Gather", 7); // no GPU Gather for opset 11 yet (change was to add negative axis support) // Invalid index 3. data[3] does not exist. test.AddAttribute("axis", 0LL); test.AddInput("data", {3, 4}, @@ -186,7 +186,7 @@ TEST(GatherOpTest, Gather_axis1_indices2d_int32) { {1, 0, 2, 1, 11, 10, 12, 11, 21, 20, 22, 21}); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Input batch size is inconsistent } TEST(GatherOpTest, Gather_axis1_indices2d_uint32) { @@ -254,7 +254,7 @@ TEST(GatherOpTest, Gather_axis1_indices2d_int8) { {1, 0, 2, 1, 11, 10, 12, 11, 21, 20, 22, 21}); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Assertion `regionRanges != nullptr' failed + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Assertion `regionRanges != nullptr' failed } TEST(GatherOpTest, Gather_axis1_indices2d_string) { @@ -320,7 +320,7 @@ TEST(GatherOpTest, Gather_axis1_neg_indices2d_int8) { {1, 0, 2, 1, 11, 10, 12, 11, 21, 20, 22, 21}); - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Assertion `regionRanges != nullptr' failed + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider}); //TensorRT: Assertion `regionRanges != nullptr' failed } } // namespace test diff --git a/onnxruntime/test/providers/cpu/tensor/unsqueeze_op_test.cc b/onnxruntime/test/providers/cpu/tensor/unsqueeze_op_test.cc index 43e81a4d19..783134c0f7 100644 --- a/onnxruntime/test/providers/cpu/tensor/unsqueeze_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/unsqueeze_op_test.cc @@ -51,7 +51,9 @@ TEST(TensorOpTest, Unsqueeze_Duplicate) { test.AddAttribute("axes", std::vector{2, 1, 0, 2}); test.AddInput("input", {2, 3, 4}, std::vector(2 * 3 * 4, 1.0f)); test.AddOutput("output", {1, 1, 1, 2, 3, 4}, std::vector(2 * 3 * 4, 1.0f)); - test.Run(OpTester::ExpectResult::kExpectFailure, "'axes' has a duplicate axis", {kTensorrtExecutionProvider}); //TensorRT failed + test.Run(OpTester::ExpectResult::kExpectFailure, + "[ShapeInferenceError] 'axes' attribute must not contain any duplicates", + {kTensorrtExecutionProvider}); //TensorRT failed } TEST(TensorOpTest, Unsqueeze_OutOfRange) { @@ -60,7 +62,8 @@ TEST(TensorOpTest, Unsqueeze_OutOfRange) { test.AddAttribute("axes", std::vector{4}); test.AddInput("input", {2, 3, 4}, std::vector(2 * 3 * 4, 1.0f)); test.AddOutput("output", {2, 1, 3, 4}, std::vector(2 * 3 * 4, 1.0f)); - test.Run(OpTester::ExpectResult::kExpectFailure, "Mismatch between number of source and target dimensions."); + test.Run(OpTester::ExpectResult::kExpectFailure, + "[ShapeInferenceError] values in 'axes' are beyond the bounds of the computed output shape"); } TEST(TensorOpTest, UnsqueezeNegAxis_3) { @@ -70,7 +73,7 @@ TEST(TensorOpTest, UnsqueezeNegAxis_3) { test.AddInput("input", {2, 3, 4}, std::vector(2 * 3 * 4, 1.0f)); test.AddOutput("output", {1, 1, 1, 2, 3, 4}, std::vector(2 * 3 * 4, 1.0f)); // nGraph and TensorRT does not support negative axis. - test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kTensorrtExecutionProvider}); + test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider, kTensorrtExecutionProvider}); } } // namespace test diff --git a/onnxruntime/test/providers/cpu/tensor/upsample_op_test.cc b/onnxruntime/test/providers/cpu/tensor/upsample_op_test.cc index e7a67bc12d..6cf7cb8e1a 100644 --- a/onnxruntime/test/providers/cpu/tensor/upsample_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/upsample_op_test.cc @@ -12,7 +12,7 @@ namespace test { // and limited data types. Those tests will fallback to other EPs TEST(UpsampleOpTest, UpsampleOpNearestTest) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 2.0f, 3.0f}; test.AddAttribute("mode", "nearest"); @@ -43,7 +43,7 @@ TEST(UpsampleOpTest, UpsampleOpNearestTest) { } TEST(UpsampleOpTest, UpsampleOpNearestTest_int32) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 2.0f, 3.0f}; test.AddAttribute("mode", "nearest"); @@ -74,7 +74,7 @@ TEST(UpsampleOpTest, UpsampleOpNearestTest_int32) { } TEST(UpsampleOpTest, UpsampleOpNearestTest_uint8) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 2.0f, 3.0f}; test.AddAttribute("mode", "nearest"); @@ -105,7 +105,7 @@ TEST(UpsampleOpTest, UpsampleOpNearestTest_uint8) { } TEST(UpsampleOpTest, UpsampleOpNearest2XTest) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 2.0f, 2.0f}; test.AddAttribute("mode", "nearest"); @@ -136,7 +136,7 @@ TEST(UpsampleOpTest, UpsampleOpNearest2XTest) { } TEST(UpsampleOpTest, UpsampleOpNearest222XTest) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{2.0f, 1.0f, 2.0f, 2.0f}; test.AddAttribute("mode", "nearest"); @@ -177,7 +177,7 @@ TEST(UpsampleOpTest, UpsampleOpNearest222XTest) { } TEST(UpsampleOpTest, UpsampleOpNearest15XTest) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 2.0f, 1.5f}; test.AddAttribute("mode", "nearest"); @@ -208,7 +208,7 @@ TEST(UpsampleOpTest, UpsampleOpNearest15XTest) { } TEST(UpsampleOpTest, UpsampleOpNearestTest_NoScale) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 1.0f, 1.0f}; test.AddAttribute("mode", "nearest"); @@ -234,7 +234,7 @@ TEST(UpsampleOpTest, UpsampleOpNearestTest_NoScale) { } TEST(UpsampleOpTest, UpsampleOpNearest2XTest_int32) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 2.0f, 2.0f}; test.AddAttribute("mode", "nearest"); @@ -265,7 +265,7 @@ TEST(UpsampleOpTest, UpsampleOpNearest2XTest_int32) { } TEST(UpsampleOpTest, UpsampleOp4DBilinearTest) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 2.0f, 4.0f}; test.AddAttribute("mode", "linear"); @@ -296,7 +296,7 @@ TEST(UpsampleOpTest, UpsampleOp4DBilinearTest) { } TEST(UpsampleOpTest, UpsampleOp2DBilinearTest) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{2.0f, 4.0f}; test.AddAttribute("mode", "linear"); @@ -312,15 +312,14 @@ TEST(UpsampleOpTest, UpsampleOp2DBilinearTest) { 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.0f, 3.0f, 3.0f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.0f, 4.0f, 4.0f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.0f, 5.0f, 5.0f, - 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.0f, 5.0f, 5.0f - }; + 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.0f, 5.0f, 5.0f}; test.AddOutput("Y", {(int64_t)(H * scales[0]), (int64_t)(W * scales[1])}, Y); test.Run(); } TEST(UpsampleOpTest, UpsampleOp4DBilinearTest_ScalesNoOp) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 1.0f, 1.0f}; test.AddAttribute("mode", "linear"); @@ -346,7 +345,7 @@ TEST(UpsampleOpTest, UpsampleOp4DBilinearTest_ScalesNoOp) { } TEST(UpsampleOpTest, UpsampleOp4DBilinearTest_int32) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{1.0f, 1.0f, 2.0f, 4.0f}; test.AddAttribute("mode", "linear"); @@ -377,7 +376,7 @@ TEST(UpsampleOpTest, UpsampleOp4DBilinearTest_int32) { } TEST(UpsampleOpTest, UpsampleOpNearestTest_1D) { - OpTester test("Upsample"); + OpTester test("Upsample", 7); std::vector scales{2.0f}; test.AddAttribute("mode", "nearest"); diff --git a/onnxruntime/test/providers/provider_test_utils.h b/onnxruntime/test/providers/provider_test_utils.h index 1c91ccba71..3bd3157fbc 100644 --- a/onnxruntime/test/providers/provider_test_utils.h +++ b/onnxruntime/test/providers/provider_test_utils.h @@ -242,8 +242,14 @@ const SequenceTensorTypeProto SequenceTensorType::s_sequence // explanatory class OpTester { public: - explicit OpTester(const char* op, int opset_version = 7, const char* domain = onnxruntime::kOnnxDomain) - : op_(op), domain_(domain), opset_version_(opset_version) {} + explicit OpTester(const char* op, int opset_version = -1, const char* domain = onnxruntime::kOnnxDomain) + : op_(op), domain_(domain), opset_version_(opset_version) { + if (opset_version_ < 0) { + static int latest_onnx_version = + ONNX_NAMESPACE::OpSchemaRegistry::DomainToVersionRange().Map().at(ONNX_NAMESPACE::ONNX_DOMAIN).second; + opset_version_ = latest_onnx_version; + } + } ~OpTester();