From e175933fd8be8836ef348e8eb861e1bf281f15ba Mon Sep 17 00:00:00 2001 From: evolosen Date: Fri, 23 Jul 2021 13:32:19 +0300 Subject: [PATCH 01/30] Add If implementation with reference --- ngraph/core/include/ngraph/op/if.hpp | 98 ++++++ ngraph/core/include/ngraph/ops.hpp | 1 + .../core/include/ngraph/opsets/opset8_tbl.hpp | 3 +- .../include/ngraph/runtime/reference/if.hpp | 24 ++ .../reference/src/runtime/reference/if.cpp | 50 +++ ngraph/core/src/op/if.cpp | 323 ++++++++++++++++++ ngraph/test/op_eval/if_eval.cpp | 195 +++++++++++ ngraph/test/type_prop/if.cpp | 124 +++++++ 8 files changed, 817 insertions(+), 1 deletion(-) create mode 100644 ngraph/core/include/ngraph/op/if.hpp create mode 100644 ngraph/core/reference/include/ngraph/runtime/reference/if.hpp create mode 100644 ngraph/core/reference/src/runtime/reference/if.cpp create mode 100644 ngraph/core/src/op/if.cpp create mode 100644 ngraph/test/op_eval/if_eval.cpp create mode 100644 ngraph/test/type_prop/if.cpp diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp new file mode 100644 index 00000000000000..fd7980c1dd489a --- /dev/null +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -0,0 +1,98 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +#include "ngraph/function.hpp" +#include "ngraph/op/parameter.hpp" +#include "ngraph/op/util/multi_subgraph_base.hpp" + +namespace ngraph +{ + namespace op + { + namespace v8 + { + /// \brief If operation. + class NGRAPH_API If : public util::MultiSubGraphOp + { + public: + enum BodyIndexes + { + then_body_index = 0, + else_body_index = 1 + }; + + NGRAPH_RTTI_DECLARATION; + bool visit_attributes(AttributeVisitor& visitor) override; + + /// \brief Constructs If with condition + /// + /// \param execution_condition condition node. + If(const Output& execution_condition); + If(); + explicit If(const OutputVector& values); + + std::shared_ptr + clone_with_new_inputs(const OutputVector& new_args) const override; + + /// \return then_body as ngraph::Function. + std::shared_ptr get_then_body() const + { + return m_bodies[then_body_index]; + } + /// \return else_body as ngraph::Function. + std::shared_ptr get_else_body() const + { + return m_bodies[else_body_index]; + } + /// \brief sets new ngraph::Function as new then_body. + /// + /// \param body new body for 'then' branch. + void set_then_body(const std::shared_ptr& body) + { + m_bodies[then_body_index] = body; + } + /// \brief sets new ngraph::Function as new else_body. + /// + /// \param body new body for 'else' branch. + void set_else_body(const std::shared_ptr& body) + { + m_bodies[else_body_index] = body; + } + /// \brief sets new input to the operation associated with parameters + /// of each sub-graphs + /// + /// \param value input to operation + /// \param then_parameter parameter for then_body + /// \param else_parameter parameter for else_body + void set_input(const Output& value, + const std::shared_ptr then_parameter, + const std::shared_ptr else_parameter); + /// \brief sets new output from the operation associated with results + /// of each sub-graphs + /// + /// \param then_result result from then_body + /// \param else_parameter pesult from else_body + /// \return output from operation + Output set_output(const std::shared_ptr then_result, + const std::shared_ptr else_result); + + void validate_and_infer_types() override; + bool evaluate(const HostTensorVector& outputs, + const HostTensorVector& inputs) const override; + + private: + void validate_and_infer_type_body( + std::shared_ptr body, + ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors); + void fill_body(std::shared_ptr new_op, + size_t branch_index, + const OutputVector& new_args) const; + }; + } // namespace v8 + } // namespace op +} // namespace ngraph \ No newline at end of file diff --git a/ngraph/core/include/ngraph/ops.hpp b/ngraph/core/include/ngraph/ops.hpp index 4701a2f733fa49..5f6ba251e7aa56 100644 --- a/ngraph/core/include/ngraph/ops.hpp +++ b/ngraph/core/include/ngraph/ops.hpp @@ -167,3 +167,4 @@ #include "ngraph/op/util/op_types.hpp" #include "ngraph/op/variadic_split.hpp" #include "ngraph/op/xor.hpp" +#include "ngraph/op/if.hpp" diff --git a/ngraph/core/include/ngraph/opsets/opset8_tbl.hpp b/ngraph/core/include/ngraph/opsets/opset8_tbl.hpp index 0004161dc48dd5..3d90560d899aa5 100644 --- a/ngraph/core/include/ngraph/opsets/opset8_tbl.hpp +++ b/ngraph/core/include/ngraph/opsets/opset8_tbl.hpp @@ -180,4 +180,5 @@ NGRAPH_OP(AdaptiveAvgPool, ngraph::op::v8) NGRAPH_OP(AdaptiveMaxPool, ngraph::op::v8) NGRAPH_OP(DeformableConvolution, ngraph::op::v8) NGRAPH_OP(MatrixNms, ngraph::op::v8) -NGRAPH_OP(MulticlassNms, ngraph::op::v8) \ No newline at end of file +NGRAPH_OP(MulticlassNms, ngraph::op::v8) +NGRAPH_OP(If, ngraph::op::v8) \ No newline at end of file diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp new file mode 100644 index 00000000000000..58fd97ae3961ae --- /dev/null +++ b/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp @@ -0,0 +1,24 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +namespace ngraph +{ + namespace runtime + { + namespace reference + { + void if_reference( + const std::vector>& body, + const std::vector& out_descs, + const std::vector& input_descs, + const HostTensorVector& out, + const HostTensorVector& args); + } + } // namespace runtime +} // namespace ngraph \ No newline at end of file diff --git a/ngraph/core/reference/src/runtime/reference/if.cpp b/ngraph/core/reference/src/runtime/reference/if.cpp new file mode 100644 index 00000000000000..6947c5d81c11ec --- /dev/null +++ b/ngraph/core/reference/src/runtime/reference/if.cpp @@ -0,0 +1,50 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ngraph/runtime/reference/if.hpp" +#include "ngraph/runtime/reference/concat.hpp" +#include "ngraph/runtime/reference/function.hpp" +#include "ngraph/runtime/reference/split.hpp" +namespace ngraph +{ + namespace runtime + { + namespace reference + { + using namespace op::v8; + enum if_body_indexes + { + then_body_index = 0, + else_body_index = 1 + }; + void if_reference( + const std::vector>& bodies, + const std::vector& out_descs, + const std::vector& input_descs, + const HostTensorVector& out, + const HostTensorVector& args) + { + auto condition_value = args[0]->get_data_ptr()[0]; + auto branch_index = (condition_value) ? if_body_indexes::then_body_index + : if_body_indexes::else_body_index; + HostTensorVector inputs_to_body; + HostTensorVector outs_from_body; + // TODO: need find num of inputs in bode and reserve inputs_to_body + inputs_to_body.resize(input_descs[branch_index].size()); + for (auto input_desc : input_descs[branch_index]) + { + inputs_to_body[input_desc->m_body_parameter_index] = + args[input_desc->m_input_index]; + } + reference::function(bodies[branch_index], inputs_to_body, outs_from_body); + for (auto out_descr : out_descs[branch_index]) + { + auto res = outs_from_body[out_descr->m_body_value_index]; + out[out_descr->m_output_index]->write(res->get_data_ptr(), + res->get_size_in_bytes()); + } + } + } // namespace reference + } // namespace runtime +} // namespace ngraph \ No newline at end of file diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp new file mode 100644 index 00000000000000..6db84f86093c45 --- /dev/null +++ b/ngraph/core/src/op/if.cpp @@ -0,0 +1,323 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ngraph/op/if.hpp" +#include +#include +#include +#include "itt.hpp" +#include "ngraph/factory.hpp" +#include "ngraph/graph_util.hpp" +#include "ngraph/op/util/multi_subgraph_base.hpp" +#include "ngraph/specialize_function.hpp" + +#include "ngraph/runtime/reference/if.hpp" + +using namespace std; +using namespace ngraph; + +NGRAPH_RTTI_DEFINITION(ngraph::op::v8::If, "If", 8); + +op::v8::If::If() + : MultiSubGraphOp(2) +{ +} + +op::v8::If::If(const OutputVector& values) + : op::util::MultiSubGraphOp(values, 2) +{ +} + +op::v8::If::If(const Output& execution_condition) + : If() +{ + set_argument(0, execution_condition); +} + +ngraph::PartialShape resolve_shape(ngraph::PartialShape then_pshape, + ngraph::PartialShape else_pshape) +{ + auto then_rank = then_pshape.rank(); + auto else_rank = else_pshape.rank(); + if (then_rank.is_dynamic() || else_rank.is_dynamic() || + then_rank.get_length() != else_rank.get_length()) + { + return ngraph::PartialShape::dynamic(ngraph::Rank::dynamic()); + } + std::vector new_dims; + for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); + then_it != then_pshape.cend(); + then_it++, else_it++) + { + if ((*then_it).is_dynamic() || (*else_it).is_dynamic()) + { + new_dims.push_back(Dimension::dynamic()); + } + else if (*then_it == *else_it) + { + new_dims.push_back(Dimension(*then_it)); + } + else + { + auto dim_min = std::min((*then_it).get_min_length(), (*else_it).get_min_length()); + auto dim_max = std::max((*then_it).get_min_length(), (*else_it).get_min_length()); + new_dims.push_back(Dimension(dim_min, dim_max)); + } + } + + return PartialShape(new_dims); +} + +bool op::v8::If::visit_attributes(AttributeVisitor& visitor) +{ + NGRAPH_OP_SCOPE(v8_If_visit_attributes); + m_bodies[then_body_index] = + std::make_shared(OutputVector{}, ParameterVector{}, "then_branch"); + m_bodies[else_body_index] = + std::make_shared(OutputVector{}, ParameterVector{}, "else_branch"); + visitor.on_attribute("then_body", m_bodies[then_body_index]); + visitor.on_attribute("else_body", m_bodies[else_body_index]); + visitor.on_attribute("then_inputs", m_input_descriptions[then_body_index]); + visitor.on_attribute("else_inputs", m_input_descriptions[else_body_index]); + visitor.on_attribute("then_outputs", m_output_descriptions[then_body_index]); + visitor.on_attribute("else_outputs", m_output_descriptions[else_body_index]); + return true; +} + +void op::v8::If::validate_and_infer_type_body( + std::shared_ptr body, + ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors) +{ + auto layer_id_map = std::map>(); + for (auto param : body->get_parameters()) + { + layer_id_map.insert({param->get_instance_id(), param}); + } + for (const auto& input_description : input_descriptors) + { + auto index = input_description->m_input_index; + + auto body_parameter = body->get_parameters().at(input_description->m_body_parameter_index); + auto input_partial_shape = inputs().at(index).get_source_output().get_partial_shape(); + if (input_partial_shape.is_static()) + { + auto input_shape = input_partial_shape.to_shape(); + Shape out_shape{input_shape}; + body_parameter->set_partial_shape(out_shape); + } + else + { + body_parameter->set_partial_shape(input_partial_shape); + } + } + body->validate_nodes_and_infer_types(); +} +void op::v8::If::validate_and_infer_types() +{ + NGRAPH_OP_SCOPE(v8_If_validate_and_infer_types); + auto cond_output = inputs().at(0).get_source_output(); + + auto cond_partial_shape = cond_output.get_partial_shape(); + auto cond_rank = cond_partial_shape.rank(); + if (cond_rank.is_static()) + { + NODE_VALIDATION_CHECK(this, cond_rank.get_length() < 2, "Incorrect condition"); + } + if (cond_partial_shape.is_static()) + { + auto cond_shape = cond_partial_shape.to_shape(); + if (cond_rank.get_length() == 1) + { + NODE_VALIDATION_CHECK(this, cond_shape.at(0) == 1, "Incorrect shape of condition"); + } + } + // Trying to get cond as const value + if (const auto& cond_value = get_constant_from_source(cond_output)) + { + auto val = cond_value->cast_vector(); + auto cond_index = val[0] ? then_body_index : else_body_index; + auto body = m_bodies[cond_index]; + auto input_descriptors = m_input_descriptions[cond_index]; + validate_and_infer_type_body(body, input_descriptors); + auto output_nodes = outputs(); + for (auto output_descr : m_output_descriptions[cond_index]) + { + auto body_value = + body->get_results().at(output_descr->m_body_value_index)->input_value(0); + auto body_value_partial_shape = body_value.get_partial_shape(); + set_output_type(output_descr->m_body_value_index, + body_value.get_element_type(), + PartialShape::dynamic()); + if (body_value_partial_shape.is_static()) + { + auto body_value_shape = body_value_partial_shape.to_shape(); + Shape out_shape{body_value_shape}; + + if (body_value_shape.empty()) + { + out_shape = Shape(1); + } + + set_output_type( + output_descr->m_output_index, body_value.get_element_type(), out_shape); + } + else + { + set_output_type(output_descr->m_output_index, + body_value.get_element_type(), + PartialShape::dynamic(body_value.get_partial_shape().rank())); + } + } + } + else // condition is non constant + { + validate_and_infer_type_body(get_then_body(), m_input_descriptions[then_body_index]); + validate_and_infer_type_body(get_else_body(), m_input_descriptions[else_body_index]); + + std::set then_output_indexes{}; + std::set else_output_indexes{}; + auto output_nodes = outputs(); + for (auto then_output_description : m_output_descriptions[then_body_index]) + { + auto out_index = then_output_description->m_output_index; + auto cond = [=](Output& node) { return node.get_index() == out_index; }; + auto it = std::find_if(output_nodes.begin(), output_nodes.end(), cond); + NGRAPH_CHECK(it != output_nodes.end(), + "Incorrect output with index %i i n \'then_body\'", + out_index); + then_output_indexes.insert(then_output_description->m_output_index); + } + + NGRAPH_CHECK( + then_output_indexes.size() == output_nodes.size(), + "Incorect then_body! Number of then_body outputs must be same as number If outputs"); + + for (auto else_output_description : m_output_descriptions[else_body_index]) + { + auto out_index = else_output_description->m_output_index; + + NGRAPH_CHECK(then_output_indexes.find(out_index) != then_output_indexes.end(), + "Incorrect output with index %i in \'else_body\'", + out_index); + else_output_indexes.insert(else_output_description->m_output_index); + } + + NGRAPH_CHECK( + else_output_indexes.size() == else_output_indexes.size(), + "Incorect else_body! Number of then_body outputs must be same as number If outputs"); + + for (auto output_index : then_output_indexes) + { + auto description_find_lambda = [=](MultiSubgraphOutputDescriptionPtr& descr) { + return descr->m_output_index == static_cast(output_index); + }; + + auto then_output_description = *find_if(m_output_descriptions[then_body_index].begin(), + m_output_descriptions[then_body_index].end(), + description_find_lambda); + auto else_output_description = *find_if(m_output_descriptions[else_body_index].begin(), + m_output_descriptions[else_body_index].end(), + description_find_lambda); + auto then_out_node = m_bodies[then_body_index] + ->get_results() + .at(then_output_description->m_body_value_index) + ->input_value(0); + auto else_out_node = m_bodies[else_body_index] + ->get_results() + .at(else_output_description->m_body_value_index) + ->input_value(0); + // TODO: check_types + auto then_node_partial_shape = then_out_node.get_partial_shape(); + auto else_node_partial_shape = else_out_node.get_partial_shape(); + auto partial_shape = resolve_shape(then_node_partial_shape, else_node_partial_shape); + set_output_type(output_index, then_out_node.get_element_type(), partial_shape); + } + } +} + +void op::v8::If::fill_body(std::shared_ptr new_op, + size_t branch_index, + const OutputVector& new_args) const +{ + auto body = m_bodies[branch_index]; + auto param_size = body->get_parameters().size(); + std::vector<::ngraph::element::Type> types(param_size); + std::vector<::ngraph::PartialShape> new_shapes(param_size); + auto& input_descriptions = m_input_descriptions[branch_index]; + size_t parameters_num = 0; + for (auto& input_description : input_descriptions) + { + if (input_description->m_input_index < new_args.size()) + { + types[input_description->m_body_parameter_index] = + new_args[input_description->m_input_index].get_element_type(); + new_shapes[input_description->m_body_parameter_index] = + new_args[input_description->m_input_index].get_partial_shape(); + parameters_num++; + } + } + auto func = + std::make_shared(body->get_results(), body->get_sinks(), body->get_parameters()); + auto spec_func = + specialize_function(func, types, new_shapes, std::vector(parameters_num, nullptr)); + new_op->m_bodies[branch_index] = std::make_shared( + spec_func->get_results(), spec_func->get_sinks(), spec_func->get_parameters()); + + for (auto& input_description : input_descriptions) + { + new_op->m_input_descriptions[branch_index].push_back(input_description->copy()); + } + for (auto& output_description : m_output_descriptions[branch_index]) + { + new_op->m_output_descriptions[branch_index].push_back(output_description->copy()); + } +} + +std::shared_ptr op::v8::If::clone_with_new_inputs(const OutputVector& new_args) const +{ + NGRAPH_OP_SCOPE(v8_If_clone_with_new_inputs); + auto op = make_shared(new_args); + NGRAPH_CHECK(op.get(), + op != nullptr, + "Cannot clone ", + description(), + " operation with name ", + get_friendly_name()); + + // TODO: check size of output + op->set_output_size(m_output_descriptions[0].size()); + fill_body(op, then_body_index, new_args); + fill_body(op, else_body_index, new_args); + op->validate_and_infer_types(); + return op; +} + +bool op::v8::If::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const +{ + NGRAPH_OP_SCOPE(v8_If_evaluate); + runtime::reference::if_reference( + m_bodies, m_output_descriptions, m_input_descriptions, outputs, inputs); + return true; +} + +void op::v8::If::set_input(const Output& value, + const std::shared_ptr then_parameter, + const std::shared_ptr else_parameter) +{ + ParameterVector param_vec; + if (then_parameter != nullptr) { + param_vec.push_back(then_parameter); + } + if (else_parameter != nullptr) + { + param_vec.push_back(else_parameter); + } + set_invariant_inputs(value, param_vec); +} + +Output op::v8::If::set_output(const std::shared_ptr then_result, + const std::shared_ptr else_result) +{ + return set_body_outputs({then_result, else_result}); +} \ No newline at end of file diff --git a/ngraph/test/op_eval/if_eval.cpp b/ngraph/test/op_eval/if_eval.cpp new file mode 100644 index 00000000000000..df40388e9a6c58 --- /dev/null +++ b/ngraph/test/op_eval/if_eval.cpp @@ -0,0 +1,195 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include + +#include "gtest/gtest.h" + +#include +#include "ngraph/opsets/opset1.hpp" +#include "ngraph/opsets/opset5.hpp" +#include "ngraph/opsets/opset8.hpp" +#include "ngraph/runtime/host_tensor.hpp" +#include "ngraph/validation_util.hpp" +#include "runtime/backend.hpp" +#include "util/test_tools.hpp" + +using namespace std; +using namespace ngraph; + + +TEST(op_eval, if_condition_const) +{ + auto X = make_shared(element::f32, Shape{1, 2, 2}); + auto Y = make_shared(element::f32, Shape{1, 2, 2}); + auto cond = std::make_shared(element::boolean, Shape{1}, true); + auto cond2 = std::make_shared(element::boolean, Shape{1}, false); + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + auto then_op = std::make_shared(Xt, Yt); + auto res0 = make_shared(then_op); + auto res1 = make_shared(Xe); + auto then_body = make_shared(OutputVector{res0}, ParameterVector{Xt, Yt}); + auto else_body = make_shared(OutputVector{res1}, ParameterVector{Xe}); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, nullptr); + if_op->set_output(res0, res1); + if_op->validate_and_infer_types(); + auto if_op2 = if_op->clone_with_new_inputs(OutputVector{cond2, X, Y}); + std::vector X_v{1.0, 1.0, 1.0, 1.0}; + std::vector Y_v{2.0, 2.0, 2.0, 2.0}; + auto fun = make_shared(OutputVector{if_op}, ParameterVector{X, Y}); + auto fun2 = make_shared(OutputVector{if_op2}, ParameterVector{X, Y}); + auto result = make_shared(); + ASSERT_TRUE(fun->evaluate({result}, + {make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{1, 2, 2}, Y_v)})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); + auto result_data = read_vector(result); + std::vector expected_results{2.0, 2.0, 2.0, 2.0}; + for (auto i = 0; i < expected_results.size(); i++) + EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); + + auto result1 = make_shared(); + ASSERT_TRUE(fun2->evaluate({result1}, + {make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{1, 2, 2}, Y_v)})); + EXPECT_EQ(result1->get_element_type(), element::f32); + EXPECT_EQ(result1->get_shape(), Shape{std::vector({1, 2, 2})}); + auto result_data1 = read_vector(result1); + for (auto i = 0; i < expected_results.size(); i++) + EXPECT_NEAR(result_data1[i], X_v[i], 0.000001); +} + +TEST(op_eval, if_condition_non_const) +{ + auto X = make_shared(element::f32, Shape{1, 2, 2}); + auto Y = make_shared(element::f32, Shape{1, 2, 2}); + auto cond = make_shared(element::boolean, Shape{1}); + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto else_op = std::make_shared(Xe, Ye); + auto then_op_result = make_shared(then_op); + auto else_op_result = make_shared(else_op); + auto then_body = + make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = + make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + if_op->set_output(then_op_result, else_op_result); + if_op->validate_and_infer_types(); + std::vector X_v{1.0, 2.0, 3.0, 4.0}; + std::vector Y_v{2.0, 1.0, 2.0, 3.0}; + auto fun = make_shared(OutputVector{if_op}, ParameterVector{cond, X, Y}); + auto result = make_shared(); + ASSERT_TRUE(fun->evaluate({result}, + {make_host_tensor(Shape{1}, {true}), + make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{1, 2, 2}, Y_v)})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); + auto result_data = read_vector(result); + std::vector expected_results{2.0, 2.0, 6.0, 12.0}; + for (auto i = 0; i < expected_results.size(); i++) + EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); + ASSERT_TRUE(fun->evaluate({result}, + {make_host_tensor(Shape{1}, {false}), + make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{1, 2, 2}, Y_v)})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); + result_data = read_vector(result); + expected_results = {3.0, 3.0, 5.0, 7.0}; + + for (auto i = 0; i < expected_results.size(); i++) + EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); +} + +TEST(op_eval, if_free_sample) +{ + auto cond = make_shared(element::boolean, Shape{1}); + auto A = std::make_shared(element::f32, Shape{1}, 8.0); + auto B = std::make_shared(element::f32, Shape{1}, 2.0); + auto A_res = std::make_shared(A); + auto B_res = std::make_shared(B); + auto then_body = make_shared(OutputVector{A_res}, ParameterVector{}); + auto else_body = make_shared(OutputVector{B_res}, ParameterVector{}); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + auto res = if_op->set_output(A_res, B_res); + auto fun = make_shared(OutputVector{res}, ParameterVector{cond}); + fun->validate_nodes_and_infer_types(); + auto result1 = make_shared(), result2 = make_shared(); + ASSERT_TRUE( + fun->evaluate({result1}, {make_host_tensor(Shape{1}, {true})})); + ASSERT_TRUE( + fun->evaluate({result2}, {make_host_tensor(Shape{1}, {false})})); + auto result_data1 = read_vector(result1); + auto result_data2 = read_vector(result2); + EXPECT_EQ(result1->get_element_type(), element::f32); + EXPECT_EQ(result1->get_shape(), Shape{std::vector({1})}); + EXPECT_EQ(result2->get_element_type(), element::f32); + EXPECT_EQ(result2->get_shape(), Shape{std::vector({1})}); + EXPECT_NEAR(result_data1[0], 8.0, 0.000001); + EXPECT_NEAR(result_data2[0], 2.0, 0.000001); +} + +TEST(op_eval, if_constant_folding) +{ + auto cond = std::make_shared(element::boolean, Shape{1}, false); + auto A1 = std::make_shared(element::f32, Shape{1}, 37.0); + auto A2 = std::make_shared(element::f32, Shape{1}, 45.0); + auto B1 = std::make_shared(element::f32, Shape{1}, 10.0); + auto B2 = std::make_shared(element::f32, Shape{1}, 3.0); + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + auto a_add = std::make_shared(Xt, Yt); + auto b_pow = std::make_shared(Xe, Ye); + auto then_res = std::make_shared(a_add); + auto then_body = make_shared(OutputVector{then_res}, ParameterVector{Xt, Yt}); + auto else_res = std::make_shared(b_pow); + auto else_body = make_shared(OutputVector{else_res}, ParameterVector{Xe, Ye}); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(A1, Xt, nullptr); + if_op->set_input(A2, Yt, nullptr); + if_op->set_input(B1, nullptr, Xe); + if_op->set_input(B2, nullptr, Ye); + if_op->set_output(then_res, else_res); + + auto fun = make_shared(OutputVector{if_op}, ParameterVector{}); + fun->validate_nodes_and_infer_types(); + ngraph::pass::ConstantFolding().run_on_function(fun); + auto results = fun->get_results(); + EXPECT_EQ(results.size(), 1); + auto result = results[0]; + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), Shape{1}); + const auto& cond_value = get_constant_from_source(result); + auto val = cond_value->cast_vector(); + EXPECT_NEAR(val[0], 1000.0, 0.000001); +} + +// TO DO: Add test for dynamic cases diff --git a/ngraph/test/type_prop/if.cpp b/ngraph/test/type_prop/if.cpp new file mode 100644 index 00000000000000..a06e1e9c4cd24e --- /dev/null +++ b/ngraph/test/type_prop/if.cpp @@ -0,0 +1,124 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "gtest/gtest.h" +#include "ngraph/builder/reshape.hpp" +#include "ngraph/ngraph.hpp" +#include "ngraph/opsets/opset5.hpp" +#include "util/type_prop.hpp" + +using namespace std; +using namespace ngraph; + +TEST(type_prop, if_simple_test) +{ + // That which we iterate over + auto X = make_shared(element::f32, Shape{32, 40, 10}); + auto Y = make_shared(element::f32, Shape{32, 40, 10}); + auto cond = std::make_shared( + ngraph::element::boolean, ngraph::Shape{1}, true); + + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto then_op_res = std::make_shared(then_op); + + auto then_body = + make_shared(OutputVector{then_op_res}, ParameterVector{Xt, Yt}); + + auto else_op = std::make_shared(Xe, Ye); + auto else_op_res = std::make_shared(else_op); + auto else_body = + make_shared(OutputVector{else_op_res}, ParameterVector{Xe, Ye}); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto res = if_op->set_output(then_op_res, else_op_res); + if_op->validate_and_infer_types(); + + auto result0 = make_shared(res); + Shape out0_shape{32, 40, 10}; + auto sh = result0->get_output_shape(0); + EXPECT_EQ(sh, out0_shape); +} + +TEST(type_prop, if_non_const_condition_test) +{ + // That which we iterate over + auto X = make_shared(element::f32, Shape{32, 40, 10}); + auto Y = make_shared(element::f32, Shape{32, 40, 10}); + auto cond = make_shared(element::boolean, Shape{1}); + + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto then_body_res = make_shared(then_op); + auto then_body = + make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); + + auto else_op = std::make_shared(Xe, Ye); + auto else_body_res = make_shared(else_op); + auto else_body = + make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); + + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto res = if_op->set_output(then_body_res, else_body_res); + if_op->validate_and_infer_types(); + auto result0 = make_shared(res); + Shape out0_shape{32, 40, 10}; + auto sh = result0->get_output_shape(0); + EXPECT_EQ(sh, out0_shape); +} + +TEST(type_prop, if_clone_test) +{ + auto X = make_shared(element::f32, Shape{32, 40, 10}); + auto Y = make_shared(element::f32, Shape{32, 40, 10}); + auto cond = make_shared(element::boolean, Shape{1}); + + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + auto Xnew = make_shared(element::f32, PartialShape::dynamic()); + auto Ynew = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto then_body_res = make_shared(then_op); + auto then_body = + make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); + auto else_op = std::make_shared(Xe, Ye); + auto else_body_res = make_shared(else_op); + auto else_body = + make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); + + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto res = if_op->set_output(then_body_res, else_body_res); + + auto new_if = std::dynamic_pointer_cast( + if_op->clone_with_new_inputs(OutputVector{cond, Xnew, Ynew})); + EXPECT_EQ(true, true); +} \ No newline at end of file From 5dd4ef408624210f6806f7d497dc6444316105e3 Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 28 Jul 2021 12:49:53 +0300 Subject: [PATCH 02/30] fix test --- ngraph/core/include/ngraph/op/if.hpp | 14 +- .../reference/src/runtime/reference/if.cpp | 8 +- ngraph/core/src/op/if.cpp | 89 ++++------- ngraph/test/op_eval/if_eval.cpp | 145 +++++++++++++++++- ngraph/test/type_prop/if.cpp | 84 +++++++++- 5 files changed, 265 insertions(+), 75 deletions(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index fd7980c1dd489a..d0ecc0278eb25e 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -70,16 +70,16 @@ namespace ngraph /// \param then_parameter parameter for then_body /// \param else_parameter parameter for else_body void set_input(const Output& value, - const std::shared_ptr then_parameter, - const std::shared_ptr else_parameter); + const std::shared_ptr& then_parameter, + const std::shared_ptr& else_parameter); /// \brief sets new output from the operation associated with results /// of each sub-graphs /// /// \param then_result result from then_body /// \param else_parameter pesult from else_body /// \return output from operation - Output set_output(const std::shared_ptr then_result, - const std::shared_ptr else_result); + Output set_output(const std::shared_ptr& then_result, + const std::shared_ptr& else_result); void validate_and_infer_types() override; bool evaluate(const HostTensorVector& outputs, @@ -87,9 +87,9 @@ namespace ngraph private: void validate_and_infer_type_body( - std::shared_ptr body, - ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors); - void fill_body(std::shared_ptr new_op, + const std::shared_ptr& body, + const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors); + void fill_body(const std::shared_ptr& new_op, size_t branch_index, const OutputVector& new_args) const; }; diff --git a/ngraph/core/reference/src/runtime/reference/if.cpp b/ngraph/core/reference/src/runtime/reference/if.cpp index 6947c5d81c11ec..92e741446bff50 100644 --- a/ngraph/core/reference/src/runtime/reference/if.cpp +++ b/ngraph/core/reference/src/runtime/reference/if.cpp @@ -3,9 +3,7 @@ // #include "ngraph/runtime/reference/if.hpp" -#include "ngraph/runtime/reference/concat.hpp" #include "ngraph/runtime/reference/function.hpp" -#include "ngraph/runtime/reference/split.hpp" namespace ngraph { namespace runtime @@ -30,17 +28,17 @@ namespace ngraph : if_body_indexes::else_body_index; HostTensorVector inputs_to_body; HostTensorVector outs_from_body; - // TODO: need find num of inputs in bode and reserve inputs_to_body inputs_to_body.resize(input_descs[branch_index].size()); - for (auto input_desc : input_descs[branch_index]) + for (const auto& input_desc : input_descs[branch_index]) { inputs_to_body[input_desc->m_body_parameter_index] = args[input_desc->m_input_index]; } reference::function(bodies[branch_index], inputs_to_body, outs_from_body); - for (auto out_descr : out_descs[branch_index]) + for (const auto& out_descr : out_descs[branch_index]) { auto res = outs_from_body[out_descr->m_body_value_index]; + out[out_descr->m_output_index]->set_shape(res->get_shape()); out[out_descr->m_output_index]->write(res->get_data_ptr(), res->get_size_in_bytes()); } diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 6db84f86093c45..74c5f3d69afa0a 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -35,8 +35,8 @@ op::v8::If::If(const Output& execution_condition) set_argument(0, execution_condition); } -ngraph::PartialShape resolve_shape(ngraph::PartialShape then_pshape, - ngraph::PartialShape else_pshape) +ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, + const ngraph::PartialShape& else_pshape) { auto then_rank = then_pshape.rank(); auto else_rank = else_pshape.rank(); @@ -86,30 +86,16 @@ bool op::v8::If::visit_attributes(AttributeVisitor& visitor) } void op::v8::If::validate_and_infer_type_body( - std::shared_ptr body, - ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors) + const std::shared_ptr& body, + const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors) { - auto layer_id_map = std::map>(); - for (auto param : body->get_parameters()) - { - layer_id_map.insert({param->get_instance_id(), param}); - } for (const auto& input_description : input_descriptors) { auto index = input_description->m_input_index; auto body_parameter = body->get_parameters().at(input_description->m_body_parameter_index); auto input_partial_shape = inputs().at(index).get_source_output().get_partial_shape(); - if (input_partial_shape.is_static()) - { - auto input_shape = input_partial_shape.to_shape(); - Shape out_shape{input_shape}; - body_parameter->set_partial_shape(out_shape); - } - else - { - body_parameter->set_partial_shape(input_partial_shape); - } + body_parameter->set_partial_shape(input_partial_shape); } body->validate_nodes_and_infer_types(); } @@ -141,33 +127,14 @@ void op::v8::If::validate_and_infer_types() auto input_descriptors = m_input_descriptions[cond_index]; validate_and_infer_type_body(body, input_descriptors); auto output_nodes = outputs(); - for (auto output_descr : m_output_descriptions[cond_index]) + for (const auto& output_descr : m_output_descriptions[cond_index]) { auto body_value = body->get_results().at(output_descr->m_body_value_index)->input_value(0); auto body_value_partial_shape = body_value.get_partial_shape(); - set_output_type(output_descr->m_body_value_index, + set_output_type(output_descr->m_output_index, body_value.get_element_type(), - PartialShape::dynamic()); - if (body_value_partial_shape.is_static()) - { - auto body_value_shape = body_value_partial_shape.to_shape(); - Shape out_shape{body_value_shape}; - - if (body_value_shape.empty()) - { - out_shape = Shape(1); - } - - set_output_type( - output_descr->m_output_index, body_value.get_element_type(), out_shape); - } - else - { - set_output_type(output_descr->m_output_index, - body_value.get_element_type(), - PartialShape::dynamic(body_value.get_partial_shape().rank())); - } + body_value_partial_shape); } } else // condition is non constant @@ -178,13 +145,13 @@ void op::v8::If::validate_and_infer_types() std::set then_output_indexes{}; std::set else_output_indexes{}; auto output_nodes = outputs(); - for (auto then_output_description : m_output_descriptions[then_body_index]) + for (const auto& then_output_description : m_output_descriptions[then_body_index]) { auto out_index = then_output_description->m_output_index; auto cond = [=](Output& node) { return node.get_index() == out_index; }; auto it = std::find_if(output_nodes.begin(), output_nodes.end(), cond); NGRAPH_CHECK(it != output_nodes.end(), - "Incorrect output with index %i i n \'then_body\'", + "Incorrect output with index %i in \'then_body\'", out_index); then_output_indexes.insert(then_output_description->m_output_index); } @@ -193,21 +160,22 @@ void op::v8::If::validate_and_infer_types() then_output_indexes.size() == output_nodes.size(), "Incorect then_body! Number of then_body outputs must be same as number If outputs"); - for (auto else_output_description : m_output_descriptions[else_body_index]) + for (const auto& else_output_description : m_output_descriptions[else_body_index]) { auto out_index = else_output_description->m_output_index; - - NGRAPH_CHECK(then_output_indexes.find(out_index) != then_output_indexes.end(), + auto cond = [=](Output& node) { return node.get_index() == out_index; }; + auto it = std::find_if(output_nodes.begin(), output_nodes.end(), cond); + NGRAPH_CHECK(it != output_nodes.end(), "Incorrect output with index %i in \'else_body\'", out_index); else_output_indexes.insert(else_output_description->m_output_index); } NGRAPH_CHECK( - else_output_indexes.size() == else_output_indexes.size(), - "Incorect else_body! Number of then_body outputs must be same as number If outputs"); + else_output_indexes.size() == output_nodes.size(), + "Incorect else_body! Number of else_body outputs must be same as number If outputs"); - for (auto output_index : then_output_indexes) + for (const auto& output_index : then_output_indexes) { auto description_find_lambda = [=](MultiSubgraphOutputDescriptionPtr& descr) { return descr->m_output_index == static_cast(output_index); @@ -227,16 +195,18 @@ void op::v8::If::validate_and_infer_types() ->get_results() .at(else_output_description->m_body_value_index) ->input_value(0); - // TODO: check_types auto then_node_partial_shape = then_out_node.get_partial_shape(); auto else_node_partial_shape = else_out_node.get_partial_shape(); + NGRAPH_CHECK(then_out_node.get_element_type() == else_out_node.get_element_type(), + "type of then_body output is not equal type of else_body output"); + auto partial_shape = resolve_shape(then_node_partial_shape, else_node_partial_shape); set_output_type(output_index, then_out_node.get_element_type(), partial_shape); } } } -void op::v8::If::fill_body(std::shared_ptr new_op, +void op::v8::If::fill_body(const std::shared_ptr& new_op, size_t branch_index, const OutputVector& new_args) const { @@ -264,11 +234,11 @@ void op::v8::If::fill_body(std::shared_ptr new_op, new_op->m_bodies[branch_index] = std::make_shared( spec_func->get_results(), spec_func->get_sinks(), spec_func->get_parameters()); - for (auto& input_description : input_descriptions) + for (const auto& input_description : input_descriptions) { new_op->m_input_descriptions[branch_index].push_back(input_description->copy()); } - for (auto& output_description : m_output_descriptions[branch_index]) + for (const auto& output_description : m_output_descriptions[branch_index]) { new_op->m_output_descriptions[branch_index].push_back(output_description->copy()); } @@ -284,8 +254,6 @@ std::shared_ptr op::v8::If::clone_with_new_inputs(const OutputVector& new_ description(), " operation with name ", get_friendly_name()); - - // TODO: check size of output op->set_output_size(m_output_descriptions[0].size()); fill_body(op, then_body_index, new_args); fill_body(op, else_body_index, new_args); @@ -302,11 +270,12 @@ bool op::v8::If::evaluate(const HostTensorVector& outputs, const HostTensorVecto } void op::v8::If::set_input(const Output& value, - const std::shared_ptr then_parameter, - const std::shared_ptr else_parameter) + const std::shared_ptr& then_parameter, + const std::shared_ptr& else_parameter) { ParameterVector param_vec; - if (then_parameter != nullptr) { + if (then_parameter != nullptr) + { param_vec.push_back(then_parameter); } if (else_parameter != nullptr) @@ -316,8 +285,8 @@ void op::v8::If::set_input(const Output& value, set_invariant_inputs(value, param_vec); } -Output op::v8::If::set_output(const std::shared_ptr then_result, - const std::shared_ptr else_result) +Output op::v8::If::set_output(const std::shared_ptr& then_result, + const std::shared_ptr& else_result) { return set_body_outputs({then_result, else_result}); } \ No newline at end of file diff --git a/ngraph/test/op_eval/if_eval.cpp b/ngraph/test/op_eval/if_eval.cpp index df40388e9a6c58..1938d6d8f9ec50 100644 --- a/ngraph/test/op_eval/if_eval.cpp +++ b/ngraph/test/op_eval/if_eval.cpp @@ -19,7 +19,6 @@ using namespace std; using namespace ngraph; - TEST(op_eval, if_condition_const) { auto X = make_shared(element::f32, Shape{1, 2, 2}); @@ -192,4 +191,146 @@ TEST(op_eval, if_constant_folding) EXPECT_NEAR(val[0], 1000.0, 0.000001); } -// TO DO: Add test for dynamic cases +TEST(op_eval, if_dynamism) +{ + auto X = make_shared(element::f32, Shape{1, 2, 2}); + auto Y = make_shared(element::f32, Shape{4, 2, 2}); + auto Z = make_shared(element::f32, Shape{8, 8, 8}); + auto cond = make_shared(element::boolean, Shape{1}); + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ze = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Xt); + auto else_op = std::make_shared(Xe, Xe); + auto then_op_result1 = make_shared(then_op); + auto then_op_result2 = make_shared(Yt); + auto else_op_result1 = make_shared(else_op); + auto else_op_result2 = make_shared(Ze); + auto then_body = make_shared(OutputVector{then_op_result1, then_op_result2}, + ParameterVector{Xt, Yt}); + auto else_body = make_shared(OutputVector{else_op_result1, else_op_result2}, + ParameterVector{Xe, Ze}); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, nullptr); + if_op->set_input(Z, nullptr, Ze); + auto res1 = if_op->set_output(then_op_result1, else_op_result1); + auto res2 = if_op->set_output(then_op_result2, else_op_result2); + auto result_if1 = make_shared(res1); + auto result_if2 = make_shared(res2); + if_op->validate_and_infer_types(); + std::vector X_v{1.0, 2.0, 3.0, 4.0}; + std::vector Y_v, Z_v; + for (auto c_ind = 0; c_ind < 4; ++c_ind) + { + for (auto d_ind = 0; d_ind < 4; ++d_ind) + { + Y_v.push_back(static_cast(c_ind * d_ind)); + } + } + for (auto c_ind = 0; c_ind < 8; ++c_ind) + { + for (auto d_ind = 0; d_ind < 64; ++d_ind) + { + Z_v.push_back(static_cast(c_ind * d_ind)); + } + } + auto fun = + make_shared(OutputVector{result_if1, result_if2}, ParameterVector{cond, X, Y, Z}); + auto result1 = make_shared(); + auto result2 = make_shared(); + ASSERT_TRUE(fun->evaluate({result1, result2}, + {make_host_tensor(Shape{1}, {true}), + make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{4, 2, 2}, Y_v), + make_host_tensor(Shape{8, 8, 8}, Z_v)})); + EXPECT_EQ(result1->get_element_type(), element::f32); + EXPECT_EQ(result1->get_shape(), Shape{std::vector({1, 2, 2})}); + auto result1_data = read_vector(result1); + std::vector expected_results1{1.0, 4.0, 9.0, 16.0}; + for (auto i = 0; i < expected_results1.size(); i++) + EXPECT_NEAR(result1_data[i], expected_results1[i], 0.000001); + EXPECT_EQ(result2->get_element_type(), element::f32); + EXPECT_EQ(result2->get_shape(), Shape{std::vector({4, 2, 2})}); + auto result2_data = read_vector(result2); + for (auto i = 0; i < Y_v.size(); i++) + EXPECT_NEAR(result2_data[i], Y_v[i], 0.000001); + auto result3 = make_shared(); + auto result4 = make_shared(); + ASSERT_TRUE(fun->evaluate({result3, result4}, + {make_host_tensor(Shape{1}, {false}), + make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{4, 2, 2}, Y_v), + make_host_tensor(Shape{8, 8, 8}, Z_v)})); + EXPECT_EQ(result3->get_element_type(), element::f32); + EXPECT_EQ(result3->get_shape(), Shape{std::vector({1, 2, 2})}); + auto result3_data = read_vector(result3); + std::vector expected_results2{2.0, 4.0, 6.0, 8.0}; + for (auto i = 0; i < expected_results2.size(); i++) + EXPECT_NEAR(result3_data[i], expected_results2[i], 0.000001); + EXPECT_EQ(result4->get_element_type(), element::f32); + EXPECT_EQ(result4->get_shape(), Shape{std::vector({8, 8, 8})}); + auto result4_data = read_vector(result4); + for (auto i = 0; i < Z_v.size(); i++) + EXPECT_NEAR(result4_data[i], Z_v[i], 0.000001); +} + +TEST(op_eval, if_condition_non_const_scalar) +{ + auto X = make_shared(element::f32, Shape{1, 2, 2}); + auto Y = make_shared(element::f32, Shape{1, 2, 2}); + auto cond = make_shared(element::boolean, Shape{}); + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto else_op = std::make_shared(Xe, Ye); + auto then_op_result = make_shared(then_op); + auto else_op_result = make_shared(else_op); + auto then_body = + make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = + make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + if_op->set_output(then_op_result, else_op_result); + if_op->validate_and_infer_types(); + std::vector X_v{1.0, 2.0, 3.0, 4.0}; + std::vector Y_v{2.0, 1.0, 2.0, 3.0}; + auto fun = make_shared(OutputVector{if_op}, ParameterVector{cond, X, Y}); + auto result = make_shared(); + ASSERT_TRUE(fun->evaluate({result}, + {make_host_tensor(Shape{1}, {true}), + make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{1, 2, 2}, Y_v)})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); + auto result_data = read_vector(result); + std::vector expected_results{2.0, 2.0, 6.0, 12.0}; + for (auto i = 0; i < expected_results.size(); i++) + EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); + ASSERT_TRUE(fun->evaluate({result}, + {make_host_tensor(Shape{1}, {false}), + make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{1, 2, 2}, Y_v)})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); + result_data = read_vector(result); + expected_results = {3.0, 3.0, 5.0, 7.0}; + + for (auto i = 0; i < expected_results.size(); i++) + EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); +} \ No newline at end of file diff --git a/ngraph/test/type_prop/if.cpp b/ngraph/test/type_prop/if.cpp index a06e1e9c4cd24e..2dcf9b57145367 100644 --- a/ngraph/test/type_prop/if.cpp +++ b/ngraph/test/type_prop/if.cpp @@ -43,7 +43,7 @@ TEST(type_prop, if_simple_test) if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_op_res, else_op_res); if_op->validate_and_infer_types(); - + auto result0 = make_shared(res); Shape out0_shape{32, 40, 10}; auto sh = result0->get_output_shape(0); @@ -121,4 +121,86 @@ TEST(type_prop, if_clone_test) auto new_if = std::dynamic_pointer_cast( if_op->clone_with_new_inputs(OutputVector{cond, Xnew, Ynew})); EXPECT_EQ(true, true); +} + +TEST(type_prop, if_multiple_outputs) +{ + auto X = make_shared(element::f32, Shape{32, 40, 10}); + auto Y = make_shared(element::f32, Shape{32, 40, 10}); + auto cond = make_shared(element::boolean, Shape{1}); + + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + auto Xnew = make_shared(element::f32, PartialShape::dynamic()); + auto Ynew = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto then_body_res_1 = make_shared(then_op); + auto then_body_res_2 = make_shared(Xt); + auto then_body = make_shared(OutputVector{then_body_res_1, then_body_res_2}, + ParameterVector{Xt, Yt}); + auto else_op = std::make_shared(Xe, Ye); + auto else_const = std::make_shared( + ngraph::element::f32, ngraph::Shape{1, 1, 1}, std::vector{0.5f}); + auto else_body_res_1 = make_shared(else_op); + auto else_body_res_2 = make_shared(else_const); + auto else_body = make_shared(OutputVector{else_body_res_1, else_body_res_2}, + ParameterVector{Xe, Ye}); + + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto res1 = if_op->set_output(then_body_res_1, else_body_res_1); + auto res2 = if_op->set_output(then_body_res_2, else_body_res_2); + if_op->validate_and_infer_types(); + auto result1 = make_shared(res1); + auto result2 = make_shared(res2); + Shape out0_shape{32, 40, 10}; + auto sh = result1->get_output_shape(0); + auto is_dynamic = result2->is_dynamic(); + EXPECT_EQ(out0_shape, sh); + EXPECT_EQ(is_dynamic, true); +} + +TEST(type_prop, if_scalar_condition) +{ + // That which we iterate over + auto X = make_shared(element::f32, Shape{32, 40, 10}); + auto Y = make_shared(element::f32, Shape{32, 40, 10}); + auto cond = make_shared(element::boolean, Shape{}); + + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto then_body_res = make_shared(then_op); + auto then_body = + make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); + + auto else_op = std::make_shared(Xe, Ye); + auto else_body_res = make_shared(else_op); + auto else_body = + make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); + + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto res = if_op->set_output(then_body_res, else_body_res); + if_op->validate_and_infer_types(); + auto result0 = make_shared(res); + Shape out0_shape{32, 40, 10}; + auto sh = result0->get_output_shape(0); + EXPECT_EQ(sh, out0_shape); } \ No newline at end of file From 474935cd4cacb10c301abbb841ffa503e41c4ada Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 28 Jul 2021 13:10:26 +0300 Subject: [PATCH 03/30] fix comments --- ngraph/core/include/ngraph/op/if.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index d0ecc0278eb25e..e2c8fa0ce9bd9d 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -39,16 +39,22 @@ namespace ngraph std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; + /// \brief gets then_body as ngraph::Function. + /// /// \return then_body as ngraph::Function. std::shared_ptr get_then_body() const { return m_bodies[then_body_index]; } + + /// \brief gets else_body as ngraph::Function. + /// /// \return else_body as ngraph::Function. std::shared_ptr get_else_body() const { return m_bodies[else_body_index]; } + /// \brief sets new ngraph::Function as new then_body. /// /// \param body new body for 'then' branch. @@ -56,6 +62,7 @@ namespace ngraph { m_bodies[then_body_index] = body; } + /// \brief sets new ngraph::Function as new else_body. /// /// \param body new body for 'else' branch. @@ -63,6 +70,7 @@ namespace ngraph { m_bodies[else_body_index] = body; } + /// \brief sets new input to the operation associated with parameters /// of each sub-graphs /// @@ -72,6 +80,7 @@ namespace ngraph void set_input(const Output& value, const std::shared_ptr& then_parameter, const std::shared_ptr& else_parameter); + /// \brief sets new output from the operation associated with results /// of each sub-graphs /// From 0fb7096e47d748f16f4b37dd24110fa480b07e2a Mon Sep 17 00:00:00 2001 From: evolosen Date: Fri, 30 Jul 2021 14:59:26 +0300 Subject: [PATCH 04/30] Fix validate_and_INFER_TYPES --- ngraph/core/include/ngraph/op/if.hpp | 11 +- ngraph/core/src/op/if.cpp | 259 ++++++++++++++------------- 2 files changed, 138 insertions(+), 132 deletions(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index e2c8fa0ce9bd9d..725df10c4028ad 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -34,7 +34,6 @@ namespace ngraph /// \param execution_condition condition node. If(const Output& execution_condition); If(); - explicit If(const OutputVector& values); std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; @@ -95,12 +94,16 @@ namespace ngraph const HostTensorVector& inputs) const override; private: + using OutputMap = + std::map>; void validate_and_infer_type_body( const std::shared_ptr& body, const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors); - void fill_body(const std::shared_ptr& new_op, - size_t branch_index, - const OutputVector& new_args) const; + void clone_to(If& dst, const OutputVector& new_args) const; + + OutputMap get_mapping_outputs_on_body_description( + const ngraph::op::util::MultiSubgraphOutputDescriptionVector& + output_descriptors); }; } // namespace v8 } // namespace op diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 74c5f3d69afa0a..818c13207b4893 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -24,11 +24,6 @@ op::v8::If::If() { } -op::v8::If::If(const OutputVector& values) - : op::util::MultiSubGraphOp(values, 2) -{ -} - op::v8::If::If(const Output& execution_condition) : If() { @@ -94,7 +89,7 @@ void op::v8::If::validate_and_infer_type_body( auto index = input_description->m_input_index; auto body_parameter = body->get_parameters().at(input_description->m_body_parameter_index); - auto input_partial_shape = inputs().at(index).get_source_output().get_partial_shape(); + auto input_partial_shape = input_value(index).get_partial_shape(); body_parameter->set_partial_shape(input_partial_shape); } body->validate_nodes_and_infer_types(); @@ -102,26 +97,35 @@ void op::v8::If::validate_and_infer_type_body( void op::v8::If::validate_and_infer_types() { NGRAPH_OP_SCOPE(v8_If_validate_and_infer_types); - auto cond_output = inputs().at(0).get_source_output(); - auto cond_partial_shape = cond_output.get_partial_shape(); - auto cond_rank = cond_partial_shape.rank(); - if (cond_rank.is_static()) + NODE_VALIDATION_CHECK( + this, m_bodies.size() == 2, "If contains incorrect number of bodies:", m_bodies.size()); + + NODE_VALIDATION_CHECK(this, + m_input_descriptions.size() == 2, + "If contains incorrect number of body input descriptions:", + m_input_descriptions.size()); + NODE_VALIDATION_CHECK(this, + m_output_descriptions.size() == 2, + "If contains incorrect number of body output descriptions:", + m_output_descriptions.size()); + + const auto& if_condition = input_value(0); + const auto& if_condition_rank = if_condition.get_partial_shape().rank(); + if (if_condition_rank.is_static()) { - NODE_VALIDATION_CHECK(this, cond_rank.get_length() < 2, "Incorrect condition"); - } - if (cond_partial_shape.is_static()) - { - auto cond_shape = cond_partial_shape.to_shape(); - if (cond_rank.get_length() == 1) - { - NODE_VALIDATION_CHECK(this, cond_shape.at(0) == 1, "Incorrect shape of condition"); - } + NODE_VALIDATION_CHECK(this, + if_condition_rank.compatible(1) || if_condition_rank.compatible(0), + "Rank of If condition input must be equal to 0 or 1"); } // Trying to get cond as const value - if (const auto& cond_value = get_constant_from_source(cond_output)) + if (const auto& cond_value = get_constant_from_source(if_condition)) { auto val = cond_value->cast_vector(); + NODE_VALIDATION_CHECK(this, + val.size() == 1, + "The number of values in the If condition constant is greater than 1"); + auto cond_index = val[0] ? then_body_index : else_body_index; auto body = m_bodies[cond_index]; auto input_descriptors = m_input_descriptions[cond_index]; @@ -141,126 +145,112 @@ void op::v8::If::validate_and_infer_types() { validate_and_infer_type_body(get_then_body(), m_input_descriptions[then_body_index]); validate_and_infer_type_body(get_else_body(), m_input_descriptions[else_body_index]); - - std::set then_output_indexes{}; - std::set else_output_indexes{}; auto output_nodes = outputs(); - for (const auto& then_output_description : m_output_descriptions[then_body_index]) - { - auto out_index = then_output_description->m_output_index; - auto cond = [=](Output& node) { return node.get_index() == out_index; }; - auto it = std::find_if(output_nodes.begin(), output_nodes.end(), cond); - NGRAPH_CHECK(it != output_nodes.end(), - "Incorrect output with index %i in \'then_body\'", - out_index); - then_output_indexes.insert(then_output_description->m_output_index); - } - NGRAPH_CHECK( - then_output_indexes.size() == output_nodes.size(), - "Incorect then_body! Number of then_body outputs must be same as number If outputs"); + auto then_outputs_map = + get_mapping_outputs_on_body_description(m_output_descriptions[then_body_index]); + auto else_outputs_map = + get_mapping_outputs_on_body_description(m_output_descriptions[else_body_index]); + + for (size_t output_index = 0; output_index < output_nodes.size(); ++output_index) { + + NODE_VALIDATION_CHECK(this, + then_outputs_map.count(output_index)!=0, + "Incorrect associating in then_body! Output ", + output_index, + " is not associated with results in then_body!"); + NODE_VALIDATION_CHECK(this, + else_outputs_map.count(output_index) != 0, + "Incorrect associating in else_body! Output ", + output_index, + " is not associated with results in else_body!"); + + auto then_desc = then_outputs_map.at(output_index); + auto else_desc = else_outputs_map.at(output_index); - for (const auto& else_output_description : m_output_descriptions[else_body_index]) - { - auto out_index = else_output_description->m_output_index; - auto cond = [=](Output& node) { return node.get_index() == out_index; }; - auto it = std::find_if(output_nodes.begin(), output_nodes.end(), cond); - NGRAPH_CHECK(it != output_nodes.end(), - "Incorrect output with index %i in \'else_body\'", - out_index); - else_output_indexes.insert(else_output_description->m_output_index); - } - - NGRAPH_CHECK( - else_output_indexes.size() == output_nodes.size(), - "Incorect else_body! Number of else_body outputs must be same as number If outputs"); + auto then_node_result = m_bodies[then_body_index] + ->get_results() + .at(then_desc->m_body_value_index) + ->input_value(0); - for (const auto& output_index : then_output_indexes) - { - auto description_find_lambda = [=](MultiSubgraphOutputDescriptionPtr& descr) { - return descr->m_output_index == static_cast(output_index); - }; - - auto then_output_description = *find_if(m_output_descriptions[then_body_index].begin(), - m_output_descriptions[then_body_index].end(), - description_find_lambda); - auto else_output_description = *find_if(m_output_descriptions[else_body_index].begin(), - m_output_descriptions[else_body_index].end(), - description_find_lambda); - auto then_out_node = m_bodies[then_body_index] - ->get_results() - .at(then_output_description->m_body_value_index) - ->input_value(0); - auto else_out_node = m_bodies[else_body_index] - ->get_results() - .at(else_output_description->m_body_value_index) - ->input_value(0); - auto then_node_partial_shape = then_out_node.get_partial_shape(); - auto else_node_partial_shape = else_out_node.get_partial_shape(); - NGRAPH_CHECK(then_out_node.get_element_type() == else_out_node.get_element_type(), - "type of then_body output is not equal type of else_body output"); + auto else_node_result = m_bodies[else_body_index] + ->get_results() + .at(else_desc->m_body_value_index) + ->input_value(0); - auto partial_shape = resolve_shape(then_node_partial_shape, else_node_partial_shape); - set_output_type(output_index, then_out_node.get_element_type(), partial_shape); - } - } -} + NODE_VALIDATION_CHECK(this, + then_node_result.get_element_type() == + else_node_result.get_element_type(), + "type of then_body output is not equal type of else_body output"); -void op::v8::If::fill_body(const std::shared_ptr& new_op, - size_t branch_index, - const OutputVector& new_args) const -{ - auto body = m_bodies[branch_index]; - auto param_size = body->get_parameters().size(); - std::vector<::ngraph::element::Type> types(param_size); - std::vector<::ngraph::PartialShape> new_shapes(param_size); - auto& input_descriptions = m_input_descriptions[branch_index]; - size_t parameters_num = 0; - for (auto& input_description : input_descriptions) - { - if (input_description->m_input_index < new_args.size()) - { - types[input_description->m_body_parameter_index] = - new_args[input_description->m_input_index].get_element_type(); - new_shapes[input_description->m_body_parameter_index] = - new_args[input_description->m_input_index].get_partial_shape(); - parameters_num++; + auto partial_shape = resolve_shape(then_node_result.get_partial_shape(), + else_node_result.get_partial_shape()); + set_output_type(output_index, then_node_result.get_element_type(), partial_shape); } } - auto func = - std::make_shared(body->get_results(), body->get_sinks(), body->get_parameters()); - auto spec_func = - specialize_function(func, types, new_shapes, std::vector(parameters_num, nullptr)); - new_op->m_bodies[branch_index] = std::make_shared( - spec_func->get_results(), spec_func->get_sinks(), spec_func->get_parameters()); - - for (const auto& input_description : input_descriptions) - { - new_op->m_input_descriptions[branch_index].push_back(input_description->copy()); - } - for (const auto& output_description : m_output_descriptions[branch_index]) - { - new_op->m_output_descriptions[branch_index].push_back(output_description->copy()); - } } std::shared_ptr op::v8::If::clone_with_new_inputs(const OutputVector& new_args) const { NGRAPH_OP_SCOPE(v8_If_clone_with_new_inputs); - auto op = make_shared(new_args); + + check_new_args_count(this, new_args); + auto op = make_shared(); NGRAPH_CHECK(op.get(), op != nullptr, "Cannot clone ", description(), " operation with name ", get_friendly_name()); - op->set_output_size(m_output_descriptions[0].size()); - fill_body(op, then_body_index, new_args); - fill_body(op, else_body_index, new_args); - op->validate_and_infer_types(); + clone_to(*op, new_args); return op; } +op::v8::If::OutputMap op::v8::If::get_mapping_outputs_on_body_description( + const ngraph::op::util::MultiSubgraphOutputDescriptionVector& output_descriptors) +{ + OutputMap outputs_map = OutputMap(); + std::unordered_set checked_results_in_body; + + for (const auto& output_description : output_descriptors) + { + auto out_index = output_description->m_output_index; + auto internal_result_index = output_description->m_body_value_index; + NODE_VALIDATION_CHECK(this, + checked_results_in_body.count(internal_result_index) == 0, + "Incorrect associating in then_body! Result ", + internal_result_index, + " is already associated with another output!"); + NODE_VALIDATION_CHECK(this, + outputs_map.count(out_index) == 0, + "Incorrect associating in then_body! Several results try to " + "associate with the same output!"); + checked_results_in_body.insert(internal_result_index); + outputs_map.insert({out_index, output_description}); + } + + return outputs_map; +} +void op::v8::If::clone_to(op::v8::If& dst, const OutputVector& new_args) const + { + dst.set_arguments(new_args); + dst.set_output_size(m_output_descriptions[0].size()); + dst.set_then_body(clone_function(*get_then_body())); + dst.set_else_body(clone_function(*get_else_body())); + + for (auto body_index = 0; body_index < 2; ++body_index) { + for (const auto& m_input_descr : m_input_descriptions[body_index]) { + dst.m_input_descriptions[body_index].push_back(m_input_descr->copy()); + } + for (const auto& m_output_descr : m_output_descriptions[body_index]) + { + dst.m_output_descriptions[body_index].push_back(m_output_descr->copy()); + } + } + dst.validate_and_infer_types(); +} + + bool op::v8::If::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const { NGRAPH_OP_SCOPE(v8_If_evaluate); @@ -273,20 +263,33 @@ void op::v8::If::set_input(const Output& value, const std::shared_ptr& then_parameter, const std::shared_ptr& else_parameter) { - ParameterVector param_vec; - if (then_parameter != nullptr) - { - param_vec.push_back(then_parameter); - } - if (else_parameter != nullptr) - { - param_vec.push_back(else_parameter); - } - set_invariant_inputs(value, param_vec); + auto then_param_index = m_bodies[then_body_index]->get_parameter_index(then_parameter); + auto else_param_index = m_bodies[else_body_index]->get_parameter_index(else_parameter); + NGRAPH_CHECK(then_parameter == nullptr || then_param_index != -1, + "Missing parameter ", then_parameter->get_friendly_name(), " for \'then_body\'!"); + NGRAPH_CHECK(else_parameter == nullptr || else_param_index != -1, + "Missing parameter ", + else_parameter->get_friendly_name(), + " for \'else_body\'!"); + set_invariant_inputs(value, {then_parameter, else_parameter}); } Output op::v8::If::set_output(const std::shared_ptr& then_result, const std::shared_ptr& else_result) { + NGRAPH_CHECK(then_result != nullptr, + "Incorrect result in \"then_body\"! Result cant be \'nullptr\'"); + NGRAPH_CHECK(else_result != nullptr, + "Incorrect result in \"else_body\"! Result cant be \'nullptr\'"); + auto then_result_id = m_bodies[then_body_index]->get_result_index(then_result); + auto else_result_id = m_bodies[else_body_index]->get_result_index(else_result); + + NGRAPH_CHECK(then_result_id != -1, + "Missing result ", then_result->get_friendly_name(), "in \'then_body\'!"); + NGRAPH_CHECK(else_result_id != -1, + "Missing result ", + else_result->get_friendly_name(), + "in \'then_body\'!"); + return set_body_outputs({then_result, else_result}); } \ No newline at end of file From e3bd48cb2fb11da61c8c54df1b4c8b66e38a6bbc Mon Sep 17 00:00:00 2001 From: evolosen Date: Tue, 3 Aug 2021 11:24:52 +0300 Subject: [PATCH 05/30] rewrite tests for dynamic cases --- ngraph/core/include/ngraph/op/if.hpp | 6 +- ngraph/core/src/op/if.cpp | 44 +++++++------ ngraph/test/op_eval/if_eval.cpp | 53 ++++++++++++++++ ngraph/test/type_prop/if.cpp | 94 ++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 22 deletions(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index 725df10c4028ad..21c5b8cbc9ad9e 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -94,7 +94,7 @@ namespace ngraph const HostTensorVector& inputs) const override; private: - using OutputMap = + using OutputMap = std::map>; void validate_and_infer_type_body( const std::shared_ptr& body, @@ -102,8 +102,8 @@ namespace ngraph void clone_to(If& dst, const OutputVector& new_args) const; OutputMap get_mapping_outputs_on_body_description( - const ngraph::op::util::MultiSubgraphOutputDescriptionVector& - output_descriptors); + const ngraph::op::util::MultiSubgraphOutputDescriptionVector& + output_descriptors); }; } // namespace v8 } // namespace op diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 818c13207b4893..6d0cd05b20b2e6 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -122,9 +122,10 @@ void op::v8::If::validate_and_infer_types() if (const auto& cond_value = get_constant_from_source(if_condition)) { auto val = cond_value->cast_vector(); - NODE_VALIDATION_CHECK(this, - val.size() == 1, - "The number of values in the If condition constant is greater than 1"); + NODE_VALIDATION_CHECK( + this, + val.size() == 1, + "The number of values in the If condition constant is greater than 1"); auto cond_index = val[0] ? then_body_index : else_body_index; auto body = m_bodies[cond_index]; @@ -147,15 +148,15 @@ void op::v8::If::validate_and_infer_types() validate_and_infer_type_body(get_else_body(), m_input_descriptions[else_body_index]); auto output_nodes = outputs(); - auto then_outputs_map = + auto then_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[then_body_index]); auto else_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[else_body_index]); - - for (size_t output_index = 0; output_index < output_nodes.size(); ++output_index) { - + + for (size_t output_index = 0; output_index < output_nodes.size(); ++output_index) + { NODE_VALIDATION_CHECK(this, - then_outputs_map.count(output_index)!=0, + then_outputs_map.count(output_index) != 0, "Incorrect associating in then_body! Output ", output_index, " is not associated with results in then_body!"); @@ -164,7 +165,7 @@ void op::v8::If::validate_and_infer_types() "Incorrect associating in else_body! Output ", output_index, " is not associated with results in else_body!"); - + auto then_desc = then_outputs_map.at(output_index); auto else_desc = else_outputs_map.at(output_index); @@ -207,7 +208,7 @@ std::shared_ptr op::v8::If::clone_with_new_inputs(const OutputVector& new_ } op::v8::If::OutputMap op::v8::If::get_mapping_outputs_on_body_description( - const ngraph::op::util::MultiSubgraphOutputDescriptionVector& output_descriptors) + const ngraph::op::util::MultiSubgraphOutputDescriptionVector& output_descriptors) { OutputMap outputs_map = OutputMap(); std::unordered_set checked_results_in_body; @@ -232,14 +233,16 @@ op::v8::If::OutputMap op::v8::If::get_mapping_outputs_on_body_description( return outputs_map; } void op::v8::If::clone_to(op::v8::If& dst, const OutputVector& new_args) const - { +{ dst.set_arguments(new_args); dst.set_output_size(m_output_descriptions[0].size()); dst.set_then_body(clone_function(*get_then_body())); dst.set_else_body(clone_function(*get_else_body())); - - for (auto body_index = 0; body_index < 2; ++body_index) { - for (const auto& m_input_descr : m_input_descriptions[body_index]) { + + for (auto body_index = 0; body_index < 2; ++body_index) + { + for (const auto& m_input_descr : m_input_descriptions[body_index]) + { dst.m_input_descriptions[body_index].push_back(m_input_descr->copy()); } for (const auto& m_output_descr : m_output_descriptions[body_index]) @@ -250,7 +253,6 @@ void op::v8::If::clone_to(op::v8::If& dst, const OutputVector& new_args) const dst.validate_and_infer_types(); } - bool op::v8::If::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const { NGRAPH_OP_SCOPE(v8_If_evaluate); @@ -266,10 +268,12 @@ void op::v8::If::set_input(const Output& value, auto then_param_index = m_bodies[then_body_index]->get_parameter_index(then_parameter); auto else_param_index = m_bodies[else_body_index]->get_parameter_index(else_parameter); NGRAPH_CHECK(then_parameter == nullptr || then_param_index != -1, - "Missing parameter ", then_parameter->get_friendly_name(), " for \'then_body\'!"); + "Missing parameter ", + then_parameter->get_friendly_name(), + " for \'then_body\'!"); NGRAPH_CHECK(else_parameter == nullptr || else_param_index != -1, "Missing parameter ", - else_parameter->get_friendly_name(), + else_parameter->get_friendly_name(), " for \'else_body\'!"); set_invariant_inputs(value, {then_parameter, else_parameter}); } @@ -285,10 +289,12 @@ Output op::v8::If::set_output(const std::shared_ptr& then_result, auto else_result_id = m_bodies[else_body_index]->get_result_index(else_result); NGRAPH_CHECK(then_result_id != -1, - "Missing result ", then_result->get_friendly_name(), "in \'then_body\'!"); + "Missing result ", + then_result->get_friendly_name(), + "in \'then_body\'!"); NGRAPH_CHECK(else_result_id != -1, "Missing result ", - else_result->get_friendly_name(), + else_result->get_friendly_name(), "in \'then_body\'!"); return set_body_outputs({then_result, else_result}); diff --git a/ngraph/test/op_eval/if_eval.cpp b/ngraph/test/op_eval/if_eval.cpp index 1938d6d8f9ec50..1d0192d57a3f23 100644 --- a/ngraph/test/op_eval/if_eval.cpp +++ b/ngraph/test/op_eval/if_eval.cpp @@ -331,6 +331,59 @@ TEST(op_eval, if_condition_non_const_scalar) result_data = read_vector(result); expected_results = {3.0, 3.0, 5.0, 7.0}; + for (auto i = 0; i < expected_results.size(); i++) + EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); +} +TEST(op_eval, if_condition_is_dynamic) +{ + auto X = make_shared(element::f32, Shape{1, 2, 2}); + auto Y = make_shared(element::f32, Shape{1, 2, 2}); + auto cond = make_shared(element::boolean, PartialShape{Dimension::dynamic()}); + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto else_op = std::make_shared(Xe, Ye); + auto then_op_result = make_shared(then_op); + auto else_op_result = make_shared(else_op); + auto then_body = + make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = + make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + if_op->set_output(then_op_result, else_op_result); + if_op->validate_and_infer_types(); + std::vector X_v{1.0, 2.0, 3.0, 4.0}; + std::vector Y_v{2.0, 1.0, 2.0, 3.0}; + auto fun = make_shared(OutputVector{if_op}, ParameterVector{cond, X, Y}); + auto result = make_shared(); + ASSERT_TRUE(fun->evaluate({result}, + {make_host_tensor(Shape{1}, {true}), + make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{1, 2, 2}, Y_v)})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); + auto result_data = read_vector(result); + std::vector expected_results{2.0, 2.0, 6.0, 12.0}; + for (auto i = 0; i < expected_results.size(); i++) + EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); + ASSERT_TRUE(fun->evaluate({result}, + {make_host_tensor(Shape{1}, {false}), + make_host_tensor(Shape{1, 2, 2}, X_v), + make_host_tensor(Shape{1, 2, 2}, Y_v)})); + EXPECT_EQ(result->get_element_type(), element::f32); + EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); + result_data = read_vector(result); + expected_results = {3.0, 3.0, 5.0, 7.0}; + for (auto i = 0; i < expected_results.size(); i++) EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); } \ No newline at end of file diff --git a/ngraph/test/type_prop/if.cpp b/ngraph/test/type_prop/if.cpp index 2dcf9b57145367..44094110f1b2c2 100644 --- a/ngraph/test/type_prop/if.cpp +++ b/ngraph/test/type_prop/if.cpp @@ -203,4 +203,98 @@ TEST(type_prop, if_scalar_condition) Shape out0_shape{32, 40, 10}; auto sh = result0->get_output_shape(0); EXPECT_EQ(sh, out0_shape); +} + +TEST(type_prop, if_dynamic_output) +{ + // That which we iterate over + auto X_shape = Shape{1, 20, 5, 30}; + auto Y_shape = Shape{18, 16, 14, 12}; + auto X = make_shared(element::f32, X_shape); + auto Y = make_shared(element::f32, Y_shape); + auto cond = make_shared(element::boolean, Shape{1}); + + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Xt); + auto then_body_res = make_shared(then_op); + auto then_body = + make_shared(OutputVector{then_body_res}, ParameterVector{Xt}); + + auto else_op = std::make_shared(Ye, Ye); + auto else_body_res = make_shared(else_op); + auto else_body = + make_shared(OutputVector{else_body_res}, ParameterVector{Ye}); + + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, nullptr); + if_op->set_input(Y, nullptr, Ye); + auto res = if_op->set_output(then_body_res, else_body_res); + if_op->validate_and_infer_types(); + auto result0 = make_shared(res); + auto dynamic_shape = result0->get_output_partial_shape(0); + + EXPECT_EQ(X_shape.size(), dynamic_shape.rank().get_length()); + for (auto shape_index = 0; shape_index < X_shape.size(); shape_index++) + { + auto x_shape_it = X_shape.begin(); + auto y_shape_it = Y_shape.begin(); + auto res_it = dynamic_shape.begin(); + EXPECT_EQ(std::max(*x_shape_it, *y_shape_it), (*res_it).get_max_length()); + EXPECT_EQ(std::min(*x_shape_it, *y_shape_it), (*res_it).get_min_length()); + x_shape_it++; + y_shape_it++; + res_it++; + } +} + +TEST(type_prop, if_dynamic_inputs) +{ + // That which we iterate over + auto X_shape = PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}; + auto Y_shape = PartialShape{Dimension::dynamic(), 20, 30}; + ; + auto X = make_shared(element::f32, X_shape); + auto Y = make_shared(element::f32, Y_shape); + auto cond = make_shared(element::boolean, Shape{1}); + + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto then_body_res = make_shared(then_op); + auto then_body = + make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); + + auto else_op = std::make_shared(Xe, Ye); + auto else_body_res = make_shared(else_op); + auto else_body = + make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); + + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto res = if_op->set_output(then_body_res, else_body_res); + if_op->validate_and_infer_types(); + auto result0 = make_shared(res); + auto dynamic_shape = result0->get_output_partial_shape(0); + auto expected_result = PartialShape{Dimension::dynamic(), 20, 30}; + EXPECT_EQ(3, dynamic_shape.rank().get_length()); + for (auto dim_index = 0; dim_index < 3; dim_index++) + { + auto exp_res_it = expected_result.begin(); + auto res_it = dynamic_shape.begin(); + EXPECT_EQ(*exp_res_it, *res_it); + } } \ No newline at end of file From 5f1b9c0abf3ea08ecd1a1d32402924cdf457c549 Mon Sep 17 00:00:00 2001 From: evolosen Date: Fri, 6 Aug 2021 10:17:58 +0300 Subject: [PATCH 06/30] Fix ci failed --- ngraph/core/include/ngraph/op/if.hpp | 2 +- ngraph/core/include/ngraph/ops.hpp | 2 +- ngraph/core/src/op/if.cpp | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index 21c5b8cbc9ad9e..a93e960ffb2a5d 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -84,7 +84,7 @@ namespace ngraph /// of each sub-graphs /// /// \param then_result result from then_body - /// \param else_parameter pesult from else_body + /// \param else_parameter result from else_body /// \return output from operation Output set_output(const std::shared_ptr& then_result, const std::shared_ptr& else_result); diff --git a/ngraph/core/include/ngraph/ops.hpp b/ngraph/core/include/ngraph/ops.hpp index 5f6ba251e7aa56..9a1147438ab1ef 100644 --- a/ngraph/core/include/ngraph/ops.hpp +++ b/ngraph/core/include/ngraph/ops.hpp @@ -75,6 +75,7 @@ #include "ngraph/op/hsigmoid.hpp" #include "ngraph/op/hswish.hpp" #include "ngraph/op/idft.hpp" +#include "ngraph/op/if.hpp" #include "ngraph/op/interpolate.hpp" #include "ngraph/op/less.hpp" #include "ngraph/op/less_eq.hpp" @@ -167,4 +168,3 @@ #include "ngraph/op/util/op_types.hpp" #include "ngraph/op/variadic_split.hpp" #include "ngraph/op/xor.hpp" -#include "ngraph/op/if.hpp" diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 6d0cd05b20b2e6..7a649f3d691931 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -94,6 +94,7 @@ void op::v8::If::validate_and_infer_type_body( } body->validate_nodes_and_infer_types(); } + void op::v8::If::validate_and_infer_types() { NGRAPH_OP_SCOPE(v8_If_validate_and_infer_types); From 21b79a43ebdf12d005a0c1b67062d360bb5919f4 Mon Sep 17 00:00:00 2001 From: evolosen Date: Mon, 9 Aug 2021 12:32:18 +0300 Subject: [PATCH 07/30] add comentaries for validate_and_infer_types --- ngraph/core/include/ngraph/op/if.hpp | 4 +- .../include/ngraph/runtime/reference/if.hpp | 2 +- .../reference/src/runtime/reference/if.cpp | 1 - ngraph/core/src/op/if.cpp | 89 +++++++++++-------- 4 files changed, 55 insertions(+), 41 deletions(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index a93e960ffb2a5d..29b94d5e3fd4be 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -74,8 +74,8 @@ namespace ngraph /// of each sub-graphs /// /// \param value input to operation - /// \param then_parameter parameter for then_body - /// \param else_parameter parameter for else_body + /// \param then_parameter parameter for then_body or nullptr + /// \param else_parameter parameter for else_body or nullpt void set_input(const Output& value, const std::shared_ptr& then_parameter, const std::shared_ptr& else_parameter); diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp index 58fd97ae3961ae..ffb84c89bcc402 100644 --- a/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp +++ b/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp @@ -5,7 +5,7 @@ #pragma once #include -#include +#include "ngraph/op/util/multi_subgraph_base.hpp" namespace ngraph { diff --git a/ngraph/core/reference/src/runtime/reference/if.cpp b/ngraph/core/reference/src/runtime/reference/if.cpp index 92e741446bff50..2d8f70e752de7c 100644 --- a/ngraph/core/reference/src/runtime/reference/if.cpp +++ b/ngraph/core/reference/src/runtime/reference/if.cpp @@ -10,7 +10,6 @@ namespace ngraph { namespace reference { - using namespace op::v8; enum if_body_indexes { then_body_index = 0, diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 7a649f3d691931..96fd43589252ad 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -30,40 +30,6 @@ op::v8::If::If(const Output& execution_condition) set_argument(0, execution_condition); } -ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, - const ngraph::PartialShape& else_pshape) -{ - auto then_rank = then_pshape.rank(); - auto else_rank = else_pshape.rank(); - if (then_rank.is_dynamic() || else_rank.is_dynamic() || - then_rank.get_length() != else_rank.get_length()) - { - return ngraph::PartialShape::dynamic(ngraph::Rank::dynamic()); - } - std::vector new_dims; - for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); - then_it != then_pshape.cend(); - then_it++, else_it++) - { - if ((*then_it).is_dynamic() || (*else_it).is_dynamic()) - { - new_dims.push_back(Dimension::dynamic()); - } - else if (*then_it == *else_it) - { - new_dims.push_back(Dimension(*then_it)); - } - else - { - auto dim_min = std::min((*then_it).get_min_length(), (*else_it).get_min_length()); - auto dim_max = std::max((*then_it).get_min_length(), (*else_it).get_min_length()); - new_dims.push_back(Dimension(dim_min, dim_max)); - } - } - - return PartialShape(new_dims); -} - bool op::v8::If::visit_attributes(AttributeVisitor& visitor) { NGRAPH_OP_SCOPE(v8_If_visit_attributes); @@ -119,9 +85,12 @@ void op::v8::If::validate_and_infer_types() if_condition_rank.compatible(1) || if_condition_rank.compatible(0), "Rank of If condition input must be equal to 0 or 1"); } + // Trying to get cond as const value if (const auto& cond_value = get_constant_from_source(if_condition)) { + + // If cond is const shape and inference is run for one of bodies another body is skipped auto val = cond_value->cast_vector(); NODE_VALIDATION_CHECK( this, @@ -133,6 +102,8 @@ void op::v8::If::validate_and_infer_types() auto input_descriptors = m_input_descriptions[cond_index]; validate_and_infer_type_body(body, input_descriptors); auto output_nodes = outputs(); + + //shape and type inference for outputs from If operations for (const auto& output_descr : m_output_descriptions[cond_index]) { auto body_value = @@ -145,15 +116,19 @@ void op::v8::If::validate_and_infer_types() } else // condition is non constant { + + //If cond is non const, shape and type inference is run for both bodies validate_and_infer_type_body(get_then_body(), m_input_descriptions[then_body_index]); validate_and_infer_type_body(get_else_body(), m_input_descriptions[else_body_index]); auto output_nodes = outputs(); - + + // Getting map. This map guarantees that each output from the body will be met in it once. auto then_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[then_body_index]); auto else_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[else_body_index]); + //Checking each output from If. Each output must be associated with one output from each body for (size_t output_index = 0; output_index < output_nodes.size(); ++output_index) { NODE_VALIDATION_CHECK(this, @@ -184,7 +159,8 @@ void op::v8::If::validate_and_infer_types() then_node_result.get_element_type() == else_node_result.get_element_type(), "type of then_body output is not equal type of else_body output"); - + + //shape inference for output and associated with it body outputs auto partial_shape = resolve_shape(then_node_result.get_partial_shape(), else_node_result.get_partial_shape()); set_output_type(output_index, then_node_result.get_element_type(), partial_shape); @@ -266,6 +242,8 @@ void op::v8::If::set_input(const Output& value, const std::shared_ptr& then_parameter, const std::shared_ptr& else_parameter) { + NGRAPH_CHECK(then_parameter != nullptr || else_parameter != nullptr, + "Missing parameters! Both parameters are nullptr!"); auto then_param_index = m_bodies[then_body_index]->get_parameter_index(then_parameter); auto else_param_index = m_bodies[else_body_index]->get_parameter_index(else_parameter); NGRAPH_CHECK(then_parameter == nullptr || then_param_index != -1, @@ -299,4 +277,41 @@ Output op::v8::If::set_output(const std::shared_ptr& then_result, "in \'then_body\'!"); return set_body_outputs({then_result, else_result}); -} \ No newline at end of file +} + +namespace +{ + ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, + const ngraph::PartialShape& else_pshape) + { + auto then_rank = then_pshape.rank(); + auto else_rank = else_pshape.rank(); + if (then_rank.is_dynamic() || else_rank.is_dynamic() || + then_rank.get_length() != else_rank.get_length()) + { + return ngraph::PartialShape::dynamic(ngraph::Rank::dynamic()); + } + std::vector new_dims; + for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); + then_it != then_pshape.cend(); + then_it++, else_it++) + { + if ((*then_it).is_dynamic() || (*else_it).is_dynamic()) + { + new_dims.push_back(Dimension::dynamic()); + } + else if (*then_it == *else_it) + { + new_dims.push_back(Dimension(*then_it)); + } + else + { + auto dim_min = std::min((*then_it).get_min_length(), (*else_it).get_min_length()); + auto dim_max = std::max((*then_it).get_min_length(), (*else_it).get_min_length()); + new_dims.push_back(Dimension(dim_min, dim_max)); + } + } + + return PartialShape(new_dims); + } +} // namespace \ No newline at end of file From ff15d83aa4ae3c9bc5acf796f51b896086068cb0 Mon Sep 17 00:00:00 2001 From: evolosen Date: Mon, 9 Aug 2021 22:09:25 +0300 Subject: [PATCH 08/30] fix api --- ngraph/core/include/ngraph/op/if.hpp | 5 +- ngraph/core/src/op/if.cpp | 135 +++++++++++++-------------- 2 files changed, 67 insertions(+), 73 deletions(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index 29b94d5e3fd4be..be6df62ca5be3f 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -41,7 +41,7 @@ namespace ngraph /// \brief gets then_body as ngraph::Function. /// /// \return then_body as ngraph::Function. - std::shared_ptr get_then_body() const + const std::shared_ptr& get_then_body() const { return m_bodies[then_body_index]; } @@ -49,7 +49,7 @@ namespace ngraph /// \brief gets else_body as ngraph::Function. /// /// \return else_body as ngraph::Function. - std::shared_ptr get_else_body() const + const std::shared_ptr& get_else_body() const { return m_bodies[else_body_index]; } @@ -99,7 +99,6 @@ namespace ngraph void validate_and_infer_type_body( const std::shared_ptr& body, const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors); - void clone_to(If& dst, const OutputVector& new_args) const; OutputMap get_mapping_outputs_on_body_description( const ngraph::op::util::MultiSubgraphOutputDescriptionVector& diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 96fd43589252ad..ce269f56a7d7e0 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -17,7 +17,7 @@ using namespace std; using namespace ngraph; -NGRAPH_RTTI_DEFINITION(ngraph::op::v8::If, "If", 8); +NGRAPH_RTTI_DEFINITION(ngraph::op::v8::If, "If", 8, MultiSubGraphOp); op::v8::If::If() : MultiSubGraphOp(2) @@ -30,6 +30,40 @@ op::v8::If::If(const Output& execution_condition) set_argument(0, execution_condition); } +static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, + const ngraph::PartialShape& else_pshape) +{ + auto then_rank = then_pshape.rank(); + auto else_rank = else_pshape.rank(); + if (then_rank.is_dynamic() || else_rank.is_dynamic() || + then_rank.get_length() != else_rank.get_length()) + { + return ngraph::PartialShape::dynamic(ngraph::Rank::dynamic()); + } + std::vector new_dims; + for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); + then_it != then_pshape.cend(); + then_it++, else_it++) + { + if ((*then_it).is_dynamic() || (*else_it).is_dynamic()) + { + new_dims.push_back(Dimension::dynamic()); + } + else if (*then_it == *else_it) + { + new_dims.push_back(Dimension(*then_it)); + } + else + { + auto dim_min = std::min((*then_it).get_min_length(), (*else_it).get_min_length()); + auto dim_max = std::max((*then_it).get_min_length(), (*else_it).get_min_length()); + new_dims.push_back(Dimension(dim_min, dim_max)); + } + } + + return PartialShape(new_dims); +} + bool op::v8::If::visit_attributes(AttributeVisitor& visitor) { NGRAPH_OP_SCOPE(v8_If_visit_attributes); @@ -89,7 +123,6 @@ void op::v8::If::validate_and_infer_types() // Trying to get cond as const value if (const auto& cond_value = get_constant_from_source(if_condition)) { - // If cond is const shape and inference is run for one of bodies another body is skipped auto val = cond_value->cast_vector(); NODE_VALIDATION_CHECK( @@ -102,8 +135,8 @@ void op::v8::If::validate_and_infer_types() auto input_descriptors = m_input_descriptions[cond_index]; validate_and_infer_type_body(body, input_descriptors); auto output_nodes = outputs(); - - //shape and type inference for outputs from If operations + + // shape and type inference for outputs from If operations for (const auto& output_descr : m_output_descriptions[cond_index]) { auto body_value = @@ -116,19 +149,20 @@ void op::v8::If::validate_and_infer_types() } else // condition is non constant { - - //If cond is non const, shape and type inference is run for both bodies + // If cond is non const, shape and type inference is run for both bodies validate_and_infer_type_body(get_then_body(), m_input_descriptions[then_body_index]); validate_and_infer_type_body(get_else_body(), m_input_descriptions[else_body_index]); auto output_nodes = outputs(); - - // Getting map. This map guarantees that each output from the body will be met in it once. + + // Getting map. This map guarantees that each + // output from the body will be met in it once. auto then_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[then_body_index]); auto else_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[else_body_index]); - //Checking each output from If. Each output must be associated with one output from each body + // Checking each output from If. Each output must be associated with one output from each + // body for (size_t output_index = 0; output_index < output_nodes.size(); ++output_index) { NODE_VALIDATION_CHECK(this, @@ -159,8 +193,8 @@ void op::v8::If::validate_and_infer_types() then_node_result.get_element_type() == else_node_result.get_element_type(), "type of then_body output is not equal type of else_body output"); - - //shape inference for output and associated with it body outputs + + // shape inference for output and associated with it body outputs auto partial_shape = resolve_shape(then_node_result.get_partial_shape(), else_node_result.get_partial_shape()); set_output_type(output_index, then_node_result.get_element_type(), partial_shape); @@ -180,7 +214,25 @@ std::shared_ptr op::v8::If::clone_with_new_inputs(const OutputVector& new_ description(), " operation with name ", get_friendly_name()); - clone_to(*op, new_args); + + op->set_arguments(new_args); + op->set_output_size(m_output_descriptions[0].size()); + op->set_then_body(clone_function(*get_then_body())); + op->set_else_body(clone_function(*get_else_body())); + + for (auto body_index = 0; body_index < 2; ++body_index) + { + for (const auto& m_input_descr : m_input_descriptions[body_index]) + { + op->m_input_descriptions[body_index].push_back(m_input_descr->copy()); + } + for (const auto& m_output_descr : m_output_descriptions[body_index]) + { + op->m_output_descriptions[body_index].push_back(m_output_descr->copy()); + } + } + op->validate_and_infer_types(); + return op; } @@ -209,26 +261,6 @@ op::v8::If::OutputMap op::v8::If::get_mapping_outputs_on_body_description( return outputs_map; } -void op::v8::If::clone_to(op::v8::If& dst, const OutputVector& new_args) const -{ - dst.set_arguments(new_args); - dst.set_output_size(m_output_descriptions[0].size()); - dst.set_then_body(clone_function(*get_then_body())); - dst.set_else_body(clone_function(*get_else_body())); - - for (auto body_index = 0; body_index < 2; ++body_index) - { - for (const auto& m_input_descr : m_input_descriptions[body_index]) - { - dst.m_input_descriptions[body_index].push_back(m_input_descr->copy()); - } - for (const auto& m_output_descr : m_output_descriptions[body_index]) - { - dst.m_output_descriptions[body_index].push_back(m_output_descr->copy()); - } - } - dst.validate_and_infer_types(); -} bool op::v8::If::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const { @@ -277,41 +309,4 @@ Output op::v8::If::set_output(const std::shared_ptr& then_result, "in \'then_body\'!"); return set_body_outputs({then_result, else_result}); -} - -namespace -{ - ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, - const ngraph::PartialShape& else_pshape) - { - auto then_rank = then_pshape.rank(); - auto else_rank = else_pshape.rank(); - if (then_rank.is_dynamic() || else_rank.is_dynamic() || - then_rank.get_length() != else_rank.get_length()) - { - return ngraph::PartialShape::dynamic(ngraph::Rank::dynamic()); - } - std::vector new_dims; - for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); - then_it != then_pshape.cend(); - then_it++, else_it++) - { - if ((*then_it).is_dynamic() || (*else_it).is_dynamic()) - { - new_dims.push_back(Dimension::dynamic()); - } - else if (*then_it == *else_it) - { - new_dims.push_back(Dimension(*then_it)); - } - else - { - auto dim_min = std::min((*then_it).get_min_length(), (*else_it).get_min_length()); - auto dim_max = std::max((*then_it).get_min_length(), (*else_it).get_min_length()); - new_dims.push_back(Dimension(dim_min, dim_max)); - } - } - - return PartialShape(new_dims); - } -} // namespace \ No newline at end of file +} \ No newline at end of file From bdb648313a887d2052f587741a800200e5f39e16 Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 11 Aug 2021 09:17:06 +0300 Subject: [PATCH 09/30] Added ngraph checks and delete copied op from opset8 --- ngraph/core/include/ngraph/opsets/opset8_tbl.hpp | 1 - ngraph/core/reference/src/runtime/reference/if.cpp | 12 +++++------- ngraph/core/src/op/if.cpp | 10 ++++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ngraph/core/include/ngraph/opsets/opset8_tbl.hpp b/ngraph/core/include/ngraph/opsets/opset8_tbl.hpp index cecaccdaba84a4..3dbf735021e445 100644 --- a/ngraph/core/include/ngraph/opsets/opset8_tbl.hpp +++ b/ngraph/core/include/ngraph/opsets/opset8_tbl.hpp @@ -179,7 +179,6 @@ NGRAPH_OP(AdaptiveAvgPool, ngraph::op::v8) NGRAPH_OP(AdaptiveMaxPool, ngraph::op::v8) NGRAPH_OP(DeformableConvolution, ngraph::op::v8) NGRAPH_OP(MatrixNms, ngraph::op::v8) -NGRAPH_OP(MulticlassNms, ngraph::op::v8) NGRAPH_OP(MaxPool, ngraph::op::v8) NGRAPH_OP(MulticlassNms, ngraph::op::v8) NGRAPH_OP(RandomUniform, ngraph::op::v8) diff --git a/ngraph/core/reference/src/runtime/reference/if.cpp b/ngraph/core/reference/src/runtime/reference/if.cpp index 2d8f70e752de7c..18d8d5edab2dce 100644 --- a/ngraph/core/reference/src/runtime/reference/if.cpp +++ b/ngraph/core/reference/src/runtime/reference/if.cpp @@ -4,17 +4,14 @@ #include "ngraph/runtime/reference/if.hpp" #include "ngraph/runtime/reference/function.hpp" +#include "ngraph/op/if.hpp" + namespace ngraph { namespace runtime { namespace reference { - enum if_body_indexes - { - then_body_index = 0, - else_body_index = 1 - }; void if_reference( const std::vector>& bodies, const std::vector& out_descs, @@ -22,9 +19,10 @@ namespace ngraph const HostTensorVector& out, const HostTensorVector& args) { + NGRAPH_CHECK(args.size() > 0, "If operation must have input condition value"); auto condition_value = args[0]->get_data_ptr()[0]; - auto branch_index = (condition_value) ? if_body_indexes::then_body_index - : if_body_indexes::else_body_index; + auto branch_index = (condition_value) ? op::v8::If::then_body_index + : op::v8::If::else_body_index; HostTensorVector inputs_to_body; HostTensorVector outs_from_body; inputs_to_body.resize(input_descs[branch_index].size()); diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index ce269f56a7d7e0..6a35bc4b3fb576 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -30,17 +30,27 @@ op::v8::If::If(const Output& execution_condition) set_argument(0, execution_condition); } +// This function tries to calculate the output shape of the if operation by two outputs from two +// subgraphs. static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, const ngraph::PartialShape& else_pshape) { + // then_pshape - shape of output from then_body + // else_pshape - shape of output from else_body auto then_rank = then_pshape.rank(); auto else_rank = else_pshape.rank(); + // if rangs of shapes are not equal or rang of one of them is dynamic function + // return shape with dynamic rank if (then_rank.is_dynamic() || else_rank.is_dynamic() || then_rank.get_length() != else_rank.get_length()) { return ngraph::PartialShape::dynamic(ngraph::Rank::dynamic()); } std::vector new_dims; + + // If rangs are equal each dimesion of then_body output is union with each dimension of + // else_body + for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); then_it != then_pshape.cend(); then_it++, else_it++) From cfc70ccbcce91bd40e20aeb81bd04e1b59a3a638 Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 11 Aug 2021 09:21:19 +0300 Subject: [PATCH 10/30] code style fix --- ngraph/core/reference/src/runtime/reference/if.cpp | 7 ++++--- ngraph/core/src/op/if.cpp | 5 ++++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ngraph/core/reference/src/runtime/reference/if.cpp b/ngraph/core/reference/src/runtime/reference/if.cpp index 18d8d5edab2dce..4ce218cb35a2ff 100644 --- a/ngraph/core/reference/src/runtime/reference/if.cpp +++ b/ngraph/core/reference/src/runtime/reference/if.cpp @@ -3,8 +3,8 @@ // #include "ngraph/runtime/reference/if.hpp" -#include "ngraph/runtime/reference/function.hpp" #include "ngraph/op/if.hpp" +#include "ngraph/runtime/reference/function.hpp" namespace ngraph { @@ -20,9 +20,10 @@ namespace ngraph const HostTensorVector& args) { NGRAPH_CHECK(args.size() > 0, "If operation must have input condition value"); + auto condition_value = args[0]->get_data_ptr()[0]; - auto branch_index = (condition_value) ? op::v8::If::then_body_index - : op::v8::If::else_body_index; + auto branch_index = + (condition_value) ? op::v8::If::then_body_index : op::v8::If::else_body_index; HostTensorVector inputs_to_body; HostTensorVector outs_from_body; inputs_to_body.resize(input_descs[branch_index].size()); diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 6a35bc4b3fb576..3dff38e31328b6 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -35,10 +35,12 @@ op::v8::If::If(const Output& execution_condition) static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, const ngraph::PartialShape& else_pshape) { + // then_pshape - shape of output from then_body // else_pshape - shape of output from else_body auto then_rank = then_pshape.rank(); auto else_rank = else_pshape.rank(); + // if rangs of shapes are not equal or rang of one of them is dynamic function // return shape with dynamic rank if (then_rank.is_dynamic() || else_rank.is_dynamic() || @@ -50,7 +52,6 @@ static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshap // If rangs are equal each dimesion of then_body output is union with each dimension of // else_body - for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); then_it != then_pshape.cend(); then_it++, else_it++) @@ -133,6 +134,7 @@ void op::v8::If::validate_and_infer_types() // Trying to get cond as const value if (const auto& cond_value = get_constant_from_source(if_condition)) { + // If cond is const shape and inference is run for one of bodies another body is skipped auto val = cond_value->cast_vector(); NODE_VALIDATION_CHECK( @@ -159,6 +161,7 @@ void op::v8::If::validate_and_infer_types() } else // condition is non constant { + // If cond is non const, shape and type inference is run for both bodies validate_and_infer_type_body(get_then_body(), m_input_descriptions[then_body_index]); validate_and_infer_type_body(get_else_body(), m_input_descriptions[else_body_index]); From 9dc5741f8f8fa5abcab0d1c0720317f63203f62e Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 11 Aug 2021 09:41:04 +0300 Subject: [PATCH 11/30] fix code style --- ngraph/core/src/op/if.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 3dff38e31328b6..ea6626c4d13f5c 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -35,7 +35,6 @@ op::v8::If::If(const Output& execution_condition) static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, const ngraph::PartialShape& else_pshape) { - // then_pshape - shape of output from then_body // else_pshape - shape of output from else_body auto then_rank = then_pshape.rank(); @@ -134,7 +133,6 @@ void op::v8::If::validate_and_infer_types() // Trying to get cond as const value if (const auto& cond_value = get_constant_from_source(if_condition)) { - // If cond is const shape and inference is run for one of bodies another body is skipped auto val = cond_value->cast_vector(); NODE_VALIDATION_CHECK( @@ -161,7 +159,6 @@ void op::v8::If::validate_and_infer_types() } else // condition is non constant { - // If cond is non const, shape and type inference is run for both bodies validate_and_infer_type_body(get_then_body(), m_input_descriptions[then_body_index]); validate_and_infer_type_body(get_else_body(), m_input_descriptions[else_body_index]); From 8ea85d7d5632df2bfda7bb427019aa6d8e152994 Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 11 Aug 2021 11:46:00 +0300 Subject: [PATCH 12/30] add checkers to reference --- ngraph/core/reference/src/runtime/reference/if.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ngraph/core/reference/src/runtime/reference/if.cpp b/ngraph/core/reference/src/runtime/reference/if.cpp index 4ce218cb35a2ff..397f872ab022ec 100644 --- a/ngraph/core/reference/src/runtime/reference/if.cpp +++ b/ngraph/core/reference/src/runtime/reference/if.cpp @@ -27,14 +27,22 @@ namespace ngraph HostTensorVector inputs_to_body; HostTensorVector outs_from_body; inputs_to_body.resize(input_descs[branch_index].size()); + auto inputs_size = args.size(); + auto output_size = out.size(); for (const auto& input_desc : input_descs[branch_index]) { + NGRAPH_CHECK(inputs_size > input_desc->m_input_index, + "Incorrect associating! If has not input with id ", + input_desc->m_input_index); inputs_to_body[input_desc->m_body_parameter_index] = args[input_desc->m_input_index]; } reference::function(bodies[branch_index], inputs_to_body, outs_from_body); for (const auto& out_descr : out_descs[branch_index]) { + NGRAPH_CHECK(output_size > out_descr->m_output_index, + "Incorrect associating! If has not output with id ", + out_descr->m_output_index); auto res = outs_from_body[out_descr->m_body_value_index]; out[out_descr->m_output_index]->set_shape(res->get_shape()); out[out_descr->m_output_index]->write(res->get_data_ptr(), From 26f4c82d725168a495b50a278889f9256c5d0a0e Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 11 Aug 2021 21:19:48 +0300 Subject: [PATCH 13/30] add has_evaluate --- ngraph/core/include/ngraph/op/if.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index be6df62ca5be3f..7e5f0e5134e650 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -93,6 +93,8 @@ namespace ngraph bool evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const override; + bool has_evaluate() const override { return true; } + private: using OutputMap = std::map>; From ba1dc6c9ec31352422ec6095c978c7b9d064e354 Mon Sep 17 00:00:00 2001 From: evolosen Date: Thu, 12 Aug 2021 00:22:55 +0300 Subject: [PATCH 14/30] fix eval --- ngraph/core/include/ngraph/op/if.hpp | 3 ++- ngraph/core/src/op/if.cpp | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index 7e5f0e5134e650..3c1674bef07868 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -93,11 +93,12 @@ namespace ngraph bool evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const override; - bool has_evaluate() const override { return true; } + bool has_evaluate() const override; private: using OutputMap = std::map>; + void validate_and_infer_type_body( const std::shared_ptr& body, const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors); diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index ea6626c4d13f5c..7bc4503ffcf876 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -280,6 +280,12 @@ bool op::v8::If::evaluate(const HostTensorVector& outputs, const HostTensorVecto return true; } +bool op::v8::If::has_evaluate() const +{ + NGRAPH_OP_SCOPE(v8_If_has_evaluate); + return true; +} + void op::v8::If::set_input(const Output& value, const std::shared_ptr& then_parameter, const std::shared_ptr& else_parameter) From e2e9562f8d9bdbeb6b9668139c32667d623d7fd6 Mon Sep 17 00:00:00 2001 From: evolosen Date: Fri, 13 Aug 2021 09:59:09 +0300 Subject: [PATCH 15/30] Fix code style --- ngraph/core/include/ngraph/op/if.hpp | 182 ++++++++---------- .../include/ngraph/runtime/reference/if.hpp | 27 ++- .../reference/src/runtime/reference/if.cpp | 81 ++++---- ngraph/core/src/op/if.cpp | 169 ++++++---------- ngraph/test/op_eval/if_eval.cpp | 71 +++---- ngraph/test/type_prop/if.cpp | 82 +++----- 6 files changed, 239 insertions(+), 373 deletions(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index 3c1674bef07868..fed9d152a6fb0a 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -10,103 +10,85 @@ #include "ngraph/op/parameter.hpp" #include "ngraph/op/util/multi_subgraph_base.hpp" -namespace ngraph -{ - namespace op - { - namespace v8 - { - /// \brief If operation. - class NGRAPH_API If : public util::MultiSubGraphOp - { - public: - enum BodyIndexes - { - then_body_index = 0, - else_body_index = 1 - }; - - NGRAPH_RTTI_DECLARATION; - bool visit_attributes(AttributeVisitor& visitor) override; - - /// \brief Constructs If with condition - /// - /// \param execution_condition condition node. - If(const Output& execution_condition); - If(); - - std::shared_ptr - clone_with_new_inputs(const OutputVector& new_args) const override; - - /// \brief gets then_body as ngraph::Function. - /// - /// \return then_body as ngraph::Function. - const std::shared_ptr& get_then_body() const - { - return m_bodies[then_body_index]; - } - - /// \brief gets else_body as ngraph::Function. - /// - /// \return else_body as ngraph::Function. - const std::shared_ptr& get_else_body() const - { - return m_bodies[else_body_index]; - } - - /// \brief sets new ngraph::Function as new then_body. - /// - /// \param body new body for 'then' branch. - void set_then_body(const std::shared_ptr& body) - { - m_bodies[then_body_index] = body; - } - - /// \brief sets new ngraph::Function as new else_body. - /// - /// \param body new body for 'else' branch. - void set_else_body(const std::shared_ptr& body) - { - m_bodies[else_body_index] = body; - } - - /// \brief sets new input to the operation associated with parameters - /// of each sub-graphs - /// - /// \param value input to operation - /// \param then_parameter parameter for then_body or nullptr - /// \param else_parameter parameter for else_body or nullpt - void set_input(const Output& value, - const std::shared_ptr& then_parameter, - const std::shared_ptr& else_parameter); - - /// \brief sets new output from the operation associated with results - /// of each sub-graphs - /// - /// \param then_result result from then_body - /// \param else_parameter result from else_body - /// \return output from operation - Output set_output(const std::shared_ptr& then_result, - const std::shared_ptr& else_result); - - void validate_and_infer_types() override; - bool evaluate(const HostTensorVector& outputs, - const HostTensorVector& inputs) const override; - - bool has_evaluate() const override; - - private: - using OutputMap = - std::map>; - - void validate_and_infer_type_body( - const std::shared_ptr& body, - const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors); - - OutputMap get_mapping_outputs_on_body_description( - const ngraph::op::util::MultiSubgraphOutputDescriptionVector& - output_descriptors); - }; - } // namespace v8 - } // namespace op -} // namespace ngraph \ No newline at end of file +namespace ngraph { +namespace op { +namespace v8 { +/// \brief If operation. +class NGRAPH_API If : public util::MultiSubGraphOp { +public: + enum BodyIndexes { then_body_index = 0, else_body_index = 1 }; + + NGRAPH_RTTI_DECLARATION; + bool visit_attributes(AttributeVisitor& visitor) override; + + /// \brief Constructs If with condition + /// + /// \param execution_condition condition node. + If(const Output& execution_condition); + If(); + + std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; + + /// \brief gets then_body as ngraph::Function. + /// + /// \return then_body as ngraph::Function. + const std::shared_ptr& get_then_body() const { + return m_bodies[then_body_index]; + } + + /// \brief gets else_body as ngraph::Function. + /// + /// \return else_body as ngraph::Function. + const std::shared_ptr& get_else_body() const { + return m_bodies[else_body_index]; + } + + /// \brief sets new ngraph::Function as new then_body. + /// + /// \param body new body for 'then' branch. + void set_then_body(const std::shared_ptr& body) { + m_bodies[then_body_index] = body; + } + + /// \brief sets new ngraph::Function as new else_body. + /// + /// \param body new body for 'else' branch. + void set_else_body(const std::shared_ptr& body) { + m_bodies[else_body_index] = body; + } + + /// \brief sets new input to the operation associated with parameters + /// of each sub-graphs + /// + /// \param value input to operation + /// \param then_parameter parameter for then_body or nullptr + /// \param else_parameter parameter for else_body or nullpt + void set_input(const Output& value, + const std::shared_ptr& then_parameter, + const std::shared_ptr& else_parameter); + + /// \brief sets new output from the operation associated with results + /// of each sub-graphs + /// + /// \param then_result result from then_body + /// \param else_parameter result from else_body + /// \return output from operation + Output set_output(const std::shared_ptr& then_result, const std::shared_ptr& else_result); + + void validate_and_infer_types() override; + bool evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const override; + + bool has_evaluate() const override; + +private: + using OutputMap = std::map>; + + void validate_and_infer_type_body(const std::shared_ptr& body, + const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors); + + OutputMap get_mapping_outputs_on_body_description( + const ngraph::op::util::MultiSubgraphOutputDescriptionVector& output_descriptors); +}; +} // namespace v8 +} // namespace op +} // namespace ngraph \ No newline at end of file diff --git a/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp b/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp index ffb84c89bcc402..ccb098c9edfc87 100644 --- a/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp +++ b/ngraph/core/reference/include/ngraph/runtime/reference/if.hpp @@ -5,20 +5,17 @@ #pragma once #include + #include "ngraph/op/util/multi_subgraph_base.hpp" -namespace ngraph -{ - namespace runtime - { - namespace reference - { - void if_reference( - const std::vector>& body, - const std::vector& out_descs, - const std::vector& input_descs, - const HostTensorVector& out, - const HostTensorVector& args); - } - } // namespace runtime -} // namespace ngraph \ No newline at end of file +namespace ngraph { +namespace runtime { +namespace reference { +void if_reference(const std::vector>& body, + const std::vector& out_descs, + const std::vector& input_descs, + const HostTensorVector& out, + const HostTensorVector& args); +} +} // namespace runtime +} // namespace ngraph \ No newline at end of file diff --git a/ngraph/core/reference/src/runtime/reference/if.cpp b/ngraph/core/reference/src/runtime/reference/if.cpp index 397f872ab022ec..9b74a878c6483f 100644 --- a/ngraph/core/reference/src/runtime/reference/if.cpp +++ b/ngraph/core/reference/src/runtime/reference/if.cpp @@ -3,52 +3,43 @@ // #include "ngraph/runtime/reference/if.hpp" + #include "ngraph/op/if.hpp" #include "ngraph/runtime/reference/function.hpp" -namespace ngraph -{ - namespace runtime - { - namespace reference - { - void if_reference( - const std::vector>& bodies, - const std::vector& out_descs, - const std::vector& input_descs, - const HostTensorVector& out, - const HostTensorVector& args) - { - NGRAPH_CHECK(args.size() > 0, "If operation must have input condition value"); +namespace ngraph { +namespace runtime { +namespace reference { +void if_reference(const std::vector>& bodies, + const std::vector& out_descs, + const std::vector& input_descs, + const HostTensorVector& out, + const HostTensorVector& args) { + NGRAPH_CHECK(args.size() > 0, "If operation must have input condition value"); - auto condition_value = args[0]->get_data_ptr()[0]; - auto branch_index = - (condition_value) ? op::v8::If::then_body_index : op::v8::If::else_body_index; - HostTensorVector inputs_to_body; - HostTensorVector outs_from_body; - inputs_to_body.resize(input_descs[branch_index].size()); - auto inputs_size = args.size(); - auto output_size = out.size(); - for (const auto& input_desc : input_descs[branch_index]) - { - NGRAPH_CHECK(inputs_size > input_desc->m_input_index, - "Incorrect associating! If has not input with id ", - input_desc->m_input_index); - inputs_to_body[input_desc->m_body_parameter_index] = - args[input_desc->m_input_index]; - } - reference::function(bodies[branch_index], inputs_to_body, outs_from_body); - for (const auto& out_descr : out_descs[branch_index]) - { - NGRAPH_CHECK(output_size > out_descr->m_output_index, - "Incorrect associating! If has not output with id ", - out_descr->m_output_index); - auto res = outs_from_body[out_descr->m_body_value_index]; - out[out_descr->m_output_index]->set_shape(res->get_shape()); - out[out_descr->m_output_index]->write(res->get_data_ptr(), - res->get_size_in_bytes()); - } - } - } // namespace reference - } // namespace runtime -} // namespace ngraph \ No newline at end of file + auto condition_value = args[0]->get_data_ptr()[0]; + auto branch_index = (condition_value) ? op::v8::If::then_body_index : op::v8::If::else_body_index; + HostTensorVector inputs_to_body; + HostTensorVector outs_from_body; + inputs_to_body.resize(input_descs[branch_index].size()); + auto inputs_size = args.size(); + auto output_size = out.size(); + for (const auto& input_desc : input_descs[branch_index]) { + NGRAPH_CHECK(inputs_size > input_desc->m_input_index, + "Incorrect associating! If has not input with id ", + input_desc->m_input_index); + inputs_to_body[input_desc->m_body_parameter_index] = args[input_desc->m_input_index]; + } + reference::function(bodies[branch_index], inputs_to_body, outs_from_body); + for (const auto& out_descr : out_descs[branch_index]) { + NGRAPH_CHECK(output_size > out_descr->m_output_index, + "Incorrect associating! If has not output with id ", + out_descr->m_output_index); + auto res = outs_from_body[out_descr->m_body_value_index]; + out[out_descr->m_output_index]->set_shape(res->get_shape()); + out[out_descr->m_output_index]->write(res->get_data_ptr(), res->get_size_in_bytes()); + } +} +} // namespace reference +} // namespace runtime +} // namespace ngraph \ No newline at end of file diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index 7bc4503ffcf876..e27c22afbdf8e7 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -3,38 +3,33 @@ // #include "ngraph/op/if.hpp" + #include #include #include + #include "itt.hpp" #include "ngraph/factory.hpp" #include "ngraph/graph_util.hpp" #include "ngraph/op/util/multi_subgraph_base.hpp" -#include "ngraph/specialize_function.hpp" - #include "ngraph/runtime/reference/if.hpp" +#include "ngraph/specialize_function.hpp" using namespace std; using namespace ngraph; NGRAPH_RTTI_DEFINITION(ngraph::op::v8::If, "If", 8, MultiSubGraphOp); -op::v8::If::If() - : MultiSubGraphOp(2) -{ -} +op::v8::If::If() : MultiSubGraphOp(2) {} -op::v8::If::If(const Output& execution_condition) - : If() -{ +op::v8::If::If(const Output& execution_condition) : If() { set_argument(0, execution_condition); } // This function tries to calculate the output shape of the if operation by two outputs from two // subgraphs. static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshape, - const ngraph::PartialShape& else_pshape) -{ + const ngraph::PartialShape& else_pshape) { // then_pshape - shape of output from then_body // else_pshape - shape of output from else_body auto then_rank = then_pshape.rank(); @@ -42,29 +37,20 @@ static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshap // if rangs of shapes are not equal or rang of one of them is dynamic function // return shape with dynamic rank - if (then_rank.is_dynamic() || else_rank.is_dynamic() || - then_rank.get_length() != else_rank.get_length()) - { + if (then_rank.is_dynamic() || else_rank.is_dynamic() || then_rank.get_length() != else_rank.get_length()) { return ngraph::PartialShape::dynamic(ngraph::Rank::dynamic()); } std::vector new_dims; // If rangs are equal each dimesion of then_body output is union with each dimension of // else_body - for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); - then_it != then_pshape.cend(); - then_it++, else_it++) - { - if ((*then_it).is_dynamic() || (*else_it).is_dynamic()) - { + for (auto then_it = then_pshape.cbegin(), else_it = else_pshape.cbegin(); then_it != then_pshape.cend(); + then_it++, else_it++) { + if ((*then_it).is_dynamic() || (*else_it).is_dynamic()) { new_dims.push_back(Dimension::dynamic()); - } - else if (*then_it == *else_it) - { + } else if (*then_it == *else_it) { new_dims.push_back(Dimension(*then_it)); - } - else - { + } else { auto dim_min = std::min((*then_it).get_min_length(), (*else_it).get_min_length()); auto dim_max = std::max((*then_it).get_min_length(), (*else_it).get_min_length()); new_dims.push_back(Dimension(dim_min, dim_max)); @@ -74,13 +60,10 @@ static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshap return PartialShape(new_dims); } -bool op::v8::If::visit_attributes(AttributeVisitor& visitor) -{ +bool op::v8::If::visit_attributes(AttributeVisitor& visitor) { NGRAPH_OP_SCOPE(v8_If_visit_attributes); - m_bodies[then_body_index] = - std::make_shared(OutputVector{}, ParameterVector{}, "then_branch"); - m_bodies[else_body_index] = - std::make_shared(OutputVector{}, ParameterVector{}, "else_branch"); + m_bodies[then_body_index] = std::make_shared(OutputVector{}, ParameterVector{}, "then_branch"); + m_bodies[else_body_index] = std::make_shared(OutputVector{}, ParameterVector{}, "else_branch"); visitor.on_attribute("then_body", m_bodies[then_body_index]); visitor.on_attribute("else_body", m_bodies[else_body_index]); visitor.on_attribute("then_inputs", m_input_descriptions[then_body_index]); @@ -92,10 +75,8 @@ bool op::v8::If::visit_attributes(AttributeVisitor& visitor) void op::v8::If::validate_and_infer_type_body( const std::shared_ptr& body, - const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors) -{ - for (const auto& input_description : input_descriptors) - { + const ngraph::op::util::MultiSubgraphInputDescriptionVector& input_descriptors) { + for (const auto& input_description : input_descriptors) { auto index = input_description->m_input_index; auto body_parameter = body->get_parameters().at(input_description->m_body_parameter_index); @@ -105,12 +86,10 @@ void op::v8::If::validate_and_infer_type_body( body->validate_nodes_and_infer_types(); } -void op::v8::If::validate_and_infer_types() -{ +void op::v8::If::validate_and_infer_types() { NGRAPH_OP_SCOPE(v8_If_validate_and_infer_types); - NODE_VALIDATION_CHECK( - this, m_bodies.size() == 2, "If contains incorrect number of bodies:", m_bodies.size()); + NODE_VALIDATION_CHECK(this, m_bodies.size() == 2, "If contains incorrect number of bodies:", m_bodies.size()); NODE_VALIDATION_CHECK(this, m_input_descriptions.size() == 2, @@ -123,22 +102,19 @@ void op::v8::If::validate_and_infer_types() const auto& if_condition = input_value(0); const auto& if_condition_rank = if_condition.get_partial_shape().rank(); - if (if_condition_rank.is_static()) - { + if (if_condition_rank.is_static()) { NODE_VALIDATION_CHECK(this, if_condition_rank.compatible(1) || if_condition_rank.compatible(0), "Rank of If condition input must be equal to 0 or 1"); } // Trying to get cond as const value - if (const auto& cond_value = get_constant_from_source(if_condition)) - { + if (const auto& cond_value = get_constant_from_source(if_condition)) { // If cond is const shape and inference is run for one of bodies another body is skipped auto val = cond_value->cast_vector(); - NODE_VALIDATION_CHECK( - this, - val.size() == 1, - "The number of values in the If condition constant is greater than 1"); + NODE_VALIDATION_CHECK(this, + val.size() == 1, + "The number of values in the If condition constant is greater than 1"); auto cond_index = val[0] ? then_body_index : else_body_index; auto body = m_bodies[cond_index]; @@ -147,17 +123,12 @@ void op::v8::If::validate_and_infer_types() auto output_nodes = outputs(); // shape and type inference for outputs from If operations - for (const auto& output_descr : m_output_descriptions[cond_index]) - { - auto body_value = - body->get_results().at(output_descr->m_body_value_index)->input_value(0); + for (const auto& output_descr : m_output_descriptions[cond_index]) { + auto body_value = body->get_results().at(output_descr->m_body_value_index)->input_value(0); auto body_value_partial_shape = body_value.get_partial_shape(); - set_output_type(output_descr->m_output_index, - body_value.get_element_type(), - body_value_partial_shape); + set_output_type(output_descr->m_output_index, body_value.get_element_type(), body_value_partial_shape); } - } - else // condition is non constant + } else // condition is non constant { // If cond is non const, shape and type inference is run for both bodies validate_and_infer_type_body(get_then_body(), m_input_descriptions[then_body_index]); @@ -166,15 +137,12 @@ void op::v8::If::validate_and_infer_types() // Getting map. This map guarantees that each // output from the body will be met in it once. - auto then_outputs_map = - get_mapping_outputs_on_body_description(m_output_descriptions[then_body_index]); - auto else_outputs_map = - get_mapping_outputs_on_body_description(m_output_descriptions[else_body_index]); + auto then_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[then_body_index]); + auto else_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[else_body_index]); // Checking each output from If. Each output must be associated with one output from each // body - for (size_t output_index = 0; output_index < output_nodes.size(); ++output_index) - { + for (size_t output_index = 0; output_index < output_nodes.size(); ++output_index) { NODE_VALIDATION_CHECK(this, then_outputs_map.count(output_index) != 0, "Incorrect associating in then_body! Output ", @@ -189,55 +157,41 @@ void op::v8::If::validate_and_infer_types() auto then_desc = then_outputs_map.at(output_index); auto else_desc = else_outputs_map.at(output_index); - auto then_node_result = m_bodies[then_body_index] - ->get_results() - .at(then_desc->m_body_value_index) - ->input_value(0); + auto then_node_result = + m_bodies[then_body_index]->get_results().at(then_desc->m_body_value_index)->input_value(0); - auto else_node_result = m_bodies[else_body_index] - ->get_results() - .at(else_desc->m_body_value_index) - ->input_value(0); + auto else_node_result = + m_bodies[else_body_index]->get_results().at(else_desc->m_body_value_index)->input_value(0); NODE_VALIDATION_CHECK(this, - then_node_result.get_element_type() == - else_node_result.get_element_type(), + then_node_result.get_element_type() == else_node_result.get_element_type(), "type of then_body output is not equal type of else_body output"); // shape inference for output and associated with it body outputs - auto partial_shape = resolve_shape(then_node_result.get_partial_shape(), - else_node_result.get_partial_shape()); + auto partial_shape = + resolve_shape(then_node_result.get_partial_shape(), else_node_result.get_partial_shape()); set_output_type(output_index, then_node_result.get_element_type(), partial_shape); } } } -std::shared_ptr op::v8::If::clone_with_new_inputs(const OutputVector& new_args) const -{ +std::shared_ptr op::v8::If::clone_with_new_inputs(const OutputVector& new_args) const { NGRAPH_OP_SCOPE(v8_If_clone_with_new_inputs); check_new_args_count(this, new_args); auto op = make_shared(); - NGRAPH_CHECK(op.get(), - op != nullptr, - "Cannot clone ", - description(), - " operation with name ", - get_friendly_name()); + NGRAPH_CHECK(op.get(), op != nullptr, "Cannot clone ", description(), " operation with name ", get_friendly_name()); op->set_arguments(new_args); op->set_output_size(m_output_descriptions[0].size()); op->set_then_body(clone_function(*get_then_body())); op->set_else_body(clone_function(*get_else_body())); - for (auto body_index = 0; body_index < 2; ++body_index) - { - for (const auto& m_input_descr : m_input_descriptions[body_index]) - { + for (auto body_index = 0; body_index < 2; ++body_index) { + for (const auto& m_input_descr : m_input_descriptions[body_index]) { op->m_input_descriptions[body_index].push_back(m_input_descr->copy()); } - for (const auto& m_output_descr : m_output_descriptions[body_index]) - { + for (const auto& m_output_descr : m_output_descriptions[body_index]) { op->m_output_descriptions[body_index].push_back(m_output_descr->copy()); } } @@ -247,13 +201,11 @@ std::shared_ptr op::v8::If::clone_with_new_inputs(const OutputVector& new_ } op::v8::If::OutputMap op::v8::If::get_mapping_outputs_on_body_description( - const ngraph::op::util::MultiSubgraphOutputDescriptionVector& output_descriptors) -{ + const ngraph::op::util::MultiSubgraphOutputDescriptionVector& output_descriptors) { OutputMap outputs_map = OutputMap(); std::unordered_set checked_results_in_body; - for (const auto& output_description : output_descriptors) - { + for (const auto& output_description : output_descriptors) { auto out_index = output_description->m_output_index; auto internal_result_index = output_description->m_body_value_index; NODE_VALIDATION_CHECK(this, @@ -272,24 +224,20 @@ op::v8::If::OutputMap op::v8::If::get_mapping_outputs_on_body_description( return outputs_map; } -bool op::v8::If::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const -{ +bool op::v8::If::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const { NGRAPH_OP_SCOPE(v8_If_evaluate); - runtime::reference::if_reference( - m_bodies, m_output_descriptions, m_input_descriptions, outputs, inputs); + runtime::reference::if_reference(m_bodies, m_output_descriptions, m_input_descriptions, outputs, inputs); return true; } -bool op::v8::If::has_evaluate() const -{ +bool op::v8::If::has_evaluate() const { NGRAPH_OP_SCOPE(v8_If_has_evaluate); return true; } void op::v8::If::set_input(const Output& value, const std::shared_ptr& then_parameter, - const std::shared_ptr& else_parameter) -{ + const std::shared_ptr& else_parameter) { NGRAPH_CHECK(then_parameter != nullptr || else_parameter != nullptr, "Missing parameters! Both parameters are nullptr!"); auto then_param_index = m_bodies[then_body_index]->get_parameter_index(then_parameter); @@ -306,23 +254,14 @@ void op::v8::If::set_input(const Output& value, } Output op::v8::If::set_output(const std::shared_ptr& then_result, - const std::shared_ptr& else_result) -{ - NGRAPH_CHECK(then_result != nullptr, - "Incorrect result in \"then_body\"! Result cant be \'nullptr\'"); - NGRAPH_CHECK(else_result != nullptr, - "Incorrect result in \"else_body\"! Result cant be \'nullptr\'"); + const std::shared_ptr& else_result) { + NGRAPH_CHECK(then_result != nullptr, "Incorrect result in \"then_body\"! Result cant be \'nullptr\'"); + NGRAPH_CHECK(else_result != nullptr, "Incorrect result in \"else_body\"! Result cant be \'nullptr\'"); auto then_result_id = m_bodies[then_body_index]->get_result_index(then_result); auto else_result_id = m_bodies[else_body_index]->get_result_index(else_result); - NGRAPH_CHECK(then_result_id != -1, - "Missing result ", - then_result->get_friendly_name(), - "in \'then_body\'!"); - NGRAPH_CHECK(else_result_id != -1, - "Missing result ", - else_result->get_friendly_name(), - "in \'then_body\'!"); + NGRAPH_CHECK(then_result_id != -1, "Missing result ", then_result->get_friendly_name(), "in \'then_body\'!"); + NGRAPH_CHECK(else_result_id != -1, "Missing result ", else_result->get_friendly_name(), "in \'then_body\'!"); return set_body_outputs({then_result, else_result}); } \ No newline at end of file diff --git a/ngraph/test/op_eval/if_eval.cpp b/ngraph/test/op_eval/if_eval.cpp index 1d0192d57a3f23..41a1cb9424f30d 100644 --- a/ngraph/test/op_eval/if_eval.cpp +++ b/ngraph/test/op_eval/if_eval.cpp @@ -2,12 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 // +#include #include #include #include "gtest/gtest.h" - -#include #include "ngraph/opsets/opset1.hpp" #include "ngraph/opsets/opset5.hpp" #include "ngraph/opsets/opset8.hpp" @@ -19,8 +18,7 @@ using namespace std; using namespace ngraph; -TEST(op_eval, if_condition_const) -{ +TEST(op_eval, if_condition_const) { auto X = make_shared(element::f32, Shape{1, 2, 2}); auto Y = make_shared(element::f32, Shape{1, 2, 2}); auto cond = std::make_shared(element::boolean, Shape{1}, true); @@ -68,8 +66,7 @@ TEST(op_eval, if_condition_const) EXPECT_NEAR(result_data1[i], X_v[i], 0.000001); } -TEST(op_eval, if_condition_non_const) -{ +TEST(op_eval, if_condition_non_const) { auto X = make_shared(element::f32, Shape{1, 2, 2}); auto Y = make_shared(element::f32, Shape{1, 2, 2}); auto cond = make_shared(element::boolean, Shape{1}); @@ -84,10 +81,8 @@ TEST(op_eval, if_condition_non_const) auto else_op = std::make_shared(Xe, Ye); auto then_op_result = make_shared(then_op); auto else_op_result = make_shared(else_op); - auto then_body = - make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); - auto else_body = - make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto then_body = make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); if_op->set_else_body(else_body); @@ -122,8 +117,7 @@ TEST(op_eval, if_condition_non_const) EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); } -TEST(op_eval, if_free_sample) -{ +TEST(op_eval, if_free_sample) { auto cond = make_shared(element::boolean, Shape{1}); auto A = std::make_shared(element::f32, Shape{1}, 8.0); auto B = std::make_shared(element::f32, Shape{1}, 2.0); @@ -138,10 +132,8 @@ TEST(op_eval, if_free_sample) auto fun = make_shared(OutputVector{res}, ParameterVector{cond}); fun->validate_nodes_and_infer_types(); auto result1 = make_shared(), result2 = make_shared(); - ASSERT_TRUE( - fun->evaluate({result1}, {make_host_tensor(Shape{1}, {true})})); - ASSERT_TRUE( - fun->evaluate({result2}, {make_host_tensor(Shape{1}, {false})})); + ASSERT_TRUE(fun->evaluate({result1}, {make_host_tensor(Shape{1}, {true})})); + ASSERT_TRUE(fun->evaluate({result2}, {make_host_tensor(Shape{1}, {false})})); auto result_data1 = read_vector(result1); auto result_data2 = read_vector(result2); EXPECT_EQ(result1->get_element_type(), element::f32); @@ -152,8 +144,7 @@ TEST(op_eval, if_free_sample) EXPECT_NEAR(result_data2[0], 2.0, 0.000001); } -TEST(op_eval, if_constant_folding) -{ +TEST(op_eval, if_constant_folding) { auto cond = std::make_shared(element::boolean, Shape{1}, false); auto A1 = std::make_shared(element::f32, Shape{1}, 37.0); auto A2 = std::make_shared(element::f32, Shape{1}, 45.0); @@ -191,8 +182,7 @@ TEST(op_eval, if_constant_folding) EXPECT_NEAR(val[0], 1000.0, 0.000001); } -TEST(op_eval, if_dynamism) -{ +TEST(op_eval, if_dynamism) { auto X = make_shared(element::f32, Shape{1, 2, 2}); auto Y = make_shared(element::f32, Shape{4, 2, 2}); auto Z = make_shared(element::f32, Shape{8, 8, 8}); @@ -210,10 +200,10 @@ TEST(op_eval, if_dynamism) auto then_op_result2 = make_shared(Yt); auto else_op_result1 = make_shared(else_op); auto else_op_result2 = make_shared(Ze); - auto then_body = make_shared(OutputVector{then_op_result1, then_op_result2}, - ParameterVector{Xt, Yt}); - auto else_body = make_shared(OutputVector{else_op_result1, else_op_result2}, - ParameterVector{Xe, Ze}); + auto then_body = + make_shared(OutputVector{then_op_result1, then_op_result2}, ParameterVector{Xt, Yt}); + auto else_body = + make_shared(OutputVector{else_op_result1, else_op_result2}, ParameterVector{Xe, Ze}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); if_op->set_else_body(else_body); @@ -227,22 +217,17 @@ TEST(op_eval, if_dynamism) if_op->validate_and_infer_types(); std::vector X_v{1.0, 2.0, 3.0, 4.0}; std::vector Y_v, Z_v; - for (auto c_ind = 0; c_ind < 4; ++c_ind) - { - for (auto d_ind = 0; d_ind < 4; ++d_ind) - { + for (auto c_ind = 0; c_ind < 4; ++c_ind) { + for (auto d_ind = 0; d_ind < 4; ++d_ind) { Y_v.push_back(static_cast(c_ind * d_ind)); } } - for (auto c_ind = 0; c_ind < 8; ++c_ind) - { - for (auto d_ind = 0; d_ind < 64; ++d_ind) - { + for (auto c_ind = 0; c_ind < 8; ++c_ind) { + for (auto d_ind = 0; d_ind < 64; ++d_ind) { Z_v.push_back(static_cast(c_ind * d_ind)); } } - auto fun = - make_shared(OutputVector{result_if1, result_if2}, ParameterVector{cond, X, Y, Z}); + auto fun = make_shared(OutputVector{result_if1, result_if2}, ParameterVector{cond, X, Y, Z}); auto result1 = make_shared(); auto result2 = make_shared(); ASSERT_TRUE(fun->evaluate({result1, result2}, @@ -281,8 +266,7 @@ TEST(op_eval, if_dynamism) EXPECT_NEAR(result4_data[i], Z_v[i], 0.000001); } -TEST(op_eval, if_condition_non_const_scalar) -{ +TEST(op_eval, if_condition_non_const_scalar) { auto X = make_shared(element::f32, Shape{1, 2, 2}); auto Y = make_shared(element::f32, Shape{1, 2, 2}); auto cond = make_shared(element::boolean, Shape{}); @@ -297,10 +281,8 @@ TEST(op_eval, if_condition_non_const_scalar) auto else_op = std::make_shared(Xe, Ye); auto then_op_result = make_shared(then_op); auto else_op_result = make_shared(else_op); - auto then_body = - make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); - auto else_body = - make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto then_body = make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); if_op->set_else_body(else_body); @@ -334,8 +316,7 @@ TEST(op_eval, if_condition_non_const_scalar) for (auto i = 0; i < expected_results.size(); i++) EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); } -TEST(op_eval, if_condition_is_dynamic) -{ +TEST(op_eval, if_condition_is_dynamic) { auto X = make_shared(element::f32, Shape{1, 2, 2}); auto Y = make_shared(element::f32, Shape{1, 2, 2}); auto cond = make_shared(element::boolean, PartialShape{Dimension::dynamic()}); @@ -350,10 +331,8 @@ TEST(op_eval, if_condition_is_dynamic) auto else_op = std::make_shared(Xe, Ye); auto then_op_result = make_shared(then_op); auto else_op_result = make_shared(else_op); - auto then_body = - make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); - auto else_body = - make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto then_body = make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); if_op->set_else_body(else_body); diff --git a/ngraph/test/type_prop/if.cpp b/ngraph/test/type_prop/if.cpp index 44094110f1b2c2..d60d4890f1d961 100644 --- a/ngraph/test/type_prop/if.cpp +++ b/ngraph/test/type_prop/if.cpp @@ -11,13 +11,11 @@ using namespace std; using namespace ngraph; -TEST(type_prop, if_simple_test) -{ +TEST(type_prop, if_simple_test) { // That which we iterate over auto X = make_shared(element::f32, Shape{32, 40, 10}); auto Y = make_shared(element::f32, Shape{32, 40, 10}); - auto cond = std::make_shared( - ngraph::element::boolean, ngraph::Shape{1}, true); + auto cond = std::make_shared(ngraph::element::boolean, ngraph::Shape{1}, true); // Set up the cell body, a function from (Xi, Yi) -> (Zo) // Body parameters @@ -29,13 +27,11 @@ TEST(type_prop, if_simple_test) auto then_op = std::make_shared(Xt, Yt); auto then_op_res = std::make_shared(then_op); - auto then_body = - make_shared(OutputVector{then_op_res}, ParameterVector{Xt, Yt}); + auto then_body = make_shared(OutputVector{then_op_res}, ParameterVector{Xt, Yt}); auto else_op = std::make_shared(Xe, Ye); auto else_op_res = std::make_shared(else_op); - auto else_body = - make_shared(OutputVector{else_op_res}, ParameterVector{Xe, Ye}); + auto else_body = make_shared(OutputVector{else_op_res}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); if_op->set_else_body(else_body); @@ -50,8 +46,7 @@ TEST(type_prop, if_simple_test) EXPECT_EQ(sh, out0_shape); } -TEST(type_prop, if_non_const_condition_test) -{ +TEST(type_prop, if_non_const_condition_test) { // That which we iterate over auto X = make_shared(element::f32, Shape{32, 40, 10}); auto Y = make_shared(element::f32, Shape{32, 40, 10}); @@ -66,13 +61,11 @@ TEST(type_prop, if_non_const_condition_test) // Body auto then_op = std::make_shared(Xt, Yt); auto then_body_res = make_shared(then_op); - auto then_body = - make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); + auto then_body = make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); auto else_op = std::make_shared(Xe, Ye); auto else_body_res = make_shared(else_op); - auto else_body = - make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); + auto else_body = make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); @@ -87,8 +80,7 @@ TEST(type_prop, if_non_const_condition_test) EXPECT_EQ(sh, out0_shape); } -TEST(type_prop, if_clone_test) -{ +TEST(type_prop, if_clone_test) { auto X = make_shared(element::f32, Shape{32, 40, 10}); auto Y = make_shared(element::f32, Shape{32, 40, 10}); auto cond = make_shared(element::boolean, Shape{1}); @@ -104,12 +96,10 @@ TEST(type_prop, if_clone_test) // Body auto then_op = std::make_shared(Xt, Yt); auto then_body_res = make_shared(then_op); - auto then_body = - make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); + auto then_body = make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); auto else_op = std::make_shared(Xe, Ye); auto else_body_res = make_shared(else_op); - auto else_body = - make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); + auto else_body = make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); @@ -118,13 +108,11 @@ TEST(type_prop, if_clone_test) if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - auto new_if = std::dynamic_pointer_cast( - if_op->clone_with_new_inputs(OutputVector{cond, Xnew, Ynew})); + auto new_if = std::dynamic_pointer_cast(if_op->clone_with_new_inputs(OutputVector{cond, Xnew, Ynew})); EXPECT_EQ(true, true); } -TEST(type_prop, if_multiple_outputs) -{ +TEST(type_prop, if_multiple_outputs) { auto X = make_shared(element::f32, Shape{32, 40, 10}); auto Y = make_shared(element::f32, Shape{32, 40, 10}); auto cond = make_shared(element::boolean, Shape{1}); @@ -141,15 +129,16 @@ TEST(type_prop, if_multiple_outputs) auto then_op = std::make_shared(Xt, Yt); auto then_body_res_1 = make_shared(then_op); auto then_body_res_2 = make_shared(Xt); - auto then_body = make_shared(OutputVector{then_body_res_1, then_body_res_2}, - ParameterVector{Xt, Yt}); + auto then_body = + make_shared(OutputVector{then_body_res_1, then_body_res_2}, ParameterVector{Xt, Yt}); auto else_op = std::make_shared(Xe, Ye); - auto else_const = std::make_shared( - ngraph::element::f32, ngraph::Shape{1, 1, 1}, std::vector{0.5f}); + auto else_const = std::make_shared(ngraph::element::f32, + ngraph::Shape{1, 1, 1}, + std::vector{0.5f}); auto else_body_res_1 = make_shared(else_op); auto else_body_res_2 = make_shared(else_const); - auto else_body = make_shared(OutputVector{else_body_res_1, else_body_res_2}, - ParameterVector{Xe, Ye}); + auto else_body = + make_shared(OutputVector{else_body_res_1, else_body_res_2}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); @@ -168,8 +157,7 @@ TEST(type_prop, if_multiple_outputs) EXPECT_EQ(is_dynamic, true); } -TEST(type_prop, if_scalar_condition) -{ +TEST(type_prop, if_scalar_condition) { // That which we iterate over auto X = make_shared(element::f32, Shape{32, 40, 10}); auto Y = make_shared(element::f32, Shape{32, 40, 10}); @@ -184,13 +172,11 @@ TEST(type_prop, if_scalar_condition) // Body auto then_op = std::make_shared(Xt, Yt); auto then_body_res = make_shared(then_op); - auto then_body = - make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); + auto then_body = make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); auto else_op = std::make_shared(Xe, Ye); auto else_body_res = make_shared(else_op); - auto else_body = - make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); + auto else_body = make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); @@ -205,8 +191,7 @@ TEST(type_prop, if_scalar_condition) EXPECT_EQ(sh, out0_shape); } -TEST(type_prop, if_dynamic_output) -{ +TEST(type_prop, if_dynamic_output) { // That which we iterate over auto X_shape = Shape{1, 20, 5, 30}; auto Y_shape = Shape{18, 16, 14, 12}; @@ -221,13 +206,11 @@ TEST(type_prop, if_dynamic_output) // Body auto then_op = std::make_shared(Xt, Xt); auto then_body_res = make_shared(then_op); - auto then_body = - make_shared(OutputVector{then_body_res}, ParameterVector{Xt}); + auto then_body = make_shared(OutputVector{then_body_res}, ParameterVector{Xt}); auto else_op = std::make_shared(Ye, Ye); auto else_body_res = make_shared(else_op); - auto else_body = - make_shared(OutputVector{else_body_res}, ParameterVector{Ye}); + auto else_body = make_shared(OutputVector{else_body_res}, ParameterVector{Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); @@ -240,8 +223,7 @@ TEST(type_prop, if_dynamic_output) auto dynamic_shape = result0->get_output_partial_shape(0); EXPECT_EQ(X_shape.size(), dynamic_shape.rank().get_length()); - for (auto shape_index = 0; shape_index < X_shape.size(); shape_index++) - { + for (auto shape_index = 0; shape_index < X_shape.size(); shape_index++) { auto x_shape_it = X_shape.begin(); auto y_shape_it = Y_shape.begin(); auto res_it = dynamic_shape.begin(); @@ -253,8 +235,7 @@ TEST(type_prop, if_dynamic_output) } } -TEST(type_prop, if_dynamic_inputs) -{ +TEST(type_prop, if_dynamic_inputs) { // That which we iterate over auto X_shape = PartialShape{Dimension::dynamic(), Dimension::dynamic(), Dimension::dynamic()}; auto Y_shape = PartialShape{Dimension::dynamic(), 20, 30}; @@ -272,13 +253,11 @@ TEST(type_prop, if_dynamic_inputs) // Body auto then_op = std::make_shared(Xt, Yt); auto then_body_res = make_shared(then_op); - auto then_body = - make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); + auto then_body = make_shared(OutputVector{then_body_res}, ParameterVector{Xt, Yt}); auto else_op = std::make_shared(Xe, Ye); auto else_body_res = make_shared(else_op); - auto else_body = - make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); + auto else_body = make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); auto if_op = make_shared(cond); if_op->set_then_body(then_body); @@ -291,8 +270,7 @@ TEST(type_prop, if_dynamic_inputs) auto dynamic_shape = result0->get_output_partial_shape(0); auto expected_result = PartialShape{Dimension::dynamic(), 20, 30}; EXPECT_EQ(3, dynamic_shape.rank().get_length()); - for (auto dim_index = 0; dim_index < 3; dim_index++) - { + for (auto dim_index = 0; dim_index < 3; dim_index++) { auto exp_res_it = expected_result.begin(); auto res_it = dynamic_shape.begin(); EXPECT_EQ(*exp_res_it, *res_it); From c7b6a62063713091d4b3caf17215a4d6dafe5bfa Mon Sep 17 00:00:00 2001 From: evolosen Date: Fri, 13 Aug 2021 10:33:48 +0300 Subject: [PATCH 16/30] fix code style --- ngraph/core/include/ngraph/op/if.hpp | 10 ++--- .../reference/src/runtime/reference/if.cpp | 2 +- ngraph/core/src/op/if.cpp | 38 +++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/ngraph/core/include/ngraph/op/if.hpp b/ngraph/core/include/ngraph/op/if.hpp index fed9d152a6fb0a..32ed1d5b8467c1 100644 --- a/ngraph/core/include/ngraph/op/if.hpp +++ b/ngraph/core/include/ngraph/op/if.hpp @@ -16,7 +16,7 @@ namespace v8 { /// \brief If operation. class NGRAPH_API If : public util::MultiSubGraphOp { public: - enum BodyIndexes { then_body_index = 0, else_body_index = 1 }; + enum BodyIndexes { THEN_BODY_INDEX = 0, ELSE_BODY_INDEX = 1 }; NGRAPH_RTTI_DECLARATION; bool visit_attributes(AttributeVisitor& visitor) override; @@ -33,28 +33,28 @@ class NGRAPH_API If : public util::MultiSubGraphOp { /// /// \return then_body as ngraph::Function. const std::shared_ptr& get_then_body() const { - return m_bodies[then_body_index]; + return m_bodies[THEN_BODY_INDEX]; } /// \brief gets else_body as ngraph::Function. /// /// \return else_body as ngraph::Function. const std::shared_ptr& get_else_body() const { - return m_bodies[else_body_index]; + return m_bodies[ELSE_BODY_INDEX]; } /// \brief sets new ngraph::Function as new then_body. /// /// \param body new body for 'then' branch. void set_then_body(const std::shared_ptr& body) { - m_bodies[then_body_index] = body; + m_bodies[THEN_BODY_INDEX] = body; } /// \brief sets new ngraph::Function as new else_body. /// /// \param body new body for 'else' branch. void set_else_body(const std::shared_ptr& body) { - m_bodies[else_body_index] = body; + m_bodies[ELSE_BODY_INDEX] = body; } /// \brief sets new input to the operation associated with parameters diff --git a/ngraph/core/reference/src/runtime/reference/if.cpp b/ngraph/core/reference/src/runtime/reference/if.cpp index 9b74a878c6483f..e6dc5f83eef211 100644 --- a/ngraph/core/reference/src/runtime/reference/if.cpp +++ b/ngraph/core/reference/src/runtime/reference/if.cpp @@ -18,7 +18,7 @@ void if_reference(const std::vector>& bodies, NGRAPH_CHECK(args.size() > 0, "If operation must have input condition value"); auto condition_value = args[0]->get_data_ptr()[0]; - auto branch_index = (condition_value) ? op::v8::If::then_body_index : op::v8::If::else_body_index; + auto branch_index = (condition_value) ? op::v8::If::THEN_BODY_INDEX : op::v8::If::ELSE_BODY_INDEX; HostTensorVector inputs_to_body; HostTensorVector outs_from_body; inputs_to_body.resize(input_descs[branch_index].size()); diff --git a/ngraph/core/src/op/if.cpp b/ngraph/core/src/op/if.cpp index e27c22afbdf8e7..ea8c76d0c8e91a 100644 --- a/ngraph/core/src/op/if.cpp +++ b/ngraph/core/src/op/if.cpp @@ -62,14 +62,14 @@ static ngraph::PartialShape resolve_shape(const ngraph::PartialShape& then_pshap bool op::v8::If::visit_attributes(AttributeVisitor& visitor) { NGRAPH_OP_SCOPE(v8_If_visit_attributes); - m_bodies[then_body_index] = std::make_shared(OutputVector{}, ParameterVector{}, "then_branch"); - m_bodies[else_body_index] = std::make_shared(OutputVector{}, ParameterVector{}, "else_branch"); - visitor.on_attribute("then_body", m_bodies[then_body_index]); - visitor.on_attribute("else_body", m_bodies[else_body_index]); - visitor.on_attribute("then_inputs", m_input_descriptions[then_body_index]); - visitor.on_attribute("else_inputs", m_input_descriptions[else_body_index]); - visitor.on_attribute("then_outputs", m_output_descriptions[then_body_index]); - visitor.on_attribute("else_outputs", m_output_descriptions[else_body_index]); + m_bodies[THEN_BODY_INDEX] = std::make_shared(OutputVector{}, ParameterVector{}, "then_branch"); + m_bodies[ELSE_BODY_INDEX] = std::make_shared(OutputVector{}, ParameterVector{}, "else_branch"); + visitor.on_attribute("then_body", m_bodies[THEN_BODY_INDEX]); + visitor.on_attribute("else_body", m_bodies[ELSE_BODY_INDEX]); + visitor.on_attribute("then_inputs", m_input_descriptions[THEN_BODY_INDEX]); + visitor.on_attribute("else_inputs", m_input_descriptions[ELSE_BODY_INDEX]); + visitor.on_attribute("then_outputs", m_output_descriptions[THEN_BODY_INDEX]); + visitor.on_attribute("else_outputs", m_output_descriptions[ELSE_BODY_INDEX]); return true; } @@ -116,7 +116,7 @@ void op::v8::If::validate_and_infer_types() { val.size() == 1, "The number of values in the If condition constant is greater than 1"); - auto cond_index = val[0] ? then_body_index : else_body_index; + auto cond_index = val[0] ? THEN_BODY_INDEX : ELSE_BODY_INDEX; auto body = m_bodies[cond_index]; auto input_descriptors = m_input_descriptions[cond_index]; validate_and_infer_type_body(body, input_descriptors); @@ -131,14 +131,14 @@ void op::v8::If::validate_and_infer_types() { } else // condition is non constant { // If cond is non const, shape and type inference is run for both bodies - validate_and_infer_type_body(get_then_body(), m_input_descriptions[then_body_index]); - validate_and_infer_type_body(get_else_body(), m_input_descriptions[else_body_index]); + validate_and_infer_type_body(get_then_body(), m_input_descriptions[THEN_BODY_INDEX]); + validate_and_infer_type_body(get_else_body(), m_input_descriptions[ELSE_BODY_INDEX]); auto output_nodes = outputs(); // Getting map. This map guarantees that each // output from the body will be met in it once. - auto then_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[then_body_index]); - auto else_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[else_body_index]); + auto then_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[THEN_BODY_INDEX]); + auto else_outputs_map = get_mapping_outputs_on_body_description(m_output_descriptions[ELSE_BODY_INDEX]); // Checking each output from If. Each output must be associated with one output from each // body @@ -158,10 +158,10 @@ void op::v8::If::validate_and_infer_types() { auto else_desc = else_outputs_map.at(output_index); auto then_node_result = - m_bodies[then_body_index]->get_results().at(then_desc->m_body_value_index)->input_value(0); + m_bodies[THEN_BODY_INDEX]->get_results().at(then_desc->m_body_value_index)->input_value(0); auto else_node_result = - m_bodies[else_body_index]->get_results().at(else_desc->m_body_value_index)->input_value(0); + m_bodies[ELSE_BODY_INDEX]->get_results().at(else_desc->m_body_value_index)->input_value(0); NODE_VALIDATION_CHECK(this, then_node_result.get_element_type() == else_node_result.get_element_type(), @@ -240,8 +240,8 @@ void op::v8::If::set_input(const Output& value, const std::shared_ptr& else_parameter) { NGRAPH_CHECK(then_parameter != nullptr || else_parameter != nullptr, "Missing parameters! Both parameters are nullptr!"); - auto then_param_index = m_bodies[then_body_index]->get_parameter_index(then_parameter); - auto else_param_index = m_bodies[else_body_index]->get_parameter_index(else_parameter); + auto then_param_index = m_bodies[THEN_BODY_INDEX]->get_parameter_index(then_parameter); + auto else_param_index = m_bodies[ELSE_BODY_INDEX]->get_parameter_index(else_parameter); NGRAPH_CHECK(then_parameter == nullptr || then_param_index != -1, "Missing parameter ", then_parameter->get_friendly_name(), @@ -257,8 +257,8 @@ Output op::v8::If::set_output(const std::shared_ptr& then_result, const std::shared_ptr& else_result) { NGRAPH_CHECK(then_result != nullptr, "Incorrect result in \"then_body\"! Result cant be \'nullptr\'"); NGRAPH_CHECK(else_result != nullptr, "Incorrect result in \"else_body\"! Result cant be \'nullptr\'"); - auto then_result_id = m_bodies[then_body_index]->get_result_index(then_result); - auto else_result_id = m_bodies[else_body_index]->get_result_index(else_result); + auto then_result_id = m_bodies[THEN_BODY_INDEX]->get_result_index(then_result); + auto else_result_id = m_bodies[ELSE_BODY_INDEX]->get_result_index(else_result); NGRAPH_CHECK(then_result_id != -1, "Missing result ", then_result->get_friendly_name(), "in \'then_body\'!"); NGRAPH_CHECK(else_result_id != -1, "Missing result ", else_result->get_friendly_name(), "in \'then_body\'!"); From 4c2cb038162ebaf82dc907fb7a78aadbfbd3960b Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 18 Aug 2021 13:10:24 +0300 Subject: [PATCH 17/30] Add template plugin tests --- .../op_reference/base_reference_test.cpp | 1 + .../tests/functional/op_reference/if.cpp | 302 ++++++++++++++++++ ngraph/test/op_eval/if_eval.cpp | 177 +--------- 3 files changed, 304 insertions(+), 176 deletions(-) create mode 100644 docs/template_plugin/tests/functional/op_reference/if.cpp diff --git a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp index f2d2cf68aa39a2..a91ef4860ab32f 100644 --- a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp +++ b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp @@ -23,6 +23,7 @@ void CommonReferenceTest::Exec() { } void CommonReferenceTest::LoadNetwork() { + function->validate_nodes_and_infer_types(); InferenceEngine::CNNNetwork cnnNetwork(function); auto inputInfo = cnnNetwork.getInputsInfo(); auto outputInfo = cnnNetwork.getOutputsInfo(); diff --git a/docs/template_plugin/tests/functional/op_reference/if.cpp b/docs/template_plugin/tests/functional/op_reference/if.cpp new file mode 100644 index 00000000000000..e3b0b48af551e2 --- /dev/null +++ b/docs/template_plugin/tests/functional/op_reference/if.cpp @@ -0,0 +1,302 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include +#include +#include +#include +#include + +#include "base_reference_test.hpp" + +using namespace reference_tests; +using namespace ngraph; +using namespace InferenceEngine; + +struct IfFunctionalBase { + virtual std::shared_ptr create_function(const std::vector& if_inputs, + const std::vector& results) = 0; + IfFunctionalBase() {} +}; + +struct IfCondConst : public IfFunctionalBase { + std::shared_ptr create_function(const std::vector& if_inputs, + const std::vector& results) override { + NGRAPH_CHECK(if_inputs.size() == 2, "Incorrect test case! Number of inputs is not 2!"); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); + + auto X = std::make_shared(if_inputs[0].type, if_inputs[0].shape); + auto Y = std::make_shared(if_inputs[1].type, if_inputs[1].shape); + auto cond = std::make_shared(ngraph::element::boolean, Shape{1}, cond_value); + auto Xt = std::make_shared(if_inputs[0].type, PartialShape::dynamic()); + auto Yt = std::make_shared(if_inputs[1].type, PartialShape::dynamic()); + auto Xe = std::make_shared(if_inputs[0].type, PartialShape::dynamic()); + auto then_op = std::make_shared(Xt, Yt); + auto res0 = std::make_shared(then_op); + auto res1 = std::make_shared(Xe); + auto then_body = std::make_shared(OutputVector{res0}, ParameterVector{Xt, Yt}); + auto else_body = std::make_shared(OutputVector{res1}, ParameterVector{Xe}); + auto if_op = std::make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, nullptr); + auto result = if_op->set_output(res0, res1); + auto res = std::make_shared(result); + auto fun = std::make_shared(OutputVector{res}, ParameterVector{X, Y}); + return fun; + } + + IfCondConst(bool value) : cond_value(value) {} + bool cond_value; +}; + +struct IfCondIsNonConst : public IfFunctionalBase { + std::shared_ptr create_function(const std::vector& if_inputs, + const std::vector& results) override { + NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 3!"); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); + + auto X = std::make_shared(element::f32, Shape{1, 2, 2}); + auto Y = std::make_shared(element::f32, Shape{1, 2, 2}); + auto cond = std::make_shared(element::boolean, Shape{1}); + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = std::make_shared(element::f32, PartialShape::dynamic()); + auto Yt = std::make_shared(element::f32, PartialShape::dynamic()); + auto Xe = std::make_shared(element::f32, PartialShape::dynamic()); + auto Ye = std::make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto else_op = std::make_shared(Xe, Ye); + auto then_op_result = std::make_shared(then_op); + auto else_op_result = std::make_shared(else_op); + auto then_body = std::make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = std::make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto if_op = std::make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto result = if_op->set_output(then_op_result, else_op_result); + auto res = std::make_shared(result); + auto fun = std::make_shared(OutputVector{res}, ParameterVector{cond, X, Y}); + return fun; + } +}; + +struct IfWithoutAdditionalInputs : IfFunctionalBase { + std::shared_ptr create_function(const std::vector& if_inputs, + const std::vector& results) override { + NGRAPH_CHECK(if_inputs.size() == 1, "Incorrect test case! Number of inputs is not 1!"); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); + + auto cond = std::make_shared(element::boolean, Shape{1}); + auto A = std::make_shared(element::f32, Shape{1}, 8.0); + auto B = std::make_shared(element::f32, Shape{1}, 2.0); + auto A_res = std::make_shared(A); + auto B_res = std::make_shared(B); + auto then_body = std::make_shared(OutputVector{A_res}, ParameterVector{}); + auto else_body = std::make_shared(OutputVector{B_res}, ParameterVector{}); + auto if_op = std::make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + auto res = if_op->set_output(A_res, B_res); + auto fun = std::make_shared(OutputVector{res}, ParameterVector{cond}); + return fun; + } +}; + +struct IfDynamismCaseWithStaticInputs : public IfFunctionalBase { + std::shared_ptr create_function(const std::vector& if_inputs, + const std::vector& results) override { + NGRAPH_CHECK(if_inputs.size() == 4, "Incorrect test case! Number of inputs is not 4!"); + NGRAPH_CHECK(results.size() == 2, "Incorrect test case! Number of outputs is not 2!"); + + auto X = std::make_shared(element::f32, Shape{1, 2, 2}); + auto Y = std::make_shared(element::f32, Shape{4, 2, 2}); + auto Z = std::make_shared(element::f32, Shape{8, 8, 8}); + auto cond = std::make_shared(element::boolean, Shape{1}); + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = std::make_shared(element::f32, PartialShape::dynamic()); + auto Yt = std::make_shared(element::f32, PartialShape::dynamic()); + auto Xe = std::make_shared(element::f32, PartialShape::dynamic()); + auto Ze = std::make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Xt); + auto else_op = std::make_shared(Xe, Xe); + auto then_op_result1 = std::make_shared(then_op); + auto then_op_result2 = std::make_shared(Yt); + auto else_op_result1 = std::make_shared(else_op); + auto else_op_result2 = std::make_shared(Ze); + auto then_body = + std::make_shared(OutputVector{then_op_result1, then_op_result2}, ParameterVector{Xt, Yt}); + auto else_body = + std::make_shared(OutputVector{else_op_result1, else_op_result2}, ParameterVector{Xe, Ze}); + auto if_op = std::make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, nullptr); + if_op->set_input(Z, nullptr, Ze); + auto res1 = if_op->set_output(then_op_result1, else_op_result1); + auto res2 = if_op->set_output(then_op_result2, else_op_result2); + auto result_if1 = std::make_shared(res1); + auto result_if2 = std::make_shared(res2); + auto fun = std::make_shared(OutputVector{result_if1, result_if2}, ParameterVector{cond, X, Y, Z}); + return fun; + } +}; + +struct IfConditionIsScalar : public IfFunctionalBase { + std::shared_ptr create_function(const std::vector& if_inputs, + const std::vector& results) override { + NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 2!"); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); + + auto X = std::make_shared(element::f32, Shape{1, 2, 2}); + auto Y = std::make_shared(element::f32, Shape{1, 2, 2}); + auto cond = std::make_shared(element::boolean, Shape{}); + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = std::make_shared(element::f32, PartialShape::dynamic()); + auto Yt = std::make_shared(element::f32, PartialShape::dynamic()); + auto Xe = std::make_shared(element::f32, PartialShape::dynamic()); + auto Ye = std::make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto else_op = std::make_shared(Xe, Ye); + auto then_op_result = std::make_shared(then_op); + auto else_op_result = std::make_shared(else_op); + auto then_body = std::make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = std::make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto if_op = std::make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto res = if_op->set_output(then_op_result, else_op_result); + if_op->validate_and_infer_types(); + std::vector X_v{1.0, 2.0, 3.0, 4.0}; + std::vector Y_v{2.0, 1.0, 2.0, 3.0}; + auto fun = std::make_shared(OutputVector{res}, ParameterVector{cond, X, Y}); + return fun; + } +}; +struct IfParams { + IfParams(const std::shared_ptr& functional, + const std::vector& if_inputs, + const std::vector& expected_results, + const std::string& test_case_name) + : functional(functional), + inputs(if_inputs), + expected_results(expected_results), + test_case_name(test_case_name) {} + + std::vector inputs; + std::vector expected_results; + std::shared_ptr functional; + std::string test_case_name; +}; + +class ReferenceIfLayerTest : public testing::TestWithParam, public CommonReferenceTest { +public: + void SetUp() override { + auto params = GetParam(); + function = params.functional->create_function(params.inputs, params.expected_results); + inputData.reserve(params.inputs.size()); + refOutData.reserve(params.expected_results.size()); + for (auto& input_tensor : params.inputs) { + inputData.push_back(input_tensor.data); + } + for (auto& expected_tensor : params.expected_results) { + refOutData.push_back(expected_tensor.data); + } + } + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + auto param = obj.param; + return param.test_case_name; + } +}; + +std::vector y_gen() { + std::vector result; + for (auto c_ind = 0; c_ind < 4; ++c_ind) { + for (auto d_ind = 0; d_ind < 4; ++d_ind) { + result.push_back(static_cast(c_ind * d_ind)); + } + } + return result; +} + +std::vector z_gen() { + std::vector result; + for (auto c_ind = 0; c_ind < 8; ++c_ind) { + for (auto d_ind = 0; d_ind < 64; ++d_ind) { + result.push_back(static_cast(c_ind * d_ind)); + } + } + return result; +} +TEST_P(ReferenceIfLayerTest, IfWithHardcodedRefs) { + Exec(); +} + +INSTANTIATE_TEST_SUITE_P( + smoke_If_With_Hardcoded_Refs, + ReferenceIfLayerTest, + ::testing::Values( + IfParams( + std::make_shared(true), + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 1.0, 1.0, 1.0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 2.0, 2.0})}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 2.0, 2.0})}, + "if_condition_const_is_true"), + IfParams( + std::make_shared(false), + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 1.0, 1.0, 1.0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 2.0, 2.0})}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 1.0, 1.0, 1.0})}, + "if_condition_const_is_false"), + IfParams( + std::make_shared(), + std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{true}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 6.0, 12.0})}, + "if_condition_si_non_const_true"), + IfParams( + std::make_shared(), + std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{false}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{3.0, 3.0, 5.0, 7.0})}, + "if_condition_is_non_const_false"), + IfParams(std::make_shared(), + std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{true})}, + std::vector{Tensor(Shape{1}, ngraph::element::f32, std::vector{8.0})}, + "if_without_addition_inputs_condition_is_true"), + IfParams(std::make_shared(), + std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{false})}, + std::vector{Tensor(Shape{1}, ngraph::element::f32, std::vector{2.0})}, + "if_without_addition_inputs_condition_is_false"), + IfParams( + std::make_shared(), + std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{true}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 6.0, 12.0})}, + "if_condition_is_scalar_cond_true"), + IfParams( + std::make_shared(), + std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{false}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{3.0, 3.0, 5.0, 7.0})}, + "if_condition_is_scalar_cond_false") + )); diff --git a/ngraph/test/op_eval/if_eval.cpp b/ngraph/test/op_eval/if_eval.cpp index 41a1cb9424f30d..800746d08e116c 100644 --- a/ngraph/test/op_eval/if_eval.cpp +++ b/ngraph/test/op_eval/if_eval.cpp @@ -18,132 +18,7 @@ using namespace std; using namespace ngraph; -TEST(op_eval, if_condition_const) { - auto X = make_shared(element::f32, Shape{1, 2, 2}); - auto Y = make_shared(element::f32, Shape{1, 2, 2}); - auto cond = std::make_shared(element::boolean, Shape{1}, true); - auto cond2 = std::make_shared(element::boolean, Shape{1}, false); - auto Xt = make_shared(element::f32, PartialShape::dynamic()); - auto Yt = make_shared(element::f32, PartialShape::dynamic()); - auto Xe = make_shared(element::f32, PartialShape::dynamic()); - auto Ye = make_shared(element::f32, PartialShape::dynamic()); - auto then_op = std::make_shared(Xt, Yt); - auto res0 = make_shared(then_op); - auto res1 = make_shared(Xe); - auto then_body = make_shared(OutputVector{res0}, ParameterVector{Xt, Yt}); - auto else_body = make_shared(OutputVector{res1}, ParameterVector{Xe}); - auto if_op = make_shared(cond); - if_op->set_then_body(then_body); - if_op->set_else_body(else_body); - if_op->set_input(X, Xt, Xe); - if_op->set_input(Y, Yt, nullptr); - if_op->set_output(res0, res1); - if_op->validate_and_infer_types(); - auto if_op2 = if_op->clone_with_new_inputs(OutputVector{cond2, X, Y}); - std::vector X_v{1.0, 1.0, 1.0, 1.0}; - std::vector Y_v{2.0, 2.0, 2.0, 2.0}; - auto fun = make_shared(OutputVector{if_op}, ParameterVector{X, Y}); - auto fun2 = make_shared(OutputVector{if_op2}, ParameterVector{X, Y}); - auto result = make_shared(); - ASSERT_TRUE(fun->evaluate({result}, - {make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{1, 2, 2}, Y_v)})); - EXPECT_EQ(result->get_element_type(), element::f32); - EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); - auto result_data = read_vector(result); - std::vector expected_results{2.0, 2.0, 2.0, 2.0}; - for (auto i = 0; i < expected_results.size(); i++) - EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); - - auto result1 = make_shared(); - ASSERT_TRUE(fun2->evaluate({result1}, - {make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{1, 2, 2}, Y_v)})); - EXPECT_EQ(result1->get_element_type(), element::f32); - EXPECT_EQ(result1->get_shape(), Shape{std::vector({1, 2, 2})}); - auto result_data1 = read_vector(result1); - for (auto i = 0; i < expected_results.size(); i++) - EXPECT_NEAR(result_data1[i], X_v[i], 0.000001); -} - -TEST(op_eval, if_condition_non_const) { - auto X = make_shared(element::f32, Shape{1, 2, 2}); - auto Y = make_shared(element::f32, Shape{1, 2, 2}); - auto cond = make_shared(element::boolean, Shape{1}); - // Set up the cell body, a function from (Xi, Yi) -> (Zo) - // Body parameters - auto Xt = make_shared(element::f32, PartialShape::dynamic()); - auto Yt = make_shared(element::f32, PartialShape::dynamic()); - auto Xe = make_shared(element::f32, PartialShape::dynamic()); - auto Ye = make_shared(element::f32, PartialShape::dynamic()); - // Body - auto then_op = std::make_shared(Xt, Yt); - auto else_op = std::make_shared(Xe, Ye); - auto then_op_result = make_shared(then_op); - auto else_op_result = make_shared(else_op); - auto then_body = make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); - auto else_body = make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); - auto if_op = make_shared(cond); - if_op->set_then_body(then_body); - if_op->set_else_body(else_body); - if_op->set_input(X, Xt, Xe); - if_op->set_input(Y, Yt, Ye); - if_op->set_output(then_op_result, else_op_result); - if_op->validate_and_infer_types(); - std::vector X_v{1.0, 2.0, 3.0, 4.0}; - std::vector Y_v{2.0, 1.0, 2.0, 3.0}; - auto fun = make_shared(OutputVector{if_op}, ParameterVector{cond, X, Y}); - auto result = make_shared(); - ASSERT_TRUE(fun->evaluate({result}, - {make_host_tensor(Shape{1}, {true}), - make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{1, 2, 2}, Y_v)})); - EXPECT_EQ(result->get_element_type(), element::f32); - EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); - auto result_data = read_vector(result); - std::vector expected_results{2.0, 2.0, 6.0, 12.0}; - for (auto i = 0; i < expected_results.size(); i++) - EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); - ASSERT_TRUE(fun->evaluate({result}, - {make_host_tensor(Shape{1}, {false}), - make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{1, 2, 2}, Y_v)})); - EXPECT_EQ(result->get_element_type(), element::f32); - EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); - result_data = read_vector(result); - expected_results = {3.0, 3.0, 5.0, 7.0}; - - for (auto i = 0; i < expected_results.size(); i++) - EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); -} - -TEST(op_eval, if_free_sample) { - auto cond = make_shared(element::boolean, Shape{1}); - auto A = std::make_shared(element::f32, Shape{1}, 8.0); - auto B = std::make_shared(element::f32, Shape{1}, 2.0); - auto A_res = std::make_shared(A); - auto B_res = std::make_shared(B); - auto then_body = make_shared(OutputVector{A_res}, ParameterVector{}); - auto else_body = make_shared(OutputVector{B_res}, ParameterVector{}); - auto if_op = make_shared(cond); - if_op->set_then_body(then_body); - if_op->set_else_body(else_body); - auto res = if_op->set_output(A_res, B_res); - auto fun = make_shared(OutputVector{res}, ParameterVector{cond}); - fun->validate_nodes_and_infer_types(); - auto result1 = make_shared(), result2 = make_shared(); - ASSERT_TRUE(fun->evaluate({result1}, {make_host_tensor(Shape{1}, {true})})); - ASSERT_TRUE(fun->evaluate({result2}, {make_host_tensor(Shape{1}, {false})})); - auto result_data1 = read_vector(result1); - auto result_data2 = read_vector(result2); - EXPECT_EQ(result1->get_element_type(), element::f32); - EXPECT_EQ(result1->get_shape(), Shape{std::vector({1})}); - EXPECT_EQ(result2->get_element_type(), element::f32); - EXPECT_EQ(result2->get_shape(), Shape{std::vector({1})}); - EXPECT_NEAR(result_data1[0], 8.0, 0.000001); - EXPECT_NEAR(result_data2[0], 2.0, 0.000001); -} - +// Move these tests when dynamism will be support in template plugin TEST(op_eval, if_constant_folding) { auto cond = std::make_shared(element::boolean, Shape{1}, false); auto A1 = std::make_shared(element::f32, Shape{1}, 37.0); @@ -266,56 +141,6 @@ TEST(op_eval, if_dynamism) { EXPECT_NEAR(result4_data[i], Z_v[i], 0.000001); } -TEST(op_eval, if_condition_non_const_scalar) { - auto X = make_shared(element::f32, Shape{1, 2, 2}); - auto Y = make_shared(element::f32, Shape{1, 2, 2}); - auto cond = make_shared(element::boolean, Shape{}); - // Set up the cell body, a function from (Xi, Yi) -> (Zo) - // Body parameters - auto Xt = make_shared(element::f32, PartialShape::dynamic()); - auto Yt = make_shared(element::f32, PartialShape::dynamic()); - auto Xe = make_shared(element::f32, PartialShape::dynamic()); - auto Ye = make_shared(element::f32, PartialShape::dynamic()); - // Body - auto then_op = std::make_shared(Xt, Yt); - auto else_op = std::make_shared(Xe, Ye); - auto then_op_result = make_shared(then_op); - auto else_op_result = make_shared(else_op); - auto then_body = make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); - auto else_body = make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); - auto if_op = make_shared(cond); - if_op->set_then_body(then_body); - if_op->set_else_body(else_body); - if_op->set_input(X, Xt, Xe); - if_op->set_input(Y, Yt, Ye); - if_op->set_output(then_op_result, else_op_result); - if_op->validate_and_infer_types(); - std::vector X_v{1.0, 2.0, 3.0, 4.0}; - std::vector Y_v{2.0, 1.0, 2.0, 3.0}; - auto fun = make_shared(OutputVector{if_op}, ParameterVector{cond, X, Y}); - auto result = make_shared(); - ASSERT_TRUE(fun->evaluate({result}, - {make_host_tensor(Shape{1}, {true}), - make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{1, 2, 2}, Y_v)})); - EXPECT_EQ(result->get_element_type(), element::f32); - EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); - auto result_data = read_vector(result); - std::vector expected_results{2.0, 2.0, 6.0, 12.0}; - for (auto i = 0; i < expected_results.size(); i++) - EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); - ASSERT_TRUE(fun->evaluate({result}, - {make_host_tensor(Shape{1}, {false}), - make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{1, 2, 2}, Y_v)})); - EXPECT_EQ(result->get_element_type(), element::f32); - EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); - result_data = read_vector(result); - expected_results = {3.0, 3.0, 5.0, 7.0}; - - for (auto i = 0; i < expected_results.size(); i++) - EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); -} TEST(op_eval, if_condition_is_dynamic) { auto X = make_shared(element::f32, Shape{1, 2, 2}); auto Y = make_shared(element::f32, Shape{1, 2, 2}); From 212cd960c21f0372d3fd4648203ae67faee7fdb7 Mon Sep 17 00:00:00 2001 From: evolosen Date: Thu, 19 Aug 2021 12:41:37 +0300 Subject: [PATCH 18/30] fix code style --- docs/template_plugin/tests/functional/op_reference/if.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/template_plugin/tests/functional/op_reference/if.cpp b/docs/template_plugin/tests/functional/op_reference/if.cpp index e3b0b48af551e2..7e9c848286023b 100644 --- a/docs/template_plugin/tests/functional/op_reference/if.cpp +++ b/docs/template_plugin/tests/functional/op_reference/if.cpp @@ -156,7 +156,7 @@ struct IfDynamismCaseWithStaticInputs : public IfFunctionalBase { struct IfConditionIsScalar : public IfFunctionalBase { std::shared_ptr create_function(const std::vector& if_inputs, const std::vector& results) override { - NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 2!"); + NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 3!"); NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); auto X = std::make_shared(element::f32, Shape{1, 2, 2}); @@ -298,5 +298,4 @@ INSTANTIATE_TEST_SUITE_P( Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{3.0, 3.0, 5.0, 7.0})}, - "if_condition_is_scalar_cond_false") - )); + "if_condition_is_scalar_cond_false"))); From 5e4d3a7f763c343671445b6f7b8597eb5d6e9188 Mon Sep 17 00:00:00 2001 From: evolosen Date: Thu, 19 Aug 2021 13:42:34 +0300 Subject: [PATCH 19/30] delete boolean --- .../tests/functional/op_reference/if.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/template_plugin/tests/functional/op_reference/if.cpp b/docs/template_plugin/tests/functional/op_reference/if.cpp index 7e9c848286023b..eec5e5510835b1 100644 --- a/docs/template_plugin/tests/functional/op_reference/if.cpp +++ b/docs/template_plugin/tests/functional/op_reference/if.cpp @@ -265,36 +265,36 @@ INSTANTIATE_TEST_SUITE_P( "if_condition_const_is_false"), IfParams( std::make_shared(), - std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{true}), + std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{1}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 6.0, 12.0})}, "if_condition_si_non_const_true"), IfParams( std::make_shared(), - std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{false}), + std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{3.0, 3.0, 5.0, 7.0})}, "if_condition_is_non_const_false"), IfParams(std::make_shared(), - std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{true})}, + std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{1})}, std::vector{Tensor(Shape{1}, ngraph::element::f32, std::vector{8.0})}, "if_without_addition_inputs_condition_is_true"), IfParams(std::make_shared(), - std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{false})}, + std::vector{Tensor(Shape{1}, ngraph::element::boolean, std::vector{0})}, std::vector{Tensor(Shape{1}, ngraph::element::f32, std::vector{2.0})}, "if_without_addition_inputs_condition_is_false"), IfParams( std::make_shared(), - std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{true}), + std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{1}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 6.0, 12.0})}, "if_condition_is_scalar_cond_true"), IfParams( std::make_shared(), - std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{false}), + std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{3.0, 3.0, 5.0, 7.0})}, From 1c68c62ce81e9ea0cb2446459061c006e25e59ca Mon Sep 17 00:00:00 2001 From: evolosen Date: Fri, 20 Aug 2021 10:18:21 +0300 Subject: [PATCH 20/30] fix IfParams --- docs/template_plugin/tests/functional/op_reference/if.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/template_plugin/tests/functional/op_reference/if.cpp b/docs/template_plugin/tests/functional/op_reference/if.cpp index eec5e5510835b1..9202c05bfbc6e3 100644 --- a/docs/template_plugin/tests/functional/op_reference/if.cpp +++ b/docs/template_plugin/tests/functional/op_reference/if.cpp @@ -188,19 +188,20 @@ struct IfConditionIsScalar : public IfFunctionalBase { return fun; } }; + struct IfParams { IfParams(const std::shared_ptr& functional, const std::vector& if_inputs, const std::vector& expected_results, const std::string& test_case_name) - : functional(functional), + : function(functional), inputs(if_inputs), expected_results(expected_results), test_case_name(test_case_name) {} + std::shared_ptr function; std::vector inputs; std::vector expected_results; - std::shared_ptr functional; std::string test_case_name; }; @@ -208,7 +209,7 @@ class ReferenceIfLayerTest : public testing::TestWithParam, public Com public: void SetUp() override { auto params = GetParam(); - function = params.functional->create_function(params.inputs, params.expected_results); + function = params.function->create_function(params.inputs, params.expected_results); inputData.reserve(params.inputs.size()); refOutData.reserve(params.expected_results.size()); for (auto& input_tensor : params.inputs) { From 603533dfe97248bccb5bd0c0819a0407c8b6a57c Mon Sep 17 00:00:00 2001 From: evolosen Date: Tue, 7 Sep 2021 13:03:40 +0300 Subject: [PATCH 21/30] Fix comments --- .../tests/functional/op_reference/if.cpp | 41 +++++-------------- ngraph/test/op_eval/if_eval.cpp | 2 +- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/docs/template_plugin/tests/functional/op_reference/if.cpp b/docs/template_plugin/tests/functional/op_reference/if.cpp index 9202c05bfbc6e3..2346f9ed3dcc4a 100644 --- a/docs/template_plugin/tests/functional/op_reference/if.cpp +++ b/docs/template_plugin/tests/functional/op_reference/if.cpp @@ -26,8 +26,8 @@ struct IfFunctionalBase { struct IfCondConst : public IfFunctionalBase { std::shared_ptr create_function(const std::vector& if_inputs, const std::vector& results) override { - NGRAPH_CHECK(if_inputs.size() == 2, "Incorrect test case! Number of inputs is not 2!"); - NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); + NGRAPH_CHECK(if_inputs.size() == 2, "Incorrect test case! Number of inputs is not 2."); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1."); auto X = std::make_shared(if_inputs[0].type, if_inputs[0].shape); auto Y = std::make_shared(if_inputs[1].type, if_inputs[1].shape); @@ -51,15 +51,15 @@ struct IfCondConst : public IfFunctionalBase { return fun; } - IfCondConst(bool value) : cond_value(value) {} + explicit IfCondConst(bool value) : cond_value(value) {} bool cond_value; }; struct IfCondIsNonConst : public IfFunctionalBase { std::shared_ptr create_function(const std::vector& if_inputs, const std::vector& results) override { - NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 3!"); - NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); + NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 3."); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1."); auto X = std::make_shared(element::f32, Shape{1, 2, 2}); auto Y = std::make_shared(element::f32, Shape{1, 2, 2}); @@ -92,8 +92,8 @@ struct IfCondIsNonConst : public IfFunctionalBase { struct IfWithoutAdditionalInputs : IfFunctionalBase { std::shared_ptr create_function(const std::vector& if_inputs, const std::vector& results) override { - NGRAPH_CHECK(if_inputs.size() == 1, "Incorrect test case! Number of inputs is not 1!"); - NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); + NGRAPH_CHECK(if_inputs.size() == 1, "Incorrect test case! Number of inputs is not 1."); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1."); auto cond = std::make_shared(element::boolean, Shape{1}); auto A = std::make_shared(element::f32, Shape{1}, 8.0); @@ -114,8 +114,8 @@ struct IfWithoutAdditionalInputs : IfFunctionalBase { struct IfDynamismCaseWithStaticInputs : public IfFunctionalBase { std::shared_ptr create_function(const std::vector& if_inputs, const std::vector& results) override { - NGRAPH_CHECK(if_inputs.size() == 4, "Incorrect test case! Number of inputs is not 4!"); - NGRAPH_CHECK(results.size() == 2, "Incorrect test case! Number of outputs is not 2!"); + NGRAPH_CHECK(if_inputs.size() == 4, "Incorrect test case! Number of inputs is not 4."); + NGRAPH_CHECK(results.size() == 2, "Incorrect test case! Number of outputs is not 2."); auto X = std::make_shared(element::f32, Shape{1, 2, 2}); auto Y = std::make_shared(element::f32, Shape{4, 2, 2}); @@ -156,8 +156,8 @@ struct IfDynamismCaseWithStaticInputs : public IfFunctionalBase { struct IfConditionIsScalar : public IfFunctionalBase { std::shared_ptr create_function(const std::vector& if_inputs, const std::vector& results) override { - NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 3!"); - NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1!"); + NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 3."); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1."); auto X = std::make_shared(element::f32, Shape{1, 2, 2}); auto Y = std::make_shared(element::f32, Shape{1, 2, 2}); @@ -225,25 +225,6 @@ class ReferenceIfLayerTest : public testing::TestWithParam, public Com } }; -std::vector y_gen() { - std::vector result; - for (auto c_ind = 0; c_ind < 4; ++c_ind) { - for (auto d_ind = 0; d_ind < 4; ++d_ind) { - result.push_back(static_cast(c_ind * d_ind)); - } - } - return result; -} - -std::vector z_gen() { - std::vector result; - for (auto c_ind = 0; c_ind < 8; ++c_ind) { - for (auto d_ind = 0; d_ind < 64; ++d_ind) { - result.push_back(static_cast(c_ind * d_ind)); - } - } - return result; -} TEST_P(ReferenceIfLayerTest, IfWithHardcodedRefs) { Exec(); } diff --git a/ngraph/test/op_eval/if_eval.cpp b/ngraph/test/op_eval/if_eval.cpp index 800746d08e116c..f7ee7f4f5fe81d 100644 --- a/ngraph/test/op_eval/if_eval.cpp +++ b/ngraph/test/op_eval/if_eval.cpp @@ -18,7 +18,7 @@ using namespace std; using namespace ngraph; -// Move these tests when dynamism will be support in template plugin +// Move these tests when dynamism will be supported in the template plugin TEST(op_eval, if_constant_folding) { auto cond = std::make_shared(element::boolean, Shape{1}, false); auto A1 = std::make_shared(element::f32, Shape{1}, 37.0); From a232a9494984772a9d3e3769e98d6286ed2aade0 Mon Sep 17 00:00:00 2001 From: evolosen Date: Tue, 28 Sep 2021 15:31:58 +0300 Subject: [PATCH 22/30] intermediate commit --- .../tests/functional/op_reference/if.cpp | 81 +++++++++++++++++- ngraph/test/op_eval/if_eval.cpp | 84 ------------------- 2 files changed, 80 insertions(+), 85 deletions(-) diff --git a/docs/template_plugin/tests/functional/op_reference/if.cpp b/docs/template_plugin/tests/functional/op_reference/if.cpp index 2346f9ed3dcc4a..c8366134ba81ce 100644 --- a/docs/template_plugin/tests/functional/op_reference/if.cpp +++ b/docs/template_plugin/tests/functional/op_reference/if.cpp @@ -189,6 +189,42 @@ struct IfConditionIsScalar : public IfFunctionalBase { } }; + +struct IfConditionIsDynamic : public IfFunctionalBase { + std::shared_ptr create_function(const std::vector& if_inputs, + const std::vector& results) override { + NGRAPH_CHECK(if_inputs.size() == 3, "Incorrect test case! Number of inputs is not 3."); + NGRAPH_CHECK(results.size() == 1, "Incorrect test case! Number of outputs is not 1."); + + auto X = std::make_shared(element::f32, Shape{1, 2, 2}); + auto Y = std::make_shared(element::f32, Shape{1, 2, 2}); + auto cond = std::make_shared(element::boolean, PartialShape{Dimension::dynamic()}); + //auto cond = std::make_shared(element::boolean, Shape{1}); + // Set up the cell body, a function from (Xi, Yi) -> (Zo) + // Body parameters + auto Xt = std::make_shared(element::f32, PartialShape::dynamic()); + auto Yt = std::make_shared(element::f32, PartialShape::dynamic()); + auto Xe = std::make_shared(element::f32, PartialShape::dynamic()); + auto Ye = std::make_shared(element::f32, PartialShape::dynamic()); + // Body + auto then_op = std::make_shared(Xt, Yt); + auto else_op = std::make_shared(Xe, Ye); + auto then_op_result = std::make_shared(then_op); + auto else_op_result = std::make_shared(else_op); + auto then_body = std::make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); + auto else_body = std::make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); + auto if_op = std::make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(X, Xt, Xe); + if_op->set_input(Y, Yt, Ye); + auto rs = if_op->set_output(then_op_result, else_op_result); + auto result = std::make_shared(rs); + auto fun = std::make_shared(OutputVector{result}, ParameterVector{cond, X, Y}); + return fun; + } +}; + struct IfParams { IfParams(const std::shared_ptr& functional, const std::vector& if_inputs, @@ -228,6 +264,24 @@ class ReferenceIfLayerTest : public testing::TestWithParam, public Com TEST_P(ReferenceIfLayerTest, IfWithHardcodedRefs) { Exec(); } +std::vector Y_gen() { + std::vector Y_v; + for (auto c_ind = 0; c_ind < 4; ++c_ind) { + for (auto d_ind = 0; d_ind < 4; ++d_ind) { + Y_v.push_back(static_cast(c_ind * d_ind)); + } + } + return Y_v; +} +std::vector Z_gen() { + std::vector Z_v; + for (auto c_ind = 0; c_ind < 8; ++c_ind) { + for (auto d_ind = 0; d_ind < 64; ++d_ind) { + Z_v.push_back(static_cast(c_ind * d_ind)); + } + } + return Z_v; +} INSTANTIATE_TEST_SUITE_P( smoke_If_With_Hardcoded_Refs, @@ -280,4 +334,29 @@ INSTANTIATE_TEST_SUITE_P( Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{3.0, 3.0, 5.0, 7.0})}, - "if_condition_is_scalar_cond_false"))); + "if_condition_is_scalar_cond_false"), + IfParams( + std::make_shared(), + std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{1}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), + Tensor(Shape{4, 2, 2}, ngraph::element::f32, Y_gen()), + Tensor(Shape{8, 8, 8}, ngraph::element::f32, Z_gen())}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 4.0, 9.0, 16.0}), + Tensor(Shape{4, 2, 2}, ngraph::element::f32, Y_gen())}, + "If_dynamism_case_with_static_inputs_condition_true"), + IfParams( + std::make_shared(), + std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), + Tensor(Shape{4, 2, 2}, ngraph::element::f32, Y_gen()), + Tensor(Shape{8, 8, 8}, ngraph::element::f32, Z_gen())}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 4.0, 6.0, 8.0}), + Tensor(Shape{8, 8, 8}, ngraph::element::f32, Z_gen())}, + "If_dynamism_case_with_static_inputs_condition_false"), + IfParams( + std::make_shared(), + std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{1}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 6.0, 12.0})}, + "if_condition_is_dynamic_cond_true"))); diff --git a/ngraph/test/op_eval/if_eval.cpp b/ngraph/test/op_eval/if_eval.cpp index f7ee7f4f5fe81d..00d9c603fbee3f 100644 --- a/ngraph/test/op_eval/if_eval.cpp +++ b/ngraph/test/op_eval/if_eval.cpp @@ -57,90 +57,6 @@ TEST(op_eval, if_constant_folding) { EXPECT_NEAR(val[0], 1000.0, 0.000001); } -TEST(op_eval, if_dynamism) { - auto X = make_shared(element::f32, Shape{1, 2, 2}); - auto Y = make_shared(element::f32, Shape{4, 2, 2}); - auto Z = make_shared(element::f32, Shape{8, 8, 8}); - auto cond = make_shared(element::boolean, Shape{1}); - // Set up the cell body, a function from (Xi, Yi) -> (Zo) - // Body parameters - auto Xt = make_shared(element::f32, PartialShape::dynamic()); - auto Yt = make_shared(element::f32, PartialShape::dynamic()); - auto Xe = make_shared(element::f32, PartialShape::dynamic()); - auto Ze = make_shared(element::f32, PartialShape::dynamic()); - // Body - auto then_op = std::make_shared(Xt, Xt); - auto else_op = std::make_shared(Xe, Xe); - auto then_op_result1 = make_shared(then_op); - auto then_op_result2 = make_shared(Yt); - auto else_op_result1 = make_shared(else_op); - auto else_op_result2 = make_shared(Ze); - auto then_body = - make_shared(OutputVector{then_op_result1, then_op_result2}, ParameterVector{Xt, Yt}); - auto else_body = - make_shared(OutputVector{else_op_result1, else_op_result2}, ParameterVector{Xe, Ze}); - auto if_op = make_shared(cond); - if_op->set_then_body(then_body); - if_op->set_else_body(else_body); - if_op->set_input(X, Xt, Xe); - if_op->set_input(Y, Yt, nullptr); - if_op->set_input(Z, nullptr, Ze); - auto res1 = if_op->set_output(then_op_result1, else_op_result1); - auto res2 = if_op->set_output(then_op_result2, else_op_result2); - auto result_if1 = make_shared(res1); - auto result_if2 = make_shared(res2); - if_op->validate_and_infer_types(); - std::vector X_v{1.0, 2.0, 3.0, 4.0}; - std::vector Y_v, Z_v; - for (auto c_ind = 0; c_ind < 4; ++c_ind) { - for (auto d_ind = 0; d_ind < 4; ++d_ind) { - Y_v.push_back(static_cast(c_ind * d_ind)); - } - } - for (auto c_ind = 0; c_ind < 8; ++c_ind) { - for (auto d_ind = 0; d_ind < 64; ++d_ind) { - Z_v.push_back(static_cast(c_ind * d_ind)); - } - } - auto fun = make_shared(OutputVector{result_if1, result_if2}, ParameterVector{cond, X, Y, Z}); - auto result1 = make_shared(); - auto result2 = make_shared(); - ASSERT_TRUE(fun->evaluate({result1, result2}, - {make_host_tensor(Shape{1}, {true}), - make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{4, 2, 2}, Y_v), - make_host_tensor(Shape{8, 8, 8}, Z_v)})); - EXPECT_EQ(result1->get_element_type(), element::f32); - EXPECT_EQ(result1->get_shape(), Shape{std::vector({1, 2, 2})}); - auto result1_data = read_vector(result1); - std::vector expected_results1{1.0, 4.0, 9.0, 16.0}; - for (auto i = 0; i < expected_results1.size(); i++) - EXPECT_NEAR(result1_data[i], expected_results1[i], 0.000001); - EXPECT_EQ(result2->get_element_type(), element::f32); - EXPECT_EQ(result2->get_shape(), Shape{std::vector({4, 2, 2})}); - auto result2_data = read_vector(result2); - for (auto i = 0; i < Y_v.size(); i++) - EXPECT_NEAR(result2_data[i], Y_v[i], 0.000001); - auto result3 = make_shared(); - auto result4 = make_shared(); - ASSERT_TRUE(fun->evaluate({result3, result4}, - {make_host_tensor(Shape{1}, {false}), - make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{4, 2, 2}, Y_v), - make_host_tensor(Shape{8, 8, 8}, Z_v)})); - EXPECT_EQ(result3->get_element_type(), element::f32); - EXPECT_EQ(result3->get_shape(), Shape{std::vector({1, 2, 2})}); - auto result3_data = read_vector(result3); - std::vector expected_results2{2.0, 4.0, 6.0, 8.0}; - for (auto i = 0; i < expected_results2.size(); i++) - EXPECT_NEAR(result3_data[i], expected_results2[i], 0.000001); - EXPECT_EQ(result4->get_element_type(), element::f32); - EXPECT_EQ(result4->get_shape(), Shape{std::vector({8, 8, 8})}); - auto result4_data = read_vector(result4); - for (auto i = 0; i < Z_v.size(); i++) - EXPECT_NEAR(result4_data[i], Z_v[i], 0.000001); -} - TEST(op_eval, if_condition_is_dynamic) { auto X = make_shared(element::f32, Shape{1, 2, 2}); auto Y = make_shared(element::f32, Shape{1, 2, 2}); From 00bd5414c03966afb60dd40f7a4183066bddf6ed Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 29 Sep 2021 14:29:12 +0300 Subject: [PATCH 23/30] delete eval test --- .../op_reference/base_reference_test.cpp | 7 +- .../tests/functional/op_reference/if.cpp | 12 +- .../transformations/const_folding_for_if.cpp | 66 +++++++++++ ngraph/test/op_eval/if_eval.cpp | 109 ------------------ 4 files changed, 79 insertions(+), 115 deletions(-) create mode 100644 inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp delete mode 100644 ngraph/test/op_eval/if_eval.cpp diff --git a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp index 2a1c526938a6ef..999771c8c49f21 100644 --- a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp +++ b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp @@ -35,11 +35,12 @@ void CommonReferenceTest::LoadNetwork() { void CommonReferenceTest::FillInputs() { const auto& functionParams = function->get_parameters(); ASSERT_EQ(functionParams.size(), inputData.size()); - for (size_t i = 0; i < functionParams.size(); i++) { const auto& param = functionParams[i]; - - ov::runtime::Tensor blob(param->get_element_type(), param->get_shape()); + auto param_shape_is_static = param->get_partial_shape().is_static(); + const auto& blob_shape = (param_shape_is_static) ? param->get_shape() : inputData[i].get_shape(); + + ov::runtime::Tensor blob(param->get_element_type(), blob_shape); ASSERT_EQ(blob.get_byte_size(), inputData[i].get_byte_size()); std::memcpy(blob.data(), inputData[i].data(), inputData[i].get_byte_size()); diff --git a/docs/template_plugin/tests/functional/op_reference/if.cpp b/docs/template_plugin/tests/functional/op_reference/if.cpp index c8366134ba81ce..c02bd246c7f704 100644 --- a/docs/template_plugin/tests/functional/op_reference/if.cpp +++ b/docs/template_plugin/tests/functional/op_reference/if.cpp @@ -189,7 +189,6 @@ struct IfConditionIsScalar : public IfFunctionalBase { } }; - struct IfConditionIsDynamic : public IfFunctionalBase { std::shared_ptr create_function(const std::vector& if_inputs, const std::vector& results) override { @@ -199,7 +198,7 @@ struct IfConditionIsDynamic : public IfFunctionalBase { auto X = std::make_shared(element::f32, Shape{1, 2, 2}); auto Y = std::make_shared(element::f32, Shape{1, 2, 2}); auto cond = std::make_shared(element::boolean, PartialShape{Dimension::dynamic()}); - //auto cond = std::make_shared(element::boolean, Shape{1}); + // auto cond = std::make_shared(element::boolean, Shape{1}); // Set up the cell body, a function from (Xi, Yi) -> (Zo) // Body parameters auto Xt = std::make_shared(element::f32, PartialShape::dynamic()); @@ -359,4 +358,11 @@ INSTANTIATE_TEST_SUITE_P( Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 2.0, 6.0, 12.0})}, - "if_condition_is_dynamic_cond_true"))); + "if_condition_is_dynamic_cond_true"), + IfParams( + std::make_shared(), + std::vector{Tensor(Shape{}, ngraph::element::boolean, std::vector{0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{1.0, 2.0, 3.0, 4.0}), + Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{2.0, 1.0, 2.0, 3.0})}, + std::vector{Tensor(Shape{1, 2, 2}, ngraph::element::f32, std::vector{3.0, 3.0, 5.0, 7.0})}, + "if_condition_is_dynamic_cond_false"))); \ No newline at end of file diff --git a/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp b/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp new file mode 100644 index 00000000000000..2a33d2af5e1085 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp @@ -0,0 +1,66 @@ +#include + +#include "common_test_utils/test_common.hpp" +#include +#include "common_test_utils/ngraph_test_utils.hpp" + +#include +#include "ngraph/opsets/opset1.hpp" +#include "ngraph/opsets/opset5.hpp" +#include "ngraph/opsets/opset8.hpp" +#include + +using namespace testing; +using namespace std; +using namespace ngraph; + +TEST(TransformationTests, if_constant_folding) { + auto input = ngraph::op::Constant::create(ngraph::element::f32, ngraph::Shape{ 1, 3, 64 }, { 1 }); + auto w = ngraph::op::Constant::create(ngraph::element::f32, ngraph::Shape{ 6, 3, 3/*OIW*/ }, { 1 }); + + std::shared_ptr fun(nullptr); + { + auto cond = std::make_shared(element::boolean, Shape{ 1 }, false); + auto A1 = std::make_shared(element::f32, Shape{ 1 }, 37.0); + auto A2 = std::make_shared(element::f32, Shape{ 1 }, 45.0); + auto B1 = std::make_shared(element::f32, Shape{ 1 }, 10.0); + auto B2 = std::make_shared(element::f32, Shape{ 1 }, 3.0); + auto Xt = make_shared(element::f32, PartialShape::dynamic()); + auto Yt = make_shared(element::f32, PartialShape::dynamic()); + auto Xe = make_shared(element::f32, PartialShape::dynamic()); + auto Ye = make_shared(element::f32, PartialShape::dynamic()); + auto a_add = std::make_shared(Xt, Yt); + auto b_pow = std::make_shared(Xe, Ye); + auto then_res = std::make_shared(a_add); + auto then_body = make_shared(OutputVector{ then_res }, ParameterVector{ Xt, Yt }); + auto else_res = std::make_shared(b_pow); + auto else_body = make_shared(OutputVector{ else_res }, ParameterVector{ Xe, Ye }); + auto if_op = make_shared(cond); + if_op->set_then_body(then_body); + if_op->set_else_body(else_body); + if_op->set_input(A1, Xt, nullptr); + if_op->set_input(A2, Yt, nullptr); + if_op->set_input(B1, nullptr, Xe); + if_op->set_input(B2, nullptr, Ye); + auto if_res = if_op->set_output(then_res, else_res); + auto param_add = make_shared(element::f32, Shape{ 1 }); + auto add = make_shared(if_res, param_add); + auto add_res = make_shared(add); + fun = make_shared(OutputVector{ add_res }, ParameterVector{ param_add }); + fun->validate_nodes_and_infer_types(); + + ngraph::pass::ConstantFolding().run_on_function(fun); + + } + std::shared_ptr f_ref(nullptr); + { + auto constant_folding_if = make_shared(element::f32, Shape{ 1 }, 1000.0f); + auto param_add = make_shared(element::f32, Shape{ 1 }); + auto add = make_shared(constant_folding_if, param_add); + auto add_res = make_shared(add); + f_ref = std::make_shared(ngraph::NodeVector{ add_res }, ngraph::ParameterVector{ param_add }); + } + + auto res = compare_functions(fun, f_ref); + ASSERT_TRUE(res.first) << res.second; +} diff --git a/ngraph/test/op_eval/if_eval.cpp b/ngraph/test/op_eval/if_eval.cpp deleted file mode 100644 index 00d9c603fbee3f..00000000000000 --- a/ngraph/test/op_eval/if_eval.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (C) 2018-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 -// - -#include -#include -#include - -#include "gtest/gtest.h" -#include "ngraph/opsets/opset1.hpp" -#include "ngraph/opsets/opset5.hpp" -#include "ngraph/opsets/opset8.hpp" -#include "ngraph/runtime/host_tensor.hpp" -#include "ngraph/validation_util.hpp" -#include "runtime/backend.hpp" -#include "util/test_tools.hpp" - -using namespace std; -using namespace ngraph; - -// Move these tests when dynamism will be supported in the template plugin -TEST(op_eval, if_constant_folding) { - auto cond = std::make_shared(element::boolean, Shape{1}, false); - auto A1 = std::make_shared(element::f32, Shape{1}, 37.0); - auto A2 = std::make_shared(element::f32, Shape{1}, 45.0); - auto B1 = std::make_shared(element::f32, Shape{1}, 10.0); - auto B2 = std::make_shared(element::f32, Shape{1}, 3.0); - auto Xt = make_shared(element::f32, PartialShape::dynamic()); - auto Yt = make_shared(element::f32, PartialShape::dynamic()); - auto Xe = make_shared(element::f32, PartialShape::dynamic()); - auto Ye = make_shared(element::f32, PartialShape::dynamic()); - auto a_add = std::make_shared(Xt, Yt); - auto b_pow = std::make_shared(Xe, Ye); - auto then_res = std::make_shared(a_add); - auto then_body = make_shared(OutputVector{then_res}, ParameterVector{Xt, Yt}); - auto else_res = std::make_shared(b_pow); - auto else_body = make_shared(OutputVector{else_res}, ParameterVector{Xe, Ye}); - auto if_op = make_shared(cond); - if_op->set_then_body(then_body); - if_op->set_else_body(else_body); - if_op->set_input(A1, Xt, nullptr); - if_op->set_input(A2, Yt, nullptr); - if_op->set_input(B1, nullptr, Xe); - if_op->set_input(B2, nullptr, Ye); - if_op->set_output(then_res, else_res); - - auto fun = make_shared(OutputVector{if_op}, ParameterVector{}); - fun->validate_nodes_and_infer_types(); - ngraph::pass::ConstantFolding().run_on_function(fun); - auto results = fun->get_results(); - EXPECT_EQ(results.size(), 1); - auto result = results[0]; - EXPECT_EQ(result->get_element_type(), element::f32); - EXPECT_EQ(result->get_shape(), Shape{1}); - const auto& cond_value = get_constant_from_source(result); - auto val = cond_value->cast_vector(); - EXPECT_NEAR(val[0], 1000.0, 0.000001); -} - -TEST(op_eval, if_condition_is_dynamic) { - auto X = make_shared(element::f32, Shape{1, 2, 2}); - auto Y = make_shared(element::f32, Shape{1, 2, 2}); - auto cond = make_shared(element::boolean, PartialShape{Dimension::dynamic()}); - // Set up the cell body, a function from (Xi, Yi) -> (Zo) - // Body parameters - auto Xt = make_shared(element::f32, PartialShape::dynamic()); - auto Yt = make_shared(element::f32, PartialShape::dynamic()); - auto Xe = make_shared(element::f32, PartialShape::dynamic()); - auto Ye = make_shared(element::f32, PartialShape::dynamic()); - // Body - auto then_op = std::make_shared(Xt, Yt); - auto else_op = std::make_shared(Xe, Ye); - auto then_op_result = make_shared(then_op); - auto else_op_result = make_shared(else_op); - auto then_body = make_shared(OutputVector{then_op_result}, ParameterVector{Xt, Yt}); - auto else_body = make_shared(OutputVector{else_op_result}, ParameterVector{Xe, Ye}); - auto if_op = make_shared(cond); - if_op->set_then_body(then_body); - if_op->set_else_body(else_body); - if_op->set_input(X, Xt, Xe); - if_op->set_input(Y, Yt, Ye); - if_op->set_output(then_op_result, else_op_result); - if_op->validate_and_infer_types(); - std::vector X_v{1.0, 2.0, 3.0, 4.0}; - std::vector Y_v{2.0, 1.0, 2.0, 3.0}; - auto fun = make_shared(OutputVector{if_op}, ParameterVector{cond, X, Y}); - auto result = make_shared(); - ASSERT_TRUE(fun->evaluate({result}, - {make_host_tensor(Shape{1}, {true}), - make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{1, 2, 2}, Y_v)})); - EXPECT_EQ(result->get_element_type(), element::f32); - EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); - auto result_data = read_vector(result); - std::vector expected_results{2.0, 2.0, 6.0, 12.0}; - for (auto i = 0; i < expected_results.size(); i++) - EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); - ASSERT_TRUE(fun->evaluate({result}, - {make_host_tensor(Shape{1}, {false}), - make_host_tensor(Shape{1, 2, 2}, X_v), - make_host_tensor(Shape{1, 2, 2}, Y_v)})); - EXPECT_EQ(result->get_element_type(), element::f32); - EXPECT_EQ(result->get_shape(), Shape{std::vector({1, 2, 2})}); - result_data = read_vector(result); - expected_results = {3.0, 3.0, 5.0, 7.0}; - - for (auto i = 0; i < expected_results.size(); i++) - EXPECT_NEAR(result_data[i], expected_results[i], 0.000001); -} \ No newline at end of file From df0860d3e8f623dc5d92830160fbe52a89c6ab9a Mon Sep 17 00:00:00 2001 From: evolosen Date: Thu, 30 Sep 2021 11:30:46 +0300 Subject: [PATCH 24/30] add common header --- .../inference_engine/transformations/const_folding_for_if.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp b/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp index 2a33d2af5e1085..47fc2c04429e65 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp @@ -1,3 +1,7 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + #include #include "common_test_utils/test_common.hpp" From eb03e4b62354fd18f8fe8a0e93424e2e7ec0c8e1 Mon Sep 17 00:00:00 2001 From: evolosen Date: Thu, 30 Sep 2021 12:37:44 +0300 Subject: [PATCH 25/30] Fix codestyle --- .../inference_engine/transformations/const_folding_for_if.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp b/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp index 47fc2c04429e65..e43566175b4ea4 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp @@ -52,9 +52,7 @@ TEST(TransformationTests, if_constant_folding) { auto add_res = make_shared(add); fun = make_shared(OutputVector{ add_res }, ParameterVector{ param_add }); fun->validate_nodes_and_infer_types(); - ngraph::pass::ConstantFolding().run_on_function(fun); - } std::shared_ptr f_ref(nullptr); { From fa2c4fce4e5b30241ccca8e70ce355dc0da14cd2 Mon Sep 17 00:00:00 2001 From: evolosen Date: Mon, 4 Oct 2021 20:05:30 +0300 Subject: [PATCH 26/30] fix set_invariant_input/set_body_output --- .../tests/functional/op_reference/base_reference_test.cpp | 5 ++--- ngraph/core/src/op/util/multi_subgraph_base.cpp | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp index e92ba54eda29e2..7165b21516aa08 100644 --- a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp +++ b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp @@ -28,7 +28,6 @@ void CommonReferenceTest::Exec() { } void CommonReferenceTest::LoadNetwork() { - function->validate_nodes_and_infer_types(); executableNetwork = core->compile_model(function, targetDevice); } @@ -38,8 +37,8 @@ void CommonReferenceTest::FillInputs() { ASSERT_EQ(functionParams.size(), inputData.size()); for (size_t i = 0; i < functionParams.size(); i++) { const auto& param = functionParams[i]; - auto param_shape_is_static = param->get_partial_shape().is_static(); - const auto& blob_shape = (param_shape_is_static) ? param->get_shape() : inputData[i].get_shape(); + const auto& blob_shape = + (param->get_partial_shape().is_static()) ? param->get_shape() : inputData[i].get_shape(); ov::runtime::Tensor blob(param->get_element_type(), blob_shape); diff --git a/ngraph/core/src/op/util/multi_subgraph_base.cpp b/ngraph/core/src/op/util/multi_subgraph_base.cpp index abbcf5b2d6d7db..c4c1e1f6239eb9 100644 --- a/ngraph/core/src/op/util/multi_subgraph_base.cpp +++ b/ngraph/core/src/op/util/multi_subgraph_base.cpp @@ -135,6 +135,7 @@ void ov::op::util::MultiSubGraphOp::set_invariant_inputs(const Output& val } } } + validate_and_infer_types(); } ov::Output ov::op::util::MultiSubGraphOp::set_body_outputs(const ResultVector& bodies_results) { @@ -149,6 +150,7 @@ ov::Output ov::op::util::MultiSubGraphOp::set_body_outputs(const Resul } } set_output_size(output_index + 1); + validate_and_infer_types(); return Output(shared_from_this(), output_index); } From 6cfaa15000589d15ee491aa2d54bc9389f59b0a6 Mon Sep 17 00:00:00 2001 From: evolosen Date: Mon, 4 Oct 2021 20:07:26 +0300 Subject: [PATCH 27/30] fix code_style --- .../tests/functional/op_reference/base_reference_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp index 7165b21516aa08..a2693703979a44 100644 --- a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp +++ b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp @@ -28,7 +28,6 @@ void CommonReferenceTest::Exec() { } void CommonReferenceTest::LoadNetwork() { - executableNetwork = core->compile_model(function, targetDevice); } From cf0020ea6c71efcbe98cfc6d9ae2b86edc559f80 Mon Sep 17 00:00:00 2001 From: evolosen Date: Mon, 4 Oct 2021 21:00:06 +0300 Subject: [PATCH 28/30] fix codestyle --- .../functional/op_reference/base_reference_test.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp index a2693703979a44..00713282e2a038 100644 --- a/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp +++ b/docs/template_plugin/tests/functional/op_reference/base_reference_test.cpp @@ -34,13 +34,16 @@ void CommonReferenceTest::LoadNetwork() { void CommonReferenceTest::FillInputs() { const auto& functionParams = function->get_parameters(); ASSERT_EQ(functionParams.size(), inputData.size()); + for (size_t i = 0; i < functionParams.size(); i++) { const auto& param = functionParams[i]; - const auto& blob_shape = - (param->get_partial_shape().is_static()) ? param->get_shape() : inputData[i].get_shape(); - - ov::runtime::Tensor blob(param->get_element_type(), blob_shape); + ov::runtime::Tensor blob; + if (param->get_partial_shape().is_static()) { + blob = ov::runtime::Tensor(param->get_element_type(), param->get_shape()); + } else { + blob = ov::runtime::Tensor(param->get_element_type(), inputData[i].get_shape()); + } ASSERT_EQ(blob.get_byte_size(), inputData[i].get_byte_size()); std::memcpy(blob.data(), inputData[i].data(), inputData[i].get_byte_size()); From eb6f6e514dfda0139f6a4e530a48c8b7b228d768 Mon Sep 17 00:00:00 2001 From: evolosen Date: Tue, 5 Oct 2021 11:53:58 +0300 Subject: [PATCH 29/30] delete validate_and_infer_types from type prop tests --- ngraph/test/type_prop/if.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ngraph/test/type_prop/if.cpp b/ngraph/test/type_prop/if.cpp index d60d4890f1d961..bd993ae4524cb1 100644 --- a/ngraph/test/type_prop/if.cpp +++ b/ngraph/test/type_prop/if.cpp @@ -38,7 +38,7 @@ TEST(type_prop, if_simple_test) { if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_op_res, else_op_res); - if_op->validate_and_infer_types(); + // if_op->validate_and_infer_types(); auto result0 = make_shared(res); Shape out0_shape{32, 40, 10}; @@ -73,7 +73,7 @@ TEST(type_prop, if_non_const_condition_test) { if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - if_op->validate_and_infer_types(); + // if_op->validate_and_infer_types(); auto result0 = make_shared(res); Shape out0_shape{32, 40, 10}; auto sh = result0->get_output_shape(0); @@ -147,7 +147,7 @@ TEST(type_prop, if_multiple_outputs) { if_op->set_input(Y, Yt, Ye); auto res1 = if_op->set_output(then_body_res_1, else_body_res_1); auto res2 = if_op->set_output(then_body_res_2, else_body_res_2); - if_op->validate_and_infer_types(); + // if_op->validate_and_infer_types(); auto result1 = make_shared(res1); auto result2 = make_shared(res2); Shape out0_shape{32, 40, 10}; @@ -184,7 +184,7 @@ TEST(type_prop, if_scalar_condition) { if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - if_op->validate_and_infer_types(); + // if_op->validate_and_infer_types(); auto result0 = make_shared(res); Shape out0_shape{32, 40, 10}; auto sh = result0->get_output_shape(0); @@ -218,7 +218,7 @@ TEST(type_prop, if_dynamic_output) { if_op->set_input(X, Xt, nullptr); if_op->set_input(Y, nullptr, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - if_op->validate_and_infer_types(); + // if_op->validate_and_infer_types(); auto result0 = make_shared(res); auto dynamic_shape = result0->get_output_partial_shape(0); @@ -265,7 +265,7 @@ TEST(type_prop, if_dynamic_inputs) { if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - if_op->validate_and_infer_types(); + // if_op->validate_and_infer_types(); auto result0 = make_shared(res); auto dynamic_shape = result0->get_output_partial_shape(0); auto expected_result = PartialShape{Dimension::dynamic(), 20, 30}; From c05a072adc6bdf263781c6175fff23614d2d8537 Mon Sep 17 00:00:00 2001 From: evolosen Date: Wed, 6 Oct 2021 14:04:44 +0300 Subject: [PATCH 30/30] delete comments --- .../transformations/const_folding_for_if.cpp | 4 ---- ngraph/test/type_prop/if.cpp | 9 --------- 2 files changed, 13 deletions(-) diff --git a/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp b/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp index e43566175b4ea4..d503b2f7825848 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/const_folding_for_if.cpp @@ -19,9 +19,6 @@ using namespace std; using namespace ngraph; TEST(TransformationTests, if_constant_folding) { - auto input = ngraph::op::Constant::create(ngraph::element::f32, ngraph::Shape{ 1, 3, 64 }, { 1 }); - auto w = ngraph::op::Constant::create(ngraph::element::f32, ngraph::Shape{ 6, 3, 3/*OIW*/ }, { 1 }); - std::shared_ptr fun(nullptr); { auto cond = std::make_shared(element::boolean, Shape{ 1 }, false); @@ -51,7 +48,6 @@ TEST(TransformationTests, if_constant_folding) { auto add = make_shared(if_res, param_add); auto add_res = make_shared(add); fun = make_shared(OutputVector{ add_res }, ParameterVector{ param_add }); - fun->validate_nodes_and_infer_types(); ngraph::pass::ConstantFolding().run_on_function(fun); } std::shared_ptr f_ref(nullptr); diff --git a/ngraph/test/type_prop/if.cpp b/ngraph/test/type_prop/if.cpp index bd993ae4524cb1..80cf9a7f3dfd97 100644 --- a/ngraph/test/type_prop/if.cpp +++ b/ngraph/test/type_prop/if.cpp @@ -38,8 +38,6 @@ TEST(type_prop, if_simple_test) { if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_op_res, else_op_res); - // if_op->validate_and_infer_types(); - auto result0 = make_shared(res); Shape out0_shape{32, 40, 10}; auto sh = result0->get_output_shape(0); @@ -73,7 +71,6 @@ TEST(type_prop, if_non_const_condition_test) { if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - // if_op->validate_and_infer_types(); auto result0 = make_shared(res); Shape out0_shape{32, 40, 10}; auto sh = result0->get_output_shape(0); @@ -100,14 +97,12 @@ TEST(type_prop, if_clone_test) { auto else_op = std::make_shared(Xe, Ye); auto else_body_res = make_shared(else_op); auto else_body = make_shared(OutputVector{else_body_res}, ParameterVector{Xe, Ye}); - auto if_op = make_shared(cond); if_op->set_then_body(then_body); if_op->set_else_body(else_body); if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - auto new_if = std::dynamic_pointer_cast(if_op->clone_with_new_inputs(OutputVector{cond, Xnew, Ynew})); EXPECT_EQ(true, true); } @@ -147,7 +142,6 @@ TEST(type_prop, if_multiple_outputs) { if_op->set_input(Y, Yt, Ye); auto res1 = if_op->set_output(then_body_res_1, else_body_res_1); auto res2 = if_op->set_output(then_body_res_2, else_body_res_2); - // if_op->validate_and_infer_types(); auto result1 = make_shared(res1); auto result2 = make_shared(res2); Shape out0_shape{32, 40, 10}; @@ -184,7 +178,6 @@ TEST(type_prop, if_scalar_condition) { if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - // if_op->validate_and_infer_types(); auto result0 = make_shared(res); Shape out0_shape{32, 40, 10}; auto sh = result0->get_output_shape(0); @@ -218,7 +211,6 @@ TEST(type_prop, if_dynamic_output) { if_op->set_input(X, Xt, nullptr); if_op->set_input(Y, nullptr, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - // if_op->validate_and_infer_types(); auto result0 = make_shared(res); auto dynamic_shape = result0->get_output_partial_shape(0); @@ -265,7 +257,6 @@ TEST(type_prop, if_dynamic_inputs) { if_op->set_input(X, Xt, Xe); if_op->set_input(Y, Yt, Ye); auto res = if_op->set_output(then_body_res, else_body_res); - // if_op->validate_and_infer_types(); auto result0 = make_shared(res); auto dynamic_shape = result0->get_output_partial_shape(0); auto expected_result = PartialShape{Dimension::dynamic(), 20, 30};