From 81f9d78541e5e4986bc612724e0b96eb0173540b Mon Sep 17 00:00:00 2001 From: Bartosz Sledz Date: Wed, 12 May 2021 10:32:34 +0200 Subject: [PATCH] ONNX Subgraph - Infer types of inputs from top level Graph nodes (#5277) --- .../include/onnx_import/core/node.hpp | 4 + .../onnx_import/src/core/attribute.cpp | 54 +++-- .../onnx_import/src/core/attribute.hpp | 6 +- .../frontend/onnx_import/src/core/graph.cpp | 44 ++--- .../frontend/onnx_import/src/core/graph.hpp | 32 +-- .../frontend/onnx_import/src/core/model.cpp | 4 +- .../frontend/onnx_import/src/core/model.hpp | 8 +- ngraph/frontend/onnx_import/src/core/node.cpp | 37 +++- ngraph/frontend/onnx_import/src/op/loop.cpp | 10 +- .../frontend/onnx_import/src/utils/common.hpp | 12 ++ .../onnx_import/src/utils/onnx_internal.cpp | 6 +- ngraph/python/tests/test_onnx/test_backend.py | 8 +- ...ode_from_parent_scope_infer_types.prototxt | 176 +++++++++++++++++ ...x_controlflow_loop_2d_infer_types.prototxt | 184 ++++++++++++++++++ .../test/onnx/onnx_import_controlflow.in.cpp | 43 ++++ 15 files changed, 543 insertions(+), 85 deletions(-) create mode 100644 ngraph/test/models/onnx/loop/loop_add_node_from_parent_scope_infer_types.prototxt create mode 100644 ngraph/test/models/onnx/loop/onnx_controlflow_loop_2d_infer_types.prototxt diff --git a/ngraph/frontend/onnx_import/include/onnx_import/core/node.hpp b/ngraph/frontend/onnx_import/include/onnx_import/core/node.hpp index 9c4462e6728..fa39bd0fd46 100644 --- a/ngraph/frontend/onnx_import/include/onnx_import/core/node.hpp +++ b/ngraph/frontend/onnx_import/include/onnx_import/core/node.hpp @@ -74,6 +74,10 @@ namespace ngraph bool has_attribute(const std::string& name) const; + Subgraph get_subgraph_from_attribute( + const std::string& name, + const std::map& carried_dependencies_map) const; + template T get_attribute_value(const std::string& name, T default_value) const; diff --git a/ngraph/frontend/onnx_import/src/core/attribute.cpp b/ngraph/frontend/onnx_import/src/core/attribute.cpp index 950a8494fb7..8eaa8c93517 100644 --- a/ngraph/frontend/onnx_import/src/core/attribute.cpp +++ b/ngraph/frontend/onnx_import/src/core/attribute.cpp @@ -5,37 +5,57 @@ #include "core/attribute.hpp" #include "core/graph.hpp" #include "core/model.hpp" +#include "ngraph/log.hpp" namespace ngraph { namespace onnx_import { - std::vector Attribute::get_graph_array(Model& model) const - { - std::vector result; - for (const auto& graph : m_attribute_proto->graphs()) - { - result.emplace_back(graph, model); - } - return result; - } - - Subgraph Attribute::get_subgraph(const Graph& parent_graph) const + Subgraph Attribute::get_subgraph( + const Graph& parent_graph, + const std::map& carried_dependencies_map) const { if (m_attribute_proto->type() != ONNX_NAMESPACE::AttributeProto_AttributeType_GRAPH) { throw error::attribute::InvalidData{m_attribute_proto->type()}; } - ONNX_NAMESPACE::ModelProto model_proto; + auto model_proto = common::make_unique(); + const auto& graph = m_attribute_proto->g(); - *(model_proto.mutable_graph()) = graph; + model_proto->mutable_graph()->CopyFrom(graph); + + const std::size_t subgraph_inputs_count = + static_cast(model_proto->mutable_graph()->mutable_input()->size()); + // Use the `carried_dependencies_map` to infer the types for the subgraph inputs + for (const auto& carried_dependency : carried_dependencies_map) + { + if (carried_dependency.first >= subgraph_inputs_count) + { + NGRAPH_WARN << "Input with index: '" << carried_dependency.first + << "' was not found in the subgraph"; + } + else + { + const auto& parent_in = + parent_graph.get_ng_node_from_cache(carried_dependency.second); + const auto& carried_type = parent_in.get_element_type(); + auto subgraph_in = + model_proto->mutable_graph()->mutable_input(carried_dependency.first); + auto subgraph_in_tensor_type = + subgraph_in->mutable_type()->mutable_tensor_type(); + if (!subgraph_in_tensor_type->has_elem_type()) + { + subgraph_in_tensor_type->set_elem_type( + onnx_common::ng_to_onnx_data_type(carried_type)); + } + } + } // set opset version and domain from the parent graph - *model_proto.mutable_opset_import() = parent_graph.get_opset_imports(); - - Model model{model_proto}; - return Subgraph{graph, model, parent_graph}; + model_proto->mutable_opset_import()->CopyFrom(parent_graph.get_opset_imports()); + auto model = common::make_unique(std::move(model_proto)); + return Subgraph{std::move(model), parent_graph}; } } // namespace onnx_import diff --git a/ngraph/frontend/onnx_import/src/core/attribute.hpp b/ngraph/frontend/onnx_import/src/core/attribute.hpp index 4c86ba2ba11..80a287a55fb 100644 --- a/ngraph/frontend/onnx_import/src/core/attribute.hpp +++ b/ngraph/frontend/onnx_import/src/core/attribute.hpp @@ -281,7 +281,9 @@ namespace ngraph float get_float() const { return m_attribute_proto->f(); } int64_t get_integer() const { return m_attribute_proto->i(); } const std::string& get_string() const { return m_attribute_proto->s(); } - Subgraph get_subgraph(const Graph& parent_graph) const; + Subgraph get_subgraph( + const Graph& parent_graph, + const std::map& carried_dependencies_map) const; std::vector get_tensor_array() const { @@ -306,8 +308,6 @@ namespace ngraph std::end(m_attribute_proto->strings())}; } - std::vector get_graph_array(Model&) const; - /* explicit */ operator ONNX_NAMESPACE::AttributeProto_AttributeType() const { return m_attribute_proto->type(); diff --git a/ngraph/frontend/onnx_import/src/core/graph.cpp b/ngraph/frontend/onnx_import/src/core/graph.cpp index e5323b67fa2..c8f56327d6b 100644 --- a/ngraph/frontend/onnx_import/src/core/graph.cpp +++ b/ngraph/frontend/onnx_import/src/core/graph.cpp @@ -52,8 +52,8 @@ namespace ngraph } } // namespace detail - Graph::Graph(const ONNX_NAMESPACE::GraphProto& graph_proto, Model& model) - : Graph(graph_proto, model, std::unique_ptr(new GraphCache())) + Graph::Graph(std::unique_ptr&& model) + : Graph(std::move(model), common::make_unique()) { // Remove dangling Parameters for (auto param_it = m_parameters.begin(); param_it != m_parameters.end();) @@ -75,27 +75,14 @@ namespace ngraph param_it++; } } - Graph::Graph(const Graph& graph) - : m_parameters(graph.m_parameters) - , m_cache{new GraphCache(*graph.m_cache)} - , m_graph_proto{graph.m_graph_proto} - , m_nodes(graph.m_nodes) - , m_inputs(graph.m_inputs) - , m_outputs(graph.m_outputs) - , m_model{graph.m_model} - { - } - Graph::Graph(const ONNX_NAMESPACE::GraphProto& graph_proto, - Model& model, - std::unique_ptr&& cache) - : m_cache{std::move(cache)} - , m_graph_proto{&graph_proto} - , m_model{&model} + Graph::Graph(std::unique_ptr&& model, std::unique_ptr&& cache) + : m_model{std::move(model)} + , m_cache{std::move(cache)} { std::map initializers; // Process all initializers in the graph - for (const auto& initializer_tensor : m_graph_proto->initializer()) + for (const auto& initializer_tensor : m_model->get_graph().initializer()) { if (initializer_tensor.has_name()) { @@ -133,7 +120,7 @@ namespace ngraph } // Process all ONNX graph inputs, convert them to nGraph nodes and store in cache - for (const auto& input : m_graph_proto->input()) + for (const auto& input : m_model->get_graph().input()) { m_inputs.emplace_back(input); @@ -150,7 +137,7 @@ namespace ngraph } // Process all graph outputs - for (const auto& output : m_graph_proto->output()) + for (const auto& output : m_model->get_graph().output()) { m_outputs.emplace_back(output); } @@ -158,7 +145,7 @@ namespace ngraph // Verify that ONNX graph contains only nodes of available operator types std::map> unknown_operators; - for (const auto& node_proto : m_graph_proto->node()) + for (const auto& node_proto : m_model->get_graph().node()) { if (!m_model->is_operator_available(node_proto)) { @@ -189,7 +176,7 @@ namespace ngraph detail::to_string(unknown_operators)); // Process ONNX graph nodes, convert to nGraph nodes - for (const auto& node_proto : m_graph_proto->node()) + for (const auto& node_proto : m_model->get_graph().node()) { m_nodes.emplace_back(node_proto, *this); const Node& node{m_nodes.back()}; @@ -219,7 +206,7 @@ namespace ngraph OutputVector Graph::get_ng_outputs() const { OutputVector results; - for (const auto& output : m_graph_proto->output()) + for (const auto& output : m_model->get_graph().output()) { const auto& ng_output = get_ng_node_from_cache(output.name()); if (!ngraph::op::is_null(ng_output)) // ignore optional outputs @@ -335,17 +322,14 @@ namespace ngraph return m_model->get_opset_imports(); } - Subgraph::Subgraph(const ONNX_NAMESPACE::GraphProto& proto, - Model& model, - const Graph& parent_graph) + Subgraph::Subgraph(std::unique_ptr&& model, const Graph& parent_graph) : Graph( - proto, - model, + std::move(model), std::unique_ptr(new SubgraphCache(parent_graph.get_graph_cache()))) { // find all nodes on edge parent graph-subgraph // (it means input of node from parent graph, output from subgraph) - for (const auto& node_proto : proto.node()) + for (const auto& node_proto : m_model->get_graph().node()) { int input_index = 0; for (const auto& in_name : node_proto.input()) diff --git a/ngraph/frontend/onnx_import/src/core/graph.hpp b/ngraph/frontend/onnx_import/src/core/graph.hpp index 14e3e72f40c..6cbd8804109 100644 --- a/ngraph/frontend/onnx_import/src/core/graph.hpp +++ b/ngraph/frontend/onnx_import/src/core/graph.hpp @@ -23,8 +23,14 @@ namespace ngraph class Graph { public: - Graph(const ONNX_NAMESPACE::GraphProto& proto, Model& model); - Graph(const Graph& graph); + Graph(std::unique_ptr&& model); + Graph() = delete; + + Graph(const Graph&) = delete; + Graph(Graph&&) = default; + + Graph& operator=(const Graph&) = delete; + Graph& operator=(Graph&&) = default; const std::vector& get_nodes() const { return m_nodes; } const std::vector& get_inputs() const { return m_inputs; } const std::vector& get_outputs() const { return m_outputs; } @@ -32,16 +38,14 @@ namespace ngraph const ParameterVector& get_ng_parameters() const { return m_parameters; } bool is_node_in_cache(const std::string& name) const; Output get_ng_node_from_cache(const std::string& name) const; - const std::string& get_name() const { return m_graph_proto->name(); } + const std::string& get_name() const { return m_model->get_graph().name(); } OutputVector make_ng_nodes(const Node& onnx_node) const; const GraphCache& get_graph_cache() const; const OpsetImports& get_opset_imports() const; virtual ~Graph() = default; protected: - Graph(const ONNX_NAMESPACE::GraphProto& proto, - Model& model, - std::unique_ptr&& cache); + Graph(std::unique_ptr&& model, std::unique_ptr&& cache); void set_friendly_names(const Node& onnx_node, const OutputVector& ng_node_vector) const; @@ -57,14 +61,13 @@ namespace ngraph protected: ParameterVector m_parameters; + std::unique_ptr m_model; std::unique_ptr m_cache; private: - const ONNX_NAMESPACE::GraphProto* m_graph_proto; std::vector m_nodes; std::vector m_inputs; std::vector m_outputs; - Model* m_model; }; /// \brief Representation of ONNX subgraph. It is used for example by ONNX Loop op. @@ -75,17 +78,22 @@ namespace ngraph public: /// \brief Subgraph a GraphCache class object. /// - /// \param[in] proto The ONNX protobuf graph representation. /// \param[in] model The ONNX model object. /// \param[in] parent_graph The reference to the parent graph. - Subgraph(const ONNX_NAMESPACE::GraphProto& proto, - Model& model, - const Graph& parent_graph); + Subgraph(std::unique_ptr&& model, const Graph& parent_graph); /// \brief Return outputs which are on the edge the subgraph and the parent graph. /// \return Vector of edge nodes from parent scope. const std::vector> get_outputs_from_parent() const; + Subgraph() = delete; + + Subgraph(const Subgraph&) = delete; + Subgraph(Subgraph&&) = default; + + Subgraph& operator=(const Subgraph&) = delete; + Subgraph& operator=(Subgraph&&) = default; + private: std::vector> m_outputs_from_parent; }; diff --git a/ngraph/frontend/onnx_import/src/core/model.cpp b/ngraph/frontend/onnx_import/src/core/model.cpp index 0878b9c1463..452aea7b477 100644 --- a/ngraph/frontend/onnx_import/src/core/model.cpp +++ b/ngraph/frontend/onnx_import/src/core/model.cpp @@ -31,8 +31,8 @@ namespace ngraph throw ngraph_error("Couldn't find operator set's version for domain: " + domain + "."); } - Model::Model(const ONNX_NAMESPACE::ModelProto& model_proto) - : m_model_proto{&model_proto} + Model::Model(std::unique_ptr&& model_proto) + : m_model_proto{std::move(model_proto)} { // Walk through the elements of opset_import field and register operator sets // for each domain. An exception UnknownDomain() will raise if the domain is diff --git a/ngraph/frontend/onnx_import/src/core/model.hpp b/ngraph/frontend/onnx_import/src/core/model.hpp index e17d9e1689c..993dfb97e1a 100644 --- a/ngraph/frontend/onnx_import/src/core/model.hpp +++ b/ngraph/frontend/onnx_import/src/core/model.hpp @@ -28,10 +28,10 @@ namespace ngraph { public: Model() = delete; - explicit Model(const ONNX_NAMESPACE::ModelProto& model_proto); + explicit Model(std::unique_ptr&& model_proto); - Model(const Model&) = default; - Model(Model&&) = default; + Model(const Model&) = delete; + Model(Model&&) = delete; Model& operator=(const Model&) = delete; Model& operator=(Model&&) = delete; @@ -71,7 +71,7 @@ namespace ngraph void enable_opset_domain(const std::string& domain); private: - const ONNX_NAMESPACE::ModelProto* m_model_proto; + const std::unique_ptr m_model_proto; std::unordered_map m_opset; }; diff --git a/ngraph/frontend/onnx_import/src/core/node.cpp b/ngraph/frontend/onnx_import/src/core/node.cpp index 4a90d1dbeb7..c45215ce72f 100644 --- a/ngraph/frontend/onnx_import/src/core/node.cpp +++ b/ngraph/frontend/onnx_import/src/core/node.cpp @@ -44,6 +44,10 @@ namespace ngraph bool has_attribute(const std::string& name) const; + Subgraph get_subgraph_from_attribute( + const std::string& name, + const std::map& carried_dependencies_map) const; + template T get_attribute_value(const std::string& name, T default_value) const; @@ -90,6 +94,21 @@ namespace ngraph return it != std::end(m_attributes); } + Subgraph Node::Impl::get_subgraph_from_attribute( + const std::string& name, + const std::map& carried_dependencies_map) const + { + auto it = std::find_if( + std::begin(m_attributes), std::end(m_attributes), [&](const Attribute& attribute) { + return attribute.get_name() == name; + }); + if (it == std::end(m_attributes)) + { + throw error::node::UnknownAttribute{this->name(), name}; + } + return it->get_subgraph(graph(), carried_dependencies_map); + } + template T Node::Impl::get_attribute_value(const std::string& name, T default_value) const { @@ -121,15 +140,8 @@ namespace ngraph template <> Subgraph Node::Impl::get_attribute_value(const std::string& name) const { - auto it = std::find_if( - std::begin(m_attributes), std::end(m_attributes), [&](const Attribute& attribute) { - return attribute.get_name() == name; - }); - if (it == std::end(m_attributes)) - { - throw error::node::UnknownAttribute{this->name(), name}; - } - return it->get_subgraph(graph()); + const std::map empty_map; + return get_subgraph_from_attribute(name, empty_map); } OutputVector Node::Impl::get_ng_nodes(const Node& node) const @@ -207,6 +219,13 @@ namespace ngraph return m_pimpl->has_attribute(name); } + Subgraph Node::get_subgraph_from_attribute( + const std::string& name, + const std::map& carried_dependencies_map) const + { + return m_pimpl->get_subgraph_from_attribute(name, carried_dependencies_map); + } + std::vector Node::get_attribute_names() const { std::vector attr_names; diff --git a/ngraph/frontend/onnx_import/src/op/loop.cpp b/ngraph/frontend/onnx_import/src/op/loop.cpp index 8d8c8c66057..23ded7464e2 100644 --- a/ngraph/frontend/onnx_import/src/op/loop.cpp +++ b/ngraph/frontend/onnx_import/src/op/loop.cpp @@ -70,7 +70,15 @@ namespace ngraph const OutputVector loop_carried_dependencies{std::next(ng_inputs.begin(), 2), ng_inputs.end()}; - const Subgraph& body_graph{node.get_attribute_value("body")}; + std::map loop_carried_dependencies_map; + for (std::size_t i = 0; i < loop_carried_dependencies.size(); i++) + { + loop_carried_dependencies_map[i + 2] = + loop_carried_dependencies[i].get_node()->get_friendly_name(); + } + + const Subgraph& body_graph{ + node.get_subgraph_from_attribute("body", loop_carried_dependencies_map)}; auto body_outputs = body_graph.get_ng_outputs(); const auto& body_inputs = body_graph.get_ng_parameters(); diff --git a/ngraph/frontend/onnx_import/src/utils/common.hpp b/ngraph/frontend/onnx_import/src/utils/common.hpp index 8e9f0b0c507..b386c002b07 100644 --- a/ngraph/frontend/onnx_import/src/utils/common.hpp +++ b/ngraph/frontend/onnx_import/src/utils/common.hpp @@ -125,6 +125,18 @@ namespace ngraph const std::shared_ptr input, const std::set allowed_types = {}); + /// \brief Temporary replacement for C++14 std::make_unique. + /// \note details: https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique + /// + /// \param args List of arguments with which an instance of T will be constructed. + /// + /// \return std::unique_ptr of an instance of type T + template + std::unique_ptr make_unique(Args&&... args) + { + return std::unique_ptr(new T(std::forward(args)...)); + } + } // namespace common } // namespace onnx_import } // namespace ngraph diff --git a/ngraph/frontend/onnx_import/src/utils/onnx_internal.cpp b/ngraph/frontend/onnx_import/src/utils/onnx_internal.cpp index 00544c1fabf..74bb4a72d5c 100644 --- a/ngraph/frontend/onnx_import/src/utils/onnx_internal.cpp +++ b/ngraph/frontend/onnx_import/src/utils/onnx_internal.cpp @@ -18,8 +18,10 @@ namespace ngraph std::shared_ptr convert_to_ng_function(const ONNX_NAMESPACE::ModelProto& model_proto) { - Model model{model_proto}; - Graph graph{model_proto.graph(), model}; + auto p_model_proto = common::make_unique(model_proto); + auto model = common::make_unique(std::move(p_model_proto)); + + Graph graph{std::move(model)}; auto function = std::make_shared( graph.get_ng_outputs(), graph.get_ng_parameters(), graph.get_name()); for (std::size_t i{0}; i < function->get_output_size(); ++i) diff --git a/ngraph/python/tests/test_onnx/test_backend.py b/ngraph/python/tests/test_onnx/test_backend.py index 32442b0a375..ebfd747406e 100644 --- a/ngraph/python/tests/test_onnx/test_backend.py +++ b/ngraph/python/tests/test_onnx/test_backend.py @@ -29,7 +29,6 @@ from tests import (BACKEND_NAME, xfail_issue_38722, xfail_issue_38723, xfail_issue_38724, - xfail_issue_38725, xfail_issue_38732, xfail_issue_38734, xfail_issue_38735, @@ -299,9 +298,6 @@ tests_expected_to_fail = [ "OnnxBackendNodeModelTest.test_qlinearconv_cpu"), (xfail_issue_38724, "OnnxBackendNodeModelTest.test_resize_tf_crop_and_resize_cpu"), - (xfail_issue_38725, - "OnnxBackendNodeModelTest.test_range_int32_type_negative_delta_expanded_cpu", - "OnnxBackendNodeModelTest.test_range_float_type_positive_delta_expanded_cpu"), (xfail_issue_33512, "OnnxBackendNodeModelTest.test_einsum_transpose_cpu", "OnnxBackendNodeModelTest.test_einsum_batch_diagonal_cpu", @@ -359,7 +355,9 @@ tests_expected_to_fail = [ "OnnxBackendNodeModelTest.test_unsqueeze_two_axes_cpu", "OnnxBackendNodeModelTest.test_unsqueeze_unsorted_axes_cpu",), (xfail_issue_44956, - "OnnxBackendNodeModelTest.test_loop11_cpu"), + "OnnxBackendNodeModelTest.test_loop11_cpu", + "OnnxBackendNodeModelTest.test_range_int32_type_negative_delta_expanded_cpu", + "OnnxBackendNodeModelTest.test_range_float_type_positive_delta_expanded_cpu"), (xfail_issue_44957, "OnnxBackendNodeModelTest.test_compress_0_cpu", "OnnxBackendNodeModelTest.test_compress_1_cpu", diff --git a/ngraph/test/models/onnx/loop/loop_add_node_from_parent_scope_infer_types.prototxt b/ngraph/test/models/onnx/loop/loop_add_node_from_parent_scope_infer_types.prototxt new file mode 100644 index 00000000000..0577bf5d0ef --- /dev/null +++ b/ngraph/test/models/onnx/loop/loop_add_node_from_parent_scope_infer_types.prototxt @@ -0,0 +1,176 @@ +ir_version: 6 +producer_name: "nGraph ONNX Importer" +graph { + name: "basic loop" + node { + input: "parent_input" + input: "scale" + name: "mul_node" + op_type: "Mul" + output: "b" + } + node { + input: "parent_input" + input: "b" + name: "parent_add_node" + op_type: "Add" + output: "c" + } + node { + input: "trip_count" + input: "cond_in" + input: "a_init" + output: "a_final" + output: "a_values" + op_type: "Loop" + attribute { + name: "body" + g { + name: "simple add" + node { + input: "b" + input: "a_in" + output: "current_a" + name: "loop_body_add" + op_type: "Add" + } + node { + input: "cond" + output: "cond_out" + name: "cond_identity" + op_type: "Identity" + } + node { + input: "current_a" + output: "a_out" + name: "output_accumulator" + op_type: "Identity" + } + input { + name: "i" + type { + tensor_type { + elem_type: 7 + shape { + dim { + dim_value: 1 + } + } + } + } + } + input { + name: "cond" + type { + tensor_type { + elem_type: 9 + } + } + } + input { + name: "a_in" + } + output { + name: "cond_out" + type { + tensor_type { + elem_type: 9 + } + } + } + output { + name: "current_a" + type { + tensor_type { + elem_type: 1 + } + } + } + output { + name: "a_out" + type { + tensor_type { + elem_type: 1 + } + } + } + } + type: GRAPH + } + } + initializer { + dims: 1 + data_type: 7 + int64_data: 3 + name: "trip_count" + } + initializer { + dims: 1 + data_type: 9 + int32_data: 00000001 + name: "cond_in" + } + initializer { + dims: 1 + data_type: 1 + float_data: 2 + name: "scale" + } + + input { + name: "a_init" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 1 + } + dim { + dim_value: 2 + } + } + } + } + } + input { + name: "parent_input" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 1 + } + } + } + } + } + output { + name: "a_final" + type { + tensor_type { + elem_type: 1 + } + } + } + output { + name: "a_values" + type { + tensor_type { + elem_type: 1 + } + } + } + output { + name: "c" + type { + tensor_type { + elem_type: 1 + } + } + } +} +opset_import { + version: 11 +} diff --git a/ngraph/test/models/onnx/loop/onnx_controlflow_loop_2d_infer_types.prototxt b/ngraph/test/models/onnx/loop/onnx_controlflow_loop_2d_infer_types.prototxt new file mode 100644 index 00000000000..a29f7d97980 --- /dev/null +++ b/ngraph/test/models/onnx/loop/onnx_controlflow_loop_2d_infer_types.prototxt @@ -0,0 +1,184 @@ +ir_version: 6 +producer_name: "nGraph ONNX Importer" +graph { + name: "basic loop" + node { + input: "trip_count" + input: "cond_in" + input: "a_init" + output: "a_final" + op_type: "Loop" + attribute { + name: "body" + g { + node { + input: "a_in" + input: "b" + output: "current_a" + name: "loop_body_add" + op_type: "Add" + } + node { + input: "i" + input: "threshold" + output: "cond_out" + name: "condition_calc" + op_type: "Less" + } + node { + input: "current_a" + output: "a_out" + name: "output_accumulator" + op_type: "Identity" + } + name: "simple add" + initializer { + dims: 1 + dims: 2 + data_type: 1 + float_data: 1 + float_data: 1 + name: "b" + } + input { + name: "i" + type { + tensor_type { + elem_type: 7 + shape { + dim { + dim_value: 1 + } + } + } + } + } + input { + name: "cond" + type { + tensor_type { + elem_type: 9 + shape { + dim { + dim_value: 1 + } + } + } + } + } + input { + name: "a_in" + type { + tensor_type { + shape { + dim { + dim_value: 1 + } + dim { + dim_value: 2 + } + } + } + } + } + output { + name: "cond_out" + type { + tensor_type { + elem_type: 9 + shape { + dim { + dim_value: 1 + } + } + } + } + } + output { + name: "current_a" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 1 + } + dim { + dim_value: 2 + } + } + } + } + } + } + type: GRAPH + } + } + initializer { + dims: 1 + data_type: 7 + int64_data: 5 + name: "threshold" + } + input { + name: "trip_count" + type { + tensor_type { + elem_type: 7 + shape { + dim { + dim_value: 1 + } + } + } + } + } + input { + name: "cond_in" + type { + tensor_type { + elem_type: 9 + shape { + dim { + dim_value: 1 + } + } + } + } + } + input { + name: "a_init" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 1 + } + dim { + dim_value: 2 + } + } + } + } + } + output { + name: "a_final" + type { + tensor_type { + elem_type: 1 + shape { + dim { + dim_value: 1 + } + dim { + dim_value: 2 + } + } + } + } + } +} +opset_import { + version: 11 +} diff --git a/ngraph/test/onnx/onnx_import_controlflow.in.cpp b/ngraph/test/onnx/onnx_import_controlflow.in.cpp index fa97cd42176..1eb5ab73f97 100644 --- a/ngraph/test/onnx/onnx_import_controlflow.in.cpp +++ b/ngraph/test/onnx/onnx_import_controlflow.in.cpp @@ -381,6 +381,49 @@ NGRAPH_TEST(${BACKEND_NAME}, onnx_controlflow_loop_2d_trip_count_dynamic) test_case.run(); } +// ~~~~~~~~SUBGRAPH TYPES INFERENCE:~~~~~~~~ +NGRAPH_TEST(${BACKEND_NAME}, + onnx_controlflow_loop_2d_infer_types) +{ + const auto function = onnx_import::import_onnx_model(file_util::path_join( + SERIALIZED_ZOO, + "onnx/loop/onnx_controlflow_loop_2d_infer_types.prototxt")); + + auto test_case = test::TestCase(function); + // trip count + test_case.add_input({10}); + + // termination condition + test_case.add_input({true}); + + // a_init + test_case.add_input({0.f, 0.f}); + + test_case.add_expected_output(Shape{1, 2}, {6.f, 6.f}); + test_case.run(); +} + + +NGRAPH_TEST(${BACKEND_NAME}, + onnx_controlflow_loop_add_node_from_parent_scope_infer_types) +{ + const auto function = onnx_import::import_onnx_model(file_util::path_join( + SERIALIZED_ZOO, + "onnx/loop/loop_add_node_from_parent_scope_infer_types.prototxt")); + + auto test_case = test::TestCase(function); + // a_init + test_case.add_input({0.f, 0.f}); + // parent_input + test_case.add_input({3.f}); + + test_case.add_expected_output(Shape{1, 2}, {18.f, 18.f}); + test_case.add_expected_output(Shape{3, 1, 2}, {6.f, 6.f, 12.f, 12.f, 18.f, 18.f}); + test_case.add_expected_output(Shape{1}, {9.f}); + test_case.run(); +} + + // ~~~~~~~~ADDITIONAL TESTS:~~~~~~~~ NGRAPH_TEST(${BACKEND_NAME}, onnx_controlflow_loop_concat_values)