From d21572d7cbaad671fc1f4aa9995a517b4367f96d Mon Sep 17 00:00:00 2001 From: Mikhail Nosov Date: Thu, 14 Oct 2021 17:54:41 +0300 Subject: [PATCH] Squashed commit of the following: (#7930) commit e692037384525e24f4f88d2b10fd5f5c09881d8a Merge: a0ad24b16 82f8f19d1 Author: Michael Nosov Date: Wed Oct 13 15:06:20 2021 +0300 Merge remote-tracking branch 'upstream/master' into ov20/remove_tensor_names # Conflicts: # inference-engine/tests/functional/inference_engine/ir_serialization/rt_info_deserialization.cpp commit a0ad24b16ab6ef7cf37dedb04084813178f0d627 Merge: 3c1f7067f db527fff4 Author: Michael Nosov Date: Wed Oct 13 13:45:39 2021 +0300 Merge remote-tracking branch 'upstream/master' into ov20/remove_tensor_names commit 3c1f7067f01634378cf66eee996d8793b635a6f2 Author: Michael Nosov Date: Wed Oct 13 13:45:13 2021 +0300 Remove ignoring friendly names while comparing functions commit f31e018d9a4694e83a3f12e685d8e90a9aca9045 Author: Michael Nosov Date: Tue Oct 12 23:50:20 2021 +0300 Fix macos test commit 2e3d0ceced3bde893e1e8237f7769c94bd193531 Author: Michael Nosov Date: Tue Oct 12 20:06:06 2021 +0300 Fixes after merge commit 5f047070af7c71a75f5ec019a146e17b3f95c062 Merge: 1568c9723 c323775f2 Author: Michael Nosov Date: Tue Oct 12 18:59:21 2021 +0300 Merge remote-tracking branch 'upstream/master' into ov20/remove_tensor_names # Conflicts: # inference-engine/tests/functional/inference_engine/ir_serialization/rt_info_deserialization.cpp # inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp # ngraph/core/src/preprocess/pre_post_process.cpp # ngraph/core/src/preprocess/preprocess_steps_impl.cpp # ngraph/core/src/preprocess/preprocess_steps_impl.hpp # ngraph/test/util/graph_comparator.cpp commit 1568c97238c206a43cd8b14b6aba49fcee828386 Author: Michael Nosov Date: Tue Oct 12 13:56:48 2021 +0300 Throw an error if 'InputInfo' is specified for same parameter twice. commit d1830ba61b750b12484322c97261c7062551f798 Merge: 4f01b396b d79020457 Author: Michael Nosov Date: Tue Oct 12 13:34:32 2021 +0300 Merge remote-tracking branch 'upstream/master' into ov20/remove_tensor_names commit 4f01b396ba4b68d88d583092a38836754e78531c Author: Michael Nosov Date: Tue Oct 12 13:34:19 2021 +0300 Insert multi-plane parameters into new parameters vector (don't append them) commit 70f85e5f351a37f2b79cff118399778c55136845 Author: Michael Nosov Date: Tue Oct 12 00:26:43 2021 +0300 Fixed failed CPU/GPU test, created skipped test to clearly reproduce the problem Don't generate friendly and tensor names for sub-planes. Test is updated Keep the order of created parameters and results after pre and post processing Added tests for params/results order commit 8b2cbf6db6646f6b2a01fc9e75726b682aa87fc2 Merge: 6050afbce 6d322722c Author: Michael Nosov Date: Mon Oct 11 17:55:25 2021 +0300 Merge remote-tracking branch 'upstream/master' into ov20/remove_tensor_names commit 6050afbce256f21430322ec7b0a38105e3f06066 Author: Michael Nosov Date: Sun Oct 10 23:54:40 2021 +0300 IE reader: remove unnecessary convert_layout() commit 0f43133f6dfddf41233835678872c9a80b631565 Author: Michael Nosov Date: Sun Oct 10 23:33:29 2021 +0300 Update IE tests commit 75afe69ccf36b9764dc9285d77fe1a65ae4146b4 Merge: c86366577 67cfc9beb Author: Michael Nosov Date: Fri Oct 8 22:52:17 2021 +0300 Merge commit '67cfc9beb5bb0c66916c91ab5820dc25ad164a70' of https://github.com/openvinotoolkit/openvino into ov20/remove_tensor_names commit c86366577ede8491ed722f9d048b7556d3266c68 Author: Michael Nosov Date: Fri Oct 8 22:26:17 2021 +0300 First commit (IE func tests are failed) commit 67cfc9beb5bb0c66916c91ab5820dc25ad164a70 Author: y Date: Fri Oct 8 16:09:11 2021 +0300 Removed explicit preprocessing steps --- .../src/ie_network_reader.cpp | 19 +- .../rt_info_deserialization.cpp | 18 +- .../skip_tests_config.cpp | 5 +- .../skip_tests_config.cpp | 2 + .../subgraph_tests/preprocess.cpp | 2 + .../preprocess/preprocess_builders.hpp | 44 +++- .../openvino/core/preprocess/color_format.hpp | 3 +- .../core/preprocess/input_tensor_info.hpp | 22 +- ngraph/core/src/preprocess/color_utils.hpp | 16 +- ngraph/core/src/preprocess/function_guard.hpp | 18 ++ .../core/src/preprocess/pre_post_process.cpp | 73 ++++-- .../src/preprocess/preprocess_steps_impl.cpp | 11 - .../src/preprocess/preprocess_steps_impl.hpp | 41 --- ngraph/core/src/tensor_name_util.hpp | 16 +- ngraph/test/preprocess.cpp | 236 ++++++++++++------ 15 files changed, 307 insertions(+), 219 deletions(-) diff --git a/inference-engine/src/inference_engine/src/ie_network_reader.cpp b/inference-engine/src/inference_engine/src/ie_network_reader.cpp index a9d42422f1b..67b3874f77d 100644 --- a/inference-engine/src/inference_engine/src/ie_network_reader.cpp +++ b/inference-engine/src/inference_engine/src/ie_network_reader.cpp @@ -278,11 +278,7 @@ CNNNetwork convert_to_cnnnetwork(std::shared_ptr& function, for (size_t i = 0; i < inputs.size(); ++i) { const auto ngraph_type = inputs[i].get_element_type(); const auto legacy_type = details::toLegacyType(ngraph_type, true); - prepost.input(ov::preprocess::InputInfo(i) - .tensor(InputTensorInfo().set_element_type(legacy_type)) - .preprocess(PreProcessSteps() - // TODO: remove explicit type - .convert_element_type(ngraph_type))); + prepost.input(ov::preprocess::InputInfo(i).tensor(InputTensorInfo().set_element_type(legacy_type))); } // in order to support the following scenarios for IR v10 cases: @@ -313,9 +309,7 @@ CNNNetwork convert_to_cnnnetwork(std::shared_ptr& function, const auto ngraph_type = outputs[i].get_element_type(); const auto legacy_type = details::toLegacyType(ngraph_type, false); - prepost.output(OutputInfo(i) - .postprocess(PostProcessSteps().convert_element_type()) - .tensor(OutputTensorInfo().set_element_type(legacy_type))); + prepost.output(OutputInfo(i).tensor(OutputTensorInfo().set_element_type(legacy_type))); } function = prepost.build(function); @@ -350,18 +344,10 @@ CNNNetwork convert_to_cnnnetwork(std::shared_ptr& function, networkLayout << old_api_transpose_args[i]; } - PreProcessSteps steps; - // TODO: remove explicit type - steps.convert_element_type(parameter->get_element_type()); - // TODO: move steps directly to builder once we allow Layout() -> Layout transpose - if (!old_api_transpose_args.empty()) - steps.convert_layout(); - prepost.input( ov::preprocess::InputInfo(i) .tensor( InputTensorInfo().set_element_type(old_api_type).set_layout(ov::Layout(tensorLayout.str()))) - .preprocess(std::move(steps)) .network(InputNetworkInfo().set_layout(ov::Layout(networkLayout.str())))); // Set version to 10 @@ -395,7 +381,6 @@ CNNNetwork convert_to_cnnnetwork(std::shared_ptr& function, prepost.output(OutputInfo(i) .network(OutputNetworkInfo().set_layout(ov::Layout(networkLayout.str()))) - .postprocess(PostProcessSteps().convert_layout().convert_element_type()) .tensor(OutputTensorInfo() .set_element_type(old_api_type) .set_layout(ov::Layout(tensorLayout.str())))); diff --git a/inference-engine/tests/functional/inference_engine/ir_serialization/rt_info_deserialization.cpp b/inference-engine/tests/functional/inference_engine/ir_serialization/rt_info_deserialization.cpp index 5e8f101c024..72b568bb197 100644 --- a/inference-engine/tests/functional/inference_engine/ir_serialization/rt_info_deserialization.cpp +++ b/inference-engine/tests/functional/inference_engine/ir_serialization/rt_info_deserialization.cpp @@ -160,6 +160,7 @@ TEST_F(RTInfoDeserialization, NodeV10) { param->set_friendly_name("in1"); param->get_output_tensor(0).set_names({"input_tensor", param->get_friendly_name()}); + // TODO: No guarantee that exactly 'Convert' will be added auto convert_param = std::make_shared(param, ngraph::element::f16); auto round = std::make_shared(convert_param, @@ -316,8 +317,8 @@ TEST_F(RTInfoDeserialization, InputAndOutputV10) { param->get_output_tensor(0).set_names({"input_tensor", param->get_friendly_name()}); auto sum = std::make_shared(param, param); - sum->set_friendly_name("sum"); + // TODO: No guarantee that exactly 'convert' will be added by post-processing auto convert_result = std::make_shared(sum, ngraph::element::i32); convert_result->set_friendly_name("sum"); convert_result->get_output_tensor(0).set_names({"output_tensor", convert_result->get_friendly_name()}); @@ -472,6 +473,7 @@ TEST_F(RTInfoDeserialization, NodeV11) { param->set_friendly_name("in1"); param->get_output_tensor(0).set_names({"input_tensor"}); + // TODO: No guarantee that exactly 'convert, then transpose' will be added by implicit pre-processing auto convert_param = std::make_shared(param, ngraph::element::f32); auto constant_param = std::make_shared(ngraph::element::i64, @@ -485,16 +487,16 @@ TEST_F(RTInfoDeserialization, NodeV11) { round->get_rt_info()[VariantWrapper::get_type_info_static()] = std::make_shared>(ngraph::FusedNames("Round1,Round2")); + // TODO: No guarantee that exactly 'convert, then transpose' will be added by implicit post-processing + auto convert_result = std::make_shared(round, type); auto constant_result = std::make_shared(ngraph::element::i64, ngraph::Shape{4}, std::vector{0, 3, 1, 2}); - auto transpose_result = std::make_shared(round, constant_result); + auto transpose_result = std::make_shared(convert_result, constant_result); + transpose_result->set_friendly_name("Round"); + transpose_result->get_output_tensor(0).set_names({"output_tensor"}); - auto convert_result = std::make_shared(transpose_result, type); - convert_result->set_friendly_name("Round"); - convert_result->get_output_tensor(0).set_names({"output_tensor"}); - - auto result = std::make_shared(convert_result); + auto result = std::make_shared(transpose_result); result->set_friendly_name("output"); auto f_10_ref = @@ -508,7 +510,9 @@ TEST_F(RTInfoDeserialization, NodeV11) { check_version(f_10_core, 10); + ASSERT_GT(cnn_core.getInputsInfo().count("in1"), 0); EXPECT_EQ(InferenceEngine::Precision::FP32, cnn_core.getInputsInfo()["in1"]->getPrecision()); + ASSERT_GT(cnn_core.getOutputsInfo().count("Round"), 0); EXPECT_EQ(InferenceEngine::Precision::FP32, cnn_core.getOutputsInfo()["Round"]->getPrecision()); const auto fc = FunctionsComparator::with_default() diff --git a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp index 4e24630ba6c..cc06fb589e7 100644 --- a/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp +++ b/inference-engine/tests/functional/plugin/cpu/shared_tests_instances/skip_tests_config.cpp @@ -121,9 +121,8 @@ std::vector disabledTestPatterns() { R"(smoke_PrePostProcess.*resize_linear_nhwc.*)", // Issue 67214 R"(smoke_PrePostProcess.*resize_and_convert_layout_i8.*)", - - // TODO: - R"(smoke_PrePostProcess.*two_inputs_basic_Device.*)" + // Issue 67910 + R"(.*smoke_PrePostProcess.*two_inputs_trivial.*)", }; #define FIX_62820 0 diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/skip_tests_config.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/skip_tests_config.cpp index 987c9344b94..db927f093d4 100644 --- a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/skip_tests_config.cpp +++ b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/skip_tests_config.cpp @@ -74,5 +74,7 @@ std::vector disabledTestPatterns() { R"(.*smoke_PrePostProcess_GPU.*convert_element_type_and_mean.*)", // TODO: Issue 67408 R"(.*smoke_LSTMSequenceCommonClip.*LSTMSequenceTest.*CompareWithRefs.*)", + // TODO: Issue 67910 + R"(.*smoke_PrePostProcess_GPU.*two_inputs_trivial.*)", }; } diff --git a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/subgraph_tests/preprocess.cpp b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/subgraph_tests/preprocess.cpp index fbd6a869f13..29b83e88ab7 100644 --- a/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/subgraph_tests/preprocess.cpp +++ b/inference-engine/tests/functional/plugin/gpu/shared_tests_instances/subgraph_tests/preprocess.cpp @@ -17,6 +17,8 @@ inline std::vector GPU_smoke_preprocess_functions() { preprocess_func(mean_only, "mean_only", 0.01f), preprocess_func(scale_only, "scale_only", 0.01f), preprocess_func(convert_element_type_and_mean, "convert_element_type_and_mean", 0.01f), + preprocess_func(two_inputs_basic, "two_inputs_basic", 0.01f), + preprocess_func(two_inputs_trivial, "two_inputs_trivial", 0.01f), }; } diff --git a/inference-engine/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/preprocess/preprocess_builders.hpp b/inference-engine/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/preprocess/preprocess_builders.hpp index 43c00a837f7..39d13c89e1b 100644 --- a/inference-engine/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/preprocess/preprocess_builders.hpp +++ b/inference-engine/tests/ngraph_helpers/ngraph_functions/include/ngraph_functions/preprocess/preprocess_builders.hpp @@ -23,13 +23,15 @@ inline std::shared_ptr create_preprocess_1input(element::Type type, data1->set_friendly_name("input1"); data1->output(0).get_tensor().set_names({"input1"}); std::shared_ptr res; + auto op1 = std::make_shared(data1); if (type == element::f32) { - res = std::make_shared(data1); + res = std::make_shared(op1); } else { auto convert = std::make_shared(data1, element::f32); - res = std::make_shared(convert); + res = std::make_shared(op1); } - res->set_friendly_name("Result"); + res->set_friendly_name("Result1"); + res->output(0).get_tensor().set_names({"Result1"}); return std::make_shared(ResultVector{res}, ParameterVector{data1}); } @@ -42,17 +44,37 @@ inline std::shared_ptr create_preprocess_2inputs(element::Type type, data2->set_friendly_name("input2"); data2->output(0).get_tensor().set_names({"input2"}); std::shared_ptr res1, res2; + auto op1 = std::make_shared(data1); + auto op2 = std::make_shared(data2); if (type == element::f32) { - res1 = std::make_shared(data1); - res2 = std::make_shared(data2); + res1 = std::make_shared(op1); + res2 = std::make_shared(op2); } else { - auto convert1 = std::make_shared(data1, element::f32); + auto convert1 = std::make_shared(op1, element::f32); res1 = std::make_shared(convert1); - auto convert2 = std::make_shared(data2, element::f32); + auto convert2 = std::make_shared(op2, element::f32); res2 = std::make_shared(convert2); } res1->set_friendly_name("Result1"); + res1->output(0).get_tensor().set_names({"Result1"}); res2->set_friendly_name("Result2"); + res2->output(0).get_tensor().set_names({"Result2"}); + return std::make_shared(ResultVector{res1, res2}, ParameterVector{data1, data2}); +} + +inline std::shared_ptr create_preprocess_2inputs_trivial() { + auto data1 = std::make_shared(element::f32, Shape{1, 3, 1, 1}); + auto data2 = std::make_shared(element::f32, Shape{1, 3, 1, 1}); + + data1->set_friendly_name("input1"); + data1->output(0).get_tensor().set_names({"input1"}); + + data2->set_friendly_name("input2"); + data2->output(0).get_tensor().set_names({"input2"}); + + auto res1 = std::make_shared(data1); + auto res2 = std::make_shared(data2); + return std::make_shared(ResultVector{res1, res2}, ParameterVector{data1, data2}); } @@ -184,6 +206,13 @@ inline std::shared_ptr two_inputs_basic() { return function; } +inline std::shared_ptr two_inputs_trivial() { + using namespace ov::preprocess; + auto function = create_preprocess_2inputs_trivial(); + function = PrePostProcessor().input(InputInfo(1).preprocess(PreProcessSteps().mean(1.f).scale(2.0f))).build(function); + return function; +} + inline std::shared_ptr reuse_network_layout() { using namespace ov::preprocess; auto function = create_preprocess_1input(element::f32, PartialShape{4, 3, 2, 1}); @@ -340,6 +369,7 @@ inline std::vector generic_preprocess_functions() { preprocess_func(custom_preprocessing, "custom_preprocessing", 0.01f), preprocess_func(lvalues_multiple_ops, "lvalues_multiple_ops", 0.01f), preprocess_func(two_inputs_basic, "two_inputs_basic", 0.01f), + preprocess_func(two_inputs_trivial, "two_inputs_trivial", 0.01f), preprocess_func(reuse_network_layout, "reuse_network_layout", 0.01f), preprocess_func(tensor_layout, "tensor_layout", 0.01f), preprocess_func(resize_linear, "resize_linear", 0.01f), diff --git a/ngraph/core/include/openvino/core/preprocess/color_format.hpp b/ngraph/core/include/openvino/core/preprocess/color_format.hpp index d8963ac14ce..2f0d52ab32e 100644 --- a/ngraph/core/include/openvino/core/preprocess/color_format.hpp +++ b/ngraph/core/include/openvino/core/preprocess/color_format.hpp @@ -11,7 +11,8 @@ namespace preprocess { enum class ColorFormat { UNDEFINED, NV12_SINGLE_PLANE, // Image in NV12 format as single tensor - NV12_TWO_PLANES, // Image in NV12 format represented as separate tensors for Y and UV planes + /// \brief Image in NV12 format represented as separate tensors for Y and UV planes. + NV12_TWO_PLANES, RGB, BGR }; diff --git a/ngraph/core/include/openvino/core/preprocess/input_tensor_info.hpp b/ngraph/core/include/openvino/core/preprocess/input_tensor_info.hpp index 357ac3f37c8..ea73d7fae2d 100644 --- a/ngraph/core/include/openvino/core/preprocess/input_tensor_info.hpp +++ b/ngraph/core/include/openvino/core/preprocess/input_tensor_info.hpp @@ -123,16 +123,17 @@ public: /// /// In general way, some formats support multi-plane input, e.g. NV12 image can be represented as 2 separate tensors /// (planes): Y plane and UV plane. set_color_format API also allows to set sub_names for such parameters for - /// convenient usage of plane parameters. + /// convenient usage of plane parameters. During build stage, new parameters for each plane will be inserted to the + /// place of original parameter. This means that all parameters located after will shift their positions accordingly + /// (e.g. {param1, param2} will become {param1/Y, param1/UV, param2}) /// /// This version allows chaining for Lvalue objects. /// /// \param format Color format of input image. /// - /// \param sub_names Optional list of sub-names assigned for each plane (e.g. {"Y", "UV"}). If not specified, - /// sub-names for plane parameters are auto-generated, exact names auto-generation rules depend on specific color - /// format, and client's code shall not rely on these rules. It is not allowed to specify sub-names for single-plane - /// inputs, also is specified, number of sub-names shall match with number of planes. + /// \param sub_names Optional list of sub-names assigned for each plane (e.g. {"Y", "UV"}). If specified, number of + /// sub-names shall match with number of planes. If not specified, friendly name and tensor name for plane + /// parameters will be empty. It is not allowed to specify sub-names for single-plane inputs. /// /// \return Reference to 'this' to allow chaining with other calls in a builder-like manner. InputTensorInfo& set_color_format(const ov::preprocess::ColorFormat& format, @@ -142,16 +143,17 @@ public: /// /// In general way, some formats support multi-plane input, e.g. NV12 image can be represented as 2 separate tensors /// (planes): Y plane and UV plane. set_color_format API also allows to set sub_names for such parameters for - /// convenient usage of plane parameters. + /// convenient usage of plane parameters. During build stage, new parameters for each plane will be inserted to the + /// place of original parameter. This means that all parameters located after will shift their positions accordingly + /// (e.g. {param1, param2} will become {param1/Y, param1/UV, param2}) /// /// This version allows chaining for Rvalue objects. /// /// \param format Color format of input image. /// - /// \param sub_names Optional list of sub-names assigned for each plane (e.g. {"Y", "UV"}). If not specified, - /// sub-names for plane parameters are auto-generated, exact names auto-generation rules depend on specific color - /// format, and client's code shall not rely on these rules. It is not allowed to specify sub-names for single-plane - /// inputs, also is specified, number of sub-names shall match with number of planes. + /// \param sub_names Optional list of sub-names assigned for each plane (e.g. {"Y", "UV"}). If specified, number of + /// sub-names shall match with number of planes. If not specified, friendly name and tensor name for plane + /// parameters will be empty. It is not allowed to specify sub-names for single-plane inputs. /// /// \return Rvalue reference to 'this' to allow chaining with other calls in a builder-like manner. InputTensorInfo&& set_color_format(const ov::preprocess::ColorFormat& format, diff --git a/ngraph/core/src/preprocess/color_utils.hpp b/ngraph/core/src/preprocess/color_utils.hpp index 3758f849c5f..6db9fe4116f 100644 --- a/ngraph/core/src/preprocess/color_utils.hpp +++ b/ngraph/core/src/preprocess/color_utils.hpp @@ -60,19 +60,11 @@ public: return calculate_shape(plane_num, image_src_shape); } - std::string friendly_suffix(size_t plane_num) const { - OPENVINO_ASSERT(plane_num < planes_count(), - "Internal error: incorrect plane number specified for color format"); - return calc_name_suffix(plane_num); - } - protected: virtual PartialShape calculate_shape(size_t plane_num, const PartialShape& image_shape) const { return image_shape; } - virtual std::string calc_name_suffix(size_t plane_num) const { - return {}; - } + explicit ColorFormatInfo(ColorFormat format) : m_format(format) {} ColorFormat m_format; }; @@ -127,12 +119,6 @@ protected: } return result; } - std::string calc_name_suffix(size_t plane_num) const override { - if (plane_num == 0) { - return "/Y"; - } - return "/UV"; - } Layout default_layout() const override { return "NHWC"; diff --git a/ngraph/core/src/preprocess/function_guard.hpp b/ngraph/core/src/preprocess/function_guard.hpp index c7bad81c923..140d71fc523 100644 --- a/ngraph/core/src/preprocess/function_guard.hpp +++ b/ngraph/core/src/preprocess/function_guard.hpp @@ -13,6 +13,8 @@ namespace preprocess { class FunctionGuard { std::shared_ptr m_function; ParameterVector m_parameters; + ResultVector m_results; + std::vector> m_result_tensors; std::map, std::set>> m_backup; bool m_done = false; @@ -22,6 +24,10 @@ public: for (const auto& param : f->get_parameters()) { m_backup.insert({param, param->output(0).get_target_inputs()}); } + m_results = f->get_results(); + for (const auto& result : m_results) { + m_result_tensors.push_back(result->get_default_output().get_tensor().get_names()); + } } virtual ~FunctionGuard() { if (!m_done) { @@ -39,6 +45,18 @@ public: } } m_function->add_parameters(m_parameters); + + auto results = m_function->get_results(); + + // Remove results added by postprocessing + for (const auto& result : results) { + m_function->remove_result(result); + } + // Restore removed tensor names + for (size_t i = 0; i < m_results.size(); ++i) { + m_results[i]->get_default_output().get_tensor().set_names(m_result_tensors[i]); + } + m_function->add_results(m_results); } catch (std::exception& ex) { // Stress condition, can't recover function to original state std::cerr << "Unrecoverable error occurred during preprocessing. Function is corrupted, exiting\n"; diff --git a/ngraph/core/src/preprocess/pre_post_process.cpp b/ngraph/core/src/preprocess/pre_post_process.cpp index 77535b6b183..d959b2c8b84 100644 --- a/ngraph/core/src/preprocess/pre_post_process.cpp +++ b/ngraph/core/src/preprocess/pre_post_process.cpp @@ -324,6 +324,7 @@ PrePostProcessor&& PrePostProcessor::output(OutputInfo&& builder) && { std::shared_ptr PrePostProcessor::build(const std::shared_ptr& function) { FunctionGuard guard(function); + std::tuple, bool> existing_names{std::unordered_set{}, false}; bool tensor_data_updated = false; for (const auto& input : m_impl->in_contexts) { std::shared_ptr param; @@ -344,7 +345,8 @@ std::shared_ptr PrePostProcessor::build(const std::shared_ptrm_resolved_param = param; } auto results = function->get_results(); - auto parameters = function->get_parameters(); + auto parameters_list = std::list>(function->get_parameters().begin(), + function->get_parameters().end()); for (const auto& input : m_impl->in_contexts) { auto param = input->m_resolved_param; @@ -396,17 +398,33 @@ std::shared_ptr PrePostProcessor::build(const std::shared_ptr> nodes; std::vector> new_params; - // Create separate parameter for each plane. Shape and friendly name is based on color format + // Create separate parameter for each plane. Shape is based on color format for (size_t plane = 0; plane < color_info->planes_count(); plane++) { auto plane_shape = color_info->shape(plane, new_param_shape); auto plane_param = std::make_shared(input->m_tensor_data->get_element_type(), plane_shape); if (plane < input->m_tensor_data->planes_sub_names().size()) { - auto sub_name = std::string("/") + input->m_tensor_data->planes_sub_names()[plane]; - inherit_friendly_names(function, param, plane_param, sub_name, false); - } else { - auto sub_name = color_info->friendly_suffix(plane); - inherit_friendly_names(function, param, plane_param, sub_name); + std::unordered_set plane_tensor_names; + std::string sub_name; + sub_name = std::string("/") + input->m_tensor_data->planes_sub_names()[plane]; + if (!std::get<1>(existing_names)) { + existing_names = std::make_tuple(get_function_tensor_names(function), true); + } + for (const auto& tensor_name : param->get_default_output().get_tensor().get_names()) { + auto new_name = tensor_name + sub_name; + OPENVINO_ASSERT( + std::get<0>(existing_names).count(new_name) == 0, + "Error while trying to create plane input with name '", + new_name, + "' - name already exists in network. Please specify another sub-name for set_color_format"); + plane_tensor_names.insert(new_name); + } + plane_param->get_default_output().get_tensor().set_names(plane_tensor_names); + plane_param->set_friendly_name(param->get_friendly_name() + sub_name); + } else if (color_info->planes_count() == 1) { + plane_param->get_default_output().get_tensor().set_names( + param->get_default_output().get_tensor().get_names()); + plane_param->set_friendly_name(param->get_friendly_name()); } if (!input->m_tensor_data->get_layout().empty()) { plane_param->set_layout(input->m_tensor_data->get_layout()); @@ -466,22 +484,24 @@ std::shared_ptr PrePostProcessor::build(const std::shared_ptrget_parameters().empty()) + while (!function->get_parameters().empty()) { function->remove_parameter(*function->get_parameters().begin()); - function->add_parameters(parameters); + } + auto parameters_vec = ParameterVector(parameters_list.begin(), parameters_list.end()); + function->add_parameters(parameters_vec); } // Validate nodes after preprocessing if needed (no need to repeat it after post-processing) if (tensor_data_updated) { @@ -501,6 +521,7 @@ std::shared_ptr PrePostProcessor::build(const std::shared_ptroutput(); } auto start_out_node_names = node.get_tensor().get_names(); + node.get_tensor().set_names({}); result = std::dynamic_pointer_cast(node.get_node_shared_ptr()); // Set result layout from 'network' information if (output->m_network_data && output->m_network_data->is_layout_set() && result->get_layout().empty()) { @@ -539,26 +560,28 @@ std::shared_ptr PrePostProcessor::build(const std::shared_ptr(action_result); } + node.get_node_shared_ptr()->set_friendly_name( + result->get_input_source_output(0).get_node_shared_ptr()->get_friendly_name()); // Create result auto new_result = std::make_shared(node); + new_result->set_friendly_name(result->get_friendly_name()); if (!context.layout().empty()) { new_result->set_layout(context.layout()); } node.get_tensor().set_names(start_out_node_names); - for (size_t i = 0; i < results.size(); i++) { - if (result == results[i]) { - results[i] = new_result; + + for (auto& old_result : results) { + if (result == old_result) { + old_result = new_result; break; } } } // Add results with right order - { - while (!function->get_results().empty()) - function->remove_result(*function->get_results().begin()); - function->add_results(results); - } + while (!function->get_results().empty()) + function->remove_result(*function->get_results().begin()); + function->add_results(results); guard.reset(); return function; diff --git a/ngraph/core/src/preprocess/preprocess_steps_impl.cpp b/ngraph/core/src/preprocess/preprocess_steps_impl.cpp index bc621b89e4f..f1f7dad447f 100644 --- a/ngraph/core/src/preprocess/preprocess_steps_impl.cpp +++ b/ngraph/core/src/preprocess/preprocess_steps_impl.cpp @@ -46,10 +46,8 @@ void PreStepsList::add_scale_impl(const std::vector& values) { shape = construct_mean_scale_shape(nodes[0].get_node_shared_ptr(), values.size(), context); } auto constant = op::v0::Constant::create(element::f32, shape, values); - // inherit_friendly_names(function, nodes[0].get_node_shared_ptr(), constant, "/scale/Divide_Factor"); auto new_op = std::make_shared(nodes[0], constant); - // inherit_friendly_names(function, nodes[0].get_node_shared_ptr(), new_op, "/scale/Divide"); return std::make_tuple(std::vector>{new_op}, false); }); } @@ -69,10 +67,8 @@ void PreStepsList::add_mean_impl(const std::vector& values) { shape = construct_mean_scale_shape(nodes[0], values.size(), context); } auto constant = op::v0::Constant::create(element::f32, shape, values); - // inherit_friendly_names(function, nodes[0], constant, "/mean/Mean_Const"); auto new_op = std::make_shared(nodes[0], constant); - // inherit_friendly_names(function, nodes[0], new_op, "/mean/Subtract"); return std::make_tuple(std::vector>{new_op}, false); }); } @@ -93,7 +89,6 @@ void PreStepsList::add_convert_impl(const element::Type& type) { "Can't insert 'convert_element_type' for dynamic source tensor type."); if (t != node.get_element_type()) { auto convert = std::make_shared(node, t); - // inherit_friendly_names(function, node, convert, "/convert_element_type"); res.emplace_back(convert); convert_added = true; } else { @@ -154,7 +149,6 @@ void PreStepsList::add_resize_impl(ResizeAlgorithm alg, int dst_height, int dst_ {0, 0}); auto interp = std::make_shared(node, target_spatial_shape, scales, axes, attrs); - // inherit_friendly_names(function, nodes[0], interp, "/resize"); return std::make_tuple(std::vector>{interp}, true); }); } @@ -178,7 +172,6 @@ void PreStepsList::add_convert_layout_impl(const Layout& layout) { } auto perm_constant = op::v0::Constant::create(element::i64, Shape{permutation.size()}, permutation); auto transpose = std::make_shared(nodes[0], perm_constant); - // inherit_friendly_names(function, nodes[0], transpose, "/convert_layout"); context.layout() = dst_layout; // Update context's current layout return std::make_tuple(std::vector>{transpose}, true); }); @@ -207,7 +200,6 @@ void PreStepsList::add_convert_color_impl(const ColorFormat& dst_format) { color_format_name(dst_format), "' format:"); } - // inherit_friendly_names(function, nodes[0], convert, "/convert_color_nv12_single"); context.color_format() = dst_format; return std::make_tuple(std::vector>{convert}, true); } else if (context.color_format() == ColorFormat::NV12_TWO_PLANES) { @@ -226,7 +218,6 @@ void PreStepsList::add_convert_color_impl(const ColorFormat& dst_format) { color_format_name(dst_format), "' format:"); } - // inherit_friendly_names(function, nodes[0], convert, "/convert_color_nv12_two_planes"); context.color_format() = dst_format; return std::make_tuple(std::vector>{convert}, true); } @@ -251,7 +242,6 @@ void PostStepsList::add_convert_impl(const element::Type& type) { !t.is_dynamic() && t != element::undefined, "Can't convert to dynamic/unknown element type, consider using of InputTensorInfo::set_element_type"); auto convert = std::make_shared(node, t); - inherit_friendly_names_postprocess(convert, node); return std::make_tuple(Output(convert), true); }); } @@ -269,7 +259,6 @@ void PostStepsList::add_convert_layout_impl(const Layout& layout) { } auto perm_constant = op::v0::Constant::create(element::i64, Shape{permutation.size()}, permutation); auto transpose = std::make_shared(node, perm_constant); - inherit_friendly_names_postprocess(transpose, node); context.layout() = dst_layout; // Update context's current layout return std::make_tuple(Output(transpose), true); }); diff --git a/ngraph/core/src/preprocess/preprocess_steps_impl.hpp b/ngraph/core/src/preprocess/preprocess_steps_impl.hpp index 280a48b333e..00e15d50027 100644 --- a/ngraph/core/src/preprocess/preprocess_steps_impl.hpp +++ b/ngraph/core/src/preprocess/preprocess_steps_impl.hpp @@ -60,47 +60,6 @@ inline size_t get_and_check_channels_idx(const Layout& layout, const PartialShap return idx; } -inline void inherit_friendly_names(const std::shared_ptr& function, - const Output& src_node, - const Output& dst_node, - const std::string& suffix, - bool search_for_available_name = true) { - dst_node.get_node_shared_ptr()->set_friendly_name(src_node.get_node_shared_ptr()->get_friendly_name() + suffix); - std::unordered_set new_names; - for (const auto& tensor_name : src_node.get_tensor().get_names()) { - auto new_tensor_name = tensor_name + suffix; - if (!suffix.empty()) { - // Verify that new names are unique for a function - if (!is_tensor_name_available(new_tensor_name, function) && search_for_available_name) { - // Search for available name - size_t idx = 0; - do { - new_tensor_name = tensor_name + suffix + std::to_string(idx++); - } while (!is_tensor_name_available(new_tensor_name, function)); - } - } - new_names.emplace(new_tensor_name); - } - dst_node.get_tensor().set_names(new_names); -} - -// TODO: add uniqueness check like for preprocessing (or remove from pre-processing) -inline void inherit_friendly_names_postprocess(const Output& inserted_output, - const Output& previous_output) { - inserted_output.get_node_shared_ptr()->set_friendly_name( - previous_output.get_node_shared_ptr()->get_friendly_name()); - std::unordered_set new_names; // New name for previous node - for (const auto& tensor_name : previous_output.get_tensor().get_names()) { - auto new_tensor_name = tensor_name; - new_names.emplace(new_tensor_name); - } - previous_output.get_tensor().set_names(new_names); - - // reset names for original node - previous_output.get_node_shared_ptr()->set_friendly_name({}); - previous_output.get_tensor().set_names({}); -} - /// \brief Context passed to each pre/post-processing operation. /// This is internal structure which is not shared to custom operations yet. class PrePostProcessingContextBase { diff --git a/ngraph/core/src/tensor_name_util.hpp b/ngraph/core/src/tensor_name_util.hpp index b77c248561d..140858da4b5 100644 --- a/ngraph/core/src/tensor_name_util.hpp +++ b/ngraph/core/src/tensor_name_util.hpp @@ -9,21 +9,15 @@ namespace ov { -/// \brief Check that specified tensor name is unique for a given function. -/// -/// \param tensor_name Name to check across all tensors in a function. -/// \param function Function. -/// \return False if tensor name is already used in some function's node, True otherwise -inline bool is_tensor_name_available(const std::string& tensor_name, const std::shared_ptr& function) { +inline std::unordered_set get_function_tensor_names(const std::shared_ptr& function) { + std::unordered_set set; for (const auto& node : function->get_ordered_ops()) { for (const auto& output : node->outputs()) { - const auto& tensor = output.get_tensor(); - if (tensor.get_names().count(tensor_name)) { - return false; - } + const auto& names = output.get_tensor().get_names(); + set.insert(names.begin(), names.end()); } } - return true; + return set; } } // namespace ov diff --git a/ngraph/test/preprocess.cpp b/ngraph/test/preprocess.cpp index 5cef8a45ccf..db6981089f2 100644 --- a/ngraph/test/preprocess.cpp +++ b/ngraph/test/preprocess.cpp @@ -6,13 +6,10 @@ #include "ngraph/ngraph.hpp" #include "ngraph/ops.hpp" #include "openvino/core/preprocess/pre_post_process.hpp" -#include "util/all_close.hpp" -#include "util/all_close_f.hpp" #include "util/test_tools.hpp" using namespace ov; using namespace ov::preprocess; -using namespace ngraph::test; static std::shared_ptr create_simple_function(element::Type type, const PartialShape& shape) { auto data1 = std::make_shared(type, shape); @@ -27,24 +24,24 @@ static std::shared_ptr create_simple_function(element::Type type, cons return std::make_shared(ResultVector{res}, ParameterVector{data1}); } -static std::shared_ptr create_2inputs(element::Type type, const PartialShape& shape) { - auto data1 = std::make_shared(type, shape); - data1->set_friendly_name("input1"); - data1->get_output_tensor(0).set_names({"tensor_input1"}); - auto op1 = std::make_shared(data1); - op1->set_friendly_name("Relu1"); - auto data2 = std::make_shared(type, shape); - data2->set_friendly_name("input2"); - data2->get_output_tensor(0).set_names({"tensor_input2"}); - auto op2 = std::make_shared(data2); - op2->set_friendly_name("Relu2"); - auto res1 = std::make_shared(op1); - res1->set_friendly_name("Result1"); - res1->get_output_tensor(0).set_names({"tensor_output1"}); - auto res2 = std::make_shared(op2); - res2->set_friendly_name("Result2"); - res2->get_output_tensor(0).set_names({"tensor_output2"}); - return std::make_shared(ResultVector{res1, res2}, ParameterVector{data1, data2}); +template +static std::shared_ptr create_n_inputs(element::Type type, const PartialShape& shape) { + ResultVector res; + ParameterVector params; + for (size_t i = 0; i < N; i++) { + auto index_str = std::to_string(i); + auto data1 = std::make_shared(type, shape); + data1->set_friendly_name("input" + index_str); + data1->get_output_tensor(0).set_names({"tensor_input" + index_str}); + auto op1 = std::make_shared(data1); + op1->set_friendly_name("Relu" + index_str); + auto res1 = std::make_shared(op1); + res1->set_friendly_name("Result" + index_str); + res1->get_output_tensor(0).set_names({"tensor_output" + index_str}); + params.push_back(data1); + res.push_back(res1); + } + return std::make_shared(res, params); } TEST(pre_post_process, simple_mean_scale) { @@ -118,7 +115,7 @@ TEST(pre_post_process, empty_preprocess) { } TEST(pre_post_process, preprocess_assert_input_without_index) { - auto f = create_2inputs(element::f32, Shape{1, 3, 2, 2}); + auto f = create_n_inputs<2>(element::f32, Shape{1, 3, 2, 2}); auto inp = InputInfo(); EXPECT_ANY_THROW(f = PrePostProcessor().input(std::move(inp)).build(f)); inp = InputInfo("some_non_existing_name"); @@ -237,12 +234,6 @@ TEST(pre_post_process, convert_color_nv12_rgb_2_planes) { EXPECT_EQ(f->get_parameters()[1]->get_element_type(), element::f32); EXPECT_EQ(f->get_parameters()[0]->get_partial_shape(), (PartialShape{5, 2, 2, 1})); EXPECT_EQ(f->get_parameters()[1]->get_partial_shape(), (PartialShape{5, 1, 1, 2})); - - EXPECT_EQ(f->get_parameters()[0]->get_friendly_name(), "input1/Y"); - EXPECT_EQ(*f->get_parameters()[0]->output(0).get_tensor().get_names().begin(), "tensor_input1/Y"); - - EXPECT_EQ(f->get_parameters()[1]->get_friendly_name(), "input1/UV"); - EXPECT_EQ(*f->get_parameters()[1]->output(0).get_tensor().get_names().begin(), "tensor_input1/UV"); } TEST(pre_post_process, convert_color_nv12_bgr_2_planes_u8_lvalue) { @@ -328,8 +319,6 @@ TEST(pre_post_process, convert_color_unsupported) { TEST(pre_post_process, convert_color_incorrect_subnames) { auto f = create_simple_function(element::f32, PartialShape{Dimension::dynamic(), 2, 2, 3}); - auto name = f->get_parameters()[0]->get_friendly_name(); - auto tensor_names = f->get_parameters().front()->get_output_tensor(0).get_names(); EXPECT_THROW( f = PrePostProcessor() .input(InputInfo() @@ -352,7 +341,7 @@ TEST(pre_post_process, convert_color_incorrect_subnames) { } TEST(pre_post_process, convert_color_duplicate_subnames) { - auto f = create_2inputs(element::f32, PartialShape{1, 2, 2, 3}); + auto f = create_n_inputs<2>(element::f32, PartialShape{1, 2, 2, 3}); f->get_parameters()[0]->get_output_tensor(0).set_names({"tensor_input1"}); f->get_parameters()[1]->get_output_tensor(0).set_names({"tensor_input1/CustomUV"}); EXPECT_THROW(f = PrePostProcessor() @@ -438,9 +427,7 @@ TEST(pre_post_process, custom_preprocessing) { auto f = create_simple_function(element::i32, Shape{1, 3, 1, 1}); f = PrePostProcessor() .input(InputInfo().preprocess(PreProcessSteps().custom([](const Output& node) { - auto abs = std::make_shared(node); - abs->set_friendly_name(node.get_node_shared_ptr()->get_friendly_name() + "/abs"); - return abs; + return std::make_shared(node); }))) .build(f); EXPECT_EQ(f->get_output_element_type(0), element::i32); @@ -473,9 +460,7 @@ TEST(pre_post_process, test_lvalue) { preprocessSteps.mean({1.f, 2.f, 3.f}); preprocessSteps.scale({2.f, 3.f, 4.f}); preprocessSteps.custom([](const Output& node) { - auto abs = std::make_shared(node); - abs->set_friendly_name(node.get_node_shared_ptr()->get_friendly_name() + "/abs"); - return abs; + return std::make_shared(node); }); auto& same = preprocessSteps.convert_element_type(element::i8); inputInfo.preprocess(std::move(same)); @@ -490,7 +475,7 @@ TEST(pre_post_process, test_lvalue) { } TEST(pre_post_process, test_2_inputs_basic) { - auto f = create_2inputs(element::f32, Shape{1, 3, 1, 1}); + auto f = create_n_inputs<2>(element::f32, Shape{1, 3, 1, 1}); { f = PrePostProcessor().input(InputInfo(1).preprocess(PreProcessSteps().mean(1.f).scale(2.0f))).build(f); } EXPECT_EQ(f->get_output_element_type(0), element::f32); EXPECT_EQ(f->get_output_element_type(1), element::f32); @@ -655,8 +640,21 @@ TEST(pre_post_process, resize_no_tensor_width) { ov::AssertFailure); } +TEST(pre_post_process, double_input_info) { + auto f = create_simple_function(element::f32, Shape{1, 3, 224, 224}); + // Parameter is replaced during first pre-processing, parameter for second step will not be resolved properly + EXPECT_THROW(f = PrePostProcessor() + .input(InputInfo().tensor(InputTensorInfo().set_element_type(element::u8))) + .input(InputInfo().tensor(InputTensorInfo().set_element_type(element::u8))) + .build(f), + ov::AssertFailure); +} + TEST(pre_post_process, preprocess_convert_layout_implicit) { auto f = create_simple_function(element::f32, Shape{1, 3, 2, 2}); + auto name = f->get_results().front()->get_friendly_name(); + auto name_last_op = f->get_results().front()->get_input_source_output(0).get_node_shared_ptr()->get_friendly_name(); + auto tensor_names = f->output().get_tensor().get_names(); f = PrePostProcessor() .input( @@ -664,6 +662,10 @@ TEST(pre_post_process, preprocess_convert_layout_implicit) { .build(f); EXPECT_EQ(f->get_parameters()[0]->get_layout(), "NHWC"); EXPECT_EQ(f->get_parameters()[0]->get_output_tensor(0).get_partial_shape(), (PartialShape{1, 2, 2, 3})); + EXPECT_EQ(name, f->get_results().front()->get_friendly_name()); + EXPECT_EQ(name_last_op, + f->get_results().front()->get_input_source_output(0).get_node_shared_ptr()->get_friendly_name()); + EXPECT_EQ(tensor_names, f->output().get_tensor().get_names()); } TEST(pre_post_process, preprocess_convert_layout_default) { @@ -699,6 +701,8 @@ TEST(pre_post_process, preprocess_convert_layout_same) { TEST(pre_post_process, postprocess_convert_element_type_explicit) { auto f = create_simple_function(element::f32, Shape{1, 3, 2, 2}); + auto name = f->output().get_node_shared_ptr()->get_friendly_name(); + auto name_last_op = f->get_results().front()->get_input_source_output(0).get_node_shared_ptr()->get_friendly_name(); auto old_names = f->output().get_tensor().get_names(); f = PrePostProcessor() .output(OutputInfo().postprocess(PostProcessSteps().convert_element_type(element::u8))) @@ -708,7 +712,7 @@ TEST(pre_post_process, postprocess_convert_element_type_explicit) { EXPECT_EQ(f->output().get_tensor().get_names(), old_names); EXPECT_EQ(old_names.count("tensor_output1"), 1); auto ops = f->get_ordered_ops(); - auto res_count = std::count_if(ops.begin(), ops.end(), [](std::shared_ptr n) { + auto res_count = std::count_if(ops.begin(), ops.end(), [](const std::shared_ptr& n) { return std::dynamic_pointer_cast(n) != nullptr; }); EXPECT_EQ(res_count, 1); @@ -716,10 +720,16 @@ TEST(pre_post_process, postprocess_convert_element_type_explicit) { return n->output(0).get_tensor().get_names().count("tensor_output1") > 0; }); EXPECT_EQ(names_count, 2); // last node + result referencing to it + EXPECT_EQ(name, f->output().get_node_shared_ptr()->get_friendly_name()); + EXPECT_EQ(name_last_op, + f->get_results().front()->get_input_source_output(0).get_node_shared_ptr()->get_friendly_name()); } TEST(pre_post_process, postprocess_convert_element_type_default) { - auto f = create_2inputs(element::f32, Shape{1, 3, 2, 2}); + auto f = create_n_inputs<2>(element::f32, Shape{1, 3, 2, 2}); + auto name = f->output(1).get_node_shared_ptr()->get_friendly_name(); + auto name_last_op = f->get_results().front()->get_input_source_output(0).get_node_shared_ptr()->get_friendly_name(); + auto tensor_names = f->output(1).get_tensor().get_names(); f = PrePostProcessor() .output(OutputInfo(1) .postprocess(PostProcessSteps().convert_element_type()) @@ -727,6 +737,10 @@ TEST(pre_post_process, postprocess_convert_element_type_default) { .build(f); EXPECT_EQ(f->get_results()[0]->get_element_type(), element::f32); EXPECT_EQ(f->get_results()[1]->get_element_type(), element::u8); + EXPECT_EQ(name, f->output(1).get_node_shared_ptr()->get_friendly_name()); + EXPECT_EQ(name_last_op, + f->get_results().front()->get_input_source_output(0).get_node_shared_ptr()->get_friendly_name()); + EXPECT_EQ(tensor_names, f->output(1).get_tensor().get_names()); } TEST(pre_post_process, postprocess_convert_element_type_same) { @@ -756,6 +770,37 @@ TEST(pre_post_process, postprocess_convert_element_type_implicit) { EXPECT_EQ(f->get_results()[0]->get_element_type(), element::u8); } +TEST(pre_post_process, preprocess_keep_params_order) { + auto f = create_n_inputs<3>(element::f32, Shape{1, 2, 2, 3}); + f = PrePostProcessor() + .input(InputInfo(1) + .tensor(InputTensorInfo().set_color_format(ColorFormat::NV12_TWO_PLANES, {"Y", "UV"})) + .preprocess(PreProcessSteps().convert_color(ColorFormat::RGB))) + .input(InputInfo(0).tensor(InputTensorInfo().set_layout("NCHW"))) + .input(InputInfo(2) + .tensor(InputTensorInfo().set_color_format(ColorFormat::NV12_TWO_PLANES, {"Y", "UV"})) + .preprocess(PreProcessSteps().convert_color(ColorFormat::RGB))) + .build(f); + ASSERT_EQ(f->get_parameters().size(), 5); + EXPECT_EQ(f->get_parameters()[0]->get_layout(), "NCHW"); + EXPECT_EQ(f->get_parameters()[1]->get_layout(), "NHWC"); + EXPECT_EQ(f->get_parameters()[2]->get_layout(), "NHWC"); + EXPECT_EQ(f->get_parameters()[3]->get_layout(), "NHWC"); + EXPECT_EQ(f->get_parameters()[4]->get_layout(), "NHWC"); + + EXPECT_EQ(f->input(0).get_partial_shape(), (PartialShape{1, 2, 2, 3})); + EXPECT_EQ(f->input(1).get_partial_shape(), (PartialShape{1, 2, 2, 1})); + EXPECT_EQ(f->input(2).get_partial_shape(), (PartialShape{1, 1, 1, 2})); + EXPECT_EQ(f->input(3).get_partial_shape(), (PartialShape{1, 2, 2, 1})); + EXPECT_EQ(f->input(4).get_partial_shape(), (PartialShape{1, 1, 1, 2})); + + EXPECT_EQ(f->input(0).get_tensor().get_names(), std::unordered_set{"tensor_input0"}); + EXPECT_EQ(f->input(1).get_tensor().get_names(), std::unordered_set{"tensor_input1/Y"}); + EXPECT_EQ(f->input(2).get_tensor().get_names(), std::unordered_set{"tensor_input1/UV"}); + EXPECT_EQ(f->input(3).get_tensor().get_names(), std::unordered_set{"tensor_input2/Y"}); + EXPECT_EQ(f->input(4).get_tensor().get_names(), std::unordered_set{"tensor_input2/UV"}); +} + // --- PostProcess - set/convert layout --- TEST(pre_post_process, postprocess_set_layout_network) { auto f = create_simple_function(element::f32, Shape{1, 3, 2, 2}); @@ -783,7 +828,7 @@ TEST(pre_post_process, postprocess_convert_layout_implicit) { } TEST(pre_post_process, postprocess_convert_layout_explicit_no_target) { - auto f = create_2inputs(element::f32, Shape{1, 3, 2, 2}); + auto f = create_n_inputs<2>(element::f32, Shape{1, 3, 2, 2}); f = PrePostProcessor() .output(OutputInfo(1) .network(OutputNetworkInfo().set_layout("NCHW")) @@ -837,18 +882,18 @@ TEST(pre_post_process, postprocess_convert_layout_default_error) { TEST(pre_post_process, postprocess_custom_step) { auto f = create_simple_function(element::f32, Shape{1, 3, 2, 2}); - std::string name; + bool hit = false; f = PrePostProcessor() - .output(OutputInfo().postprocess( - PostProcessSteps().custom([&name](const ov::Output& node) -> ov::Output { - auto abs = std::make_shared(node); - abs->set_friendly_name(node.get_node()->get_friendly_name() + "/abs"); - name = node.get_node()->get_friendly_name() + "/abs"; - return abs; - }))) + .output(OutputInfo().postprocess(PostProcessSteps().custom([&hit](const ov::Output& node) { + auto abs = std::make_shared(node); + hit = true; + return abs; + }))) .build(f); - EXPECT_FALSE(name.empty()); - EXPECT_EQ(f->get_results()[0]->get_input_source_output(0).get_node()->get_friendly_name(), name); + EXPECT_TRUE(hit); + + EXPECT_EQ(std::string(f->get_results()[0]->get_input_source_output(0).get_node()->get_type_name()), + std::string(op::v0::Abs::get_type_info_static().name)); } TEST(pre_post_process, postprocess_implicit_convert_element_type_and_layout) { @@ -864,13 +909,42 @@ TEST(pre_post_process, postprocess_implicit_convert_element_type_and_layout) { } TEST(pre_post_process, postprocess_assert_output_without_index) { - auto f = create_2inputs(element::f32, Shape{1, 3, 2, 2}); + auto f = create_n_inputs<2>(element::f32, Shape{1, 3, 2, 2}); auto out = OutputInfo(); EXPECT_ANY_THROW(f = PrePostProcessor().output(std::move(out)).build(f)); out = OutputInfo("some_non_existing_name"); EXPECT_ANY_THROW(f = PrePostProcessor().output(std::move(out)).build(f)); } +TEST(pre_post_process, postprocess_keep_results_order) { + auto f = create_n_inputs<3>(element::f32, Shape{1, 3, 2, 2}); + auto names0 = f->output(0).get_tensor().get_names(); + auto names1 = f->output(1).get_tensor().get_names(); + auto names2 = f->output(2).get_tensor().get_names(); + f = PrePostProcessor() + .output(OutputInfo(0).network(OutputNetworkInfo().set_layout("NCHW"))) + .output(OutputInfo(1) + .network(OutputNetworkInfo().set_layout("NCHW")) + .tensor(OutputTensorInfo().set_layout("NHWC").set_element_type(element::u8))) + .build(f); + ASSERT_EQ(f->get_results().size(), 3); + EXPECT_EQ(f->output(0).get_element_type(), element::f32); + EXPECT_EQ(f->output(1).get_element_type(), element::u8); + EXPECT_EQ(f->output(2).get_element_type(), element::f32); + + EXPECT_EQ(f->get_results()[0]->get_layout(), "NCHW") << f->get_results()[0]->get_layout().to_string(); + EXPECT_EQ(f->get_results()[1]->get_layout(), "NHWC") << f->get_results()[1]->get_layout().to_string(); + EXPECT_EQ(f->get_results()[2]->get_layout(), "") << f->get_results()[2]->get_layout().to_string(); + + EXPECT_EQ(f->output(0).get_partial_shape(), (PartialShape{1, 3, 2, 2})); + EXPECT_EQ(f->output(1).get_partial_shape(), (PartialShape{1, 2, 2, 3})); + EXPECT_EQ(f->output(2).get_partial_shape(), (PartialShape{1, 3, 2, 2})); + + EXPECT_EQ(f->output(0).get_tensor().get_names(), names0); + EXPECT_EQ(f->output(1).get_tensor().get_names(), names1); + EXPECT_EQ(f->output(2).get_tensor().get_names(), names2); +} + TEST(pre_post_process, postprocess_lvalues_1) { auto f = create_simple_function(element::f32, Shape{1, 3, 2, 2}); bool custom_called = false; @@ -881,11 +955,9 @@ TEST(pre_post_process, postprocess_lvalues_1) { auto steps = PostProcessSteps(); steps.convert_layout(); steps.convert_element_type(); - steps.custom([&custom_called](const ov::Output& node) -> ov::Output { - auto abs = std::make_shared(node); - abs->set_friendly_name(node.get_node()->get_friendly_name() + "/abs"); + steps.custom([&custom_called](const ov::Output& node) { custom_called = true; - return abs; + return std::make_shared(node); }); auto tensorInfo = OutputTensorInfo(); @@ -903,18 +975,23 @@ TEST(pre_post_process, postprocess_lvalues_1) { f = p.build(f); EXPECT_EQ(f->get_results().size(), 1); EXPECT_EQ(f->output().get_tensor().get_names().count("tensor_output1"), 1); - EXPECT_EQ(f->get_results()[0]->get_element_type(), element::u8); + EXPECT_EQ(f->output().get_node_shared_ptr()->get_friendly_name(), "Result1"); + EXPECT_EQ(f->output().get_element_type(), element::u8); EXPECT_EQ(f->get_results()[0]->get_layout(), "NHWC"); - EXPECT_EQ(f->get_results()[0]->get_output_tensor(0).get_partial_shape(), (PartialShape{1, 2, 2, 3})); + EXPECT_EQ(f->output().get_partial_shape(), (PartialShape{1, 2, 2, 3})); EXPECT_TRUE(custom_called); } TEST(pre_post_process, exception_safety) { - auto f = create_2inputs(element::f32, Shape{1, 3, 224, 224}); - auto name0 = f->get_parameters()[0]->get_friendly_name(); - auto tensor_names0 = f->get_parameters()[0]->get_output_tensor(0).get_names(); - auto name1 = f->get_parameters()[1]->get_friendly_name(); - auto tensor_names1 = f->get_parameters()[1]->get_output_tensor(0).get_names(); + auto f = create_n_inputs<2>(element::f32, Shape{1, 3, 224, 224}); + auto name0 = f->input(0).get_node_shared_ptr()->get_friendly_name(); + auto tensor_names0 = f->input(0).get_tensor().get_names(); + auto name1 = f->input(1).get_node_shared_ptr()->get_friendly_name(); + auto tensor_names1 = f->input(1).get_tensor().get_names(); + auto out_name0 = f->output(0).get_node_shared_ptr()->get_friendly_name(); + auto out_tensor_names0 = f->output(0).get_tensor().get_names(); + auto out_name1 = f->output(1).get_node_shared_ptr()->get_friendly_name(); + auto out_tensor_names1 = f->output(1).get_tensor().get_names(); EXPECT_THROW(f = PrePostProcessor() .input(InputInfo(0) // this one is correct .tensor(InputTensorInfo().set_element_type(element::u8)) @@ -926,15 +1003,32 @@ TEST(pre_post_process, exception_safety) { }))) .build(f), ov::AssertFailure); + + EXPECT_THROW( + f = PrePostProcessor() + .output(OutputInfo(0) // this one is correct + .tensor(OutputTensorInfo().set_element_type(element::u8))) + .output(OutputInfo(1) // This one is not + .postprocess(PostProcessSteps().custom([](const Output& node) -> Output { + throw ngraph::ngraph_error("test error"); + }))) + .build(f), + ngraph::ngraph_error); EXPECT_EQ(f->get_parameters().size(), 2); - EXPECT_EQ(f->get_parameters()[0]->get_element_type(), element::f32); - EXPECT_EQ(f->get_parameters()[0]->get_partial_shape(), (PartialShape{1, 3, 224, 224})); - EXPECT_EQ(f->get_parameters()[0]->get_friendly_name(), name0); - EXPECT_EQ(f->get_parameters()[0]->get_output_tensor(0).get_names(), tensor_names0); + EXPECT_EQ(f->input(0).get_element_type(), element::f32); + EXPECT_EQ(f->input(0).get_partial_shape(), (PartialShape{1, 3, 224, 224})); + EXPECT_EQ(f->input(0).get_node_shared_ptr()->get_friendly_name(), name0); + EXPECT_EQ(f->input(0).get_tensor().get_names(), tensor_names0); - EXPECT_EQ(f->get_parameters()[1]->get_element_type(), element::f32); - EXPECT_EQ(f->get_parameters()[1]->get_partial_shape(), (PartialShape{1, 3, 224, 224})); - EXPECT_EQ(f->get_parameters()[1]->get_friendly_name(), name1); - EXPECT_EQ(f->get_parameters()[1]->get_output_tensor(0).get_names(), tensor_names1); + EXPECT_EQ(f->input(1).get_element_type(), element::f32); + EXPECT_EQ(f->input(1).get_partial_shape(), (PartialShape{1, 3, 224, 224})); + EXPECT_EQ(f->input(1).get_node_shared_ptr()->get_friendly_name(), name1); + EXPECT_EQ(f->input(1).get_tensor().get_names(), tensor_names1); + + EXPECT_EQ(f->output(0).get_node_shared_ptr()->get_friendly_name(), out_name0); + EXPECT_EQ(f->output(0).get_tensor().get_names(), out_tensor_names0); + + EXPECT_EQ(f->output(1).get_node_shared_ptr()->get_friendly_name(), out_name1); + EXPECT_EQ(f->output(1).get_tensor().get_names(), out_tensor_names1); }