From 3d241b91ed33c84a1ac52ef18d84dd171ed312bc Mon Sep 17 00:00:00 2001 From: "Raasz, Pawel" Date: Fri, 22 Mar 2024 09:15:11 +0100 Subject: [PATCH 1/7] Fix reshape ReadValue operator --- src/core/src/op/read_value.cpp | 4 ++++ src/core/tests/type_prop/read_value.cpp | 30 ++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/core/src/op/read_value.cpp b/src/core/src/op/read_value.cpp index 0c9ce8e88cc..88f9e3dce1e 100644 --- a/src/core/src/op/read_value.cpp +++ b/src/core/src/op/read_value.cpp @@ -134,6 +134,10 @@ bool ReadValue::visit_attributes(AttributeVisitor& visitor) { } void ReadValue::revalidate_and_infer_types() { + // Update variable shape if not extend new shape (e.g reshape result). + if (get_input_size() > 0 && !m_variable->get_info().data_shape.relaxes(get_input_partial_shape(0))) { + m_variable->update_data_shape(get_input_partial_shape(0)); + } Node::revalidate_and_infer_types(); } diff --git a/src/core/tests/type_prop/read_value.cpp b/src/core/tests/type_prop/read_value.cpp index c021aafd89a..7d161ceded5 100644 --- a/src/core/tests/type_prop/read_value.cpp +++ b/src/core/tests/type_prop/read_value.cpp @@ -6,9 +6,16 @@ #include "common_test_utils/type_prop.hpp" #include "dimension_util.hpp" +#include "openvino/core/model.hpp" + +namespace ov { +namespace test { using namespace std; -using namespace ov; +using ov::op::util::Variable; +using ov::op::util::VariableInfo; +using ov::op::v0::Parameter; +using ov::op::v0::Result; TEST(type_prop, read_value_deduce) { auto input = make_shared(element::f32, Shape{1, 2, 64, 64}); @@ -126,3 +133,24 @@ TEST(type_prop, DISABLED_read_value_labels_propagation_from_init_subgraph) { std::shared_ptr read_value = std::make_shared(input, variable); EXPECT_THAT(get_shape_labels(read_value->get_output_partial_shape(0)), testing::ElementsAre(10, 11, 12, 13)); } + +TEST(type_prop, read_value_v6_model_reshape) { + const auto batch_shape = PartialShape{1, 30}; + const auto new_batch_shape = PartialShape{3, 30}; + + // dummy model with ReadValue for reshape + auto input = std::make_shared(element::f16, batch_shape); + auto variable = std::make_shared(VariableInfo{batch_shape, element::f16, "ID"}); + auto read_value = std::make_shared(input, variable); + auto assign = std::make_shared(read_value, variable); + auto result = std::make_shared(read_value); + + auto model = std::make_shared(ResultVector{result}, SinkVector{assign}, ParameterVector{input}); + + ASSERT_NO_THROW(model->reshape(new_batch_shape)); + EXPECT_EQ(read_value->get_output_partial_shape(0), new_batch_shape); + EXPECT_EQ(read_value->get_variable()->get_info(), VariableInfo({new_batch_shape, element::f16, "ID"})); +} + +} // namespace test +} // namespace ov From 836f4da51dc83d9b7fc7b29766ea916cc069f213 Mon Sep 17 00:00:00 2001 From: "Raasz, Pawel" Date: Thu, 18 Apr 2024 12:49:02 +0200 Subject: [PATCH 2/7] Add `Model::reshape` where user can specify variables shapes --- src/core/include/openvino/core/model.hpp | 9 ++ src/core/src/model.cpp | 127 +++++++++++++++++------ src/core/src/op/read_value.cpp | 4 - src/core/tests/model.cpp | 127 ++++++++++++++++++++++- src/core/tests/type_prop/read_value.cpp | 19 ---- 5 files changed, 230 insertions(+), 56 deletions(-) diff --git a/src/core/include/openvino/core/model.hpp b/src/core/include/openvino/core/model.hpp index 3f82b205d0c..d5b778a6c5d 100644 --- a/src/core/include/openvino/core/model.hpp +++ b/src/core/include/openvino/core/model.hpp @@ -145,6 +145,15 @@ public: void reshape(const std::map& partial_shapes); void reshape(const std::map, ov::PartialShape>& partial_shapes); + void reshape(const ov::PartialShape& partial_shape, + const std::unordered_map& variable_shapes); + void reshape(const std::map& partial_shapes, + const std::unordered_map& variable_shapes); + void reshape(const std::map& partial_shapes, + const std::unordered_map& variable_shapes); + void reshape(const std::map, ov::PartialShape>& partial_shapes, + const std::unordered_map& variable_shapes); + /// Return the element type of output i const ov::element::Type& get_output_element_type(size_t i) const; diff --git a/src/core/src/model.cpp b/src/core/src/model.cpp index 315c3ab870f..9af76486ccd 100644 --- a/src/core/src/model.cpp +++ b/src/core/src/model.cpp @@ -30,6 +30,11 @@ atomic ov::Model::m_next_instance_id(0); namespace { +const std::unordered_map& default_variable_map() { + static const std::unordered_map variable_map; + return variable_map; +} + void check_all_variables_registered(const std::vector>& ordered_ops, const ov::op::util::VariableVector& variables) { OV_ITT_SCOPED_TASK(ov::itt::domains::ov_pass, "Model::check_all_variables_registered"); @@ -88,6 +93,43 @@ const std::shared_ptr& verify_node(const std::shared_ptr& no return node; } +std::map, ov::PartialShape> port_shapes_to_node_shapes( + ov::Model* model, + const std::map& partial_shapes) { + std::map, ov::PartialShape> node_shapes; + for (const auto& it : partial_shapes) { + const auto port = model->input(it.first); + node_shapes[port] = it.second; + } + return node_shapes; +} + +std::map, ov::PartialShape> tensor_names_shapes_to_node_shapes( + ov::Model* model, + const std::map& partial_shapes) { + std::map, ov::PartialShape> const_pshape; + std::unordered_map port_tensor_map; + for (const auto& it : partial_shapes) { + const auto port = model->input(it.first); + if (port_tensor_map.find(port.get_node()) != port_tensor_map.end()) { + OPENVINO_ASSERT(it.second == const_pshape.at(port), + "Tensor with names {'", + it.first, + "', '", + port_tensor_map[port.get_node()], + "'} has " + "conflicting shapes ", + it.second, + " and ", + const_pshape.at(port), + ", but they define the same tensor"); + } + port_tensor_map[port.get_node()] = it.first; + const_pshape[port] = it.second; + } + return const_pshape; +} + } // namespace ov::Model::Model(const ResultVector& results, const ov::ParameterVector& parameters, const std::string& name) @@ -749,41 +791,36 @@ void ov::Model::reshape(const ov::PartialShape& partial_shape) { } void ov::Model::reshape(const std::map& partial_shapes) { - std::map, ov::PartialShape> const_pshape; - std::unordered_map port_tensor_map; - for (const auto& it : partial_shapes) { - const auto port = input(it.first); - port_tensor_map[port.get_node()] = std::to_string(it.first); - const_pshape[port] = it.second; - } - reshape(const_pshape); + reshape(port_shapes_to_node_shapes(this, partial_shapes), default_variable_map()); } void ov::Model::reshape(const std::map& partial_shapes) { - std::map, ov::PartialShape> const_pshape; - std::unordered_map port_tensor_map; - for (const auto& it : partial_shapes) { - const auto port = input(it.first); - if (port_tensor_map.find(port.get_node()) != port_tensor_map.end()) { - OPENVINO_ASSERT(it.second == const_pshape.at(port), - "Tensor with names {'", - it.first, - "', '", - port_tensor_map[port.get_node()], - "'} has " - "conflicting shapes ", - it.second, - " and ", - const_pshape.at(port), - ", but they define the same tensor"); - } - port_tensor_map[port.get_node()] = it.first; - const_pshape[port] = it.second; - } - reshape(const_pshape); + reshape(tensor_names_shapes_to_node_shapes(this, partial_shapes), default_variable_map()); } void ov::Model::reshape(const std::map, ov::PartialShape>& partial_shapes) { + reshape(partial_shapes, default_variable_map()); +} + +void ov::Model::reshape(const ov::PartialShape& partial_shape, + const std::unordered_map& variable_shapes) { + OPENVINO_ASSERT(m_parameters.size() == 1, "must be called on a Model with exactly one parameter."); + std::map shapes{{0, partial_shape}}; + reshape(shapes, variable_shapes); +} + +void ov::Model::reshape(const std::map& partial_shapes, + const std::unordered_map& variable_shapes) { + reshape(port_shapes_to_node_shapes(this, partial_shapes), variable_shapes); +} + +void ov::Model::reshape(const std::map& partial_shapes, + const std::unordered_map& variable_shapes) { + reshape(tensor_names_shapes_to_node_shapes(this, partial_shapes), default_variable_map()); +} + +void ov::Model::reshape(const std::map, ov::PartialShape>& partial_shapes, + const std::unordered_map& variables_shapes) { if (partial_shapes.empty()) return; @@ -818,17 +855,43 @@ void ov::Model::reshape(const std::map, ov::PartialShape>& if (!need_reshape) return; + // const auto& variables = get_variables(); + std::unordered_map new_vars_shapes; + std::unordered_map original_vars_shapes; + for (const auto& variable : get_variables()) { + const auto& var_info = variable->get_info(); + + for (const auto& var_id_new_shape : variables_shapes) { + const auto& variable_id = var_id_new_shape.first; + const auto& new_shape = var_id_new_shape.second; + if (variable_id == var_info.variable_id && new_shape != var_info.data_shape) { + original_vars_shapes[variable.get()] = var_info.data_shape; + new_vars_shapes[variable.get()] = new_shape; + } + } + } + // save original parameters shape std::unordered_map original_input_shapes; for (const auto& param : params) { original_input_shapes[param.get()] = param->get_output_partial_shape(0); } - auto reshape_only = [&](const std::unordered_map& pshapes) { + std::unordered_map original_var_shapes; + for (const auto& v : get_variables()) { + original_var_shapes[v.get()] = v->get_info().data_shape; + } + + auto reshape_only = [this](const std::unordered_map& pshapes, + const std::unordered_map& vars_shapes) { for (const auto& pshape : pshapes) { pshape.first->set_partial_shape(pshape.second); } + for (const auto& shape : vars_shapes) { + shape.first->update_data_shape(shape.second); + } + validate_nodes_and_infer_types(); }; @@ -837,10 +900,10 @@ void ov::Model::reshape(const std::map, ov::PartialShape>& ssr_manager.register_pass(); ssr_manager.run_passes(shared_from_this()); - reshape_only(new_param_shapes); + reshape_only(new_param_shapes, new_vars_shapes); } catch (...) { // restore shapes to original ones - reshape_only(original_input_shapes); + reshape_only(original_input_shapes, original_vars_shapes); throw; } } diff --git a/src/core/src/op/read_value.cpp b/src/core/src/op/read_value.cpp index 88f9e3dce1e..0c9ce8e88cc 100644 --- a/src/core/src/op/read_value.cpp +++ b/src/core/src/op/read_value.cpp @@ -134,10 +134,6 @@ bool ReadValue::visit_attributes(AttributeVisitor& visitor) { } void ReadValue::revalidate_and_infer_types() { - // Update variable shape if not extend new shape (e.g reshape result). - if (get_input_size() > 0 && !m_variable->get_info().data_shape.relaxes(get_input_partial_shape(0))) { - m_variable->update_data_shape(get_input_partial_shape(0)); - } Node::revalidate_and_infer_types(); } diff --git a/src/core/tests/model.cpp b/src/core/tests/model.cpp index 49cc67cc02b..1989028f722 100644 --- a/src/core/tests/model.cpp +++ b/src/core/tests/model.cpp @@ -7,13 +7,18 @@ #include #include -#include #include "common_test_utils/graph_comparator.hpp" #include "common_test_utils/test_common.hpp" #include "openvino/core/except.hpp" #include "openvino/core/partial_shape.hpp" #include "openvino/opsets/opset8.hpp" +#include "shared_node_info.hpp" + +using ov::op::util::Variable; +using ov::op::util::VariableInfo; +using ov::op::v0::Parameter; +using ov::op::v0::Result; TEST(model, get_input_by_tensor_name) { auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1}); @@ -957,6 +962,126 @@ TEST(model_reshape, IncoreectReshapeBatchWithMultipleInputs) { EXPECT_THROW(f->reshape(shape), ov::Exception); } +TEST(model_reshape, ReshapeWithStaticVariableSingleInput) { + auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1, 3, 4, 5}); + + auto variable = std::make_shared(VariableInfo{arg0->get_output_partial_shape(0), ov::element::f32, "ID"}); + auto read_value = std::make_shared(arg0, variable); + auto assign = std::make_shared(read_value, variable); + + auto result1 = std::make_shared(assign); + + auto shape_of = std::make_shared(arg0); + auto result2 = std::make_shared(shape_of); + auto model = std::make_shared(ov::ResultVector{result1, result2}, ov::ParameterVector{arg0}); + + model->validate_nodes_and_infer_types(); + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 3, 4, 5})); + EXPECT_EQ(model->get_results()[0]->get_shape(), ov::Shape({1, 3, 4, 5})); + EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); + + { + ov::PartialShape shape({1, 4, 3, 3}); + model->reshape(shape, {{"ID", shape}}); + } + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 4, 3, 3})); + EXPECT_EQ(model->get_results()[0]->get_shape(), ov::Shape({1, 4, 3, 3})); + EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); +} + +TEST(model_reshape, ReshapeWithDynamicVariableSingleInput) { + auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1, 3, 4, 5}); + arg0->get_output_tensor(0).set_names({"input"}); + + auto variable = std::make_shared(VariableInfo{ov::PartialShape::dynamic(4), ov::element::f32, "ID"}); + auto read_value = std::make_shared(arg0, variable); + auto assign = std::make_shared(read_value, variable); + + auto result1 = std::make_shared(assign); + + auto shape_of = std::make_shared(arg0); + auto result2 = std::make_shared(shape_of); + auto model = std::make_shared(ov::ResultVector{result1, result2}, ov::ParameterVector{arg0}); + + model->validate_nodes_and_infer_types(); + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 3, 4, 5})); + EXPECT_EQ(model->get_results()[0]->get_output_partial_shape(0), ov::PartialShape::dynamic(4)); + EXPECT_EQ(model->get_results()[1]->get_output_partial_shape(0), ov::Shape({4})); + + model->reshape({{"input", ov::PartialShape{1, 4, 8, 9}}}); + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 4, 8, 9})); + EXPECT_EQ(model->get_results()[0]->get_output_partial_shape(0), ov::PartialShape::dynamic(4)); + EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); +} + +TEST(model_reshape, ReshapeStaticWithVariableMultipleInputs) { + auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1, 3, 4, 5}); + auto arg1 = std::make_shared(ov::element::f32, ov::PartialShape{1, 2, 4, 5}); + auto concat = std::make_shared(ov::NodeVector{arg0, arg1}, 1); + + auto variable = + std::make_shared(VariableInfo{concat->get_output_partial_shape(0), ov::element::f32, "ID"}); + auto read_value = std::make_shared(concat, variable); + auto assign = std::make_shared(read_value, variable); + + auto result1 = std::make_shared(assign); + + auto shape_of = std::make_shared(concat); + auto result2 = std::make_shared(shape_of); + auto model = std::make_shared(ov::ResultVector{result1, result2}, ov::ParameterVector{arg0, arg1}); + + model->validate_nodes_and_infer_types(); + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 3, 4, 5})); + EXPECT_EQ(model->get_parameters()[1]->get_shape(), ov::Shape({1, 2, 4, 5})); + EXPECT_EQ(model->get_results()[0]->get_shape(), ov::Shape({1, 5, 4, 5})); + EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); + + { + ov::PartialShape shape({1, 14, 4, 5}); + model->reshape({{0, shape}, {1, shape}}, {{"ID", {1, 28, 4, 5}}}); + } + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 14, 4, 5})); + EXPECT_EQ(model->get_parameters()[1]->get_shape(), ov::Shape({1, 14, 4, 5})); + EXPECT_EQ(model->get_results()[0]->get_shape(), ov::Shape({1, 28, 4, 5})); + EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); +} + +TEST(model_reshape, ReshapeWithStaticVariableIncorrectVariable) { + auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1, 3, 4, 5}); + auto arg1 = std::make_shared(ov::element::f32, ov::PartialShape{1, 2, 4, 5}); + auto concat = std::make_shared(ov::NodeVector{arg0, arg1}, 1); + + auto variable = + std::make_shared(VariableInfo{concat->get_output_partial_shape(0), ov::element::f32, "ID"}); + auto read_value = std::make_shared(concat, variable); + auto assign = std::make_shared(read_value, variable); + + auto result1 = std::make_shared(assign); + + auto shape_of = std::make_shared(concat); + auto result2 = std::make_shared(shape_of); + auto model = std::make_shared(ov::ResultVector{result1, result2}, ov::ParameterVector{arg0, arg1}); + + model->validate_nodes_and_infer_types(); + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 3, 4, 5})); + EXPECT_EQ(model->get_parameters()[1]->get_shape(), ov::Shape({1, 2, 4, 5})); + EXPECT_EQ(model->get_results()[0]->get_shape(), ov::Shape({1, 5, 4, 5})); + EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); + + ov::PartialShape shape({1, 14, 4, 5}); + ov::PartialShape wrong_var_shape({1, 20, 4, 5}); + EXPECT_THROW(model->reshape({{0, shape}, {1, shape}}), ov::AssertFailure); + EXPECT_THROW(model->reshape({{0, shape}, {1, shape}}, {{"WRONG_ID", {1, 28, 4, 5}}}), ov::AssertFailure); + EXPECT_THROW(model->reshape({{0, shape}, {1, shape}}, {{"ID", wrong_var_shape}}), ov::AssertFailure); +} + TEST(model, add_output_tensor_name) { auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1}); arg0->set_friendly_name("data"); diff --git a/src/core/tests/type_prop/read_value.cpp b/src/core/tests/type_prop/read_value.cpp index 7d161ceded5..cd56cd49b59 100644 --- a/src/core/tests/type_prop/read_value.cpp +++ b/src/core/tests/type_prop/read_value.cpp @@ -6,7 +6,6 @@ #include "common_test_utils/type_prop.hpp" #include "dimension_util.hpp" -#include "openvino/core/model.hpp" namespace ov { namespace test { @@ -134,23 +133,5 @@ TEST(type_prop, DISABLED_read_value_labels_propagation_from_init_subgraph) { EXPECT_THAT(get_shape_labels(read_value->get_output_partial_shape(0)), testing::ElementsAre(10, 11, 12, 13)); } -TEST(type_prop, read_value_v6_model_reshape) { - const auto batch_shape = PartialShape{1, 30}; - const auto new_batch_shape = PartialShape{3, 30}; - - // dummy model with ReadValue for reshape - auto input = std::make_shared(element::f16, batch_shape); - auto variable = std::make_shared(VariableInfo{batch_shape, element::f16, "ID"}); - auto read_value = std::make_shared(input, variable); - auto assign = std::make_shared(read_value, variable); - auto result = std::make_shared(read_value); - - auto model = std::make_shared(ResultVector{result}, SinkVector{assign}, ParameterVector{input}); - - ASSERT_NO_THROW(model->reshape(new_batch_shape)); - EXPECT_EQ(read_value->get_output_partial_shape(0), new_batch_shape); - EXPECT_EQ(read_value->get_variable()->get_info(), VariableInfo({new_batch_shape, element::f16, "ID"})); -} - } // namespace test } // namespace ov From 2e7389b4d6d6bea8155085f79710f8fa3d092c7d Mon Sep 17 00:00:00 2001 From: "Raasz, Pawel" Date: Thu, 18 Apr 2024 17:20:54 +0200 Subject: [PATCH 3/7] Revert changes in read_value tests --- src/core/tests/type_prop/read_value.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/core/tests/type_prop/read_value.cpp b/src/core/tests/type_prop/read_value.cpp index cd56cd49b59..c021aafd89a 100644 --- a/src/core/tests/type_prop/read_value.cpp +++ b/src/core/tests/type_prop/read_value.cpp @@ -7,14 +7,8 @@ #include "common_test_utils/type_prop.hpp" #include "dimension_util.hpp" -namespace ov { -namespace test { - using namespace std; -using ov::op::util::Variable; -using ov::op::util::VariableInfo; -using ov::op::v0::Parameter; -using ov::op::v0::Result; +using namespace ov; TEST(type_prop, read_value_deduce) { auto input = make_shared(element::f32, Shape{1, 2, 64, 64}); @@ -132,6 +126,3 @@ TEST(type_prop, DISABLED_read_value_labels_propagation_from_init_subgraph) { std::shared_ptr read_value = std::make_shared(input, variable); EXPECT_THAT(get_shape_labels(read_value->get_output_partial_shape(0)), testing::ElementsAre(10, 11, 12, 13)); } - -} // namespace test -} // namespace ov From 677024f147b21ad0fe2cbdc17ac61e4ea84be2b5 Mon Sep 17 00:00:00 2001 From: "Raasz, Pawel" Date: Mon, 22 Apr 2024 06:15:15 +0200 Subject: [PATCH 4/7] Update model test --- src/core/tests/model.cpp | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/core/tests/model.cpp b/src/core/tests/model.cpp index 1989028f722..9eb73508972 100644 --- a/src/core/tests/model.cpp +++ b/src/core/tests/model.cpp @@ -937,7 +937,7 @@ TEST(model_reshape, ReshapeBatchReLUWithOneInput) { EXPECT_EQ(model->get_results()[0]->get_shape(), ov::Shape({2, 3, 22, 22})); } -TEST(model_reshape, IncoreectReshapeBatchWithMultipleInputs) { +TEST(model_reshape, IncorrectReshapeBatchWithMultipleInputs) { auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1, 3, 3, 3}); arg0->set_friendly_name("data"); arg0->get_output_tensor(0).set_names({"input1"}); @@ -991,6 +991,41 @@ TEST(model_reshape, ReshapeWithStaticVariableSingleInput) { EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); } +TEST(model_reshape, ReshapeWithStaticVariablesSingleInput) { + auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1, 3, 4, 5}); + + auto variable = + std::make_shared(VariableInfo{arg0->get_output_partial_shape(0), ov::element::f32, "ID1"}); + auto read_value = std::make_shared(arg0, variable); + auto assign = std::make_shared(read_value, variable); + + auto add = std::make_shared(read_value, read_value); + auto var_add = std::make_shared(VariableInfo{add->get_output_partial_shape(0), ov::element::f32, "ID2"}); + auto read_value_add = std::make_shared(add, var_add); + auto assign_add = std::make_shared(read_value_add, var_add); + + auto result1 = std::make_shared(assign); + + auto shape_of = std::make_shared(add); + auto result2 = std::make_shared(shape_of); + auto model = std::make_shared(ov::ResultVector{result1, result2}, ov::ParameterVector{arg0}); + + model->validate_nodes_and_infer_types(); + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 3, 4, 5})); + EXPECT_EQ(model->get_results()[0]->get_shape(), ov::Shape({1, 3, 4, 5})); + EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); + + { + ov::PartialShape shape({1, 4, 3, 3}); + model->reshape(shape, {{"ID2", shape}, {"ID1", shape}}); + } + + EXPECT_EQ(model->get_parameters()[0]->get_shape(), ov::Shape({1, 4, 3, 3})); + EXPECT_EQ(model->get_results()[0]->get_shape(), ov::Shape({1, 4, 3, 3})); + EXPECT_EQ(model->get_results()[1]->get_shape(), ov::Shape({4})); +} + TEST(model_reshape, ReshapeWithDynamicVariableSingleInput) { auto arg0 = std::make_shared(ov::element::f32, ov::PartialShape{1, 3, 4, 5}); arg0->get_output_tensor(0).set_names({"input"}); From c6a2aa6a5131f98e73a436b3988cfdc53235747b Mon Sep 17 00:00:00 2001 From: "Raasz, Pawel" Date: Mon, 22 Apr 2024 06:16:25 +0200 Subject: [PATCH 5/7] Update python bindings to use optional parameter in reshape --- .../python/src/pyopenvino/graph/model.cpp | 255 +++++++++++++++--- .../python/tests/test_runtime/test_model.py | 141 +++++++++- 2 files changed, 352 insertions(+), 44 deletions(-) diff --git a/src/bindings/python/src/pyopenvino/graph/model.cpp b/src/bindings/python/src/pyopenvino/graph/model.cpp index 498ee992173..53ac3ed5f4b 100644 --- a/src/bindings/python/src/pyopenvino/graph/model.cpp +++ b/src/bindings/python/src/pyopenvino/graph/model.cpp @@ -84,6 +84,50 @@ static void set_correct_variables_for_assign_ops(const std::shared_ptr output_from_handle(ov::Model& model, const py::handle& handle) { + if (py::isinstance(handle)) { + return model.input(handle.cast()); + } else if (py::isinstance(handle)) { + return model.input(handle.cast()); + } else if (py::isinstance>(handle)) { + return handle.cast>(); + } else { + throw py::type_error("Incorrect key type " + std::string(py::str(handle.get_type())) + + " to reshape a model, expected keys as openvino.runtime.Output, int or str."); + } +} + +static ov::PartialShape partial_shape_from_handle(const py::handle& handle) { + if (py::isinstance(handle)) { + return handle.cast(); + } else if (py::isinstance(handle) || py::isinstance(handle)) { + return Common::partial_shape_from_list(handle.cast()); + } else if (py::isinstance(handle)) { + return ov::PartialShape(handle.cast()); + } else { + throw py::type_error( + "Incorrect value type " + std::string(py::str(handle.get_type())) + + " to reshape a model, expected values as openvino.runtime.PartialShape, str, list or tuple."); + } +} + +static std::string string_from_handle(const py::handle& handle) { + if (py::isinstance(handle)) { + return handle.cast(); + } else { + throw py::type_error("Incorrect key type " + std::string(py::str(handle.get_type())) + + " to reshape a model, expected values as str."); + } +} + +static std::unordered_map get_variables_shapes(const py::dict& variables_shapes) { + std::unordered_map variables_shape_map; + for (const auto& item : variables_shapes) { + variables_shape_map.emplace(string_from_handle(item.first), partial_shape_from_handle(item.second)); + } + return variables_shape_map; +} + void regclass_graph_Model(py::module m) { py::class_> model(m, "Model", py::module_local()); model.doc() = "openvino.runtime.Model wraps ov::Model"; @@ -309,109 +353,212 @@ void regclass_graph_Model(py::module m) { model.def( "reshape", - [](ov::Model& self, const ov::PartialShape& partial_shape) { - self.reshape(partial_shape); + [](ov::Model& self, const ov::PartialShape& partial_shape, const py::dict& variables_shapes) { + if (variables_shapes.empty()) { + py::gil_scoped_release release; + self.reshape(partial_shape); + } else { + const auto new_variables_shapes = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(partial_shape, new_variables_shapes); + } }, - py::call_guard(), py::arg("partial_shape"), + py::arg("variables_shapes") = py::dict(), R"( Reshape model input. + The allowed types of keys in the `variables_shapes` dictionary is `str`. + The allowed types of values in the `variables_shapes` are: + + (1) `openvino.runtime.PartialShape` + (2) `list` consisting of dimensions + (3) `tuple` consisting of dimensions + (4) `str`, string representation of `openvino.runtime.PartialShape` + + When list or tuple are used to describe dimensions, each dimension can be written in form: + + (1) non-negative `int` which means static value for the dimension + (2) `[min, max]`, dynamic dimension where `min` specifies lower bound and `max` specifies upper bound; + the range includes both `min` and `max`; using `-1` for `min` or `max` means no known bound (3) `(min, + max)`, the same as above (4) `-1` is a dynamic dimension without known bounds (4) + `openvino.runtime.Dimension` (5) `str` using next syntax: + '?' - to define fully dynamic dimension + '1' - to define dimension which length is 1 + '1..10' - to define bounded dimension + '..10' or '1..' to define dimension with only lower or only upper limit + GIL is released while running this function. :param partial_shape: New shape. :type partial_shape: openvino.runtime.PartialShape + :param variables_shapes: New shapes for variables + :type variables_shapes: Dict[keys, values] :return : void )"); model.def( "reshape", - [](ov::Model& self, const py::list& partial_shape) { - ov::PartialShape new_shape(Common::partial_shape_from_list(partial_shape)); - py::gil_scoped_release release; - self.reshape(new_shape); + [](ov::Model& self, const py::list& partial_shape, const py::dict& variables_shapes) { + const auto new_shape = Common::partial_shape_from_list(partial_shape); + if (variables_shapes.empty()) { + py::gil_scoped_release release; + self.reshape(new_shape); + } else { + const auto new_variables_shapes = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(new_shape, new_variables_shapes); + } }, py::arg("partial_shape"), + py::arg("variables_shapes") = py::dict(), R"( Reshape model input. + The allowed types of keys in the `variables_shapes` dictionary is `str`. + The allowed types of values in the `variables_shapes` are: + + (1) `openvino.runtime.PartialShape` + (2) `list` consisting of dimensions + (3) `tuple` consisting of dimensions + (4) `str`, string representation of `openvino.runtime.PartialShape` + + When list or tuple are used to describe dimensions, each dimension can be written in form: + + (1) non-negative `int` which means static value for the dimension + (2) `[min, max]`, dynamic dimension where `min` specifies lower bound and `max` specifies upper bound; + the range includes both `min` and `max`; using `-1` for `min` or `max` means no known bound (3) `(min, + max)`, the same as above (4) `-1` is a dynamic dimension without known bounds (4) + `openvino.runtime.Dimension` (5) `str` using next syntax: + '?' - to define fully dynamic dimension + '1' - to define dimension which length is 1 + '1..10' - to define bounded dimension + '..10' or '1..' to define dimension with only lower or only upper limit + GIL is released while running this function. :param partial_shape: New shape. :type partial_shape: list + :param variables_shapes: New shapes for variables + :type variables_shapes: Dict[keys, values] :return : void )"); model.def( "reshape", - [](ov::Model& self, const py::tuple& partial_shape) { - ov::PartialShape new_shape(Common::partial_shape_from_list(partial_shape.cast())); - py::gil_scoped_release release; - self.reshape(new_shape); + [](ov::Model& self, const py::tuple& partial_shape, const py::dict& variables_shapes) { + const auto new_shape = Common::partial_shape_from_list(partial_shape.cast()); + if (variables_shapes.empty()) { + py::gil_scoped_release release; + self.reshape(new_shape); + } else { + const auto new_variables_shapes = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(new_shape, new_variables_shapes); + } }, py::arg("partial_shape"), + py::arg("variables_shapes") = py::dict(), R"( Reshape model input. + The allowed types of keys in the `variables_shapes` dictionary is `str`. + The allowed types of values in the `variables_shapes` are: + + (1) `openvino.runtime.PartialShape` + (2) `list` consisting of dimensions + (3) `tuple` consisting of dimensions + (4) `str`, string representation of `openvino.runtime.PartialShape` + + When list or tuple are used to describe dimensions, each dimension can be written in form: + + (1) non-negative `int` which means static value for the dimension + (2) `[min, max]`, dynamic dimension where `min` specifies lower bound and `max` specifies upper bound; + the range includes both `min` and `max`; using `-1` for `min` or `max` means no known bound (3) `(min, + max)`, the same as above (4) `-1` is a dynamic dimension without known bounds (4) + `openvino.runtime.Dimension` (5) `str` using next syntax: + '?' - to define fully dynamic dimension + '1' - to define dimension which length is 1 + '1..10' - to define bounded dimension + '..10' or '1..' to define dimension with only lower or only upper limit + GIL is released while running this function. :param partial_shape: New shape. :type partial_shape: tuple + :param variables_shapes: New shapes for variables + :type variables_shapes: Dict[keys, values] :return : void )"); model.def( "reshape", - [](ov::Model& self, const std::string& partial_shape) { - self.reshape(ov::PartialShape(partial_shape)); + [](ov::Model& self, const std::string& partial_shape, const py::dict& variables_shapes) { + if (variables_shapes.empty()) { + py::gil_scoped_release release; + self.reshape(ov::PartialShape(partial_shape)); + } else { + const auto new_variables_shape = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(ov::PartialShape(partial_shape), new_variables_shape); + } }, - py::call_guard(), py::arg("partial_shape"), + py::arg("variables_shapes") = py::dict(), R"( Reshape model input. + The allowed types of keys in the `variables_shapes` dictionary is `str`. + The allowed types of values in the `variables_shapes` are: + + (1) `openvino.runtime.PartialShape` + (2) `list` consisting of dimensions + (3) `tuple` consisting of dimensions + (4) `str`, string representation of `openvino.runtime.PartialShape` + + When list or tuple are used to describe dimensions, each dimension can be written in form: + + (1) non-negative `int` which means static value for the dimension + (2) `[min, max]`, dynamic dimension where `min` specifies lower bound and `max` specifies upper bound; + the range includes both `min` and `max`; using `-1` for `min` or `max` means no known bound (3) `(min, + max)`, the same as above (4) `-1` is a dynamic dimension without known bounds (4) + `openvino.runtime.Dimension` (5) `str` using next syntax: + '?' - to define fully dynamic dimension + '1' - to define dimension which length is 1 + '1..10' - to define bounded dimension + '..10' or '1..' to define dimension with only lower or only upper limit + + GIL is released while running this function. :param partial_shape: New shape. :type partial_shape: str + :param variables_shapes: New shapes for variables + :type variables_shapes: Dict[keys, values] :return : void )"); model.def( "reshape", - [](ov::Model& self, const py::dict& partial_shapes) { + [](ov::Model& self, const py::dict& partial_shapes, const py::dict& variables_shapes) { std::map, ov::PartialShape> new_shapes; for (const auto& item : partial_shapes) { - std::pair, ov::PartialShape> new_shape; - // check keys - if (py::isinstance(item.first)) { - new_shape.first = self.input(item.first.cast()); - } else if (py::isinstance(item.first)) { - new_shape.first = self.input(item.first.cast()); - } else if (py::isinstance>(item.first)) { - new_shape.first = item.first.cast>(); - } else { - throw py::type_error("Incorrect key type " + std::string(py::str(item.first.get_type())) + - " to reshape a model, expected keys as openvino.runtime.Output, int or str."); - } - // check values - if (py::isinstance(item.second)) { - new_shape.second = item.second.cast(); - } else if (py::isinstance(item.second) || py::isinstance(item.second)) { - new_shape.second = Common::partial_shape_from_list(item.second.cast()); - } else if (py::isinstance(item.second)) { - new_shape.second = ov::PartialShape(item.second.cast()); - } else { - throw py::type_error( - "Incorrect value type " + std::string(py::str(item.second.get_type())) + - " to reshape a model, expected values as openvino.runtime.PartialShape, str, list or tuple."); - } - new_shapes.insert(new_shape); + new_shapes.emplace_hint(new_shapes.end(), + output_from_handle(self, item.first), + partial_shape_from_handle(item.second)); + } + + if (variables_shapes.empty()) { + py::gil_scoped_release release; + self.reshape(new_shapes); + } else { + const auto new_variables_shapes = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(new_shapes, new_variables_shapes); } - py::gil_scoped_release release; - self.reshape(new_shapes); }, py::arg("partial_shapes"), + py::arg("variables_shapes") = py::dict(), R"( Reshape model inputs. The allowed types of keys in the `partial_shapes` dictionary are: @@ -440,12 +587,34 @@ void regclass_graph_Model(py::module m) { '1..10' - to define bounded dimension '..10' or '1..' to define dimension with only lower or only upper limit - Reshape model input. + The allowed types of keys in the `variables_shapes` dictionary is `str`. + The allowed types of values in the `variables_shapes` are: + + (1) `openvino.runtime.PartialShape` + (2) `list` consisting of dimensions + (3) `tuple` consisting of dimensions + (4) `str`, string representation of `openvino.runtime.PartialShape` + + When list or tuple are used to describe dimensions, each dimension can be written in form: + + (1) non-negative `int` which means static value for the dimension + (2) `[min, max]`, dynamic dimension where `min` specifies lower bound and `max` specifies upper bound; + the range includes both `min` and `max`; using `-1` for `min` or `max` means no known bound (3) `(min, + max)`, the same as above (4) `-1` is a dynamic dimension without known bounds (4) + `openvino.runtime.Dimension` (5) `str` using next syntax: + '?' - to define fully dynamic dimension + '1' - to define dimension which length is 1 + '1..10' - to define bounded dimension + '..10' or '1..' to define dimension with only lower or only upper limit + + Reshape model inputs. GIL is released while running this function. :param partial_shapes: New shapes. :type partial_shapes: Dict[keys, values] + :param variables_shapes: New shapes for variables + :type variables_shapes: Dict[keys, values] )"); model.def("get_output_size", diff --git a/src/bindings/python/tests/test_runtime/test_model.py b/src/bindings/python/tests/test_runtime/test_model.py index 6d545f7760c..5cc3975cb22 100644 --- a/src/bindings/python/tests/test_runtime/test_model.py +++ b/src/bindings/python/tests/test_runtime/test_model.py @@ -26,7 +26,18 @@ from openvino import ( from openvino.runtime import Output from openvino.runtime.op.util import VariableInfo, Variable -from tests.utils.helpers import generate_add_model, generate_model_with_memory, create_filename_for_test +from tests.utils.helpers import ( + generate_add_model, + generate_model_with_memory, + create_filename_for_test, +) + + +def make_add_with_variable_model(shape, variable_id: str, dtype=np.float32) -> Model: + param1 = ops.parameter(Shape(shape), dtype=dtype, name="data1") + param2 = ops.parameter(Shape(shape), dtype=dtype, name="data2") + read_value = ops.read_value(param1, variable_id, dtype, shape) + return Model(ops.add(read_value, param2), [param1, param2]) def test_descriptor_tensor(): @@ -287,6 +298,55 @@ def test_reshape(device): assert compiled_model.input().partial_shape == ref_shape +def test_reshape_with_ports_and_variable(): + new_shape = PartialShape([46, 1]) + var_id = "ID1" + model = make_add_with_variable_model([1, 5], var_id) + for model_input in model.inputs: + assert isinstance(model_input, Output) + model.reshape({model_input: new_shape}, {var_id: new_shape}) + assert model_input.partial_shape == new_shape + + +def test_reshape_with_indexes_and_variable(): + var_id = "ID1" + model = make_add_with_variable_model([1, 5], var_id) + new_shape = PartialShape([1, 4]) + model.reshape( + {i: new_shape for i, model_input in enumerate(model.inputs)}, + {var_id: new_shape}, + ) + for model_input in model.inputs: + assert model_input.partial_shape == new_shape + + +def test_reshape_with_names_and_variables(): + var_id = "ID1" + model = make_add_with_variable_model([1, 25], var_id) + new_shape = PartialShape([4, 1]) + model.reshape( + {model_input.any_name: new_shape for model_input in model.inputs}, + {var_id: new_shape}, + ) + for model_input in model.inputs: + assert model_input.partial_shape == new_shape + + +def test_reshape_with_variable(device): + shape = PartialShape([1, 10]) + + param = ops.parameter(shape, dtype=np.float32) + read_value = ops.read_value(param, "MyVar", Type.f32, shape) + model = Model(ops.relu(read_value), [param]) + + ref_shape = model.input().partial_shape + ref_shape[0] = 3 + model.reshape(ref_shape, {"MyVar": ref_shape}) + core = Core() + compiled_model = core.compile_model(model, device) + assert compiled_model.input().partial_shape == ref_shape + + def test_reshape_with_python_types(device): model = generate_add_model() @@ -365,6 +425,85 @@ def test_reshape_with_python_types(device): ) +def test_reshape_with_python_types_for_variable(device): + var_id = "ID1" + model = make_add_with_variable_model([1, 2, 5], var_id) + + def check_shape(new_shape): + for model_input in model.inputs: + assert model_input.partial_shape == new_shape + + shape1 = [1, 4] + new_shapes = {input: PartialShape(shape1) for input in model.inputs} + model.reshape(new_shapes, {var_id: shape1}) + check_shape(PartialShape(shape1)) + + shape2 = [1, 6] + new_shapes = {input.any_name: PartialShape(shape2) for input in model.inputs} + model.reshape(new_shapes, {var_id: shape2}) + check_shape(PartialShape(shape2)) + + shape3 = [1, 8] + new_shapes = {i: PartialShape(shape3) for i, _ in enumerate(model.inputs)} + model.reshape(new_shapes, {var_id: shape3}) + check_shape(PartialShape(shape3)) + + shape4 = [1, -1] + new_shapes = {input: PartialShape(shape4) for input in model.inputs} + model.reshape(new_shapes, {var_id: shape4}) + check_shape(PartialShape([Dimension(1), Dimension(-1)])) + + shape5 = [1, (1, 10)] + new_shapes = {input: PartialShape(shape5) for input in model.inputs} + model.reshape(new_shapes, {var_id: shape5}) + check_shape(PartialShape([Dimension(1), Dimension(1, 10)])) + + shape6 = [Dimension(3), Dimension(3, 10)] + new_shapes = {input: PartialShape(shape6) for input in model.inputs} + model.reshape(new_shapes, {var_id: shape6}) + check_shape(PartialShape(shape6)) + + shape7 = "[1..10, ?]" + new_shapes = {input: PartialShape(shape7) for input in model.inputs} + model.reshape(new_shapes, {var_id: shape7}) + check_shape(PartialShape(shape7)) + + # reshape mixed keys + shape8 = [(1, 20), -1] + new_shapes = {"data1": PartialShape(shape8), 1: shape8} + model.reshape(new_shapes, {var_id: shape8}) + check_shape(PartialShape([Dimension(1, 20), Dimension(-1)])) + + # reshape with one input + param = ops.parameter([1, 3, 28, 28]) + read_value = ops.read_value(param, var_id, Type.f32, param.get_partial_shape()) + model = Model(ops.relu(read_value), [param]) + + shape9 = [-1, 3, (28, 56), (28, 56)] + model.reshape(shape9, {var_id: shape9}) + check_shape(PartialShape([Dimension(-1), Dimension(3), Dimension(28, 56), Dimension(28, 56)])) + + shape10 = "[?,3,..224,..224]" + model.reshape(shape10, {var_id: shape10}) + check_shape(PartialShape([Dimension(-1), Dimension(3), Dimension(-1, 224), Dimension(-1, 224)])) + + # check exceptions + shape10 = [1, 1, 1, 1] + with pytest.raises(TypeError) as e: + model.reshape({0: shape10}, {0: shape10}) + assert ( + "Incorrect key type to reshape a model, expected values as str." in str(e.value) + ) + + with pytest.raises(TypeError) as e: + model.reshape({0: shape10}, {var_id: range(1, 9)}) + assert ( + "Incorrect value type to reshape a model, " + "expected values as openvino.runtime.PartialShape, str, list or tuple." + in str(e.value) + ) + + # request - https://docs.pytest.org/en/7.1.x/reference/reference.html#request def test_serialize_rt_info(request, tmp_path): version = "TestVersion" From 254fc505d8929e155c7c6ebd8e7ca0bc6642f82d Mon Sep 17 00:00:00 2001 From: "Raasz, Pawel" Date: Mon, 13 May 2024 13:48:04 +0200 Subject: [PATCH 6/7] Remove commented code --- src/core/src/model.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/src/model.cpp b/src/core/src/model.cpp index 9af76486ccd..45ca8db78f3 100644 --- a/src/core/src/model.cpp +++ b/src/core/src/model.cpp @@ -855,7 +855,6 @@ void ov::Model::reshape(const std::map, ov::PartialShape>& if (!need_reshape) return; - // const auto& variables = get_variables(); std::unordered_map new_vars_shapes; std::unordered_map original_vars_shapes; for (const auto& variable : get_variables()) { From f99921eba9d121df1de96e9b53dc41714a7e10eb Mon Sep 17 00:00:00 2001 From: "Raasz, Pawel" Date: Fri, 17 May 2024 08:25:56 +0200 Subject: [PATCH 7/7] Use default parameter instead overload in Model::reshape --- .../python/src/pyopenvino/graph/model.cpp | 56 +++++-------------- src/core/include/openvino/core/model.hpp | 13 ++--- src/core/src/model.cpp | 27 +-------- 3 files changed, 20 insertions(+), 76 deletions(-) diff --git a/src/bindings/python/src/pyopenvino/graph/model.cpp b/src/bindings/python/src/pyopenvino/graph/model.cpp index 53ac3ed5f4b..7d73578a57b 100644 --- a/src/bindings/python/src/pyopenvino/graph/model.cpp +++ b/src/bindings/python/src/pyopenvino/graph/model.cpp @@ -354,14 +354,9 @@ void regclass_graph_Model(py::module m) { model.def( "reshape", [](ov::Model& self, const ov::PartialShape& partial_shape, const py::dict& variables_shapes) { - if (variables_shapes.empty()) { - py::gil_scoped_release release; - self.reshape(partial_shape); - } else { - const auto new_variables_shapes = get_variables_shapes(variables_shapes); - py::gil_scoped_release release; - self.reshape(partial_shape, new_variables_shapes); - } + const auto new_variable_shapes = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(partial_shape, new_variable_shapes); }, py::arg("partial_shape"), py::arg("variables_shapes") = py::dict(), @@ -401,14 +396,9 @@ void regclass_graph_Model(py::module m) { "reshape", [](ov::Model& self, const py::list& partial_shape, const py::dict& variables_shapes) { const auto new_shape = Common::partial_shape_from_list(partial_shape); - if (variables_shapes.empty()) { - py::gil_scoped_release release; - self.reshape(new_shape); - } else { - const auto new_variables_shapes = get_variables_shapes(variables_shapes); - py::gil_scoped_release release; - self.reshape(new_shape, new_variables_shapes); - } + const auto new_variables_shapes = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(new_shape, new_variables_shapes); }, py::arg("partial_shape"), py::arg("variables_shapes") = py::dict(), @@ -448,14 +438,9 @@ void regclass_graph_Model(py::module m) { "reshape", [](ov::Model& self, const py::tuple& partial_shape, const py::dict& variables_shapes) { const auto new_shape = Common::partial_shape_from_list(partial_shape.cast()); - if (variables_shapes.empty()) { - py::gil_scoped_release release; - self.reshape(new_shape); - } else { - const auto new_variables_shapes = get_variables_shapes(variables_shapes); - py::gil_scoped_release release; - self.reshape(new_shape, new_variables_shapes); - } + const auto new_variables_shapes = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(new_shape, new_variables_shapes); }, py::arg("partial_shape"), py::arg("variables_shapes") = py::dict(), @@ -494,14 +479,9 @@ void regclass_graph_Model(py::module m) { model.def( "reshape", [](ov::Model& self, const std::string& partial_shape, const py::dict& variables_shapes) { - if (variables_shapes.empty()) { - py::gil_scoped_release release; - self.reshape(ov::PartialShape(partial_shape)); - } else { - const auto new_variables_shape = get_variables_shapes(variables_shapes); - py::gil_scoped_release release; - self.reshape(ov::PartialShape(partial_shape), new_variables_shape); - } + const auto new_variables_shape = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(ov::PartialShape(partial_shape), new_variables_shape); }, py::arg("partial_shape"), py::arg("variables_shapes") = py::dict(), @@ -547,15 +527,9 @@ void regclass_graph_Model(py::module m) { output_from_handle(self, item.first), partial_shape_from_handle(item.second)); } - - if (variables_shapes.empty()) { - py::gil_scoped_release release; - self.reshape(new_shapes); - } else { - const auto new_variables_shapes = get_variables_shapes(variables_shapes); - py::gil_scoped_release release; - self.reshape(new_shapes, new_variables_shapes); - } + const auto new_variables_shapes = get_variables_shapes(variables_shapes); + py::gil_scoped_release release; + self.reshape(new_shapes, new_variables_shapes); }, py::arg("partial_shapes"), py::arg("variables_shapes") = py::dict(), diff --git a/src/core/include/openvino/core/model.hpp b/src/core/include/openvino/core/model.hpp index d5b778a6c5d..1b300aa5304 100644 --- a/src/core/include/openvino/core/model.hpp +++ b/src/core/include/openvino/core/model.hpp @@ -140,19 +140,14 @@ public: ov::Output add_output(const std::string& op_name, size_t output_idx); ov::Output add_output(const ov::Output& port); - void reshape(const ov::PartialShape& partial_shape); - void reshape(const std::map& partial_shapes); - void reshape(const std::map& partial_shapes); - void reshape(const std::map, ov::PartialShape>& partial_shapes); - void reshape(const ov::PartialShape& partial_shape, - const std::unordered_map& variable_shapes); + const std::unordered_map& variable_shapes = {}); void reshape(const std::map& partial_shapes, - const std::unordered_map& variable_shapes); + const std::unordered_map& variable_shapes = {}); void reshape(const std::map& partial_shapes, - const std::unordered_map& variable_shapes); + const std::unordered_map& variable_shapes = {}); void reshape(const std::map, ov::PartialShape>& partial_shapes, - const std::unordered_map& variable_shapes); + const std::unordered_map& variable_shapes = {}); /// Return the element type of output i const ov::element::Type& get_output_element_type(size_t i) const; diff --git a/src/core/src/model.cpp b/src/core/src/model.cpp index 45ca8db78f3..2b76859db96 100644 --- a/src/core/src/model.cpp +++ b/src/core/src/model.cpp @@ -30,11 +30,6 @@ atomic ov::Model::m_next_instance_id(0); namespace { -const std::unordered_map& default_variable_map() { - static const std::unordered_map variable_map; - return variable_map; -} - void check_all_variables_registered(const std::vector>& ordered_ops, const ov::op::util::VariableVector& variables) { OV_ITT_SCOPED_TASK(ov::itt::domains::ov_pass, "Model::check_all_variables_registered"); @@ -782,26 +777,6 @@ ov::Output ov::Model::input(const std::string& tensor_name) { OPENVINO_THROW("Input for tensor name '", tensor_name, "' is not found."); } -void ov::Model::reshape(const ov::PartialShape& partial_shape) { - OPENVINO_ASSERT(m_parameters.size() == 1, - "reshape(const ov::PartialShape&) must be called on a Model with exactly one parameter."); - std::map shapes; - shapes[0] = partial_shape; - reshape(shapes); -} - -void ov::Model::reshape(const std::map& partial_shapes) { - reshape(port_shapes_to_node_shapes(this, partial_shapes), default_variable_map()); -} - -void ov::Model::reshape(const std::map& partial_shapes) { - reshape(tensor_names_shapes_to_node_shapes(this, partial_shapes), default_variable_map()); -} - -void ov::Model::reshape(const std::map, ov::PartialShape>& partial_shapes) { - reshape(partial_shapes, default_variable_map()); -} - void ov::Model::reshape(const ov::PartialShape& partial_shape, const std::unordered_map& variable_shapes) { OPENVINO_ASSERT(m_parameters.size() == 1, "must be called on a Model with exactly one parameter."); @@ -816,7 +791,7 @@ void ov::Model::reshape(const std::map& partial_shapes void ov::Model::reshape(const std::map& partial_shapes, const std::unordered_map& variable_shapes) { - reshape(tensor_names_shapes_to_node_shapes(this, partial_shapes), default_variable_map()); + reshape(tensor_names_shapes_to_node_shapes(this, partial_shapes), variable_shapes); } void ov::Model::reshape(const std::map, ov::PartialShape>& partial_shapes,