From 534fe35c0a0bd110894a91193b50cef0d5ca086b Mon Sep 17 00:00:00 2001 From: Ilya Churaev Date: Tue, 28 Jul 2020 08:54:50 +0300 Subject: [PATCH] Remove old transformation passes (#1463) --- .../convert_convolution_test.cpp | 1 - .../convert_deconvolution_test.cpp | 1 - ngraph/python/src/pyngraph/passes/manager.cpp | 3 - ngraph/src/ngraph/CMakeLists.txt | 44 -- ngraph/src/ngraph/pass/assign_layout.hpp | 58 -- ngraph/src/ngraph/pass/batch_fusion.cpp | 189 ----- ngraph/src/ngraph/pass/batch_fusion.hpp | 40 - .../pass/common_function_collection.cpp | 113 --- .../pass/common_function_collection.hpp | 62 -- ngraph/src/ngraph/pass/concat_fusion.cpp | 282 ------- ngraph/src/ngraph/pass/concat_fusion.hpp | 61 -- .../src/ngraph/pass/constant_to_broadcast.cpp | 51 -- .../src/ngraph/pass/constant_to_broadcast.hpp | 33 - ngraph/src/ngraph/pass/core_fusion.cpp | 722 ------------------ ngraph/src/ngraph/pass/core_fusion.hpp | 55 -- ngraph/src/ngraph/pass/cse.cpp | 323 -------- ngraph/src/ngraph/pass/cse.hpp | 70 -- ngraph/src/ngraph/pass/dump_sorted.cpp | 77 -- ngraph/src/ngraph/pass/dump_sorted.hpp | 40 - ngraph/src/ngraph/pass/manager.cpp | 11 +- ngraph/src/ngraph/pass/manager.hpp | 2 - ngraph/src/ngraph/pass/memory_layout.cpp | 293 ------- ngraph/src/ngraph/pass/memory_layout.hpp | 97 --- ngraph/src/ngraph/pass/memory_visualize.cpp | 266 ------- ngraph/src/ngraph/pass/memory_visualize.hpp | 52 -- .../ngraph/pass/propagate_cacheability.cpp | 76 -- .../ngraph/pass/propagate_cacheability.hpp | 52 -- .../src/ngraph/pass/reshape_elimination.cpp | 304 -------- .../src/ngraph/pass/reshape_elimination.hpp | 60 -- ngraph/src/ngraph/pass/reshape_sinking.cpp | 642 ---------------- ngraph/src/ngraph/pass/reshape_sinking.hpp | 33 - ngraph/src/ngraph/pass/serialize.cpp | 43 -- ngraph/src/ngraph/pass/serialize.hpp | 40 - ngraph/src/ngraph/pass/validate_graph.cpp | 48 -- ngraph/src/ngraph/pass/validate_graph.hpp | 38 - .../pass/zero_dim_tensor_elimination.cpp | 178 ----- .../pass/zero_dim_tensor_elimination.hpp | 39 - ngraph/test/CMakeLists.txt | 14 - ngraph/test/concat_fusion.cpp | 298 -------- ngraph/test/cse.cpp | 362 --------- ngraph/test/pass.cpp | 52 -- ngraph/test/pass_liveness.cpp | 4 +- ngraph/test/pass_manager.cpp | 13 - ngraph/test/pass_memory_layout.cpp | 234 ------ ngraph/test/pass_shape_relevance.cpp | 2 +- ngraph/test/provenance.cpp | 2 +- ngraph/test/reshape_elimination.cpp | 497 ------------ ngraph/test/reshape_sinking.cpp | 184 ----- ngraph/test/runtime/CMakeLists.txt | 12 + .../test/runtime/dynamic/dynamic_backend.cpp | 4 +- .../runtime/interpreter/int_executable.cpp | 8 +- ngraph/test/runtime/opset0_downgrade.cpp | 2 +- .../runtime}/pass/dyn_elimination.cpp | 0 .../runtime}/pass/dyn_elimination.hpp | 3 +- .../runtime}/pass/fused_op_decomposition.cpp | 2 +- .../runtime}/pass/fused_op_decomposition.hpp | 3 +- .../pass/implicit_broadcast_elimination.cpp | 2 +- .../pass/implicit_broadcast_elimination.hpp | 3 +- .../runtime}/pass/like_replacement.cpp | 0 .../runtime}/pass/like_replacement.hpp | 3 +- .../ngraph => test/runtime}/pass/liveness.cpp | 2 +- .../ngraph => test/runtime}/pass/liveness.hpp | 3 +- .../runtime}/pass/shape_relevance.cpp | 2 +- .../runtime}/pass/shape_relevance.hpp | 3 +- ngraph/test/tensor.cpp | 2 +- ngraph/test/zero_dim_tensor_elimination.cpp | 166 ---- 66 files changed, 39 insertions(+), 6342 deletions(-) delete mode 100644 ngraph/src/ngraph/pass/assign_layout.hpp delete mode 100644 ngraph/src/ngraph/pass/batch_fusion.cpp delete mode 100644 ngraph/src/ngraph/pass/batch_fusion.hpp delete mode 100644 ngraph/src/ngraph/pass/common_function_collection.cpp delete mode 100644 ngraph/src/ngraph/pass/common_function_collection.hpp delete mode 100644 ngraph/src/ngraph/pass/concat_fusion.cpp delete mode 100644 ngraph/src/ngraph/pass/concat_fusion.hpp delete mode 100644 ngraph/src/ngraph/pass/constant_to_broadcast.cpp delete mode 100644 ngraph/src/ngraph/pass/constant_to_broadcast.hpp delete mode 100644 ngraph/src/ngraph/pass/core_fusion.cpp delete mode 100644 ngraph/src/ngraph/pass/core_fusion.hpp delete mode 100644 ngraph/src/ngraph/pass/cse.cpp delete mode 100644 ngraph/src/ngraph/pass/cse.hpp delete mode 100644 ngraph/src/ngraph/pass/dump_sorted.cpp delete mode 100644 ngraph/src/ngraph/pass/dump_sorted.hpp delete mode 100644 ngraph/src/ngraph/pass/memory_layout.cpp delete mode 100644 ngraph/src/ngraph/pass/memory_layout.hpp delete mode 100644 ngraph/src/ngraph/pass/memory_visualize.cpp delete mode 100644 ngraph/src/ngraph/pass/memory_visualize.hpp delete mode 100644 ngraph/src/ngraph/pass/propagate_cacheability.cpp delete mode 100644 ngraph/src/ngraph/pass/propagate_cacheability.hpp delete mode 100644 ngraph/src/ngraph/pass/reshape_elimination.cpp delete mode 100644 ngraph/src/ngraph/pass/reshape_elimination.hpp delete mode 100644 ngraph/src/ngraph/pass/reshape_sinking.cpp delete mode 100644 ngraph/src/ngraph/pass/reshape_sinking.hpp delete mode 100644 ngraph/src/ngraph/pass/serialize.cpp delete mode 100644 ngraph/src/ngraph/pass/serialize.hpp delete mode 100644 ngraph/src/ngraph/pass/validate_graph.cpp delete mode 100644 ngraph/src/ngraph/pass/validate_graph.hpp delete mode 100644 ngraph/src/ngraph/pass/zero_dim_tensor_elimination.cpp delete mode 100644 ngraph/src/ngraph/pass/zero_dim_tensor_elimination.hpp delete mode 100644 ngraph/test/concat_fusion.cpp delete mode 100644 ngraph/test/cse.cpp delete mode 100644 ngraph/test/pass.cpp delete mode 100644 ngraph/test/pass_memory_layout.cpp delete mode 100644 ngraph/test/reshape_elimination.cpp delete mode 100644 ngraph/test/reshape_sinking.cpp rename ngraph/{src/ngraph => test/runtime}/pass/dyn_elimination.cpp (100%) rename ngraph/{src/ngraph => test/runtime}/pass/dyn_elimination.hpp (96%) rename ngraph/{src/ngraph => test/runtime}/pass/fused_op_decomposition.cpp (98%) rename ngraph/{src/ngraph => test/runtime}/pass/fused_op_decomposition.hpp (97%) rename ngraph/{src/ngraph => test/runtime}/pass/implicit_broadcast_elimination.cpp (97%) rename ngraph/{src/ngraph => test/runtime}/pass/implicit_broadcast_elimination.hpp (89%) rename ngraph/{src/ngraph => test/runtime}/pass/like_replacement.cpp (100%) rename ngraph/{src/ngraph => test/runtime}/pass/like_replacement.hpp (90%) rename ngraph/{src/ngraph => test/runtime}/pass/liveness.cpp (99%) rename ngraph/{src/ngraph => test/runtime}/pass/liveness.hpp (91%) rename ngraph/{src/ngraph => test/runtime}/pass/shape_relevance.cpp (98%) rename ngraph/{src/ngraph => test/runtime}/pass/shape_relevance.hpp (91%) delete mode 100644 ngraph/test/zero_dim_tensor_elimination.cpp diff --git a/inference-engine/tests/functional/inference_engine/transformations/convert_convolution_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/convert_convolution_test.cpp index 7a676fee952..0937cea4b7a 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/convert_convolution_test.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/convert_convolution_test.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp index fded8bd3c12..21f83d8af8a 100644 --- a/inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp +++ b/inference-engine/tests/functional/inference_engine/transformations/convert_deconvolution_test.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/ngraph/python/src/pyngraph/passes/manager.cpp b/ngraph/python/src/pyngraph/passes/manager.cpp index 3aff7825e2e..eca69eb0ea6 100644 --- a/ngraph/python/src/pyngraph/passes/manager.cpp +++ b/ngraph/python/src/pyngraph/passes/manager.cpp @@ -18,7 +18,6 @@ #include #include "ngraph/pass/manager.hpp" -#include "ngraph/pass/reshape_elimination.hpp" #include "pyngraph/passes/manager.hpp" namespace py = pybind11; @@ -28,6 +27,4 @@ void regclass_pyngraph_passes_Manager(py::module m) py::class_> manager(m, "Manager"); manager.doc() = "ngraph.impl.pass.Manager wraps ngraph::pass::Manager"; manager.def("run_passes", &ngraph::pass::Manager::run_passes); - manager.def("register_pass", - &ngraph::pass::Manager::register_pass); } diff --git a/ngraph/src/ngraph/CMakeLists.txt b/ngraph/src/ngraph/CMakeLists.txt index 655b53a03cc..4c904ecf8ad 100644 --- a/ngraph/src/ngraph/CMakeLists.txt +++ b/ngraph/src/ngraph/CMakeLists.txt @@ -454,13 +454,6 @@ set (SRC partial_shape.hpp pass/algebraic_simplification.cpp pass/algebraic_simplification.hpp - pass/assign_layout.hpp - pass/implicit_broadcast_elimination.hpp - pass/implicit_broadcast_elimination.cpp - pass/batch_fusion.hpp - pass/batch_fusion.cpp - pass/common_function_collection.cpp - pass/common_function_collection.hpp pass/constant_folding_arithmetic_reduction.cpp pass/constant_folding_convert.cpp pass/constant_folding_dequantize.cpp @@ -480,62 +473,25 @@ set (SRC pass/constant_folding_transpose.cpp pass/constant_folding.cpp pass/constant_folding.hpp - pass/constant_to_broadcast.cpp pass/convert_fp32_to_fp16.hpp pass/convert_fp32_to_fp16.cpp - pass/core_fusion.cpp - pass/core_fusion.hpp - pass/cse.cpp - pass/cse.hpp - pass/dump_sorted.cpp - pass/dump_sorted.hpp - pass/dyn_elimination.cpp - pass/dyn_elimination.hpp - pass/fused_op_decomposition.cpp - pass/fused_op_decomposition.hpp pass/get_output_element_elimination.cpp pass/get_output_element_elimination.hpp pass/graph_rewrite.cpp pass/graph_rewrite.hpp - pass/like_replacement.cpp - pass/like_replacement.hpp - pass/liveness.cpp - pass/liveness.hpp pass/manager.cpp pass/manager.hpp pass/manager_state.hpp - pass/memory_layout.cpp - pass/memory_layout.hpp - pass/memory_visualize.cpp - pass/memory_visualize.hpp pass/nop_elimination.cpp pass/nop_elimination.hpp pass/pass.cpp pass/pass.hpp pass/pass_config.cpp pass/pass_config.hpp - pass/propagate_cacheability.cpp - pass/propagate_cacheability.hpp - pass/reshape_elimination.cpp - pass/reshape_elimination.hpp - pass/reshape_sinking.cpp - pass/reshape_sinking.hpp - pass/serialize.cpp - pass/serialize.hpp - pass/shape_relevance.cpp - pass/shape_relevance.hpp - pass/validate_graph.cpp - pass/validate_graph.hpp pass/validate.cpp pass/validate.hpp pass/visualize_tree.cpp pass/visualize_tree.hpp - pass/zero_dim_tensor_elimination.cpp - pass/zero_dim_tensor_elimination.cpp - pass/zero_dim_tensor_elimination.hpp - pass/zero_dim_tensor_elimination.hpp - pass/concat_fusion.hpp - pass/concat_fusion.cpp pass/pass_util.hpp pass/pass_util.cpp pattern/matcher.cpp diff --git a/ngraph/src/ngraph/pass/assign_layout.hpp b/ngraph/src/ngraph/pass/assign_layout.hpp deleted file mode 100644 index 68f7cacebc3..00000000000 --- a/ngraph/src/ngraph/pass/assign_layout.hpp +++ /dev/null @@ -1,58 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include -#include - -#include "ngraph/descriptor/output.hpp" -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - template - class AssignLayout : public NodePass - { - public: - virtual bool run_on_node(std::shared_ptr node) override - { - try - { - for (size_t i = 0; i < node->get_output_size(); ++i) - { - auto tv = &node->output(i).get_tensor(); - if (nullptr == tv->get_tensor_layout()) - { - auto layout = std::make_shared(*tv); - tv->set_tensor_layout(layout); - } - } - } - catch (const std::exception& e) - { - std::stringstream ss; - ss << "Error with node " << *node << ": "; - ss << e.what(); - throw std::invalid_argument(ss.str()); - } - return false; - } - }; - } -} diff --git a/ngraph/src/ngraph/pass/batch_fusion.cpp b/ngraph/src/ngraph/pass/batch_fusion.cpp deleted file mode 100644 index 02dd36c941f..00000000000 --- a/ngraph/src/ngraph/pass/batch_fusion.cpp +++ /dev/null @@ -1,189 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include -#include -#include -#include -#include -#include - -#include "batch_fusion.hpp" - -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/dot.hpp" -#include "ngraph/op/group_conv.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/pattern/matcher.hpp" -#include "ngraph/pattern/op/label.hpp" -#include "ngraph/util.hpp" - -using namespace ngraph; - -#define TI(x) std::type_index(typeid(x)) - -std::shared_ptr set_or_check_if_same(std::shared_ptr oldn, std::shared_ptr newn) -{ - if (!oldn) - { - return newn; - } - else - { - if (oldn != newn) - { - NGRAPH_DEBUG << " different data nodes"; - return nullptr; - } - return oldn; - } -} - -static bool is_trivial_convolution(std::shared_ptr conv) -{ - Strides stride_1{1, 1}; - CoordinateDiff pad_0{0, 0}; - return conv->get_window_dilation_strides() == stride_1 && - conv->get_data_dilation_strides() == stride_1 && conv->get_padding_above() == pad_0 && - conv->get_padding_below() == pad_0; -} - -std::shared_ptr fuse_group_convolution(const std::shared_ptr& n) -{ - Shape win_size_1{1, 1, 1, 1}; - auto data_label = std::make_shared(element::f32, Shape{1, 4, 9}); - auto weights_label = std::make_shared(element::f32, Shape{4, 2, 3}); - - auto slice_data = std::make_shared( - data_label, Coordinate{0, 0, 0}, Coordinate{1, 2, 9}, Strides{1, 1, 1}); - auto slice_weights = std::make_shared( - weights_label, Coordinate{0, 0, 0}, Coordinate{2, 2, 3}, Strides{1, 1, 1}); - - auto slice_weights_label = - std::make_shared(slice_weights, nullptr, NodeVector{slice_weights}); - auto conv = std::make_shared(slice_data, slice_weights_label); - auto matcher = std::make_shared(conv); - - NGRAPH_DEBUG << "In simplify_concat (group convolution) for " << n->get_name(); - - std::shared_ptr data; - std::shared_ptr weights; - - auto concat = std::static_pointer_cast(n); - std::shared_ptr sconv; - - NodeVector slices; - - const size_t CHANNEL = 1; - if (concat->get_concatenation_axis() != CHANNEL) - { - NGRAPH_DEBUG << "concatenating on an axis different from channel"; - return {nullptr}; - } - - for (auto val : n->input_values()) - { - auto arg = val.get_node_shared_ptr(); - if (!matcher->match(arg)) - { - NGRAPH_DEBUG << arg->get_name() << " doesn't match"; - return {nullptr}; - } - - sconv = std::static_pointer_cast(arg); - - if (arg->get_input_shape(0).size() != 4) - { - NGRAPH_DEBUG << "convolution data's rank isn't equal to 4"; - return {nullptr}; - } - - if (!is_trivial_convolution(sconv)) - { - NGRAPH_DEBUG << arg->get_name() << " isn't trivial convolution"; - return {nullptr}; - } - - auto pattern_map = matcher->get_pattern_map(); - data = set_or_check_if_same(data, pattern_map[data_label]); - weights = set_or_check_if_same(weights, pattern_map[weights_label]); - - if (!data || !weights) - { - NGRAPH_DEBUG << "data or weights nodes are different among slices"; - return {nullptr}; - } - - const size_t IC = 1; - auto slice = pattern_map[slice_weights_label]; - if (weights->get_shape().at(IC) != slice->get_shape().at(IC)) - { - slices.push_back(slice); - } - } - - // TF-flavoured group convolution needs channels re-arranged - // MKLDNN requires group slicing to be done on OC - // MKLDNN [4,2,-] - // ordering w00 w01 w10 w11 w20 w21 w30 w31 produces g00 g01 g10 g11 - // whereas - // TF [2,4,-] - // ordering w00 w01 w02 w03 w10 w11 w12 w13 produces g00 g10 g01 g11 - const size_t CONCAT_AXIS_OC = 0; - if (!slices.empty()) - { - weights = std::make_shared(slices, CONCAT_AXIS_OC); - } - - auto new_conv = std::make_shared(data, - weights, - sconv->get_window_movement_strides(), - sconv->get_window_dilation_strides(), - sconv->get_padding_below(), - sconv->get_padding_above(), - sconv->get_data_dilation_strides(), - n->input_values().size()); - - return move(new_conv); -} - -bool ngraph::pass::BatchFusion::run_on_function(std::shared_ptr func) -{ - bool modified = false; - - for (auto n : func->get_ordered_ops()) - { - const Node& node = *n; - if (TI(node) == TI(op::Concat)) - { - if (m_fusion_type.is_set(FusionType::REGULAR_FUSIONS)) - { - if (auto fused_conv = fuse_group_convolution(n)) - { - func->replace_node(n, fused_conv); - modified = true; - } - } - } - } - return modified; -} diff --git a/ngraph/src/ngraph/pass/batch_fusion.hpp b/ngraph/src/ngraph/pass/batch_fusion.hpp deleted file mode 100644 index 9f2eeda2428..00000000000 --- a/ngraph/src/ngraph/pass/batch_fusion.hpp +++ /dev/null @@ -1,40 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class NGRAPH_API BatchFusion : public ngraph::pass::FunctionPass - { - public: - BatchFusion(FusionTypeMask type = FusionType::ALL_FUSIONS) - : FunctionPass() - , m_fusion_type(type) - { - set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); - } - virtual bool run_on_function(std::shared_ptr function) override; - - private: - FusionTypeMask m_fusion_type; - }; - } -} diff --git a/ngraph/src/ngraph/pass/common_function_collection.cpp b/ngraph/src/ngraph/pass/common_function_collection.cpp deleted file mode 100644 index aee32bf8905..00000000000 --- a/ngraph/src/ngraph/pass/common_function_collection.cpp +++ /dev/null @@ -1,113 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include - -#include "common_function_collection.hpp" -#include "ngraph/op/util/op_types.hpp" - -using namespace std; -using namespace ngraph; - -pass::CommonFunctionCollection::CommonFunctionCollection(function emitter, - unordered_map& result_map, - string& emitted_functions) - : m_emit_op_as_function(emitter) - , m_node_function_map(result_map) - , m_emitted_functions(emitted_functions) -{ -} - -pass::CommonFunctionCollection::~CommonFunctionCollection() -{ -} - -bool pass::CommonFunctionCollection::run_on_module(vector>& functions) -{ - // This for loop creates a collection of functions that are called more than once - // and emitting them as globally callable functions. - - // match_function_map `key` contains the entire string of the function emitted for the - // `value` Node* - unordered_map match_function_map; - stringstream ss; - const string function_name = "__f__"; - for (const shared_ptr& current_function : functions) - { - for (const shared_ptr& n : current_function->get_ordered_ops()) - { - if (op::is_constant(n) || op::is_parameter(n)) - { - continue; - } - if (op::is_op(n)) - { - auto op = std::static_pointer_cast(n); - auto annotations = op->get_op_annotations(); - // If an op is passed through, do not add it to the common function - // collection so that the emitter can decide to eliminate it if desired - if (annotations && annotations->get_in_place_oi_pairs().size() > 0) - { - continue; - } - } - - Node& node = *n; - - // First emit the op as a function, something like this: - // static void __f__(float* _arg0, float *_out1) - // { - // op specific code here - // } - // - // Then do a simple string compare in match_function_map to see if there is - // another op that emits the exact same code. - // If a match is found then the current node is mapped to call the original node's - // function and the original node is *also* mapped to call the original node's function. - // We also emit the static function declaration to m_emitted_functions when the match - // is found the first time. - string match_function = m_emit_op_as_function(node, function_name); - auto it = match_function_map.find(match_function); - if (it != match_function_map.end()) - { - m_node_function_map.insert({&node, it->second}); - if (m_node_function_map.find(it->second) == m_node_function_map.end()) - { - m_node_function_map.insert({it->second, it->second}); - - // All of the functions are created with the same name `__f__` so here - // we rename it to something unique so we can compile everything when done. - auto offset = match_function.find(function_name); - string emitted_function = match_function; - string match_function_name = create_function_name(*it->second); - emitted_function.replace(offset, function_name.size(), match_function_name); - ss << emitted_function << "\n"; - } - } - else - { - match_function_map.insert({match_function, &node}); - } - } - } - m_emitted_functions = ss.str(); - return false; -} - -string pass::CommonFunctionCollection::create_function_name(const Node& node) -{ - return "func_" + node.get_name(); -} diff --git a/ngraph/src/ngraph/pass/common_function_collection.hpp b/ngraph/src/ngraph/pass/common_function_collection.hpp deleted file mode 100644 index c36924cd339..00000000000 --- a/ngraph/src/ngraph/pass/common_function_collection.hpp +++ /dev/null @@ -1,62 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include - -#include "ngraph/code_writer.hpp" -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class CommonFunctionCollection; - } -} - -class NGRAPH_API ngraph::pass::CommonFunctionCollection : public ModulePass -{ -public: - /// \brief Create the CommonFunctionCollection pass - /// \param function_emitter - This is a function that takes a reference to a Node and as string. - /// The string is the name of the emitted function and the body of the function is - /// the code for the op. - /// \param result_map - This is a mapping of source node -> emitted static function node, where - /// the key is the source node and the value is the emitted static function node. The - /// name of the function to call is create_function_name() - /// \param emitted_functions - string to contain the emitted code for all of the static - /// functions. - CommonFunctionCollection(std::function function_emitter, - std::unordered_map& result_map, - std::string& emitted_functions); - - virtual ~CommonFunctionCollection() override; - - bool run_on_module(std::vector>&) override; - - /// \brief Construct the name of the function to call for this op - /// \param node - Node used to construct the function name. This node is the `value` of the - /// result_map passed to the pass's constructor. - /// \return string containing the name of the function to be called - static std::string create_function_name(const Node& node); - -private: - std::function m_emit_op_as_function; - std::unordered_map& m_node_function_map; - std::string& m_emitted_functions; -}; diff --git a/ngraph/src/ngraph/pass/concat_fusion.cpp b/ngraph/src/ngraph/pass/concat_fusion.cpp deleted file mode 100644 index 2fdbd6ef7b8..00000000000 --- a/ngraph/src/ngraph/pass/concat_fusion.cpp +++ /dev/null @@ -1,282 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include "concat_fusion.hpp" -#include -#include -#include -#include - -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/pattern/matcher.hpp" -#include "ngraph/pattern/op/label.hpp" -#include "ngraph/pattern/op/skip.hpp" -#include "ngraph/util.hpp" - -using namespace ngraph; - -namespace -{ - bool check_self_concat_op(const std::shared_ptr& op) - { - auto input_vals = op->input_values(); - std::set> input_args_set; - for (auto val : input_vals) - input_args_set.emplace(val.get_node_shared_ptr()); - return (input_args_set.size() == 1); - } - - bool check_concat_axis_dim_value(const std::shared_ptr& concat_op) - { - auto input_shape = concat_op->get_input_shape(0); - size_t concat_axis = - std::static_pointer_cast(concat_op)->get_concatenation_axis(); - - return (input_shape[concat_axis] == 1); - } - - bool check_concat_has_no_fan_out(const std::shared_ptr& op) - { - auto no_fan_out = ngraph::pass::get_no_fan_out_function(); - return no_fan_out(op); - } - - bool valid_self_concat(const std::shared_ptr& Op) - { - if (!check_self_concat_op(Op)) - { - NGRAPH_DEBUG << "self_concat_fusion: Matcher matched " << Op->get_name() - << " but it is not a self concat\n"; - return false; - } - - if (!check_concat_axis_dim_value(Op)) - { - NGRAPH_DEBUG << "self_concat_fusion: Input shape value along concat axis of " - << Op->get_name() << " is not equal to 1\n"; - return false; - } - - return true; - } - - std::vector get_concatenation_axis_vector(const NodeVector& bounded_concat_ops) - { - std::vector concat_axis_vec; - for (auto iter : bounded_concat_ops) - { - auto concat_op = std::static_pointer_cast(iter); - concat_axis_vec.push_back(concat_op->get_concatenation_axis()); - } - return concat_axis_vec; - } -} - -void pass::ConcatElimination::construct_concat_elimination() -{ - auto op_label = std::make_shared(element::f32, Shape{1, 3}); - auto concat = std::make_shared(NodeVector{op_label}, 0); - auto concat_label = std::make_shared(concat, nullptr, NodeVector{concat}); - - auto callback = [op_label](pattern::Matcher& m) { - NGRAPH_DEBUG - << "concat_elimination: In callback for construct_concat_elimination against node = " - << m.get_match_root()->get_name(); - auto pattern_map = m.get_pattern_map(); - auto op = pattern_map[op_label]; - - auto root = as_type_ptr(m.get_match_root()); - if (root && (root->get_input_shape(0) == root->get_output_shape(0))) - { - NGRAPH_DEBUG << " eliminated " << m.get_match_root() << "\n"; - replace_node(m.get_match_root(), op); - - return true; - } - NGRAPH_DEBUG << " Incorrect match in callback\n"; - return false; - }; - - auto m = std::make_shared(concat_label, "ConcatElimination"); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} - -bool ngraph::pass::SelfConcatFusion::run_on_function(std::shared_ptr function) -{ - bool modify_graph = false; - auto has_multiple_inputs = [](std::shared_ptr n) { - auto input_size = n->get_input_size(); - auto root = as_type_ptr(n); - return (root && input_size > 1); - }; - - auto print_state_of_bounded_vectors = [this]() -> std::string { - std::stringstream ss; - ss << "-----------------------------------------------------------" << std::endl; - ss << "State of bounded pattern node vectors: " << std::endl; - ss << "-----------------------------------------------------------" << std::endl; - ss << "Number of pattern node vectors: " << this->m_concat_pattern_vectors.size() - << std::endl; - size_t c = 0; - for (auto iter : this->m_concat_pattern_vectors) - { - ss << "For vector " << c << std::endl; - auto iter_node_vec = iter; - ss << "concat_op_vector: "; - for (auto it : iter_node_vec) - { - ss << it->get_name() << " "; - } - ss << std::endl; - c++; - } - ss << "-----------------------------" << std::endl; - return ss.str(); - }; - - auto concat_op_label = - std::make_shared(element::f32, Shape{1, 3}, has_multiple_inputs); - auto matcher = std::make_shared(concat_op_label); - for (auto n : function->get_ordered_ops()) - { - construct_concat_patterns(matcher, concat_op_label, n); - } - - NGRAPH_DEBUG << print_state_of_bounded_vectors(); - - for (auto concat_op_pattern_node_vector : this->m_concat_pattern_vectors) - { - modify_graph = replace_patterns(concat_op_pattern_node_vector); - } - - return modify_graph; -} - -void ngraph::pass::SelfConcatFusion::construct_concat_patterns( - const std::shared_ptr& matcher, - const std::shared_ptr& concat_op_label, - const std::shared_ptr& n) -{ - if (matcher->match(n)) - { - auto concat_op = matcher->get_pattern_map()[concat_op_label]; - if (!is_type(concat_op)) - { - NGRAPH_DEBUG << "self_concat_fusion: Pattern matcher matched incorrect op. Matched " - << concat_op->get_name() << " instead of a self concat"; - return; - } - if (!valid_self_concat(concat_op)) - { - NGRAPH_DEBUG << "self_concat_fusion: " << concat_op->get_name() - << " is not a valid self concat\n"; - return; - } - else - { - NGRAPH_DEBUG << "self_concat_fusion: " << concat_op->get_name() - << " is a VALID self concat\n"; - } - - auto& concat_vectors = this->m_concat_pattern_vectors; - if (concat_vectors.empty()) - { - concat_vectors.push_back(NodeVector{concat_op}); - } - else - { - update_concat_pattern_vectors(concat_op); - } - } -} - -void ngraph::pass::SelfConcatFusion::update_concat_pattern_vectors( - const std::shared_ptr& concat_op) -{ - bool concat_source_found = false; - for (auto& concat_pattern_vec : this->m_concat_pattern_vectors) - { - auto last_op_in_pattern_vec = concat_pattern_vec.back(); - if ((concat_op->input_value(0).get_node_shared_ptr() == last_op_in_pattern_vec) && - (check_concat_has_no_fan_out(last_op_in_pattern_vec))) - { - concat_pattern_vec.push_back(concat_op); - concat_source_found = true; - break; - } - } - - if (!concat_source_found) - { - this->m_concat_pattern_vectors.push_back(NodeVector{concat_op}); - } -} - -void ngraph::pass::SelfConcatFusion::remove_single_concat_op_pattern() -{ - auto iter = m_concat_pattern_vectors.begin(); - while (iter != m_concat_pattern_vectors.end()) - { - if (iter->size() == 1) - { - iter = m_concat_pattern_vectors.erase(iter); - } - else - { - iter++; - } - } -} - -bool ngraph::pass::SelfConcatFusion::replace_patterns(const NodeVector& bounded_concat_ops) -{ - auto scalarize_dim = [](std::vector concat_axis_vector, - const Shape& input_shape) -> Shape { - - Shape scalarized_shape; - for (size_t i = 0; i < input_shape.size(); i++) - { - auto it = std::find(concat_axis_vector.begin(), concat_axis_vector.end(), i); - if (it == concat_axis_vector.end()) - { - scalarized_shape.push_back(input_shape[i]); - } - } - return scalarized_shape; - }; - - auto concat_axis_vector = get_concatenation_axis_vector(bounded_concat_ops); - - auto& first_bounded_concat = (*bounded_concat_ops.begin()); - auto driver_op = first_bounded_concat->input_value(0); - const Shape& input_shape = first_bounded_concat->get_input_shape(0); - - auto scalarized_shape = scalarize_dim(concat_axis_vector, input_shape); - AxisVector axis_order = get_default_order(input_shape); - auto reshape = std::make_shared(driver_op, axis_order, scalarized_shape); - auto last_bounded_concat_op = bounded_concat_ops.back(); - auto broadcast_out_shape = last_bounded_concat_op->get_shape(); - auto broadcast = - std::make_shared(reshape, broadcast_out_shape, concat_axis_vector); - - replace_node(last_bounded_concat_op, broadcast); - return true; -} diff --git a/ngraph/src/ngraph/pass/concat_fusion.hpp b/ngraph/src/ngraph/pass/concat_fusion.hpp deleted file mode 100644 index 0854a70f49a..00000000000 --- a/ngraph/src/ngraph/pass/concat_fusion.hpp +++ /dev/null @@ -1,61 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/graph_rewrite.hpp" -#include "ngraph/pass/pass.hpp" -#include "ngraph/pass/pass_util.hpp" -#include "ngraph/pattern/matcher.hpp" -#include "ngraph/pattern/op/label.hpp" - -namespace ngraph -{ - namespace pass - { - class ConcatElimination; - class SelfConcatFusion; - } -} - -class NGRAPH_API ngraph::pass::ConcatElimination : public ngraph::pass::GraphRewrite -{ -public: - ConcatElimination() - : GraphRewrite() - { - construct_concat_elimination(); - } - -private: - void construct_concat_elimination(); -}; - -class NGRAPH_API ngraph::pass::SelfConcatFusion : public ngraph::pass::FunctionPass -{ -public: - SelfConcatFusion() { set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); } - virtual bool run_on_function(std::shared_ptr function) override; - -private: - void update_concat_pattern_vectors(const std::shared_ptr&); - void remove_single_concat_op_pattern(); - void construct_concat_patterns(const std::shared_ptr&, - const std::shared_ptr&, - const std::shared_ptr&); - bool replace_patterns(const NodeVector&); - std::vector m_concat_pattern_vectors; -}; diff --git a/ngraph/src/ngraph/pass/constant_to_broadcast.cpp b/ngraph/src/ngraph/pass/constant_to_broadcast.cpp deleted file mode 100644 index a24a881b87b..00000000000 --- a/ngraph/src/ngraph/pass/constant_to_broadcast.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include "ngraph/pass/constant_to_broadcast.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/constant.hpp" - -using namespace std; -using namespace ngraph; - -bool pass::ConstantToBroadcast::run_on_node(shared_ptr node) -{ - const size_t minimum_size_of_interest = 32; - bool modified = false; - if (node->description() == "Constant") - { - auto constant = static_pointer_cast(node); - size_t size = shape_size(constant->get_shape()); - if (size > minimum_size_of_interest) - { - if (constant->get_all_data_elements_bitwise_identical()) - { - auto scalar_constant = make_shared( - constant->get_element_type(), Shape{}, constant->get_data_ptr()); - AxisSet broadcast_axes; - for (size_t i = 0; i < constant->get_output_shape(0).size(); i++) - { - broadcast_axes.insert(i); - } - auto broadcast = make_shared( - scalar_constant, constant->get_output_shape(0), broadcast_axes); - replace_node(constant, broadcast); - } - } - } - return modified; -} diff --git a/ngraph/src/ngraph/pass/constant_to_broadcast.hpp b/ngraph/src/ngraph/pass/constant_to_broadcast.hpp deleted file mode 100644 index 86d1afb0110..00000000000 --- a/ngraph/src/ngraph/pass/constant_to_broadcast.hpp +++ /dev/null @@ -1,33 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class ConstantToBroadcast; - } -} - -class NGRAPH_API ngraph::pass::ConstantToBroadcast : public NodePass -{ -public: - bool run_on_node(std::shared_ptr) override; -}; diff --git a/ngraph/src/ngraph/pass/core_fusion.cpp b/ngraph/src/ngraph/pass/core_fusion.cpp deleted file mode 100644 index f6e6293fa14..00000000000 --- a/ngraph/src/ngraph/pass/core_fusion.cpp +++ /dev/null @@ -1,722 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include - -#include "ngraph/pass/core_fusion.hpp" - -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/batch_norm.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/convert.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/exp.hpp" -#include "ngraph/op/log.hpp" -#include "ngraph/op/max.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/maximum.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/negative.hpp" -#include "ngraph/op/not_equal.hpp" -#include "ngraph/op/one_hot.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/op/relu.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/sigmoid.hpp" -#include "ngraph/op/softmax.hpp" -#include "ngraph/op/sqrt.hpp" -#include "ngraph/op/subtract.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/pass/graph_rewrite.hpp" -#include "ngraph/pass/manager.hpp" -#include "ngraph/pattern/matcher.hpp" -#include "ngraph/pattern/op/label.hpp" -#include "ngraph/pattern/op/skip.hpp" - -using namespace ngraph; -using namespace std; - -static shared_ptr construct_constant_node(int n) -{ - return op::Constant::create(element::f32, Shape{}, {n}); -} - -void pass::CoreFusion::construct_relu() -{ - auto iconst0 = construct_constant_node(0); - auto val = make_shared(iconst0); - auto zero = make_shared(iconst0, nullptr, NodeVector{iconst0}); - - auto skip_broadcast = make_shared(zero, pattern::has_class()); - auto max = make_shared(skip_broadcast, val); - - auto callback = [val, zero](pattern::Matcher& m) { - NGRAPH_DEBUG << "In a callback for construct_relu against " - << m.get_match_root()->get_name(); - - auto pattern_map = m.get_pattern_map(); - auto mzero = m.get_pattern_map()[zero]; - if (!is_zero(mzero)) - { - NGRAPH_DEBUG << "zero constant = " << mzero->get_name() << " not equal to 0\n"; - return false; - } - auto mpattern = m.get_match_root(); - - auto cg = shared_ptr(new op::Relu(pattern_map[val])); - replace_node(m.get_match_root(), cg); - return true; - }; - - auto m = make_shared(max, "CoreFusion.Relu"); - this->add_matcher(m, callback, all_pass_property_off); -} - -void pass::CoreFusion::construct_sigmoid() -{ - // construct variance - auto input = make_shared(element::f32, Shape{3, 4}); - auto neg_input = make_shared(input); - auto exp_neg_input = make_shared(neg_input); - - auto constant = make_shared(element::f32, Shape{3, 4}); - auto skip_broadcast = - make_shared(constant, pattern::has_class()); - - auto add_exp = make_shared(exp_neg_input, skip_broadcast); - auto divide_1_over_exp = make_shared(skip_broadcast, add_exp); - - // Define a call back that needs to called once the DFG matches the pattern - auto callback = [input, constant](pattern::Matcher& m) { - NGRAPH_DEBUG << "In a callback for construct_fprop_sigmoid pattern against " - << m.get_match_root()->get_name(); - auto pattern_map = m.get_pattern_map(); - - if (m.get_match_root()->get_element_type() != element::f32) - { - NGRAPH_DEBUG << "mpattern = " << m.get_match_root()->get_name() - << " type is not float!"; - return false; - } - - if (m.get_match_root()->get_output_size() != pattern_map[input]->get_output_size()) - { - NGRAPH_DEBUG << "mpattern = " << m.get_match_root()->get_name() - << "input= " << pattern_map[input]->get_name() << "size dont match!"; - return false; - } - - if (!is_one(pattern_map[constant])) - { - NGRAPH_DEBUG << "Node not constant or not 1"; - return false; - } - auto sigmoid_node = make_shared(pattern_map[input]); - replace_node(m.get_match_root(), sigmoid_node); - return true; - }; - - auto m = std::make_shared(divide_1_over_exp, "CoreFusion.Sigmoid"); - this->add_matcher(m, callback, all_pass_property_off); -} - -void pass::CoreFusion::construct_folded_batch_norm() -{ - Shape shape{2, 2, 1, 1}; - auto input = make_shared(element::f32, shape); - auto filters = make_shared(element::f32, shape); - - auto pconv = make_shared(input, - filters, - Strides{1, 1}, - Strides{1, 1}, - CoordinateDiff{0, 0}, - CoordinateDiff{0, 0}, - Strides{1, 1}); - auto mean_shape = Shape{2}; - auto mean = make_shared(element::f32, mean_shape); - auto var_shape = Shape{2}; - auto var = make_shared(element::f32, var_shape); - auto gamma_shape = Shape{2}; - auto gamma = make_shared(element::f32, gamma_shape); - auto beta_shape = Shape{2}; - auto beta = make_shared(element::f32, beta_shape); - double eps = 0.001; - auto shape_r = Shape{1, 2, 2, 2}; - auto bn = make_shared(pconv, gamma, beta, mean, var, eps); - - auto callback = [input, filters, mean, var, gamma, beta](pattern::Matcher& m) { - NGRAPH_DEBUG << "In callback for folded batch norm against node = " - << m.get_match_root()->get_name(); - auto pattern_map = m.get_pattern_map(); - - auto m_bn = static_pointer_cast(m.get_match_root()); - auto m_conv = - static_pointer_cast(m_bn->input_value(2).get_node_shared_ptr()); - - if (m_conv->get_users().size() > 1) - { - return false; - } - - if (m_conv->get_shape().size() != 4) - { - return false; - } - - // new weights = old weights * gamma / sqrt(variance + epsilon) - // new biases = -mean * gamma / sqrt(variance + epsilon) + beta - - auto bn_eps = op::Constant::create(element::f32, Shape{}, {m_bn->get_eps_value()}); - auto var_eps = make_shared( - pattern_map[var], - make_shared(bn_eps, pattern_map[var]->get_shape(), AxisSet{0})); - auto sqrt_var_eps = make_shared(var_eps); - - auto mean_gamma = make_shared(pattern_map[mean], pattern_map[gamma]); - auto new_biases = make_shared( - pattern_map[beta], make_shared(mean_gamma, sqrt_var_eps)); - auto weight_scaling = make_shared(pattern_map[gamma], sqrt_var_eps); - auto new_weights = make_shared( - pattern_map[filters], - make_shared( - weight_scaling, pattern_map[filters]->get_shape(), AxisSet{1, 2, 3})); - - auto conv = make_shared(pattern_map[input], - new_weights, - m_conv->get_window_movement_strides(), - m_conv->get_window_dilation_strides(), - m_conv->get_padding_below(), - m_conv->get_padding_above(), - m_conv->get_data_dilation_strides()); - auto conv_bias = - conv + make_shared(new_biases, conv->get_shape(), AxisSet{0, 2, 3}); - replace_node(m.get_match_root(), conv_bias); - - return true; - - }; - - auto m = std::make_shared(bn, "CoreFusion.FoldedBatchNorm"); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} - -void pass::CoreFusion::construct_conv_affine_folding() -{ - // A * Conv (input, filters) + B -> ConvBias (input, filters * A_c, B_c) - Shape shape{2, 2, 1, 1}; - auto input = make_shared(element::f32, shape); - auto filters = make_shared(element::f32, shape); - - auto conv = make_shared(input, - filters, - Strides{1, 1}, - Strides{1, 1}, - CoordinateDiff{0, 0}, - CoordinateDiff{0, 0}, - Strides{1, 1}); - auto conv_label = make_shared(conv, nullptr, NodeVector{conv}); - - auto Ac = make_shared(element::f32, Shape{2}); - auto A = make_shared(Ac, Shape{2, 2, 1, 1}, AxisSet{0, 2, 3}); - auto A_label = make_shared(A, nullptr, NodeVector{A}); - auto Bc = make_shared(element::f32, Shape{2}); - auto B = make_shared(Bc, Shape{2, 2, 1, 1}, AxisSet{0, 2, 3}); - auto B_label = make_shared(B, nullptr, NodeVector{B}); - auto multiply = make_shared(conv_label, A_label); - auto add = make_shared(multiply, B_label); - - auto callback = [input, filters, conv_label, A_label, B_label](pattern::Matcher& m) { - NGRAPH_DEBUG << "In callback for conv affine folding against node = " - << m.get_match_root()->get_name(); - auto pattern_map = m.get_pattern_map(); - - auto conv_m = static_pointer_cast(pattern_map[conv_label]); - - if (conv_m->get_users().size() > 1) - { - return false; - } - - if (conv_m->get_shape().size() != 4) - { - return false; - } - - auto A_m = static_pointer_cast(pattern_map[A_label]); - auto B_m = static_pointer_cast(pattern_map[B_label]); - - // Check if values are being broadcast along channel (2nd) dimension - auto is_channel_bcast = [](const shared_ptr& bcast) { - - if (bcast->get_input_shape(0).size() == 1 && - bcast->get_broadcast_axes() == AxisSet{0, 2, 3}) - { - return true; - } - - if (bcast->get_input_shape(0).size() == 2) - { - auto input_shape = bcast->get_input_shape(0); - if (input_shape[0] == 1 && bcast->get_broadcast_axes() == AxisSet{2, 3}) - return true; - } - return false; - }; - - if (!is_channel_bcast(A_m) || !is_channel_bcast(B_m)) - { - return false; - } - - auto get_bcast_input = [](const shared_ptr& bcast) { - if (bcast->get_input_shape(0).size() == 1) - { - return bcast->input_value(0).get_node_shared_ptr(); - } - if (bcast->get_input_shape(0).size() == 2) - { - Shape bshape{bcast->get_input_shape(0)[1]}; - return static_pointer_cast( - make_shared(bcast->input_value(0), AxisVector{0, 1}, bshape)); - } - throw ngraph_error("Unexpected shape for bcast input"); - }; - - auto Ac_m = get_bcast_input(A_m); - - // new weights = old weights * Ac_m - // new biases = Bc_m - - auto filters_n = make_shared( - pattern_map[filters], - make_shared(Ac_m, pattern_map[filters]->get_shape(), AxisSet{1, 2, 3})); - - auto conv_n = make_shared(pattern_map[input], - filters_n, - conv_m->get_window_movement_strides(), - conv_m->get_window_dilation_strides(), - conv_m->get_padding_below(), - conv_m->get_padding_above(), - conv_m->get_data_dilation_strides()); - auto convbias_n = conv_n + B_m; - replace_node(m.get_match_root(), convbias_n); - - return true; - - }; - - auto m = make_shared(add, "CoreFusion.ConvAffineFolding"); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} - -static bool is_trivial_convolution(shared_ptr conv, bool skip_pad_checks = false) -{ - Strides stride_1{1, 1}; - CoordinateDiff pad_0{0, 0}; - - return conv->get_window_dilation_strides() == stride_1 && - conv->get_data_dilation_strides() == stride_1 && - (skip_pad_checks || - (conv->get_padding_above() == pad_0 && conv->get_padding_below() == pad_0)); -} - -static bool are_img_dims_equal(Shape conv_shape, Shape image_shape) -{ - if (conv_shape.size() != 4) - { - return false; - } - - return conv_shape[2] == image_shape[0] && conv_shape[3] == image_shape[1]; -} - -static shared_ptr reduce_broadcast(shared_ptr broadcast) -{ - const size_t H = 2; - const size_t W = 3; - auto matched_broadcast_w1 = static_pointer_cast(broadcast); - Shape shape_w1{matched_broadcast_w1->get_shape()}; - shape_w1[H] /= 2; - shape_w1[W] /= 2; - auto new_broadcast_w1 = std::make_shared( - matched_broadcast_w1->input_value(0), shape_w1, matched_broadcast_w1->get_broadcast_axes()); - return move(new_broadcast_w1); -} - -static size_t shape_to_index(Shape shape) -{ - if (shape.size() != 4) - { - return 0; - } - const size_t HEIGHT_DIM = 2; - const size_t WIDTH_DIM = 3; - - if (shape.at(HEIGHT_DIM) != shape.at(WIDTH_DIM)) - { - return 0; - } - - switch (shape.at(HEIGHT_DIM)) - { - case 28: return 1; - case 14: return 2; - case 7: return 3; - default: return 0; - } -} - -void pass::CoreFusion::construct_reshape_broadcast() -{ - Shape input_shape{10}; - auto input = make_shared(element::f32, input_shape); - auto reshape1 = make_shared(input, AxisVector{0}, Shape{10, 1}); - auto broadcast = make_shared(reshape1, Shape{10, 1, 20}, AxisSet{2}); - - auto callback = [input](pattern::Matcher& m) { - NGRAPH_DEBUG << "In a callback for construct_reshape_broadcast against " - << m.get_match_root()->get_name(); - - auto pattern_map = m.get_pattern_map(); - auto broadcast_m = static_pointer_cast(m.get_match_root()); - auto reshape1_m = - static_pointer_cast(broadcast_m->input_value(0).get_node_shared_ptr()); - auto input_m = m.get_pattern_value_map()[input]; - - // it doesn't seem to make sense to support shapes : [0] or [1] - if (input_m.get_shape().size() != 1 || input_m.get_shape().at(0) < 2) - { - NGRAPH_DEBUG << "input_m isn't a scalar or contains zero dimension"; - return false; - } - - size_t dim = input_m.get_shape().at(0); - - // We are going to support the most common case where broadcast doesn't add 1-dimensions - // since it's also very simple to implement - size_t dim_one_count = 0; - for (auto d : reshape1_m->get_shape()) - { - if (d != 1 && d != dim) - { - NGRAPH_DEBUG << "Input is reshaped in a way we can't directly broadcast ( shape = " - << vector_to_string(reshape1_m->get_shape()) << ")"; - return false; - } - - if (d == 1) - { - dim_one_count++; - } - } - - AxisSet new_axes = broadcast_m->get_broadcast_axes(); - auto broadcast_shape = broadcast_m->get_shape(); - for (size_t i = 0; i < broadcast_shape.size(); i++) - { - if (broadcast_shape[i] == 1) - { - dim_one_count--; - new_axes.insert(i); - } - } - - if (dim_one_count != 0) - { - NGRAPH_DEBUG << "Broadcast adds 1-dimensions"; - return false; - } - - auto new_broadcast = - make_shared(input_m, broadcast_m->get_shape(), new_axes); - replace_node(m.get_match_root(), new_broadcast); - return true; - }; - - auto m = make_shared(broadcast, "CoreFusion.ReshapeBroadcast"); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} - -void pass::CoreFusion::construct_reshape_softmax_reshape() -{ - Shape input_shape{10, 20}; - AxisVector io{1, 0}; - auto input = make_shared(element::f32, input_shape); - auto reshape1 = make_shared(input, io, Shape{20, 10}); - auto softmax = make_shared(reshape1, AxisSet{1}); - auto reshape2 = make_shared(softmax, io, input_shape); - - auto callback = [input](pattern::Matcher& m) { - NGRAPH_DEBUG << "In a callback for construct_reshape_softmax_reshape against " - << m.get_match_root()->get_name(); - - auto pattern_map = m.get_pattern_map(); - auto reshape2_m = static_pointer_cast(m.get_match_root()); - auto softmax_m = - static_pointer_cast(reshape2_m->input_value(0).get_node_shared_ptr()); - auto reshape1_m = - static_pointer_cast(softmax_m->input_value(0).get_node_shared_ptr()); - auto input_m = m.get_pattern_map()[input]; - - if (!reshape2_m->get_is_transpose() || !reshape1_m->get_is_transpose()) - { - NGRAPH_DEBUG << "we expect reshape2 and reshape1 both be dimshuffles"; - return false; - } - - if (input_m->get_shape() != reshape2_m->get_shape()) - { - NGRAPH_DEBUG << "input and reshape2's shape are different"; - return false; - } - - AxisSet new_axes; - const auto& axis_order = reshape2_m->get_input_order(); - for (auto axis : softmax_m->get_axes()) - { - new_axes.insert(axis_order.at(axis)); - } - - auto new_softmax = make_shared(input_m, new_axes); - replace_node(m.get_match_root(), new_softmax); - return true; - }; - - auto m = make_shared(reshape2, "CoreFusion.ReshapeSoftmaxReshape"); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} - -static bool - zero_padded_conv_consistency_check(const std::shared_ptr& match_root, - const std::shared_ptr& pad_value_op, - const std::shared_ptr& pad_input, - const std::shared_ptr& matched_pad, - const ngraph::CoordinateDiff& padding_below, - const ngraph::CoordinateDiff& padding_above, - size_t batch_index, - size_t channel_index) -{ - // Only match float32 convolutions - if (match_root->get_element_type() != ngraph::element::f32) - { - return false; - } - - // Only match zero padding - if (pad_value_op->get_vector().at(0) != 0.0f) - { - return false; - } - - // Only match 4D tensors - if (pad_input->get_shape().size() != 4) - { - return false; - } - - // Only match convolutions with no padding specification - if (padding_below != ngraph::CoordinateDiff(2) || padding_above != ngraph::CoordinateDiff(2)) - { - return false; - } - - // Only match constant padding - if (matched_pad->get_pad_mode() != ngraph::op::PadMode::CONSTANT) - { - return false; - } - - // Only match no padding in the batch dimension - if (matched_pad->get_padding_above().at(batch_index) != 0 || - matched_pad->get_padding_below().at(batch_index) != 0) - { - return false; - } - - // Only match no padding in the channel dimension - if (matched_pad->get_padding_above().at(channel_index) != 0 || - matched_pad->get_padding_below().at(channel_index) != 0) - { - return false; - } - - return true; -} - -void pass::CoreFusion::construct_zero_padded_reshaped_conv() -{ - auto pad_input = std::make_shared(element::f32, Shape{}); - auto pad_value = std::make_shared(element::f32, Shape{}); - auto pad = - std::make_shared(pad_input, pad_value, CoordinateDiff{}, CoordinateDiff{}); - auto pad_label = std::make_shared(pad, nullptr, NodeVector{pad}); - - auto reshape = - std::make_shared(pad_label, AxisVector{}, Shape{1, 1, 1, 1}); - auto reshape_label = - std::make_shared(reshape, nullptr, NodeVector{reshape}); - - auto conv_filter = std::make_shared(element::f32, Shape{1, 1, 1, 1}); - - auto conv = std::make_shared(reshape_label, - conv_filter, - Strides{1, 1}, - Strides{1, 1}, - CoordinateDiff{1, 1}, - CoordinateDiff{1, 1}, - Strides{1, 1}); - auto conv_label = std::make_shared(conv, nullptr, NodeVector{conv}); - - auto callback = [pad_input, pad_value, pad_label, reshape_label, conv_filter, conv_label]( - pattern::Matcher& m) { - auto pattern_map = m.get_pattern_map(); - - auto pad_value_op = as_type_ptr(pattern_map[pad_value]); - if (!pad_value_op) - { - NGRAPH_DEBUG << "Pad value must be a constant"; - return false; - } - - const auto& matched_conv = as_type_ptr(pattern_map[conv_label]); - const auto& matched_pad = as_type_ptr(pattern_map[pad_label]); - const auto& matched_reshape = - std::static_pointer_cast(pattern_map[reshape_label]); - - const auto& input_order = matched_reshape->get_input_order(); - auto hoisted_reshape_output_shape = - ngraph::apply_permutation(pattern_map[pad_input]->get_shape(), input_order); - - auto hoisted_reshape = std::make_shared( - pattern_map[pad_input], - input_order, - Shape(hoisted_reshape_output_shape.begin(), hoisted_reshape_output_shape.end())); - - if (!zero_padded_conv_consistency_check(m.get_match_root(), - pad_value_op, - pattern_map[pad_input], - matched_pad, - matched_conv->get_padding_below(), - matched_conv->get_padding_above(), - input_order[0], - input_order[1])) - { - return false; - } - - CoordinateDiff padding_below{static_cast( - matched_pad->get_padding_below().at(input_order[2])), - static_cast( - matched_pad->get_padding_below().at(input_order[3]))}; - CoordinateDiff padding_above{static_cast( - matched_pad->get_padding_above().at(input_order[2])), - static_cast( - matched_pad->get_padding_above().at(input_order[3]))}; - - auto zero_padded_conv = - std::make_shared(hoisted_reshape, - pattern_map[conv_filter], - matched_conv->get_window_movement_strides(), - matched_conv->get_window_dilation_strides(), - padding_below, - padding_above, - matched_conv->get_data_dilation_strides()); - - ngraph::replace_node(m.get_match_root(), zero_padded_conv); - return true; - }; - - auto m = - std::make_shared(conv_label, "CoreFusion.ZeroPaddedReshapedConv"); - this->add_matcher(m, callback); -} - -void pass::CoreFusion::construct_zero_padded_conv() -{ - auto pad_input = std::make_shared(element::f32, Shape{1, 1, 1, 1}); - auto pad_value = std::make_shared(element::f32, Shape{}); - auto pad = std::make_shared( - pad_input, pad_value, CoordinateDiff{0, 0, 0, 0}, CoordinateDiff{0, 0, 0, 0}); - auto pad_label = std::make_shared(pad, nullptr, NodeVector{pad}); - - auto conv_filter = std::make_shared(element::f32, Shape{1, 1, 1, 1}); - - auto conv = std::make_shared(pad_label, - conv_filter, - Strides{1, 1}, - Strides{1, 1}, - CoordinateDiff{1, 1}, - CoordinateDiff{1, 1}, - Strides{1, 1}); - auto conv_label = std::make_shared(conv, nullptr, NodeVector{conv}); - - auto callback = [pad_input, pad_value, pad_label, conv_filter, conv_label]( - pattern::Matcher& m) { - auto pattern_map = m.get_pattern_map(); - - auto pad_value_op = as_type_ptr(pattern_map[pad_value]); - if (!pad_value_op) - { - NGRAPH_DEBUG << "Pad value must be a constant"; - return false; - } - - const auto& matched_conv = - std::static_pointer_cast(pattern_map[conv_label]); - const auto& matched_pad = std::static_pointer_cast(pattern_map[pad_label]); - - if (!zero_padded_conv_consistency_check(m.get_match_root(), - pad_value_op, - pattern_map[pad_input], - matched_pad, - matched_conv->get_padding_below(), - matched_conv->get_padding_above(), - 0, - 1)) - { - return false; - } - - CoordinateDiff padding_below{ - static_cast(matched_pad->get_padding_below().at(2)), - static_cast(matched_pad->get_padding_below().at(3))}; - CoordinateDiff padding_above{ - static_cast(matched_pad->get_padding_above().at(2)), - static_cast(matched_pad->get_padding_above().at(3))}; - - auto zero_padded_conv = - std::make_shared(pattern_map[pad_input], - pattern_map[conv_filter], - matched_conv->get_window_movement_strides(), - matched_conv->get_window_dilation_strides(), - padding_below, - padding_above, - matched_conv->get_data_dilation_strides()); - - ngraph::replace_node(m.get_match_root(), zero_padded_conv); - return true; - }; - - auto m = std::make_shared(conv_label, "CoreFusion.ZeroPaddedConv"); - this->add_matcher(m, callback); -} diff --git a/ngraph/src/ngraph/pass/core_fusion.hpp b/ngraph/src/ngraph/pass/core_fusion.hpp deleted file mode 100644 index c52b8b66464..00000000000 --- a/ngraph/src/ngraph/pass/core_fusion.hpp +++ /dev/null @@ -1,55 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/graph_rewrite.hpp" - -namespace ngraph -{ - namespace pass - { - class CoreFusion; - } -} - -class NGRAPH_API ngraph::pass::CoreFusion : public ngraph::pass::GraphRewrite -{ -public: - CoreFusion(FusionTypeMask fusions = FusionType::REGULAR_FUSIONS) - : GraphRewrite() - { - if (fusions.is_set(FusionType::REGULAR_FUSIONS)) - { - construct_relu(); - construct_folded_batch_norm(); - construct_conv_affine_folding(); - construct_sigmoid(); - construct_reshape_broadcast(); - construct_reshape_softmax_reshape(); - construct_zero_padded_reshaped_conv(); - construct_zero_padded_conv(); - } - } - void construct_relu(); - void construct_folded_batch_norm(); - void construct_conv_affine_folding(); - void construct_sigmoid(); - void construct_reshape_broadcast(); - void construct_reshape_softmax_reshape(); - void construct_zero_padded_reshaped_conv(); - void construct_zero_padded_conv(); -}; diff --git a/ngraph/src/ngraph/pass/cse.cpp b/ngraph/src/ngraph/pass/cse.cpp deleted file mode 100644 index 8c585b45fe7..00000000000 --- a/ngraph/src/ngraph/pass/cse.cpp +++ /dev/null @@ -1,323 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include -#include -#include - -#include "cse.hpp" -#include "ngraph/axis_vector.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/abs.hpp" -#include "ngraph/op/abs.hpp" -#include "ngraph/op/acos.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/asin.hpp" -#include "ngraph/op/atan.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/ceiling.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/cos.hpp" -#include "ngraph/op/cosh.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/exp.hpp" -#include "ngraph/op/floor.hpp" -#include "ngraph/op/log.hpp" -#include "ngraph/op/maximum.hpp" -#include "ngraph/op/minimum.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/negative.hpp" -#include "ngraph/op/one_hot.hpp" -#include "ngraph/op/power.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/relu.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/sigmoid.hpp" -#include "ngraph/op/sign.hpp" -#include "ngraph/op/sin.hpp" -#include "ngraph/op/sinh.hpp" -#include "ngraph/op/softmax.hpp" -#include "ngraph/op/sqrt.hpp" -#include "ngraph/op/subtract.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/tan.hpp" -#include "ngraph/op/tanh.hpp" -#include "ngraph/op/util/op_types.hpp" -#include "ngraph/pattern/matcher.hpp" - -using namespace std; -using namespace ngraph; - -#define TI(x) type_index(typeid(x)) - -static bool cse_constant(shared_ptr a, shared_ptr b) -{ - NGRAPH_DEBUG << "In cse_constant for " << a->get_name() << " and " << b->get_name(); - - if (a->get_shape() != b->get_shape() || a->get_element_type() != b->get_element_type()) - { - return false; - } - - const op::Constant* ca = static_cast(a.get()); - const op::Constant* cb = static_cast(b.get()); - - size_t size = shape_size(a->get_shape()) * a->get_element_type().size(); - - if (ca->get_all_data_elements_bitwise_identical() || - cb->get_all_data_elements_bitwise_identical()) - { - if (ca->get_all_data_elements_bitwise_identical() && - cb->get_all_data_elements_bitwise_identical()) - { - // Since both Constants are uniform we only need to compare a single element - return !memcmp(ca->get_data_ptr(), cb->get_data_ptr(), a->get_element_type().size()); - } - else - { - return false; - } - } - else - { - // Neither Constant is uniform so compare all elements - return !memcmp(ca->get_data_ptr(), cb->get_data_ptr(), size); - } -} - -static bool cse_reshape(shared_ptr a, shared_ptr b) -{ - NGRAPH_DEBUG << "In cse_reshape for " << a->get_name() << " and " << b->get_name(); - - const op::Reshape* reshape_a = static_cast(a.get()); - const op::Reshape* reshape_b = static_cast(b.get()); - - return (a->input_value(0) == b->input_value(0)) && - (reshape_a->get_input_order() == reshape_b->get_input_order()) && - (reshape_a->get_output_shape(0) == reshape_b->get_output_shape(0)); -} - -static bool cse_broadcast(shared_ptr a, shared_ptr b) -{ - NGRAPH_DEBUG << "In cse_broadcast for " << a->get_name() << " and " << b->get_name(); - - const op::Broadcast* broadcast_a = static_cast(a.get()); - const op::Broadcast* broadcast_b = static_cast(b.get()); - - return (a->input_value(0) == b->input_value(0)) && - (broadcast_a->get_broadcast_axes() == broadcast_b->get_broadcast_axes()) && - (broadcast_a->get_broadcast_shape() == broadcast_b->get_broadcast_shape()); -} - -static bool cse_unarywise(shared_ptr a, shared_ptr b) -{ - NGRAPH_DEBUG << "In cse_unarywise for " << a->get_name() << " and " << b->get_name(); - - return a->input_value(0) == b->input_value(0); -} - -static bool cse_binarywise(shared_ptr a, shared_ptr b) -{ - NGRAPH_DEBUG << "In cse_binary for " << a->get_name() << " and " << b->get_name(); - - return (a->input_value(0) == b->input_value(0) && a->input_value(1) == b->input_value(1)) || - (a->input_value(1) == b->input_value(0) && a->input_value(0) == b->input_value(1)); -} - -static bool cse_reduction(shared_ptr a, shared_ptr b) -{ - NGRAPH_DEBUG << "In cse_reduction for " << a->get_name() << " and " << b->get_name(); - - const op::util::ArithmeticReduction* ar_a = - static_cast(a.get()); - const op::util::ArithmeticReduction* ar_b = - static_cast(b.get()); - - return ar_a->input_value(0) == ar_b->input_value(0) && - ar_a->get_reduction_axes() == ar_b->get_reduction_axes(); -} - -static bool cse_one_hot(shared_ptr a, shared_ptr b) -{ - NGRAPH_DEBUG << "In cse_one_hot for " << a->get_name() << " and " << b->get_name(); - - const op::OneHot* one_hot_a = static_cast(a.get()); - const op::OneHot* one_hot_b = static_cast(b.get()); - - return (a->input_value(0) == b->input_value(0)) && - (one_hot_a->get_one_hot_axis() == one_hot_b->get_one_hot_axis()) && - (a->get_shape() == b->get_shape()); -} - -// To enable CSE for a new op, add a mapping between the op and a cse handler function to the map -// below. If the op doesn't map to an existing handler, create a new handler to check if -// all inputs and attributes for two nodes are exactly same. -static unordered_map, shared_ptr)>> - initialize_ops_to_cse_handlers() -{ - return unordered_map, shared_ptr)>>( - {{TI(op::Abs), cse_unarywise}, - {TI(op::Acos), cse_unarywise}, - {TI(op::Asin), cse_unarywise}, - {TI(op::Atan), cse_unarywise}, - {TI(op::Ceiling), cse_unarywise}, - {TI(op::Constant), cse_constant}, - {TI(op::Cos), cse_unarywise}, - {TI(op::Cosh), cse_unarywise}, - {TI(op::Exp), cse_unarywise}, - {TI(op::Floor), cse_unarywise}, - {TI(op::Log), cse_unarywise}, - {TI(op::Negative), cse_unarywise}, - {TI(op::OneHot), cse_one_hot}, - {TI(op::Relu), cse_unarywise}, - {TI(op::Sigmoid), cse_unarywise}, - {TI(op::Sign), cse_unarywise}, - {TI(op::Sin), cse_unarywise}, - {TI(op::Sinh), cse_unarywise}, - //{TI(op::Softmax), cse_unarywise}, - {TI(op::Sqrt), cse_unarywise}, - {TI(op::Tan), cse_unarywise}, - {TI(op::Tanh), cse_unarywise}, - {TI(op::Add), cse_binarywise}, - {TI(op::Divide), cse_binarywise}, - {TI(op::Maximum), cse_binarywise}, - {TI(op::Minimum), cse_binarywise}, - {TI(op::Multiply), cse_binarywise}, - {TI(op::Power), cse_binarywise}, - {TI(op::Subtract), cse_binarywise}, - {TI(op::Sum), cse_reduction}, - {TI(op::Product), cse_reduction}, - {TI(op::Reshape), cse_reshape}, - {TI(op::Broadcast), cse_broadcast}}); -} - -static unordered_map, shared_ptr)>> - ops_to_cse_handlers = initialize_ops_to_cse_handlers(); - -class NodeKey -{ -public: - NodeKey(const shared_ptr& n, - unordered_map, shared_ptr)>>& - backend_handlers) - : m_node(n) - , m_node_ref(*n) - , m_ti(TI(m_node_ref)) - , m_backend_handlers(backend_handlers) - { - } - - shared_ptr get_node() const { return m_node; } - bool operator==(const NodeKey& other) const - { - if (m_ti == other.m_ti) - { - auto eh = ops_to_cse_handlers.find(m_ti); - if (eh != ops_to_cse_handlers.end()) - { - return eh->second(m_node, other.m_node); - } - - eh = m_backend_handlers.find(m_ti); - if (eh != m_backend_handlers.end()) - { - return eh->second(m_node, other.m_node); - } - } - - return false; - } - -private: - shared_ptr m_node; - // m_node_ref is only to allow getting the type_index in the ctor - Node& m_node_ref; - std::type_index m_ti; - unordered_map, shared_ptr)>>& - m_backend_handlers; -}; - -namespace std -{ - template <> - struct hash - { - size_t operator()(const NodeKey& k) const - { - Node& p_this = *k.get_node().get(); - auto ti = TI(p_this); - - hash type_hash_compute{}; - auto type_hash = type_hash_compute(ti); - - vector arg_ids; - - arg_ids.push_back(type_hash); - - std::vector> cargs; - for (auto input : k.get_node()->inputs()) - { - cargs.push_back(input.get_source_output()); - } - - // TODO: Do we need another map, so we could - // specify how to compute hash for each op? - if (ngraph::op::is_commutative(&p_this)) - { - sort(begin(cargs), end(cargs)); - } - - for (auto arg : cargs) - { - arg_ids.push_back(arg.get_node_shared_ptr()->get_instance_id()); - arg_ids.push_back(arg.get_index()); - } - - auto hashc = ngraph::hash_combine(arg_ids); - return hashc; - } - }; -} - -bool ngraph::pass::CommonSubexpressionElimination::run_on_function(shared_ptr f) -{ - bool replaced = false; - unordered_map> expressions{}; - - for (auto n : f->get_ordered_ops()) - { - if (op::is_output(n) || op::is_parameter(n)) - { - continue; - } - - NodeKey n_key(n, m_backend_cse_handlers); - if (expressions.count(n_key)) - { - ngraph::replace_node(n, expressions.at(n_key)); - replaced = true; - } - else - { - expressions.insert(make_pair(n_key, n)); - } - } - - return replaced; -} diff --git a/ngraph/src/ngraph/pass/cse.hpp b/ngraph/src/ngraph/pass/cse.hpp deleted file mode 100644 index c5814257830..00000000000 --- a/ngraph/src/ngraph/pass/cse.hpp +++ /dev/null @@ -1,70 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class CommonSubexpressionElimination; - } -} - -/// \brief The Common Subexpression Elimination pass removes duplicate computations in a given -/// computation graph. -/// -/// Two computations are considered to be duplicates of each other if both apply the same operation -/// to the same set of inputs, with the same attributes. -/// -/// In the example shown below, the original graph has duplicate Add computations. -/// After applying this pass, the graph is optimized to have only one Add computation. -/// -/// -/// -/// -/// -/// -/// -/// -///
Before the pass: After the pass
\image html add_commutative_precse.svg \image html add_commutative_postcse.svg
-class NGRAPH_API ngraph::pass::CommonSubexpressionElimination : public FunctionPass -{ -public: - CommonSubexpressionElimination() - : FunctionPass() - { - set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); - } - - CommonSubexpressionElimination( - const std::unordered_map, std::shared_ptr)>>& - backend_cse_handlers) - : FunctionPass() - , m_backend_cse_handlers(backend_cse_handlers) - { - set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); - } - - std::unordered_map, std::shared_ptr)>> - m_backend_cse_handlers; - - virtual bool run_on_function(std::shared_ptr f); -}; diff --git a/ngraph/src/ngraph/pass/dump_sorted.cpp b/ngraph/src/ngraph/pass/dump_sorted.cpp deleted file mode 100644 index 62504c34769..00000000000 --- a/ngraph/src/ngraph/pass/dump_sorted.cpp +++ /dev/null @@ -1,77 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include - -#include "ngraph/descriptor/input.hpp" -#include "ngraph/descriptor/output.hpp" -#include "ngraph/pass/dump_sorted.hpp" -#include "ngraph/util.hpp" - -using namespace std; -using namespace ngraph; - -pass::DumpSorted::DumpSorted(const string& output_file) - : m_output_file{output_file} -{ -} - -bool pass::DumpSorted::run_on_module(vector>& functions) -{ - ofstream out{m_output_file}; - if (out) - { - for (shared_ptr f : functions) - { - out << "=====================================================================\n"; - out << f->get_name() << " start\n"; - out << "=====================================================================\n"; - for (const shared_ptr& node : f->get_ordered_ops()) - { - out << node->get_name() << "("; - vector inputs; - for (auto& input : node->inputs()) - { - inputs.push_back(input.get_tensor().get_name()); - } - out << join(inputs); - out << ") -> "; - - vector outputs; - for (auto& output : node->outputs()) - { - outputs.push_back(output.get_tensor().get_name()); - } - out << join(outputs); - out << "\n"; - - for (const descriptor::Tensor* tensor : node->liveness_new_list) - { - out << " N " << tensor->get_name() << "\n"; - } - for (const descriptor::Tensor* tensor : node->liveness_free_list) - { - out << " F " << tensor->get_name() << "\n"; - } - } - out << "=====================================================================\n"; - out << f->get_name() << " end\n"; - out << "=====================================================================\n"; - } - } - - return false; -} diff --git a/ngraph/src/ngraph/pass/dump_sorted.hpp b/ngraph/src/ngraph/pass/dump_sorted.hpp deleted file mode 100644 index ffe73b4e050..00000000000 --- a/ngraph/src/ngraph/pass/dump_sorted.hpp +++ /dev/null @@ -1,40 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class DumpSorted; - } -} - -class NGRAPH_API ngraph::pass::DumpSorted : public ModulePass -{ -public: - DumpSorted(const std::string& output_file); - - virtual bool run_on_module(std::vector>&) override; - -private: - const std::string m_output_file; -}; diff --git a/ngraph/src/ngraph/pass/manager.cpp b/ngraph/src/ngraph/pass/manager.cpp index 818b3a460cf..869b6e76e9e 100644 --- a/ngraph/src/ngraph/pass/manager.cpp +++ b/ngraph/src/ngraph/pass/manager.cpp @@ -27,7 +27,6 @@ #include "ngraph/pass/graph_rewrite.hpp" #include "ngraph/pass/manager.hpp" #include "ngraph/pass/pass.hpp" -#include "ngraph/pass/serialize.hpp" #include "ngraph/pass/visualize_tree.hpp" #include "ngraph/util.hpp" @@ -36,8 +35,6 @@ using namespace ngraph; pass::Manager::Manager() : m_visualize(getenv_bool("NGRAPH_ENABLE_VISUALIZE_TRACING")) - , m_serialize(getenv_bool("NGRAPH_ENABLE_SERIALIZE_TRACING")) - { } @@ -139,7 +136,7 @@ void pass::Manager::run_passes(shared_ptr func, bool /* transitive */) function_changed = call_graph_pass->run_on_call_graph(func->get_ordered_ops()); } - if (m_visualize || m_serialize) + if (m_visualize) { // visualizations and serializations will be named after the outermost function const size_t num_digits_in_pass_index = 3; @@ -156,12 +153,6 @@ void pass::Manager::run_passes(shared_ptr func, bool /* transitive */) vt.set_ops_to_details(get_state().get_visualize_tree_ops_map()); vt.run_on_module(f_array); } - - if (m_serialize) - { - pass::Serialization st(base_filename + ".json"); - st.run_on_module(f_array); - } } index++; pass_timer.stop(); diff --git a/ngraph/src/ngraph/pass/manager.hpp b/ngraph/src/ngraph/pass/manager.hpp index 98323c6de1c..04f490c2c94 100644 --- a/ngraph/src/ngraph/pass/manager.hpp +++ b/ngraph/src/ngraph/pass/manager.hpp @@ -58,7 +58,6 @@ public: PassConfig& get_pass_config() { return m_pass_config; } void set_pass_config(const PassConfig& pass_config) { m_pass_config = pass_config; } void set_pass_visualization(bool new_state) { m_visualize = new_state; } - void set_pass_serialization(bool new_state) { m_serialize = new_state; } /// \brief Set flag to enable/disable running Validate pass after executing /// each registered pass /// \param new_state Value "true" enables Validate pass run; "false", otherwise @@ -106,6 +105,5 @@ private: ManagerState m_state; PassConfig m_pass_config; bool m_visualize = false; - bool m_serialize = false; bool m_per_pass_validation = true; }; diff --git a/ngraph/src/ngraph/pass/memory_layout.cpp b/ngraph/src/ngraph/pass/memory_layout.cpp deleted file mode 100644 index d2fa9995159..00000000000 --- a/ngraph/src/ngraph/pass/memory_layout.cpp +++ /dev/null @@ -1,293 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include - -#include "ngraph/log.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/util/op_types.hpp" -#include "ngraph/pass/liveness.hpp" -#include "ngraph/pass/manager.hpp" -#include "ngraph/pass/memory_layout.hpp" -#include "ngraph/util.hpp" - -using namespace std; -using namespace ngraph; - -pass::MemoryLayout::MemoryLayout(size_t alignment, bool disable_memory_sharing) - : m_alignment(alignment) - , m_disable_memory_sharing(disable_memory_sharing) -{ - if (m_alignment == 0) - { - throw invalid_argument("Memory alignment must be > 0"); - } -} - -bool pass::MemoryLayout::run_on_function(shared_ptr function) -{ - MemoryManager mm(m_alignment, m_disable_memory_sharing); - for (shared_ptr node : function->get_ordered_ops()) - { - std::map in_place_outputs; - std::set reused_inputs; - - if (op::is_op(node)) - { - auto op = std::static_pointer_cast(node); - // concat and slice in_place_oi should be treated differently - if (!is_type(node) && !is_type(node)) - { - if (auto op_annotations = op->get_op_annotations()) - { - for (auto oi_pair : op_annotations->get_in_place_oi_pairs()) - { - auto output = &node->output(oi_pair.output).get_tensor(); - auto input = &node->get_input_tensor(oi_pair.input); - auto input_node = node->get_input_node_ptr(oi_pair.input); - - // For destructive kernel, this should be the last use - // Non-destructive kernels can pass through if memory sharing is disabled - if ((node->liveness_free_list.count(input) != 0 || - is_type(node) || - (m_disable_memory_sharing && !oi_pair.destructive && - !op::is_parameter(input_node) && !op::is_constant(input_node))) && - node->liveness_new_list.count(output) != 0) - - { - NGRAPH_DEBUG << "Reusing " << input->get_name() << " for " - << output->get_name(); - in_place_outputs.insert({output, input}); - reused_inputs.insert(input); - } - } - } - } - } - - for (descriptor::Tensor* tensor : node->liveness_new_list) - { - size_t offset = in_place_outputs.count(tensor) - ? in_place_outputs.at(tensor)->get_pool_offset() - : mm.allocate(tensor->size()); - tensor->set_pool_offset(offset); - } - - if (!m_disable_memory_sharing) - { - for (const descriptor::Tensor* tensor : node->liveness_free_list) - { - if (reused_inputs.count(tensor) == 0) - { - mm.free(tensor->get_pool_offset()); - } - } - } - } - function->set_temporary_pool_size(mm.max_allocated()); - - return false; -} - -pass::MemoryManager::node::node(size_t size, block_state state) - : m_size{size} - , m_state{state} -{ -} - -pass::MemoryManager::MemoryManager(size_t alignment, bool disable_memory_reuse) - : m_alignment{alignment} - , m_scheme{disable_memory_reuse ? allocation_scheme::NO_REUSE : allocation_scheme::FIRST_FIT} - , m_max_allocated{0} -{ - if (m_alignment == 0) - { - throw invalid_argument("Memory alignment must be > 0"); - } - m_node_list.emplace_back(numeric_limits::max(), block_state::FREE); -} - -size_t pass::MemoryManager::allocate(size_t size) -{ - size_t rc = 0; - switch (m_scheme) - { - case allocation_scheme::FIRST_FIT: rc = first_fit(size); break; - case allocation_scheme::BEST_FIT: rc = best_fit(size); break; - case allocation_scheme::NO_REUSE: rc = no_reuse_allocator(size); break; - } - return rc; -} - -size_t pass::MemoryManager::no_reuse_allocator(size_t size) -{ - size_t offset = m_max_allocated; - m_max_allocated += align(size, m_alignment); - return offset; -} - -size_t pass::MemoryManager::best_fit(size_t size) -{ - size = align(size, m_alignment); - size_t offset = 0; - size_t min_delta = numeric_limits::max(); - auto best_fit = m_node_list.end(); - size_t best_offset = offset; - for (auto it = m_node_list.begin(); it != m_node_list.end(); ++it) - { - if (it->m_state == block_state::FREE && it->m_size >= size) - { - size_t delta = it->m_size - size; - if (delta < min_delta) - { - min_delta = delta; - best_fit = it; - best_offset = offset; - } - } - offset += it->m_size; - } - - if (best_fit == m_node_list.end()) - { - throw bad_alloc(); - } - - if (min_delta == 0) - { - // exact fit - best_fit->m_state = block_state::ALLOCATED; - } - else - { - m_node_list.insert(best_fit, node{size, block_state::ALLOCATED}); - best_fit->m_size -= size; - } - m_max_allocated = max(m_max_allocated, best_offset + size); - - return best_offset; -} - -size_t pass::MemoryManager::first_fit(size_t size) -{ - size = align(size, m_alignment); - size_t offset = 0; - bool found = false; - for (auto it = m_node_list.begin(); it != m_node_list.end(); ++it) - { - if (it->m_state == block_state::FREE && it->m_size >= size) - { - if (it->m_size > size) - { - m_node_list.insert(it, node{size, block_state::ALLOCATED}); - it->m_size -= size; - } - else - { - // exact fit - it->m_state = block_state::ALLOCATED; - } - - found = true; - break; - } - offset += it->m_size; - } - if (!found) - { - throw bad_alloc(); - } - m_max_allocated = max(m_max_allocated, offset + size); - - return offset; -} - -void pass::MemoryManager::free(size_t offset) -{ - size_t search_offset = 0; - bool found = false; - for (auto it = m_node_list.begin(); it != m_node_list.end(); ++it) - { - if (offset == search_offset) - { - list::iterator it_next = next(it); - if (it == m_node_list.begin()) - { - // free the first node in the list - it->m_state = block_state::FREE; - } - else - { - // node has predecessor - list::iterator it_prev = prev(it); - if (it_prev->m_state == block_state::FREE) - { - it->m_size += it_prev->m_size; - m_node_list.erase(it_prev); - } - } - if (it_next != m_node_list.end() && it_next->m_state == block_state::FREE) - { - // join this node with next - it->m_size += it_next->m_size; - m_node_list.erase(it_next); - } - it->m_state = block_state::FREE; - found = true; - break; - } - search_offset += it->m_size; - } - if (!found) - { - throw runtime_error("bad free"); - } -} - -void pass::MemoryManager::dump(ostream& out) -{ - for (const node& n : m_node_list) - { - out << "size=" << n.m_size << ", "; - out << (n.m_state == block_state::FREE ? "FREE" : "ALLOCATED"); - out << "\n"; - } -} - -size_t pass::MemoryManager::align(size_t size, size_t alignment) -{ - if (alignment == 0) - { - throw invalid_argument("alignment must be > 0"); - } - if (size == 0) - { - size = alignment; - } - else - { - auto remainder = size % alignment; - if (remainder > 0) - { - size += (alignment - remainder); - } - } - return size; -} diff --git a/ngraph/src/ngraph/pass/memory_layout.hpp b/ngraph/src/ngraph/pass/memory_layout.hpp deleted file mode 100644 index bb749588c7e..00000000000 --- a/ngraph/src/ngraph/pass/memory_layout.hpp +++ /dev/null @@ -1,97 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include -#include -#include - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class MemoryLayout; - class MemoryNode; - class MemoryManager; - } -} - -class NGRAPH_API ngraph::pass::MemoryLayout : public FunctionPass -{ -public: - MemoryLayout(size_t alignment = 1, bool disable_memory_sharing = false); - bool run_on_function(std::shared_ptr) override; - -private: - size_t m_alignment; - bool m_disable_memory_sharing; -}; - -class NGRAPH_API ngraph::pass::MemoryManager -{ -public: - enum class block_state - { - FREE, - ALLOCATED - }; - - enum class allocation_scheme - { - FIRST_FIT, - BEST_FIT, - NO_REUSE - }; - - class node - { - public: - node(size_t size, block_state state); - - bool is_free() const { return m_state == block_state::FREE; } - size_t m_size; - block_state m_state; - }; - - MemoryManager(size_t alignment = 1, bool disable_reuse = false); - // memory_manager& alignment(size_t a); - - size_t allocate(size_t size); - void free(size_t offset); - - void dump(std::ostream&); - - static size_t align(size_t x, size_t alignment); - - std::list::iterator begin() { return m_node_list.begin(); } - std::list::iterator end() { return m_node_list.end(); } - std::list::const_iterator begin() const { return m_node_list.cbegin(); } - std::list::const_iterator end() const { return m_node_list.cend(); } - const std::list& get_node_list() const { return m_node_list; } - size_t max_allocated() const { return m_max_allocated; } -private: - size_t first_fit(size_t size); - size_t best_fit(size_t size); - size_t no_reuse_allocator(size_t size); - - std::list m_node_list; - size_t m_alignment; - allocation_scheme m_scheme; - size_t m_max_allocated; -}; diff --git a/ngraph/src/ngraph/pass/memory_visualize.cpp b/ngraph/src/ngraph/pass/memory_visualize.cpp deleted file mode 100644 index 78dad319451..00000000000 --- a/ngraph/src/ngraph/pass/memory_visualize.cpp +++ /dev/null @@ -1,266 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include -#include -#include - -#include "memory_visualize.hpp" -#include "ngraph/descriptor/tensor.hpp" -#include "ngraph/function.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/node.hpp" -#include "ngraph/util.hpp" - -using namespace std; -using namespace ngraph; - -pass::MemoryVisualize::MemoryVisualize(const string& filename) - : m_filename{filename} -{ -} - -bool pass::MemoryVisualize::run_on_module(vector>& functions) -{ - ofstream file(m_filename); - { - for (shared_ptr f : functions) - { - vector> nodes = f->get_ordered_ops(); - file << "\n\n"; - file << "\n"; - file << " \n"; - file << "\n"; - - file << "\n"; - unordered_set tensors; - size_t temp_max_size = 0; - for (shared_ptr node : nodes) - { - tensors.insert(node->liveness_new_list.begin(), node->liveness_new_list.end()); - } - for (descriptor::Tensor* tensor : tensors) - { - temp_max_size += tensor->size(); - } - - // file << "\n"; - // file << "\n"; - // file << "\n"; - // file << "\n"; - // file << "
Persistent Memory Footprint"; - // file << computation_decl.exop_block.persistent_size() << "
Temporary Memory Footprint"; - // file << computation_decl.exop_block.memory_footprint() << "
Max temporary Memory Footprint"; - // file << temp_max_size << "
\n"; - - file << "
\n"; - draw_tensor_weight(file, nodes); - // file << "
\n"; - // draw_op_influence(file); - file << "
\n"; - draw_histogram(file, nodes); - // file << "
\n"; - file << "\n\n"; - } - } - return false; -} - -unordered_set - pass::MemoryVisualize::find_largest_op(const vector>& nodes) -{ - size_t largest_size = 0; - unordered_set liveness_list; - unordered_set largest_live_list; - for (shared_ptr exop : nodes) - { - size_t size = 0; - for (const descriptor::Tensor* tensor : exop->liveness_new_list) - { - liveness_list.insert(tensor); - size += tensor->size(); - } - for (const descriptor::Tensor* tensor : liveness_list) - { - size += tensor->size(); - } - if (size > largest_size) - { - largest_size = size; - largest_live_list = liveness_list; - } - } - return largest_live_list; -} - -void pass::MemoryVisualize::draw_tensor_weight(ostream& file, const vector>& nodes) -{ - unordered_set largest_live_list = find_largest_op(nodes); - - unordered_map age_list; - vector tensor_set; - unordered_map> generator_op; - file << "\n"; - file << " "; - file << ""; - file << ""; - file << ""; - file << ""; - file << "\n"; - size_t i = 0; - for (shared_ptr exop : nodes) - { - for (const descriptor::Tensor* tensor : exop->liveness_new_list) - { - age_list[tensor] = i; - generator_op[tensor] = exop; - } - for (const descriptor::Tensor* tensor : exop->liveness_free_list) - { - size_t start = age_list[tensor]; - age_list[tensor] = (i - start); - tensor_set.push_back(tensor); - } - i++; - } - sort(tensor_set.begin(), - tensor_set.end(), - [](const descriptor::Tensor* t1, const descriptor::Tensor* t2) { - return t1->size() < t2->size(); - }); - for (const descriptor::Tensor* tensor : tensor_set) - { - int generator_weight = compute_op_weight(generator_op[tensor]); - if (largest_live_list.find(tensor) != largest_live_list.end()) - { - file << " "; - } - else - { - file << " "; - } - file << ""; - file << ""; - file << ""; - file << "\n"; - } - - file << "
tensorsizeagegenerator weight
" << tensor->get_name() << "" << tensor->size() << "" << age_list[tensor] << "" << generator_weight << "/td>"; - file << "
\n"; -} - -void pass::MemoryVisualize::draw_histogram(ostream& file, const vector>& nodes) -{ - size_t stroke_width = 14; - size_t text_offset = 4; - size_t offset = 200; - size_t width = 1000; - size_t scale = width - offset; - size_t line_spacing = static_cast(stroke_width * 1.5); - size_t line_count = 0; - for (shared_ptr node : nodes) - { - (void)node; - line_count += 1; - } - size_t height = line_count * line_spacing + stroke_width; - size_t memory_footprint = max(1, MemoryVisualize::memory_footprint(nodes)); - - file << "\n"; - size_t y = 0; - for (shared_ptr node : nodes) - { - float usage = float(MemoryVisualize::memory_usage(node)); - float footprint = float(MemoryVisualize::memory_footprint(node)); - y += line_spacing; - size_t x1 = offset; - size_t x2 = static_cast(((usage / memory_footprint) * scale) + offset); - file << "" << node->get_name() << "\n"; - file << "\n"; - x1 = x2; - x2 = static_cast(((footprint / memory_footprint) * scale) + offset); - file << "\n"; - } - file << "\n"; -} - -void pass::MemoryVisualize::draw_op_influence(ostream& file, const vector>& nodes) -{ - file << "\n"; - file << " "; - file << ""; - file << ""; - file << "\n"; - for (shared_ptr exop : nodes) - { - int weight = compute_op_weight(exop); - file << " "; - file << ""; - file << ""; - file << "\n"; - } -} - -int pass::MemoryVisualize::compute_op_weight(const shared_ptr exop) -{ - int mass = 0; - for (const descriptor::Tensor* tensor : exop->liveness_new_list) - { - mass += static_cast(tensor->size()); - } - for (const descriptor::Tensor* tensor : exop->liveness_free_list) - { - mass -= static_cast(tensor->size()); - } - return mass; -} - -size_t pass::MemoryVisualize::memory_usage(shared_ptr /* node */) -{ - return 0; -} - -size_t pass::MemoryVisualize::memory_footprint(shared_ptr /* node */) -{ - return 0; -} - -size_t pass::MemoryVisualize::memory_footprint(const std::vector>& /* nodes */) -{ - return 0; -} diff --git a/ngraph/src/ngraph/pass/memory_visualize.hpp b/ngraph/src/ngraph/pass/memory_visualize.hpp deleted file mode 100644 index 8880f9e87bb..00000000000 --- a/ngraph/src/ngraph/pass/memory_visualize.hpp +++ /dev/null @@ -1,52 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include -#include -#include - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class MemoryVisualize; - } -} - -class NGRAPH_API ngraph::pass::MemoryVisualize : public ModulePass -{ -public: - MemoryVisualize(const std::string& filename); - virtual bool run_on_module(std::vector>&) override; - -private: - std::unordered_set - find_largest_op(const std::vector>& nodes); - void draw_tensor_weight(std::ostream& file, const std::vector>& nodes); - void draw_histogram(std::ostream& file, const std::vector>& nodes); - void draw_op_influence(std::ostream& file, const std::vector>& nodes); - int compute_op_weight(std::shared_ptr exop); - - static size_t memory_usage(std::shared_ptr); - static size_t memory_footprint(std::shared_ptr); - static size_t memory_footprint(const std::vector>&); - - const std::string m_filename; -}; diff --git a/ngraph/src/ngraph/pass/propagate_cacheability.cpp b/ngraph/src/ngraph/pass/propagate_cacheability.cpp deleted file mode 100644 index 81654d5151b..00000000000 --- a/ngraph/src/ngraph/pass/propagate_cacheability.cpp +++ /dev/null @@ -1,76 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include "ngraph/pass/propagate_cacheability.hpp" - -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/op/util/op_annotations.hpp" -#include "ngraph/op/util/op_types.hpp" - -using namespace std; -using namespace ngraph; - -bool pass::PropagateCacheability::run_on_function(shared_ptr function) -{ - for (auto& node : function->get_ordered_ops()) - { - if (op::is_op(node)) - { - auto op = static_pointer_cast(node); - NGRAPH_DEBUG << "propagate cacheability: node is " << node->get_name(); - auto op_annotations = op->get_op_annotations(); - if (!op_annotations) - { - NGRAPH_DEBUG << "propagate cacheability: create op_annotations"; - op_annotations = op_annotations_factory(); - op->set_op_annotations(op_annotations); - } - if (op::is_parameter(node)) - { - auto parameter = static_pointer_cast(node); - op_annotations->set_cacheable(parameter->get_cacheable()); - NGRAPH_DEBUG << "propagate cacheability: cacheability is " - << parameter->get_cacheable(); - } - else - { - bool cacheable = true; - for (auto input : node->inputs()) - { - auto input_value_node = input.get_source_output().get_node_shared_ptr(); - NGRAPH_DEBUG << "propagate cacheability: arg is " << *input_value_node; - if (op::is_op(input_value_node)) - { - auto arg_op = static_pointer_cast(input_value_node); - auto arg_op_annotations = arg_op->get_op_annotations(); - NGRAPH_CHECK(arg_op_annotations); - if (!arg_op_annotations->is_cacheable()) - { - cacheable = false; - break; - } - } - } - NGRAPH_DEBUG << "propagate cacheability: cacheability is " << cacheable; - op_annotations->set_cacheable(cacheable); - } - } - } - return false; -} diff --git a/ngraph/src/ngraph/pass/propagate_cacheability.hpp b/ngraph/src/ngraph/pass/propagate_cacheability.hpp deleted file mode 100644 index c7f2ab30503..00000000000 --- a/ngraph/src/ngraph/pass/propagate_cacheability.hpp +++ /dev/null @@ -1,52 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class PropagateCacheability; - } -} - -class NGRAPH_API ngraph::pass::PropagateCacheability : public FunctionPass -{ -public: - PropagateCacheability() - : FunctionPass() - { - } - - PropagateCacheability( - std::function(void)> func) - : FunctionPass() - , op_annotations_factory(func) - { - } - - virtual bool run_on_function(std::shared_ptr f); - -private: - std::function(void)> op_annotations_factory = - []() -> std::shared_ptr { - auto op_annotations = std::make_shared(); - return op_annotations; - }; -}; diff --git a/ngraph/src/ngraph/pass/reshape_elimination.cpp b/ngraph/src/ngraph/pass/reshape_elimination.cpp deleted file mode 100644 index d54b5dc7433..00000000000 --- a/ngraph/src/ngraph/pass/reshape_elimination.cpp +++ /dev/null @@ -1,304 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include "reshape_elimination.hpp" -#include -#include -#include -#include - -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/dot.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/pattern/matcher.hpp" -#include "ngraph/pattern/op/label.hpp" -#include "ngraph/pattern/op/skip.hpp" -#include "ngraph/util.hpp" - -using namespace std; -using namespace ngraph; - -void pass::ReshapeElimination::construct_identity_reshape_pattern() -{ - Shape shape_op{3}; - Shape shape_r1{1, 3}; - - auto op = make_shared(element::f32, shape_op); - auto reshape1 = make_shared(op, AxisVector{0}, shape_r1); - - auto callback = [op](pattern::Matcher& m) { - NGRAPH_DEBUG << "In callback for construct_identity_reshape_pattern against node = " - << m.get_match_root()->get_name(); - auto pattern_map = m.get_pattern_value_map(); - auto gop = pattern_map[op]; - - auto r1 = as_type_ptr(m.get_match_root()); - - if (r1->get_shape() != gop.get_shape()) - { - NGRAPH_DEBUG << "Not a no-op; Shapes are different!"; - return false; - } - - auto do_r1 = get_default_order(r1->get_shape()); - - if (do_r1 != r1->get_input_order()) - { - NGRAPH_DEBUG << "Not a no-op; Not in default input order!"; - return false; - } - - m.get_match_value().replace(gop); - return true; - }; - - auto m = make_shared(reshape1); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} - -void pass::ReshapeElimination::construct_reshapex2_pattern() -{ - Shape shape_op{3}; - Shape shape_r1{1, 3}; - - auto op = make_shared(element::f32, shape_op); - auto reshape1 = make_shared(op, AxisVector{0}, shape_r1); - auto reshape2 = make_shared(reshape1, AxisVector{0, 1}, shape_op); - - auto callback = [op](pattern::Matcher& m) { - NGRAPH_DEBUG << "In callback for construct_reshapex2_pattern against node = " - << m.get_match_root()->get_name(); - auto pattern_map = m.get_pattern_map(); - - auto gop = pattern_map[op]; - - auto r2 = static_pointer_cast(m.get_match_root()); - auto r1 = static_pointer_cast(r2->input_value(0).get_node_shared_ptr()); - - if (gop->get_shape() != m.get_match_root()->get_shape()) - { - // First reshape transposes and second reshape only changes shape - // Replace with a transpose that changes shape - if (apply_permutation(gop->get_shape(), r1->get_input_order()) == r2->get_shape() && - r2->get_input_order() == get_default_order(r1->get_shape()) && - r1->get_users().size() == 1) - { - replace_node(m.get_match_root(), - make_shared(gop, r1->get_input_order(), r2->get_shape())); - return true; - } - else - { - NGRAPH_DEBUG << "Operand shape doesn't match the shape of the second reshape!"; - NGRAPH_DEBUG << "gop " << gop->get_name() - << "shape = " << vector_to_string(gop->get_shape()); - NGRAPH_DEBUG << "match_root " << m.get_match_root()->get_name() - << "shape = " << vector_to_string(m.get_match_root()->get_shape()); - return false; - } - } - - // Check for sequence of reshapes/transposes that cancel out. - auto do_r2 = get_default_order(r1->get_shape()); - auto do_r1 = get_default_order(gop->get_shape()); - - NGRAPH_DEBUG << "r1's i/o = " << vector_to_string(r1->get_input_order()) - << "do_r1 = " << vector_to_string(do_r1); - NGRAPH_DEBUG << "r2's i/o = " << vector_to_string(r2->get_input_order()) - << "do_r2 = " << vector_to_string(do_r2); - - if (r1->get_input_order() == do_r1 && r2->get_input_order() == do_r2) - { - NGRAPH_DEBUG << "Two reshapes were removed!"; - replace_node(m.get_match_root(), gop); - return true; - } - - auto perm1 = apply_permutation(do_r1, r1->get_input_order()); - auto perm2 = apply_permutation(perm1, r2->get_input_order()); - if (perm2 == do_r1) - { - NGRAPH_DEBUG << "Two transposes were removed!"; - replace_node(m.get_match_root(), gop); - return true; - } - - return false; - }; - auto m = make_shared(reshape2); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} - -void pass::ReshapeElimination::construct_dot_transpose_pattern() -{ - // dot(A,B).T = dot (B.T, A.T) - auto dot_pred = [](shared_ptr n) { return is_type(n); }; - - auto pdot = make_shared(element::f32, Shape{2, 1}, dot_pred); - auto preshape = make_shared(pdot, AxisVector{1, 0}, Shape{1, 2}); - - auto callback = [](pattern::Matcher& m) { - NGRAPH_DEBUG << "In callback for construct_dot_transpose_pattern against node = " - << m.get_match_root()->get_name(); - - auto mtranspose = static_pointer_cast(m.get_match_root()); - // this also checks the rank - if (mtranspose->get_input_order() != AxisVector{1, 0}) - { - NGRAPH_DEBUG << "Reshape isn't transpose. " - << vector_to_string(mtranspose->get_input_order()); - return false; - } - - auto mdot = mtranspose->input_value(0).get_node_shared_ptr(); - if (mdot->get_shape().size() != 2) - { - NGRAPH_DEBUG << "Dot has the wrong shape. " << vector_to_string(mdot->get_shape()); - return false; - } - - auto arg0 = mdot->input_value(0).get_node_shared_ptr(); - if (arg0->get_shape().size() != 2) - { - NGRAPH_DEBUG << "Arg0 has the wrong shape. " << vector_to_string(arg0->get_shape()); - return false; - } - auto reshape0_shape = Shape{arg0->get_shape().at(1), arg0->get_shape().at(0)}; - auto reshape0 = make_shared(arg0, AxisVector{1, 0}, reshape0_shape); - - auto arg1 = mdot->input_value(1).get_node_shared_ptr(); - if (arg1->get_shape().size() != 2) - { - NGRAPH_DEBUG << "Arg1 has the wrong shape. " << vector_to_string(arg1->get_shape()); - return false; - } - auto reshape1_shape = Shape{arg1->get_shape().at(1), arg1->get_shape().at(0)}; - auto reshape1 = make_shared(arg1, AxisVector{1, 0}, reshape1_shape); - - auto tdot = shared_ptr(new op::Dot(reshape1, reshape0)); - replace_node(m.get_match_root(), tdot); - return true; - }; - - auto m = make_shared(preshape); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} - -void pass::RecurrentReshapeElimination::construct_recurrent_reshape() -{ - Shape shape_op{3}; - Shape shape_r{1, 3}; - - auto op = make_shared(element::f32, shape_op); - auto reshape = make_shared(op, AxisVector{0}, shape_r); - auto reshape_label = - make_shared(reshape, get_no_fan_out_function(), NodeVector{reshape}); - - auto callback = [op, reshape_label](pattern::RecurrentMatcher& m) { - NGRAPH_DEBUG << "In callback for construct_recurrent_reshape against node = " - << reshape_label->input_value(0).get_node_shared_ptr()->get_name(); - auto reshape_node_vector = m.get_bound_nodes_for_pattern(reshape_label); - - // The bound node vector is in reverse order. It is convenient to have the - // bound node vector in the correct order - std::reverse(std::begin(reshape_node_vector), std::end(reshape_node_vector)); - - auto first_bound_reshape_op = reshape_node_vector.front(); - auto driver_op = first_bound_reshape_op->input_value(0); - auto last_bound_reshape_op = reshape_node_vector.back(); - - // Need to check if the user of the last bound op is a reshape since the last reshape is - // allowed to have fan-out but the matcher will discard any reshape if it has fan-out - auto user_of_last_bound_reshape_op = last_bound_reshape_op->get_users(true)[0]; - if (is_type(user_of_last_bound_reshape_op)) - { - reshape_node_vector.push_back(user_of_last_bound_reshape_op); - last_bound_reshape_op = reshape_node_vector.back(); - } - - // Return if the recurrent matcher matches only one reshape - if (reshape_node_vector.size() == 1) - { - return false; - } - - // The complete reshape node vector may not contain contiguous reshapes that can be - // fused. Only the subset of reshapes with a reshape(any axis order) followed by reshapes - // with default axis order can be fused. Creating such subpatterns here: - std::vector sub_patterns{NodeVector{first_bound_reshape_op}}; - for (auto it = std::next(reshape_node_vector.begin()); it != reshape_node_vector.end(); - it++) - { - auto r = as_type_ptr(*it); - - // Check that the input to r is the last reshape stored in the - // subpattern vector - if (!r) - { - NGRAPH_DEBUG - << "Incorrect match. Something went wrong. Non-reshape op has been matched"; - return false; - } - - auto default_order_r = get_default_order(r->get_input_shape(0)); - if (r->get_input_order() == default_order_r) - { - sub_patterns.back().push_back(r); - } - else - { - NGRAPH_DEBUG << r->get_name() << "does not have default axis order. " - << "It might be part of a different subpattern"; - sub_patterns.push_back(NodeVector{r}); - } - } - - bool modify_graph = false; - - // Replace the patterns - for (auto sub_pattern : sub_patterns) - { - // Do not consider subpatterns with just one reshape in them - if (sub_pattern.size() == 1) - { - continue; - } - - auto first_reshape = as_type_ptr(sub_pattern.front()); - auto input_to_first_reshape = first_reshape->input_value(0); - auto last_reshape = as_type_ptr(sub_pattern.back()); - - auto new_input_order = first_reshape->get_input_order(); - auto new_out_shape = last_reshape->get_shape(); - - auto new_reshape = std::make_shared( - input_to_first_reshape, new_input_order, new_out_shape); - - replace_node(last_reshape, new_reshape); - modify_graph = true; - } - - return modify_graph; - }; - std::set> empty_correlated_matches; - auto m = - std::make_shared(reshape_label, op, empty_correlated_matches); - this->add_matcher(m, callback, PassProperty::REQUIRE_STATIC_SHAPE); -} diff --git a/ngraph/src/ngraph/pass/reshape_elimination.hpp b/ngraph/src/ngraph/pass/reshape_elimination.hpp deleted file mode 100644 index 27e8743338f..00000000000 --- a/ngraph/src/ngraph/pass/reshape_elimination.hpp +++ /dev/null @@ -1,60 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/graph_rewrite.hpp" -#include "ngraph/pass/pass_util.hpp" - -namespace ngraph -{ - namespace pass - { - class ReshapeElimination; - class RecurrentReshapeElimination; - } -} - -class NGRAPH_API ngraph::pass::ReshapeElimination : public ngraph::pass::GraphRewrite -{ -public: - ReshapeElimination() - : GraphRewrite() - { - construct_dot_transpose_pattern(); - construct_identity_reshape_pattern(); - construct_reshapex2_pattern(); - } - -private: - void construct_dot_transpose_pattern(); - void construct_identity_reshape_pattern(); - void construct_reshapex2_pattern(); -}; - -class NGRAPH_API ngraph::pass::RecurrentReshapeElimination - : public ngraph::pass::RecurrentGraphRewrite -{ -public: - RecurrentReshapeElimination() - : RecurrentGraphRewrite() - { - construct_recurrent_reshape(); - } - -private: - void construct_recurrent_reshape(); -}; diff --git a/ngraph/src/ngraph/pass/reshape_sinking.cpp b/ngraph/src/ngraph/pass/reshape_sinking.cpp deleted file mode 100644 index 24bd4524650..00000000000 --- a/ngraph/src/ngraph/pass/reshape_sinking.cpp +++ /dev/null @@ -1,642 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include "reshape_sinking.hpp" -#include -#include -#include -#include -#include - -#include "ngraph/descriptor/input.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/batch_norm.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/dequantize.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/quantize.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/op/slice.hpp" -#include "ngraph/op/util/binary_elementwise_arithmetic.hpp" -#include "ngraph/op/util/op_types.hpp" -#include "ngraph/op/util/unary_elementwise_arithmetic.hpp" -#include "ngraph/pattern/op/label.hpp" -#include "ngraph/util.hpp" - -using namespace std; -using namespace ngraph; - -using ReshapeMap = unordered_map, shared_ptr>; - -static string describe_reshape(shared_ptr node) -{ - stringstream ss; - auto reshape = as_type_ptr(node); - ss << reshape->get_name() - << " ( axis order = " << ngraph::vector_to_string(reshape->get_input_order()) - << " , shape = " << vector_to_string(reshape->get_shape()) << " ) " - << " , child = " << reshape->input_value(0).get_node_shared_ptr()->get_name(); - - return ss.str(); -} - -static shared_ptr - make_reshape(shared_ptr arg, const AxisVector& input_order, const Shape& output_shape) -{ - auto reshape = make_shared(arg, input_order, output_shape); - NGRAPH_DEBUG << "Make Reshape " << describe_reshape(reshape); - return reshape; -} - -static void - write_reshapemap(ReshapeMap& reorders, shared_ptr target, shared_ptr reshape) -{ - NGRAPH_DEBUG << "Write ReshapeMap[" << target->get_name() - << "] = " << describe_reshape(reshape); - reorders[target] = reshape; -} - -static shared_ptr read_reshapemap(ReshapeMap& reorders, shared_ptr target) -{ - auto reorder = reorders.at(target); - NGRAPH_DEBUG << "Read ReshapeMap[" << target->get_name() << "] -> " - << describe_reshape(reorder); - return reorder; -} - -static shared_ptr combine_reshapes(shared_ptr r1, - shared_ptr r2) -{ - auto default_order = ngraph::get_default_order(r1->get_shape()); - auto perm_r1 = apply_permutation(default_order, r1->get_input_order()); - auto perm_r2 = apply_permutation(perm_r1, r2->get_input_order()); - auto rreshape = - make_reshape(r2->input_value(0).get_node_shared_ptr(), perm_r2, r2->get_shape()); - NGRAPH_DEBUG << "Combining " << describe_reshape(r1) << " and " << describe_reshape(r2) - << " into " << describe_reshape(rreshape); - return rreshape; -} - -static void insert_reshape(shared_ptr target, shared_ptr reshape, size_t input_index) -{ - NGRAPH_DEBUG << "Inserting reshape at input " << target->get_name() << " input index " - << input_index; - auto arg = target->input(input_index).get_source_output(); - NGRAPH_DEBUG << "Arg shape: " << arg.get_shape(); - auto new_reshape = reshape->copy_with_new_inputs({arg}); - NGRAPH_DEBUG << "Inserting reshape " << describe_reshape(new_reshape) << " at input " - << target->get_name() << " input index " << input_index; - target->input(input_index).replace_source_output(new_reshape->output(0)); -} - -static void delete_reshape(shared_ptr reshape) -{ - NGRAPH_DEBUG << "Removing reshape " << reshape->get_name(); - if (!reshape->get_users().empty()) - { - ngraph::replace_node(reshape, reshape->input_value(0).get_node_shared_ptr()); - } -} - -static void mark_reshape_for_deletion(shared_ptr reshape, - set>& reshapes_to_delete) -{ - NGRAPH_DEBUG << "Marking reshape " << reshape->get_name() << " for deletion"; - reshapes_to_delete.insert(reshape); -} - -static shared_ptr create_default_reshape(shared_ptr n) -{ - auto default_order = ngraph::get_default_order(n->get_shape()); - auto default_reshape = make_reshape(n, default_order, n->get_shape()); - NGRAPH_DEBUG << "Default reshape: " << describe_reshape(default_reshape); - return default_reshape; -} - -// compute an axis order that converts the given axis order to default -static AxisSet get_quantization_axes_in_default_order(shared_ptr arg_reshape, - const AxisSet& old_axis_set) -{ - auto perm_to_def = ngraph::get_permutation_to_default_order(arg_reshape->get_input_order()); - AxisSet axis_set; - for (auto axis : old_axis_set) - { - axis_set.insert(perm_to_def.at(axis)); - } - return axis_set; -} - -struct Swimmer -{ - Input input; - shared_ptr reshape; -}; - -// Swim is used to push/"swim" reshapes towards paramaters. -// This is typically done for binary ops when -// one operand is in nchw, while the other one is nhwc -// we prefer nchw since a lot of ngraph ops require this format, -// so keeping things in nchw allows us to eliminate as many reshapes -// as possible -void swim(Input input, shared_ptr reshape) -{ - Swimmer sw{input, reshape}; - list work_queue; - work_queue.push_back(sw); - - // TODO: if we support more ops (especially, with >1 args) - // we will need to keep track of nodes we visited and their reshapes - while (work_queue.size() > 0) - { - auto csw = work_queue.front(); - work_queue.pop_front(); - auto n_output = csw.input.get_source_output(); - auto n = n_output.get_node_shared_ptr(); - auto materialize = [csw, n_output]() { - auto n = n_output.get_node_shared_ptr(); - auto new_reshape = csw.reshape->clone_with_new_inputs({n}); - new_reshape->merge_provenance_tags_from(n); - NGRAPH_DEBUG << "Materializing new reshape " << describe_reshape(new_reshape); - csw.input.replace_source_output(new_reshape->output(0)); - }; // Only swim past nodes which have a single user - if (n->get_users().size() > 1) - { - materialize(); - continue; - } - NGRAPH_DEBUG << "Processing (swimming) " << n->get_name(); - if (op::is_unary_elementwise_arithmetic(n)) - { - Swimmer nsw{n->input(0), csw.reshape}; - work_queue.push_back(nsw); - NGRAPH_DEBUG << "Propagating reshape " << describe_reshape(csw.reshape) << " for " - << n->get_name() << " to " << n->input_value(0).get_node_shared_ptr(); - } - else if (is_type(n)) - { - auto old_broadcast = static_pointer_cast(n); - auto broadcast_axes = old_broadcast->get_broadcast_axes(); - auto broadcast_reshape = csw.reshape; - // swimming can only handle 1 dim change - if (broadcast_reshape->get_shape().size() - old_broadcast->get_shape().size() > 1) - { - materialize(); - continue; - } - bool in_order = true; - AxisSet new_broadcast_axes; - vector new_source_axes; - auto input_order = broadcast_reshape->get_input_order(); - for (size_t i = 0; i < input_order.size(); i++) - { - if (broadcast_axes.count(input_order.at(i)) != 0) - { - new_broadcast_axes.insert(i); - } - else - { - if (new_source_axes.size() != 0 && new_source_axes.back() > input_order.at(i)) - { - in_order = false; - } - new_source_axes.push_back(i); - } - } - - auto broadcast_input = old_broadcast->input_value(0).get_node_shared_ptr(); - if (!in_order) - { - AxisVector new_source_axes_sorted{new_source_axes}; - sort(new_source_axes_sorted.begin(), new_source_axes_sorted.end()); - map old_new_source_axes; - for (size_t i = 0; new_source_axes_sorted.size(); i++) - { - old_new_source_axes.insert({new_source_axes.at(i), i}); - } - - AxisVector new_source_axis_order; - for (auto axis : new_source_axes_sorted) - { - new_source_axis_order.push_back(old_new_source_axes.at(axis)); - } - - auto new_arg_shape = - ngraph::apply_permutation(broadcast_input->get_shape(), new_source_axis_order); - broadcast_input = - make_reshape(broadcast_input, new_source_axis_order, new_arg_shape); - } - - auto new_broadcast = make_shared( - broadcast_input, broadcast_reshape->get_shape(), new_broadcast_axes); - csw.input.replace_source_output(new_broadcast->output(0)); - } - // TODO: Add cases to push through Reshape and BinaryElementwiseArithmetic - else - { - // materialize - materialize(); - } - } -} - -// convert_binary_to_default_order is used when one of the arguments -// of a binary op isn't in the default format (i.e. nhwc instead of nchw) -// We have to normalize this other argument to nchw by swimming nchw towards parameters -// as far as we can -static void convert_binary_to_default_order(shared_ptr binary, - const Input& input, - shared_ptr right, - ReshapeMap& reorders, - set>& reshapes_to_delete) -{ - auto left = input.get_source_output().get_node_shared_ptr(); - auto perm_to_def = - ngraph::get_permutation_to_default_order(reorders.at(right)->get_input_order()); - auto new_shape = apply_permutation(left->get_shape(), perm_to_def); - NGRAPH_DEBUG << "right = " << ngraph::vector_to_string(right->get_shape()) << ", " - << right->get_name(); - auto new_reshape = make_reshape(left, perm_to_def, new_shape); - NGRAPH_DEBUG << "left : About to swim " << describe_reshape(new_reshape) << " up to " - << left->get_name(); - // this should now insert and swim reshape on right - swim(input, new_reshape); - mark_reshape_for_deletion(reorders.at(right), reshapes_to_delete); - write_reshapemap(reorders, binary, read_reshapemap(reorders, right)); -} - -static void materialize_shapes(shared_ptr n, - ReshapeMap& reorders, - set>& reshapes_to_delete) -{ - // skip multiple output nodes and deal with GOEs exclusively - if (n->get_output_size() > 1) - { - return; - } - - for (size_t i = 0; i < n->input_values().size(); i++) - { - // materialize all pending reshapes, flush pending reshapes - auto arg = n->input_value(i).get_node_shared_ptr(); - if (reorders.count(arg) != 0) - { - auto arg_reshape = reorders.at(arg); - NGRAPH_DEBUG << "Materializing " << describe_reshape(arg_reshape) << " for " - << arg->get_name(); - mark_reshape_for_deletion(arg_reshape, reshapes_to_delete); - auto arg_shape = arg->get_shape(); - if (arg_reshape->get_input_order() != get_default_order(arg->get_shape())) - { - // Insert if arg needs to be transposed. - insert_reshape(n, arg_reshape, i); - } - // no swimming up - } - } - write_reshapemap(reorders, n, create_default_reshape(n)); -} - -static void sink_reshape(shared_ptr reshape, - ReshapeMap& reorders, - set>& reshapes_to_delete) -{ - NGRAPH_DEBUG << "Sinking Reshape :" << describe_reshape(reshape); - auto orig_reshape = reorders.at(reshape->input_value(0).get_node_shared_ptr()); - // 1) Not a Transpose or 2) Rank changing operation. - if ((reshape->get_output_shape(0).size() != reshape->get_input_order().size()) || - (!reshape->get_is_transpose())) - { - NGRAPH_DEBUG << "Materializing " << describe_reshape(orig_reshape) << " for reshape " - << describe_reshape(reshape); - insert_reshape(reshape, orig_reshape, 0); - mark_reshape_for_deletion(orig_reshape, reshapes_to_delete); - write_reshapemap(reorders, reshape, create_default_reshape(reshape)); - } - else - { - // combine both reshapes - auto new_reshape = combine_reshapes(orig_reshape, reshape); - // remove original reshape now it's combined with a new one - // should be safe to remove an already detached node - mark_reshape_for_deletion(orig_reshape, reshapes_to_delete); - // replace reshape with combined one - ngraph::replace_node(reshape, new_reshape); - mark_reshape_for_deletion(new_reshape, reshapes_to_delete); - write_reshapemap(reorders, new_reshape, new_reshape); - } -} - -static void sink_unary(shared_ptr n, - ReshapeMap& reorders, - set>& /* reshapes_to_delete */) -{ - auto arg_reshape = read_reshapemap(reorders, n->input_value(0).get_node_shared_ptr()); - NGRAPH_DEBUG << "Propagating " << describe_reshape(arg_reshape) << " for " << n->get_name(); - write_reshapemap(reorders, n, arg_reshape); -} - -static void sink_binary(shared_ptr binary, - ReshapeMap& reorders, - set>& reshapes_to_delete) -{ - auto left = binary->input_value(0).get_node_shared_ptr(); - auto right = binary->input_value(1).get_node_shared_ptr(); - - if (reorders.at(left)->get_input_order() == reorders.at(right)->get_input_order()) - { - NGRAPH_DEBUG << "Propagating " << describe_reshape(reorders.at(left)) << " for " - << binary->get_name(); - write_reshapemap(reorders, binary, read_reshapemap(reorders, left)); - // at this point, both reshapes will be eventually removed - mark_reshape_for_deletion(reorders.at(left), reshapes_to_delete); - mark_reshape_for_deletion(reorders.at(right), reshapes_to_delete); - } - else if (reorders.at(left)->get_input_order() == ngraph::get_default_order(left->get_shape())) - { - convert_binary_to_default_order( - binary, binary->input(0), right, reorders, reshapes_to_delete); - } - else if (reorders.at(right)->get_input_order() == ngraph::get_default_order(right->get_shape())) - { - convert_binary_to_default_order( - binary, binary->input(1), left, reorders, reshapes_to_delete); - } - else - { - NGRAPH_DEBUG << "Materializing both reshapes for " << binary->get_name(); - NGRAPH_DEBUG << "Left = " << describe_reshape(reorders.at(left)); - NGRAPH_DEBUG << "Right = " << describe_reshape(reorders.at(right)); - mark_reshape_for_deletion(reorders.at(left), reshapes_to_delete); - mark_reshape_for_deletion(reorders.at(right), reshapes_to_delete); - insert_reshape(binary, reorders.at(left), 0); - insert_reshape(binary, reorders.at(right), 1); - } -} - -static void sink_slice(shared_ptr n, - ReshapeMap& reorders, - set>& /* reshapes_to_delete */) -{ - auto arg_reshape = reorders.at(n->input_value(0).get_node_shared_ptr()); - auto order = arg_reshape->get_input_order(); - - // we need the correct input shape to produce the right output shape - // we are going to create a label of the right input shape, - // so a new slice will have the right shape - auto def_order = ngraph::get_permutation_to_default_order(order); - auto input_shape = ngraph::apply_permutation(arg_reshape->get_shape(), def_order); - auto dummy_correct_shape = - make_shared(arg_reshape->get_element_type(), input_shape); - - auto new_lower = ngraph::apply_permutation(n->get_lower_bounds(), def_order); - auto new_upper = ngraph::apply_permutation(n->get_upper_bounds(), def_order); - auto new_strides = ngraph::apply_permutation(n->get_strides(), def_order); - auto new_slice = make_shared(dummy_correct_shape, new_lower, new_upper, new_strides); - ngraph::replace_node(dummy_correct_shape, n->input_value(0).get_node_shared_ptr()); - NGRAPH_DEBUG << "Replacing " << n->get_name() << " with " << new_slice->get_name(); - ngraph::replace_node(n, new_slice); - - auto new_reshape = make_reshape(new_slice, order, n->get_shape()); - NGRAPH_DEBUG << "Propagating " << describe_reshape(new_reshape) << " for " << n->get_name(); - write_reshapemap(reorders, new_slice, new_reshape); -} - -static void sink_pad(shared_ptr n, - ReshapeMap& reorders, - set>& /* reshapes_to_delete */) -{ - auto arg_reshape = reorders.at(n->input_value(0).get_node_shared_ptr()); - auto order = arg_reshape->get_input_order(); - // we need the correct input shape to produce the right output shape - // we are going to create a label of the right input shape, - // so a new pad will have the right shape - auto def_order = ngraph::get_permutation_to_default_order(order); - auto input_shape = ngraph::apply_permutation(arg_reshape->get_shape(), def_order); - auto dummy_correct_shape = - make_shared(arg_reshape->get_element_type(), input_shape); - - auto new_lower = ngraph::apply_permutation(n->get_padding_below(), def_order); - auto new_upper = ngraph::apply_permutation(n->get_padding_above(), def_order); - auto new_pad = make_shared(dummy_correct_shape, - n->input_value(1).get_node_shared_ptr(), - new_lower, - new_upper, - n->get_pad_mode()); - ngraph::replace_node(dummy_correct_shape, n->input_value(0).get_node_shared_ptr()); - NGRAPH_DEBUG << "Replacing " << n->get_name() << " with " << new_pad->get_name(); - ngraph::replace_node(n, new_pad); - auto new_reshape = make_reshape(new_pad, order, n->get_shape()); - NGRAPH_DEBUG << "Propagating " << describe_reshape(new_reshape) << " for " << n->get_name(); - write_reshapemap(reorders, new_pad, new_reshape); -} -static void sink_quantize(shared_ptr quantize, - ReshapeMap& reorders, - set>& /* reshapes_to_delete */) -{ - auto arg_reshape = reorders.at(quantize->input_value(0).get_node_shared_ptr()); - AxisSet axes_in_def_order = - get_quantization_axes_in_default_order(arg_reshape, quantize->get_axes()); - auto new_quantize = make_shared(quantize->input_value(0), - quantize->input_value(1), - quantize->input_value(2), - quantize->get_element_type(), - axes_in_def_order, - quantize->get_round_mode()); - - ngraph::replace_node(quantize, new_quantize); - write_reshapemap(reorders, new_quantize, arg_reshape); -} - -static void sink_concat(shared_ptr n, - ReshapeMap& reorders, - set>& reshapes_to_delete) -{ - auto arg_reshape = reorders.at(n->input_value(0).get_node_shared_ptr()); - auto order = arg_reshape->get_input_order(); - // we need the correct input shape to produce the right output shape - // we are going to create a label of the right input shape, - // so a new slice will have the right shape - auto def_order = ngraph::get_permutation_to_default_order(order); - auto input_shape = ngraph::apply_permutation(arg_reshape->get_shape(), def_order); - auto dummy_correct_shape = - make_shared(arg_reshape->get_element_type(), input_shape); - - NodeVector new_args; - new_args.push_back(dummy_correct_shape); - - for (size_t i = 1; i < n->get_input_size(); i++) - { - auto iarg_reshape = reorders.at(n->input_value(i).get_node_shared_ptr()); - auto iorder = iarg_reshape->get_input_order(); - if (iorder != order) - { - NGRAPH_DEBUG << " input order at " << i << "-th arg is different from first arg"; - materialize_shapes(n, reorders, reshapes_to_delete); - return; - } - - auto iinput_shape = ngraph::apply_permutation(iarg_reshape->get_shape(), def_order); - auto idummy_correct_shape = - make_shared(iarg_reshape->get_element_type(), iinput_shape); - new_args.push_back(idummy_correct_shape); - } - - auto new_axis = order.at(n->get_concatenation_axis()); - auto new_concat = make_shared(new_args, new_axis); - // put back the original arguments - for (size_t i = 0; i < new_concat->get_input_size(); i++) - { - ngraph::replace_node(new_args.at(i), n->input_value(i).get_node_shared_ptr()); - } - NGRAPH_DEBUG << "Replacing " << n->get_name() << " with " << new_concat->get_name(); - ngraph::replace_node(n, new_concat); - - auto new_reshape = make_reshape(new_concat, order, n->get_shape()); - NGRAPH_DEBUG << "Propagating " << describe_reshape(new_reshape) << " for " << n->get_name(); - write_reshapemap(reorders, new_concat, new_reshape); -} - -static void sink_dequantize(shared_ptr dequantize, - ReshapeMap& reorders, - set>& /* reshapes_to_delete */) -{ - auto arg_reshape = reorders.at(dequantize->input_value(0).get_node_shared_ptr()); - AxisSet axes_in_def_order = - get_quantization_axes_in_default_order(arg_reshape, dequantize->get_axes()); - auto new_dequantize = make_shared(dequantize->input_value(0), - dequantize->input_value(1), - dequantize->input_value(2), - dequantize->get_element_type(), - axes_in_def_order); - - ngraph::replace_node(dequantize, new_dequantize); - write_reshapemap(reorders, new_dequantize, arg_reshape); -} - -// The goal of ReshapeSinking is to remove -// round-trip reshapes(i.e. nhwc->nchw(nchw-only-op)->nhwc) -// around nchw-only-op (e.g.Convolution, Batchnorm, Avg/MaxPool) -// This is achieved by both **sinking**, propagating reshapes -// through ops towards op::Results, -// or **swimming** Reshapes up towards op::Parameter -// For each op type we support we can either combine -// two reshapes by replacing the existing Reshape, -// materialize pending reshapes if they can't be propagated through op -bool ngraph::pass::ReshapeSinking::run_on_function(shared_ptr f) -{ - ReshapeMap reorders; - NodeVector results; - set> reshapes_to_delete; - - // STEP 1 : Sink or Swim reshapes away for op clusters - for (auto n : f->get_ordered_ops()) - { - NGRAPH_DEBUG << "Start: Processing node " << n->get_name(); - // collect all Result nodes for a sanity check - if (ngraph::op::is_output(n)) - { - results.push_back(n); - } - - if (auto reshape = as_type_ptr(n)) - { - sink_reshape(reshape, reorders, reshapes_to_delete); - } - else if (op::is_unary_elementwise_arithmetic(n)) - { - sink_unary(n, reorders, reshapes_to_delete); - } - else if (op::is_binary_elementwise_arithmetic(n)) - { - sink_binary(n, reorders, reshapes_to_delete); - } - else if (auto goe = as_type_ptr(n)) - { - write_reshapemap(reorders, goe, create_default_reshape(goe)); - } - else if (auto quantize = as_type_ptr(n)) - { - sink_quantize(quantize, reorders, reshapes_to_delete); - } - else if (auto dequantize = as_type_ptr(n)) - { - sink_dequantize(dequantize, reorders, reshapes_to_delete); - } - else if (auto slice = as_type_ptr(n)) - { - // A heuristic. If Reshape has multiple slice users, if sunk - // it will be replicated by the number of its users - // TODO: we should have a pre-pass that looks at this kind of - // scenarios and marks some reshapes as too "toxic" to sink - // For now, this heuristic works really well. - // Note, get_users(*true*) which means we only care about - // live users of Reshape. However get_users(*true*) cause - // significant time increase on graphs with many slice ops, - // so for now we are removing "true" check and let backend - // handle reshape sinking for slice operation. - if (slice->input_value(0).get_node_shared_ptr()->get_users().size() == 1) - { - sink_slice(slice, reorders, reshapes_to_delete); - } - else - { - materialize_shapes(n, reorders, reshapes_to_delete); - } - } - else if (auto pad = as_type_ptr(n)) - { - sink_pad(pad, reorders, reshapes_to_delete); - } - else if (auto concat = as_type_ptr(n)) - { - sink_concat(concat, reorders, reshapes_to_delete); - } - else - { - materialize_shapes(n, reorders, reshapes_to_delete); - } - NGRAPH_DEBUG << "End: Processing node " << n->get_name(); - } - - // STEP 2: purge all the reshapes we either sunk or swam. - for (auto r : reshapes_to_delete) - { - delete_reshape(r); - } - - // make sure shapes are always materialized before results - for (auto r : results) - { - NGRAPH_CHECK(r->get_shape() == r->get_input_shape(0) && - r->get_element_type() == - r->input_value(0).get_node_shared_ptr()->get_element_type(), - " op::Result = ", - *r, - ", Arg = ", - *r->input_value(0).get_node_shared_ptr()); - } - - // STEP 3: fix wrong shape info wholesale - for (auto n : f->get_ordered_ops()) - { - n->revalidate_and_infer_types(); - } - return true; -} diff --git a/ngraph/src/ngraph/pass/reshape_sinking.hpp b/ngraph/src/ngraph/pass/reshape_sinking.hpp deleted file mode 100644 index c7efd49d3b1..00000000000 --- a/ngraph/src/ngraph/pass/reshape_sinking.hpp +++ /dev/null @@ -1,33 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/pass.hpp" -#include "ngraph/util.hpp" - -namespace ngraph -{ - namespace pass - { - class NGRAPH_API ReshapeSinking : public pass::FunctionPass - { - public: - ReshapeSinking() { set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); } - bool run_on_function(std::shared_ptr function) override; - }; - } -} diff --git a/ngraph/src/ngraph/pass/serialize.cpp b/ngraph/src/ngraph/pass/serialize.cpp deleted file mode 100644 index 97c43d643b6..00000000000 --- a/ngraph/src/ngraph/pass/serialize.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include - -#include "ngraph/file_util.hpp" -#include "ngraph/pass/serialize.hpp" -#include "ngraph/util.hpp" -#ifndef NGRAPH_JSON_DISABLE -#include "ngraph/serializer.hpp" -#include "nlohmann/json.hpp" -#endif - -using namespace std; -using namespace ngraph; - -pass::Serialization::Serialization(const string& name) - : m_name{name} -{ -} - -bool pass::Serialization::run_on_module(vector>& functions) -{ -#ifndef NGRAPH_JSON_DISABLE - // serializing the outermost functions - // also implicitly serializes any inner functions - serialize(m_name, functions.at(0), 4); -#endif - return false; -} diff --git a/ngraph/src/ngraph/pass/serialize.hpp b/ngraph/src/ngraph/pass/serialize.hpp deleted file mode 100644 index 53e51ed2739..00000000000 --- a/ngraph/src/ngraph/pass/serialize.hpp +++ /dev/null @@ -1,40 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class Serialization; - } -} - -class NGRAPH_API ngraph::pass::Serialization : public ModulePass -{ -public: - Serialization(const std::string& name); - - virtual bool run_on_module(std::vector>&) override; - -private: - const std::string m_name; -}; diff --git a/ngraph/src/ngraph/pass/validate_graph.cpp b/ngraph/src/ngraph/pass/validate_graph.cpp deleted file mode 100644 index 224609998e6..00000000000 --- a/ngraph/src/ngraph/pass/validate_graph.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include "ngraph/pass/validate_graph.hpp" - -using namespace std; -using namespace ngraph; - -bool pass::ValidateGraph::run_on_module(vector>& functions) -{ - for (shared_ptr f : functions) - { - validate_parameters(*f); - } - return false; -} - -void pass::ValidateGraph::validate_parameters(const Function& function) -{ - auto parameters = function.get_parameters(); - for (auto node : function.get_ops()) - { - shared_ptr p = as_type_ptr(node); - if (nullptr != p) - { - auto it = find_if(parameters.begin(), - parameters.end(), - [p](shared_ptr q) { return (p == q); }); - if (it == parameters.end()) - { - throw ngraph_error("Function references undeclared parameter"); - } - } - } -} diff --git a/ngraph/src/ngraph/pass/validate_graph.hpp b/ngraph/src/ngraph/pass/validate_graph.hpp deleted file mode 100644 index 5638890ac66..00000000000 --- a/ngraph/src/ngraph/pass/validate_graph.hpp +++ /dev/null @@ -1,38 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class ValidateGraph; - } -} - -class NGRAPH_API ngraph::pass::ValidateGraph : public ModulePass -{ -public: - bool run_on_module(std::vector>&) override; - -private: - void validate_parameters(const Function&); -}; diff --git a/ngraph/src/ngraph/pass/zero_dim_tensor_elimination.cpp b/ngraph/src/ngraph/pass/zero_dim_tensor_elimination.cpp deleted file mode 100644 index f40db8d9be8..00000000000 --- a/ngraph/src/ngraph/pass/zero_dim_tensor_elimination.cpp +++ /dev/null @@ -1,178 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include - -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/op/avg_pool.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/convolution.hpp" -#include "ngraph/op/max_pool.hpp" -#include "ngraph/op/pad.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/replace_slice.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/op/util/op_types.hpp" -#include "ngraph/type.hpp" -#include "zero_dim_tensor_elimination.hpp" - -using namespace std; -using namespace ngraph; - -static bool has_zero_dim(const Output& output) -{ - const auto& shape = output.get_shape(); - return find(shape.begin(), shape.end(), 0) != shape.end(); -} - -static bool verify_no_internal_zero_length_ops(shared_ptr f) -{ - set> zero_length_source_outputs; - for (auto n : f->get_ordered_ops()) - { - if (op::is_output(n) || op::is_parameter(n) || op::is_constant(n) || - n->get_output_size() > 1) - { - continue; - } - - for (auto& output : n->outputs()) - { - if (has_zero_dim(output)) - { - zero_length_source_outputs.insert(output); - } - } - } - - // all zero-length ops should be in a result set - // if we remove all such nodes included in the result set - // from zero_length_nodes and there are still nodes left - //(in zero_length_nodes), this means we have INTERNAL - // zero-length nodes (which violates our assumption) - for (auto r : f->get_results()) - { - for (auto& input : r->inputs()) - { - if (zero_length_source_outputs.count(input.get_source_output()) != 0) - { - zero_length_source_outputs.erase(input.get_source_output()); - } - } - } - - return zero_length_source_outputs.size() > 0; -} - -bool pass::ZeroDimTensorElimination::run_on_function(shared_ptr f) -{ - bool replaced = false; - auto cvals = vector(0); - // we need to go over all nodes since we could have sum or any other 0-length-tensor-to scalar - // op as an internal node (i.e. a node that isn't an argument to `op::Result`) - for (auto n : f->get_ordered_ops()) - { - // don't try to replace `op::Result` - // all multi-output feed into `GetOutputElement` - // if any `GetOutputElement` is zero-length - // we replace it w/ a signalling constant - // so we don't have to deal w/ multi-output nodes directly - if (op::is_output(n) || op::is_parameter(n) || n->get_output_size() > 1) - { - continue; - } - - if (has_zero_dim(n)) - { - // we don't have to create constants every time but this is the easiest - // and it's CSE's job to eliminate the same ones - auto constant = make_shared(n->get_element_type(), n->get_shape(), cvals); - replace_node(n, constant); - NGRAPH_DEBUG << " Replacing " << n->get_name() << " with " << constant->get_name(); - replaced = true; - continue; - } - - if (n->get_input_size() == 0) - { - continue; - } - - if (auto concat = as_type_ptr(n)) - { - OutputVector non_zero_dim_args; - for (auto arg : concat->input_values()) - { - if (!has_zero_dim(arg)) - { - non_zero_dim_args.push_back(arg); - } - } - - if (non_zero_dim_args.size() < concat->get_input_size()) - { - auto new_concat = concat->clone_with_new_inputs(non_zero_dim_args); - NGRAPH_DEBUG << " Replacing " << n->get_name() << " with " - << new_concat->get_name(); - replace_node(concat, new_concat); - continue; - } - } - else if (auto replace_slice = as_type_ptr(n)) - { - const Shape& replacement_shape = replace_slice->get_input_shape(1); - if (shape_size(replacement_shape) == 0) - { - // Op is a noop - Output source_output = replace_slice->input_value(0); - Output output = replace_slice->output(0); - for (Input input : output.get_target_inputs()) - { - input.replace_source_output(source_output); - } - } - } - - auto source_output = n->input_value(0); - - if (source_output.get_node()->get_output_size() != 1 || !has_zero_dim(source_output)) - { - continue; - } - - auto new_node = n->get_default_value(); - - if (!new_node) - { - continue; - } - - replaced = true; - NGRAPH_DEBUG << " Replacing " << n->get_name() << " with " << new_node->get_name(); - replace_node(n, new_node); - } - - if (verify_no_internal_zero_length_ops(f)) - { - throw ngraph_error("there were internal zero-length nodes in a graph"); - } - - return replaced; -} diff --git a/ngraph/src/ngraph/pass/zero_dim_tensor_elimination.hpp b/ngraph/src/ngraph/pass/zero_dim_tensor_elimination.hpp deleted file mode 100644 index 724af9e98b7..00000000000 --- a/ngraph/src/ngraph/pass/zero_dim_tensor_elimination.hpp +++ /dev/null @@ -1,39 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#pragma once - -#include "ngraph/pass/pass.hpp" - -namespace ngraph -{ - namespace pass - { - class ZeroDimTensorElimination; - } -} - -class NGRAPH_API ngraph::pass::ZeroDimTensorElimination : public FunctionPass -{ -public: - ZeroDimTensorElimination() - : FunctionPass() - { - set_property(PassProperty::REQUIRE_STATIC_SHAPE, true); - } - - virtual bool run_on_function(std::shared_ptr f); -}; diff --git a/ngraph/test/CMakeLists.txt b/ngraph/test/CMakeLists.txt index 0b01eb0e173..e89a0765220 100644 --- a/ngraph/test/CMakeLists.txt +++ b/ngraph/test/CMakeLists.txt @@ -42,7 +42,6 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") endif() set(SRC - algebraic_simplification.cpp aligned_buffer.cpp all_close_f.cpp assertion.cpp @@ -58,8 +57,6 @@ set(SRC coordinate.cpp copy.cpp cpio.cpp - cse.cpp - dyn_elimination.cpp element_type.cpp eval.cpp file_util.cpp @@ -98,16 +95,12 @@ set(SRC opset_pass/topk_opset_pass.cpp opset_pass/transpose_opset_pass.cpp partial_shape.cpp - pass.cpp pass_liveness.cpp pass_manager.cpp - pass_memory_layout.cpp pass_shape_relevance.cpp pattern.cpp provenance.cpp replace_node.cpp - reshape_elimination.cpp - reshape_sinking.cpp shape.cpp specialize_function.cpp tensor.cpp @@ -195,15 +188,8 @@ set(SRC type_prop_benchmark.cpp type_prop_layers.cpp util.cpp - zero_dim_tensor_elimination.cpp ) -if(NGRAPH_INTERPRETER_ENABLE) - list(APPEND SRC - concat_fusion.cpp - ) -endif() - # This code generates one source file per header file under ngraph/src where the source file # has just a single #include statement. This checks that each header in the source tree is # complete and self-contained so it can be included without requiring any other includes. diff --git a/ngraph/test/concat_fusion.cpp b/ngraph/test/concat_fusion.cpp deleted file mode 100644 index 72d1d0e590d..00000000000 --- a/ngraph/test/concat_fusion.cpp +++ /dev/null @@ -1,298 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" - -#include "ngraph/file_util.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/ngraph.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/concat.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/op/reshape.hpp" -#include "ngraph/pass/concat_fusion.hpp" -#include "ngraph/pass/graph_rewrite.hpp" -#include "ngraph/pass/manager.hpp" -#include "ngraph/pass/visualize_tree.hpp" -#include "ngraph/pattern/matcher.hpp" -#include "ngraph/pattern/op/label.hpp" -#include "ngraph/pattern/op/skip.hpp" -#include "ngraph/serializer.hpp" -#include "ngraph/util.hpp" -#include "util/all_close.hpp" -#include "util/matcher.hpp" -#include "util/random.hpp" -#include "util/test_tools.hpp" - -using namespace ngraph; -using namespace std; - -TEST(concat_fusion, single_branch) -{ - Shape shape_a{12, 8, 1, 1}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - - auto concat_1 = make_shared(NodeVector{A}, 2); - auto concat_2 = make_shared(NodeVector{concat_1}, 2); - auto concat_3 = make_shared( - NodeVector{concat_2, concat_2, concat_2, concat_2, concat_2, concat_2, concat_2}, 2); - auto concat_4 = make_shared( - NodeVector{concat_3, concat_3, concat_3, concat_3, concat_3, concat_3, concat_3}, 3); - auto f_concat_1 = make_shared(NodeVector{concat_4}, ParameterVector{A}); - return f_concat_1; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - size_t num_broadcast_optimzed = count_ops_of_type(optimized_f); - - ASSERT_EQ(num_reshapes_optimized, 1); - ASSERT_EQ(num_broadcast_optimzed, 1); -} - -TEST(concat_fusion, multiple_branches_1) -{ - Shape shape_a{16, 8, 1, 1}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - - auto concat_1 = make_shared(NodeVector{A}, 2); - auto concat_2 = make_shared(NodeVector{concat_1}, 2); - auto concat_3 = make_shared( - NodeVector{concat_2, concat_2, concat_2, concat_2, concat_2, concat_2, concat_2}, 2); - auto concat_4 = make_shared( - NodeVector{concat_3, concat_3, concat_3, concat_3, concat_3, concat_3, concat_3}, 3); - - auto concat_5 = make_shared(NodeVector{A, A}, 2); - auto concat_6 = make_shared(NodeVector{concat_5, concat_5, concat_5}, 3); - auto f_concat_1 = make_shared(NodeVector{concat_4, concat_6}, ParameterVector{A}); - return f_concat_1; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - size_t num_broadcast_optimzed = count_ops_of_type(optimized_f); - - ASSERT_EQ(num_reshapes_optimized, 2); - ASSERT_EQ(num_broadcast_optimzed, 2); -} - -TEST(concat_fusion, multiple_branches_2) -{ - Shape shape_a{16, 8, 1, 1}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - auto concat_3 = make_shared(NodeVector{A, A, A, A, A, A, A}, 2); - auto concat_4 = make_shared( - NodeVector{concat_3, concat_3, concat_3, concat_3, concat_3, concat_3, concat_3}, 3); - - auto concat_6 = make_shared(NodeVector{A, A, A}, 3); - auto f_concat_1 = make_shared(NodeVector{concat_4, concat_6}, ParameterVector{A}); - return f_concat_1; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - size_t num_broadcast_optimized = count_ops_of_type(optimized_f); - - ASSERT_EQ(num_reshapes_optimized, 2); - ASSERT_EQ(num_broadcast_optimized, 2); -} - -TEST(concat_fusion, non_fusable_self_concat) -{ - Shape shape_a{32, 1, 1, 1}; - Shape shape_b{32, 1, 1}; - auto generate_func = [shape_a, shape_b]() { - auto A = make_shared(element::f32, shape_a); - auto B = make_shared(element::f32, shape_b); - - auto concat_1 = make_shared(NodeVector{A, A, A, A}, 1); - auto concat_2 = make_shared( - NodeVector{concat_1, concat_1, concat_1, concat_1, concat_1, concat_1, concat_1}, 2); - auto concat_3 = make_shared(NodeVector{concat_2, concat_2}, 1); - auto concat_4 = make_shared(NodeVector{concat_3, concat_3, concat_3}, 3); - - auto concat_5 = make_shared(NodeVector{B, B, B, B, B, B, B}, 1); - auto concat_6 = make_shared(NodeVector{concat_5, concat_5, concat_5}, 2); - auto broadcast = make_shared(concat_6, Shape{32, 8, 7, 3}, AxisSet{1}); - auto add = make_shared(concat_4, broadcast); - auto f_concat_1 = make_shared(NodeVector{add}, ParameterVector{A, B}); - return f_concat_1; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape_1 = baseline_f->get_parameters().at(0)->get_shape(); - auto baseline_input_shape_2 = baseline_f->get_parameters().at(1)->get_shape(); - - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val_1(shape_size(baseline_input_shape_1)); - vector tensor_val_2(shape_size(baseline_input_shape_2)); - rng.initialize(tensor_val_1); - rng.initialize(tensor_val_2); - args.push_back(tensor_val_1); - args.push_back(tensor_val_2); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - size_t num_broadcast_optimzed = count_ops_of_type(optimized_f); - - ASSERT_EQ(num_reshapes_optimized, 3); - ASSERT_EQ(num_broadcast_optimzed, 4); -} - -TEST(concat_fusion, self_concat_with_fan_out) -{ - Shape shape_a{8, 1, 1, 1}; - Shape shape_b{8, 4, 1, 1}; - auto generate_func = [shape_a, shape_b]() { - auto A = make_shared(element::f32, shape_a); - auto B = make_shared(element::f32, shape_b); - - auto concat_1 = make_shared(NodeVector{A, A, A, A, A, A, A}, 2); - auto concat_2 = - make_shared(NodeVector{concat_1, concat_1, concat_1, concat_1}, 1); - auto concat_3 = - make_shared(NodeVector{concat_2, concat_2, concat_2, concat_2}, 3); - - auto concat_4 = make_shared(NodeVector{B, B, B, B, B, B, B}, 2); - auto concat_5 = make_shared(NodeVector{concat_4, concat_4, concat_4}, 3); - auto concat_6 = make_shared(NodeVector{concat_2, concat_4}, 3); - auto f_concat_1 = - make_shared(NodeVector{concat_3, concat_6}, ParameterVector{A, B}); - return f_concat_1; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape_1 = baseline_f->get_parameters().at(0)->get_shape(); - auto baseline_input_shape_2 = baseline_f->get_parameters().at(1)->get_shape(); - - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val_1(shape_size(baseline_input_shape_1)); - vector tensor_val_2(shape_size(baseline_input_shape_2)); - rng.initialize(tensor_val_1); - rng.initialize(tensor_val_2); - args.push_back(tensor_val_1); - args.push_back(tensor_val_2); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - size_t num_broadcast_optimzed = count_ops_of_type(optimized_f); - - ASSERT_EQ(num_reshapes_optimized, 3); - ASSERT_EQ(num_broadcast_optimzed, 3); -} - -TEST(concat_fusion, pass_property) -{ - { - auto pass = std::make_shared(); - ASSERT_FALSE(pass->get_property(pass::PassProperty::REQUIRE_STATIC_SHAPE)); - ASSERT_FALSE(pass->get_property(pass::PassProperty::CHANGE_DYNAMIC_STATE)); - } - - { - auto pass = std::make_shared(); - ASSERT_TRUE(pass->get_property(pass::PassProperty::REQUIRE_STATIC_SHAPE)); - ASSERT_FALSE(pass->get_property(pass::PassProperty::CHANGE_DYNAMIC_STATE)); - } -} diff --git a/ngraph/test/cse.cpp b/ngraph/test/cse.cpp deleted file mode 100644 index d8a8c7b3aec..00000000000 --- a/ngraph/test/cse.cpp +++ /dev/null @@ -1,362 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include - -#include "gtest/gtest.h" -#include "ngraph/file_util.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/ngraph.hpp" -#include "ngraph/op/abs.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/sqrt.hpp" -#include "ngraph/op/subtract.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/pass/cse.hpp" -#include "ngraph/pass/manager.hpp" -#include "util/test_tools.hpp" - -using namespace ngraph; -using namespace std; - -TEST(CSE, abs_abs) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto abs1 = std::make_shared(A); - auto abs2 = std::make_shared(A); - auto f = std::make_shared(NodeVector{abs1, abs2}, ParameterVector{A}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); -} - -TEST(CSE, abs_abs_negative) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto B = std::make_shared(element::i32, zero_shape); - auto abs1 = std::make_shared(A); - auto abs2 = std::make_shared(B); - auto f = std::make_shared(NodeVector{abs1, abs2}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), abs1); - ASSERT_EQ(f->get_results().at(1)->input_value(0).get_node_shared_ptr(), abs2); -} - -TEST(CSE, add_add) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto B = std::make_shared(element::i32, zero_shape); - auto add1 = std::make_shared(A, B); - auto add2 = std::make_shared(A, B); - auto f = std::make_shared(NodeVector{add1, add2}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); -} - -TEST(CSE, add_add_commutative) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto B = std::make_shared(element::i32, zero_shape); - auto add1 = std::make_shared(A, B); - auto add2 = std::make_shared(B, A); - auto f = std::make_shared(NodeVector{add1, add2}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); -} - -TEST(CSE, add_add_negative) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto B = std::make_shared(element::i32, zero_shape); - auto C = std::make_shared(element::i32, zero_shape); - auto D = std::make_shared(element::i32, zero_shape); - auto add1 = std::make_shared(A, B); - auto add2 = std::make_shared(C, D); - auto f = std::make_shared(NodeVector{add1, add2}, ParameterVector{A, B, C, D}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), add1); - ASSERT_EQ(f->get_results().at(1)->input_value(0).get_node_shared_ptr(), add2); -} - -TEST(CSE, abs_add) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto B = std::make_shared(element::i32, zero_shape); - auto abs_a1 = std::make_shared(A); - auto abs_b1 = std::make_shared(B); - auto abs_a2 = std::make_shared(A); - auto abs_b2 = std::make_shared(B); - auto add1 = std::make_shared(abs_a1, abs_b1); - auto add2 = std::make_shared(abs_a2, abs_b2); - auto f = std::make_shared(NodeVector{add1, add2}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); -} - -TEST(CSE, abs_add_reshape_broadcast) -{ - Shape zero_shape{1}; - auto A = std::make_shared(element::i32, zero_shape); - auto B = std::make_shared(element::i32, zero_shape); - auto abs_a1 = std::make_shared(A); - auto abs_b1 = std::make_shared(B); - auto abs_a2 = std::make_shared(A); - auto abs_b2 = std::make_shared(B); - auto add1 = std::make_shared(abs_a1, abs_b1); - auto add2 = std::make_shared(abs_a2, abs_b2); - { - // success case - auto reshape1 = std::make_shared(add1, AxisVector{0}, Shape{1, 1}); - auto reshape2 = std::make_shared(add2, AxisVector{0}, Shape{1, 1}); - auto broadcast1 = std::make_shared(reshape1, Shape{1, 1, 3}, AxisSet{2}); - auto broadcast2 = std::make_shared(reshape2, Shape{1, 1, 3}, AxisSet{2}); - auto f = - std::make_shared(NodeVector{broadcast1, broadcast2}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); - } - { - // fail case - auto reshape1 = std::make_shared(add1, AxisVector{0}, Shape{1}); - auto reshape2 = std::make_shared(add2, AxisVector{0}, Shape{1, 1}); - auto f = std::make_shared(NodeVector{reshape1, reshape2}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_NE(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); - } - { - // fail case - auto broadcast1 = std::make_shared(add1, Shape{1, 2}, AxisSet{1}); - auto broadcast2 = std::make_shared(add2, Shape{1, 1, 2}, AxisSet{1, 2}); - auto f = - std::make_shared(NodeVector{broadcast1, broadcast2}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_NE(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); - } -} - -TEST(CSE, abs_add_abs_add) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto B = std::make_shared(element::i32, zero_shape); - auto abs_a1 = std::make_shared(A); - auto abs_b1 = std::make_shared(B); - auto abs_a2 = std::make_shared(A); - auto abs_b2 = std::make_shared(B); - auto add1 = std::make_shared(abs_a1, abs_b1); - auto add2 = std::make_shared(abs_a2, abs_b2); - auto abs_add1 = std::make_shared(add1); - auto abs_add2 = std::make_shared(add2); - auto C = std::make_shared(element::i32, zero_shape); - auto add3 = std::make_shared(abs_add1, C); - auto add4 = std::make_shared(abs_add2, C); - auto f = std::make_shared(NodeVector{add3, add4}, ParameterVector{A, B, C}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); -} - -TEST(CSE, abs_add_abs_add_negative) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto B = std::make_shared(element::i32, zero_shape); - auto abs_a1 = std::make_shared(A); - auto abs_b1 = std::make_shared(B); - auto abs_a2 = std::make_shared(A); - auto abs_b2 = std::make_shared(B); - auto add1 = std::make_shared(abs_a1, abs_b1); - auto add2 = std::make_shared(abs_a2, abs_b2); - auto abs_add1 = std::make_shared(add1); - auto abs_add2 = std::make_shared(add2); - auto C = std::make_shared(element::i32, zero_shape); - auto D = std::make_shared(element::i32, zero_shape); - auto add3 = std::make_shared(abs_add1, C); - auto add4 = std::make_shared(abs_add2, D); - auto f = std::make_shared(NodeVector{add3, add4}, ParameterVector{A, B, C, D}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - auto oadd3 = f->get_results().at(0)->input_value(0).get_node_shared_ptr(); - auto oadd4 = f->get_results().at(1)->input_value(0).get_node_shared_ptr(); - ASSERT_EQ(oadd3, add3); - ASSERT_EQ(oadd4, add4); - ASSERT_EQ(oadd3->input_value(1).get_node_shared_ptr(), C); - ASSERT_EQ(oadd4->input_value(1).get_node_shared_ptr(), D); - ASSERT_EQ(oadd3->input_value(0).get_node_shared_ptr(), - oadd4->input_value(0).get_node_shared_ptr()); -} - -template -static void execute_cse_reduction_test() -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, Shape{3, 5}); - auto a_reduction_op = std::make_shared(A, AxisSet{0, 1}); - auto a_reduction_op2 = std::make_shared(A, AxisSet{0, 1}); - auto a_reduction_op3 = std::make_shared(A, AxisSet{0}); - auto sub_aa = a_reduction_op - a_reduction_op2; - - auto B = std::make_shared(element::i32, Shape{3, 5}); - auto b_reduction_op = std::make_shared(B, AxisSet{0, 1}); - - auto sub_ab = a_reduction_op - b_reduction_op; - auto f = std::make_shared(NodeVector{sub_aa, sub_ab, a_reduction_op3}, - ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - - ASSERT_EQ(sub_aa->input_value(0).get_node_shared_ptr(), - sub_aa->input_value(1).get_node_shared_ptr()); - ASSERT_NE(sub_ab->input_value(0).get_node_shared_ptr(), - sub_ab->input_value(1).get_node_shared_ptr()); - ASSERT_NE(f->get_results().at(2)->input_value(0).get_node_shared_ptr(), - sub_aa->input_value(0).get_node_shared_ptr()); -} - -TEST(CSE, reduction_ops) -{ - execute_cse_reduction_test(); - execute_cse_reduction_test(); -} - -TEST(CSE, constant) -{ - Shape zero_shape{0}; - auto iconst0 = op::Constant::create(element::i32, Shape{}, {0}); - auto iconst0_1 = op::Constant::create(element::i32, Shape{}, {0}); - auto iconst1 = op::Constant::create(element::i32, Shape{}, {1}); - auto iconst1_1 = op::Constant::create(element::i32, Shape{}, {1}); - auto fconst0 = op::Constant::create(element::f32, Shape{}, {0}); - auto iconst111 = op::Constant::create(element::i32, Shape{3}, {1, 1, 1}); - auto iconst112 = op::Constant::create(element::i32, Shape{3}, {1, 1, 2}); - - auto abs0 = std::make_shared(iconst0); - auto abs0_1 = std::make_shared(iconst0_1); - - auto abs1 = std::make_shared(iconst1); - auto abs1_1 = std::make_shared(iconst1_1); - - auto absf = std::make_shared(fconst0); - - auto abs111 = std::make_shared(iconst111); - auto abs112 = std::make_shared(iconst112); - - auto f = std::make_shared( - NodeVector{abs0, abs0_1, abs1, abs1_1, absf, abs111, abs112}, ParameterVector{}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.run_passes(f); - - ASSERT_EQ(abs0->input_value(0).get_node_shared_ptr(), - abs0_1->input_value(0).get_node_shared_ptr()); - ASSERT_EQ(abs1->input_value(0).get_node_shared_ptr(), - abs1_1->input_value(0).get_node_shared_ptr()); - ASSERT_NE(abs0->input_value(0).get_node_shared_ptr(), - abs1->input_value(0).get_node_shared_ptr()); - ASSERT_NE(abs0->input_value(0).get_node_shared_ptr(), - absf->input_value(0).get_node_shared_ptr()); - ASSERT_NE(abs111->input_value(0).get_node_shared_ptr(), - abs112->input_value(0).get_node_shared_ptr()); -} - -TEST(CSE, one_hot) -{ - pass::Manager pass_manager; - pass_manager.register_pass(); - { - Shape param_shape{8}; - Shape out_shape{8, 16}; - auto A = std::make_shared(element::i32, param_shape); - auto onehot1 = std::make_shared(A, out_shape, 1); - auto onehot2 = std::make_shared(A, out_shape, 1); - auto f = std::make_shared(NodeVector{onehot1, onehot2}, ParameterVector{A}); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); - } - { - Shape param_shape{8, 1}; - Shape out_shape{8, 16}; - auto A = std::make_shared(element::i32, param_shape); - auto reshape1 = std::make_shared(A, AxisVector{0, 1}, Shape{8}); - auto reshape2 = std::make_shared(A, AxisVector{0, 1}, Shape{8}); - auto onehot1 = std::make_shared(reshape1, out_shape, 1); - auto onehot2 = std::make_shared(reshape2, out_shape, 1); - auto f = std::make_shared(NodeVector{onehot1, onehot2}, ParameterVector{A}); - pass_manager.run_passes(f); - ASSERT_EQ(f->get_results().at(0)->input_value(0).get_node_shared_ptr(), - f->get_results().at(1)->input_value(0).get_node_shared_ptr()); - } -} - -TEST(CSE, pass_property) -{ - auto pass = std::make_shared(); - ASSERT_TRUE(pass->get_property(pass::PassProperty::REQUIRE_STATIC_SHAPE)); - ASSERT_FALSE(pass->get_property(pass::PassProperty::CHANGE_DYNAMIC_STATE)); -} diff --git a/ngraph/test/pass.cpp b/ngraph/test/pass.cpp deleted file mode 100644 index ff6aae51f8d..00000000000 --- a/ngraph/test/pass.cpp +++ /dev/null @@ -1,52 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" -#include "ngraph/op/add.hpp" -#include "ngraph/op/broadcast.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/pass/constant_to_broadcast.hpp" -#include "ngraph/pass/manager.hpp" -#include "ngraph/pass/visualize_tree.hpp" -#include "ngraph/serializer.hpp" -#include "util/test_tools.hpp" - -using namespace ngraph; -using namespace std; - -TEST(pass, constant_to_broadcast) -{ - Shape shape{128, 256, 1, 1}; - vector v = {3}; - auto c = make_shared(element::f32, shape, v); - auto f = make_shared(c, ParameterVector{}); - - { - ngraph::pass::Manager pm; - pm.register_pass(); - EXPECT_EQ(count_ops_of_type(f), 0); - pm.run_passes(f); - EXPECT_EQ(count_ops_of_type(f), 1); - } -} diff --git a/ngraph/test/pass_liveness.cpp b/ngraph/test/pass_liveness.cpp index d1005848640..63ef1126582 100644 --- a/ngraph/test/pass_liveness.cpp +++ b/ngraph/test/pass_liveness.cpp @@ -23,11 +23,9 @@ #include "ngraph/log.hpp" #include "ngraph/ngraph.hpp" -#include "ngraph/pass/dump_sorted.hpp" -#include "ngraph/pass/liveness.hpp" -#include "ngraph/pass/liveness.hpp" #include "ngraph/pass/manager.hpp" #include "ngraph/pass/visualize_tree.hpp" +#include "pass/liveness.hpp" #include "util/test_tools.hpp" diff --git a/ngraph/test/pass_manager.cpp b/ngraph/test/pass_manager.cpp index c7224fe2b6e..f709a941a62 100644 --- a/ngraph/test/pass_manager.cpp +++ b/ngraph/test/pass_manager.cpp @@ -54,16 +54,3 @@ namespace bool run_on_function(std::shared_ptr /* f */) override { return false; } }; } - -// Regression test: We've had an issue in the past where enabling per-pass validation and -// per-pass serialization at the same time causes a crash. -TEST(pass_manager, serialize_with_revalidate_does_not_crash) -{ - pass::Manager pass_manager; - pass_manager.set_per_pass_validation(true); - pass_manager.set_pass_serialization(true); - shared_ptr dummy = pass_manager.register_pass(); - - auto graph = make_test_graph(); - pass_manager.run_passes(graph); -} diff --git a/ngraph/test/pass_memory_layout.cpp b/ngraph/test/pass_memory_layout.cpp deleted file mode 100644 index 80a4bcfb5c5..00000000000 --- a/ngraph/test/pass_memory_layout.cpp +++ /dev/null @@ -1,234 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include -#include -#include - -#include "gtest/gtest.h" - -#include "ngraph/ngraph.hpp" -#include "ngraph/pass/dump_sorted.hpp" -#include "ngraph/pass/liveness.hpp" -#include "ngraph/pass/liveness.hpp" -#include "ngraph/pass/manager.hpp" -#include "ngraph/pass/memory_layout.hpp" -#include "ngraph/pass/visualize_tree.hpp" -#include "util/test_tools.hpp" - -using namespace ngraph; -using namespace std; - -static vector get_node_list(const pass::MemoryManager& mm) -{ - vector rc; - rc.insert(rc.end(), mm.begin(), mm.end()); - return rc; -} - -TEST(memory_manager, allocate) -{ - pass::MemoryManager mm{1}; - - // Special case, allocating size zero bumps the size of the alloc up to the alignment size - EXPECT_EQ(0, mm.allocate(0)); - EXPECT_EQ(1, mm.allocate(10)); - EXPECT_EQ(11, mm.allocate(10)); - EXPECT_EQ(21, mm.allocate(10)); -} - -TEST(memory_manager, free_first_allocated) -{ - pass::MemoryManager mm{1}; - - EXPECT_EQ(0, mm.allocate(10)); - EXPECT_EQ(10, mm.allocate(10)); - EXPECT_EQ(3, mm.get_node_list().size()); - - mm.free(0); - - auto node_list = get_node_list(mm); - EXPECT_EQ(3, node_list.size()); - EXPECT_TRUE(node_list[0].is_free()); - EXPECT_FALSE(node_list[1].is_free()); - EXPECT_TRUE(node_list[2].is_free()); -} - -TEST(memory_manager, free_middle_allocated) -{ - pass::MemoryManager mm{1}; - - EXPECT_EQ(0, mm.allocate(10)); - EXPECT_EQ(10, mm.allocate(10)); - EXPECT_EQ(20, mm.allocate(10)); - EXPECT_EQ(30, mm.allocate(10)); - EXPECT_EQ(40, mm.allocate(10)); - EXPECT_EQ(6, mm.get_node_list().size()); - - mm.free(10); - - auto node_list = get_node_list(mm); - EXPECT_EQ(6, node_list.size()); - EXPECT_FALSE(node_list[0].is_free()); - EXPECT_TRUE(node_list[1].is_free()); - EXPECT_FALSE(node_list[2].is_free()); - EXPECT_FALSE(node_list[3].is_free()); - EXPECT_FALSE(node_list[4].is_free()); -} - -TEST(memory_manager, free_last_allocated) -{ - pass::MemoryManager mm{1}; - - EXPECT_EQ(0, mm.allocate(10)); - EXPECT_EQ(10, mm.allocate(10)); - EXPECT_EQ(20, mm.allocate(10)); - EXPECT_EQ(30, mm.allocate(10)); - EXPECT_EQ(40, mm.allocate(10)); - EXPECT_EQ(6, mm.get_node_list().size()); - - mm.free(40); - - auto node_list = get_node_list(mm); - EXPECT_EQ(5, node_list.size()); - EXPECT_FALSE(node_list[0].is_free()); - EXPECT_FALSE(node_list[1].is_free()); - EXPECT_FALSE(node_list[2].is_free()); - EXPECT_FALSE(node_list[3].is_free()); - EXPECT_TRUE(node_list[4].is_free()); -} - -TEST(memory_manager, free_first_free) -{ - pass::MemoryManager mm{1}; - - EXPECT_EQ(0, mm.allocate(10)); - EXPECT_EQ(10, mm.allocate(10)); - EXPECT_EQ(20, mm.allocate(10)); - EXPECT_EQ(30, mm.allocate(10)); - EXPECT_EQ(40, mm.allocate(10)); - EXPECT_EQ(6, mm.get_node_list().size()); - - mm.free(10); - mm.free(0); - - auto node_list = get_node_list(mm); - EXPECT_EQ(5, node_list.size()); - EXPECT_TRUE(node_list[0].is_free()); - EXPECT_FALSE(node_list[1].is_free()); - EXPECT_FALSE(node_list[2].is_free()); - EXPECT_FALSE(node_list[3].is_free()); -} - -TEST(memory_manager, free_middle_free) -{ - pass::MemoryManager mm{1}; - - EXPECT_EQ(0, mm.allocate(10)); - EXPECT_EQ(10, mm.allocate(10)); - EXPECT_EQ(20, mm.allocate(10)); - EXPECT_EQ(30, mm.allocate(10)); - EXPECT_EQ(40, mm.allocate(10)); - EXPECT_EQ(6, mm.get_node_list().size()); - - mm.free(0); - mm.free(20); - mm.free(10); - - auto node_list = get_node_list(mm); - EXPECT_EQ(4, node_list.size()); - EXPECT_TRUE(node_list[0].is_free()); - EXPECT_FALSE(node_list[1].is_free()); - EXPECT_FALSE(node_list[2].is_free()); -} - -TEST(memory_manager, max_allocated) -{ - pass::MemoryManager mm{1}; - - EXPECT_EQ(0, mm.allocate(10)); - EXPECT_EQ(10, mm.allocate(10)); - EXPECT_EQ(20, mm.allocate(10)); - EXPECT_EQ(30, mm.allocate(10)); - EXPECT_EQ(40, mm.allocate(10)); - EXPECT_EQ(6, mm.get_node_list().size()); - - mm.free(0); - mm.free(20); - mm.free(10); - - EXPECT_EQ(mm.max_allocated(), 50); -} - -TEST(memory_manager, bad_free) -{ - pass::MemoryManager mm{1}; - - EXPECT_THROW(mm.free(10), std::runtime_error); -} - -TEST(memory_manager, align) -{ - EXPECT_EQ(8, pass::MemoryManager::align(0, 8)); - EXPECT_EQ(8, pass::MemoryManager::align(1, 8)); - EXPECT_EQ(8, pass::MemoryManager::align(2, 8)); - EXPECT_EQ(8, pass::MemoryManager::align(3, 8)); - EXPECT_EQ(8, pass::MemoryManager::align(4, 8)); - EXPECT_EQ(8, pass::MemoryManager::align(5, 8)); - EXPECT_EQ(8, pass::MemoryManager::align(6, 8)); - EXPECT_EQ(8, pass::MemoryManager::align(7, 8)); - EXPECT_EQ(8, pass::MemoryManager::align(8, 8)); - EXPECT_EQ(16, pass::MemoryManager::align(9, 8)); -} - -TEST(memory_manager, memory_align) -{ - pass::MemoryManager mm{64}; - - EXPECT_EQ(0, mm.allocate(4)); - EXPECT_EQ(64, mm.allocate(4)); - EXPECT_EQ(128, mm.allocate(4)); -} - -TEST(memory_layout, basic) -{ - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.register_pass(); - - auto graph = make_test_graph(); - pass_manager.run_passes(graph); - auto sorted = graph->get_ordered_ops(); - size_t temporary_pool_size = graph->get_temporary_pool_size(); - EXPECT_EQ(12, temporary_pool_size); -} - -TEST(memory_layout, constant) -{ - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.register_pass(); - - Shape shape{1}; - auto c = op::Constant::create(element::i32, shape, {5}); - auto f = make_shared(make_shared(c), ParameterVector{}); - - pass_manager.run_passes(f); - auto sorted = f->get_ordered_ops(); - size_t temporary_pool_size = f->get_temporary_pool_size(); - EXPECT_EQ(4, temporary_pool_size); -} diff --git a/ngraph/test/pass_shape_relevance.cpp b/ngraph/test/pass_shape_relevance.cpp index 940fab04d44..6f23d623587 100644 --- a/ngraph/test/pass_shape_relevance.cpp +++ b/ngraph/test/pass_shape_relevance.cpp @@ -23,7 +23,7 @@ #include "ngraph/ngraph.hpp" #include "ngraph/pass/manager.hpp" -#include "ngraph/pass/shape_relevance.hpp" +#include "pass/shape_relevance.hpp" using namespace ngraph; using namespace std; diff --git a/ngraph/test/provenance.cpp b/ngraph/test/provenance.cpp index 6662eb05c68..9a8aa8ac45f 100644 --- a/ngraph/test/provenance.cpp +++ b/ngraph/test/provenance.cpp @@ -25,11 +25,11 @@ #include "ngraph/builder/norm.hpp" #include "ngraph/graph_util.hpp" #include "ngraph/ngraph.hpp" -#include "ngraph/pass/fused_op_decomposition.hpp" #include "ngraph/pass/manager.hpp" #include "ngraph/provenance.hpp" #include "opset0_downgrade.hpp" #include "opset1_upgrade.hpp" +#include "pass/fused_op_decomposition.hpp" #include "util/provenance_enabler.hpp" using namespace std; diff --git a/ngraph/test/reshape_elimination.cpp b/ngraph/test/reshape_elimination.cpp deleted file mode 100644 index 4066758e513..00000000000 --- a/ngraph/test/reshape_elimination.cpp +++ /dev/null @@ -1,497 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" -#include "ngraph/file_util.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/ngraph.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/pass/graph_rewrite.hpp" -#include "ngraph/pass/manager.hpp" -#include "ngraph/pass/reshape_elimination.hpp" -#include "ngraph/pass/visualize_tree.hpp" -#include "ngraph/pattern/matcher.hpp" -#include "ngraph/pattern/op/label.hpp" -#include "ngraph/pattern/op/skip.hpp" -#include "ngraph/serializer.hpp" -#include "ngraph/util.hpp" -#include "ngraph/util.hpp" -#include "util/all_close.hpp" -#include "util/matcher.hpp" -#include "util/random.hpp" -#include "util/test_tools.hpp" - -using namespace ngraph; -using namespace std; - -#ifndef NGRAPH_JSON_DISABLE -TEST(reshape_elimination, remove_reshape) -{ - pass::Manager pass_manager; - pass_manager.register_pass(); - const string json_path = file_util::path_join(SERIALIZED_ZOO, "mxnet/bn_fprop.json"); - const string json_string = file_util::read_file_to_string(json_path); - stringstream ss(json_string); - shared_ptr func = ngraph::deserialize(ss); - size_t count_before = count_ops_of_type(func); - pass_manager.run_passes(func); - size_t count_after = count_ops_of_type(func); - ASSERT_TRUE(count_after < count_before); -} - -TEST(reshape_elimination, remove_tranpose) -{ - pass::Manager pass_manager; - pass_manager.register_pass(); - const string json_path = file_util::path_join(SERIALIZED_ZOO, "mxnet/tranpose.json"); - const string json_string = file_util::read_file_to_string(json_path); - stringstream ss(json_string); - shared_ptr func = ngraph::deserialize(ss); - size_t count_before = count_ops_of_type(func); - pass_manager.run_passes(func); - size_t count_after = count_ops_of_type(func); - ASSERT_TRUE(count_after < count_before); -} - -TEST(reshape_elimination, bn_bprop_rewrite) -{ - pass::Manager pass_manager; - pass_manager.register_pass(); - const string json_path = file_util::path_join(SERIALIZED_ZOO, "mxnet/bn_bprop.json"); - const string json_string = file_util::read_file_to_string(json_path); - stringstream ss(json_string); - shared_ptr func = ngraph::deserialize(ss); - size_t count_before = count_ops_of_type(func); - pass_manager.run_passes(func); - size_t count_after = count_ops_of_type(func); - ASSERT_TRUE(count_after < count_before); -} -#endif - -#ifdef NGRAPH_INTERPRETER_ENABLE -TEST(reshape_elimination, transpose_reshape_pattern_fuse) -{ - auto generate_func = []() { - auto input = make_shared(element::f32, Shape{8, 2, 4, 6}); - auto transpose = make_shared(input, AxisVector{0, 2, 1, 3}, Shape{8, 2, 4, 6}); - auto reshape = - make_shared(transpose, AxisVector{0, 1, 2, 3}, Shape{8, 4, 2, 6}); - return make_shared(reshape, ParameterVector{input}); - }; - - auto fuse_func = generate_func(); - auto nofuse_func = generate_func(); - - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.run_passes(fuse_func); - ASSERT_TRUE(count_ops_of_type(fuse_func) == 1); - ASSERT_TRUE(count_ops_of_type(nofuse_func) == 2); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(Shape{8, 2, 4, 6})); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(fuse_func, args, "INTERPRETER"); - auto optimized_results = execute(nofuse_func, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); -} -#endif - -TEST(reshape_elimination, transpose_reshape_pattern_nofuse) -{ - auto input = make_shared(element::f32, Shape{8, 2, 4, 6}); - auto transpose = make_shared(input, AxisVector{0, 2, 1, 3}, Shape{8, 2, 4, 6}); - auto reshape = make_shared(transpose, AxisVector{2, 1, 0, 3}, Shape{8, 4, 2, 6}); - auto f = make_shared(reshape, ParameterVector{input}); - - pass::Manager pass_manager; - pass_manager.register_pass(); - pass_manager.run_passes(f); - ASSERT_TRUE(count_ops_of_type(f) == 2); -} - -TEST(reshape_elimination, dot_transpose_to_dot_w_transpose_args) -{ - Shape shape_w{2, 4}; - Shape shape_x{4, 1}; - auto W = make_shared(element::f32, shape_w); - auto x = make_shared(element::f32, shape_x); - - auto dot = make_shared(W, x); - auto reshape_dot = std::make_shared(dot, AxisVector{1, 0}, Shape{1, 2}); - auto graph = make_shared(reshape_dot); - - pass::Manager pass_manager; - pass_manager.register_pass(); - auto func = make_shared(graph, ParameterVector{W, x}); - pass_manager.run_passes(func); - auto gdot = graph->input_value(0).get_node_shared_ptr(); - ASSERT_TRUE(as_type_ptr(gdot)); - ASSERT_TRUE(as_type_ptr(gdot->input_value(0).get_node_shared_ptr())); - ASSERT_TRUE(as_type_ptr(gdot->input_value(1).get_node_shared_ptr())); - ASSERT_EQ(gdot->input_value(0).get_node_shared_ptr()->input_value(0).get_node_shared_ptr(), x); - ASSERT_EQ(gdot->input_value(1).get_node_shared_ptr()->input_value(0).get_node_shared_ptr(), W); - ASSERT_EQ(gdot->get_shape(), (Shape{1, 2})); -} - -#ifdef NGRAPH_INTERPRETER_ENABLE -TEST(reshape_elimination, recurrent_reshapes) -{ - Shape shape_a{2, 2, 3, 3, 2, 4}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - Shape shape_r_1{3, 2, 2, 4, 6}; - Shape shape_r_2{6, 8, 3, 2}; - Shape shape_r_3{6, 8, 6}; - Shape shape_r_4{6, 2, 2, 2, 6}; - Shape shape_r_5{2, 3, 2, 2, 2, 3, 2}; - Shape shape_r_6{48, 6}; - - auto r_1 = make_shared(A, AxisVector{2, 4, 0, 5, 3, 1}, shape_r_1); - auto r_2 = make_shared(r_1, AxisVector{0, 1, 2, 3, 4}, shape_r_2); - auto r_3 = make_shared(r_2, AxisVector{0, 1, 2, 3}, shape_r_3); - auto r_4 = make_shared(r_3, AxisVector{0, 1, 2}, shape_r_4); - auto r_5 = make_shared(r_4, AxisVector{0, 1, 2, 3, 4}, shape_r_5); - auto r_6 = make_shared(r_5, AxisVector{0, 1, 2, 3, 4, 5, 6}, shape_r_6); - - auto f = make_shared(r_6, ParameterVector{A}); - return f; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - // pass_manager.register_pass("before_recurrent_reshapes.png"); - pass_manager.register_pass(); - // pass_manager.register_pass("after_recurrent_reshapes.png"); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - ASSERT_EQ(num_reshapes_optimized, 1); -} - -TEST(reshape_elimination, recurrent_reshapes_elimination) -{ - Shape shape_a{2, 2, 3, 3, 2, 4}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - Shape shape_r_1{3, 2, 2, 4, 6}; - Shape shape_r_2{6, 8, 3, 2}; - Shape shape_r_3{6, 8, 6}; - Shape shape_r_4{6, 2, 2, 2, 6}; - Shape shape_r_5{2, 3, 2, 2, 2, 3, 2}; - Shape shape_r_6{48, 6}; - Shape shape_r_7{2, 2, 3, 3, 2, 4}; - - auto r_1 = make_shared(A, AxisVector{0, 1, 2, 3, 4, 5}, shape_r_1); - auto r_2 = make_shared(r_1, AxisVector{0, 1, 2, 3, 4}, shape_r_2); - auto r_3 = make_shared(r_2, AxisVector{0, 1, 2, 3}, shape_r_3); - auto r_4 = make_shared(r_3, AxisVector{0, 1, 2}, shape_r_4); - auto r_5 = make_shared(r_4, AxisVector{0, 1, 2, 3, 4}, shape_r_5); - auto r_6 = make_shared(r_5, AxisVector{0, 1, 2, 3, 4, 5, 6}, shape_r_6); - auto r_7 = make_shared(r_6, AxisVector{0, 1}, shape_r_7); - auto f = make_shared(r_7, ParameterVector{A}); - return f; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - // pass_manager.register_pass("before_recurrent_reshapes_elimination.png"); - pass_manager.register_pass(); - // pass_manager.register_pass("after_1_recurrent_reshapes_elimination.png"); - pass_manager.register_pass(); - // pass_manager.register_pass("after_2_recurrent_reshapes_elimination.png"); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - ASSERT_EQ(num_reshapes_optimized, 0); -} - -TEST(reshape_elimination, recurrent_reshapes_fan_out) -{ - Shape shape_a{4, 6, 10, 2}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - Shape shape_r_1{6, 4, 5, 4}; - Shape shape_r_2{24, 20}; - auto reshape_1 = make_shared(A, AxisVector{0, 3, 2, 1}, shape_r_1); - auto reshape_2 = make_shared(reshape_1, AxisVector{0, 1, 2, 3}, shape_r_2); - auto reshape_3 = make_shared(reshape_2, AxisVector{0, 1}, shape_a); - auto f_ = make_shared(NodeVector{reshape_2, reshape_3}, ParameterVector{A}); - return f_; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - // pass_manager.register_pass("before_recurrent_reshapes_fan_out.png"); - pass_manager.register_pass(); - // pass_manager.register_pass("after_recurrent_reshapes_fan_out.png"); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - ASSERT_EQ(num_reshapes_optimized, 2); -} - -TEST(reshape_elimination, recurrent_reshapes_fan_out_at_end) -{ - Shape shape_a{12, 8, 1, 1}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - - auto reshape_1 = make_shared(A, AxisVector{0, 3, 2, 1}, Shape{4, 3, 8, 1}); - auto reshape_2 = make_shared(reshape_1, AxisVector{0, 1, 2, 3}, shape_a); - auto reshape_3 = - make_shared(reshape_2, AxisVector{0, 1, 2, 3}, Shape{4, 3, 8, 1}); - auto abs_1 = make_shared(reshape_3); - auto f_ = make_shared(NodeVector{abs_1, reshape_3}, ParameterVector{A}); - return f_; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - // pass_manager.register_pass("before_recurrent_reshapes_fan_out_at_end.png"); - pass_manager.register_pass(); - // pass_manager.register_pass("after_recurrent_reshapes_fan_out_at_end.png"); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - ASSERT_EQ(num_reshapes_optimized, 1); -} - -TEST(reshape_elimination, recurrent_reshapes_multiple_fusions) -{ - Shape shape_a{2, 2, 3, 3, 2, 4}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - Shape shape_r_1{3, 2, 2, 4, 6}; - Shape shape_r_2{6, 8, 3, 2}; - Shape shape_r_3{6, 8, 6}; - Shape shape_r_4{6, 2, 2, 2, 6}; - Shape shape_r_5{2, 3, 2, 2, 2, 3, 2}; - Shape shape_r_6{48, 6}; - - auto r_1 = make_shared(A, AxisVector{2, 4, 0, 5, 3, 1}, shape_r_1); - auto r_2 = make_shared(r_1, AxisVector{0, 1, 2, 3, 4}, shape_r_2); - auto r_3 = make_shared(r_2, AxisVector{0, 1, 2, 3}, shape_r_3); - auto r_4 = make_shared(r_3, AxisVector{1, 0, 2}, shape_r_4); - auto r_5 = make_shared(r_4, AxisVector{0, 1, 2, 3, 4}, shape_r_5); - auto r_6 = make_shared(r_5, AxisVector{0, 1, 2, 3, 4, 5, 6}, shape_r_6); - - auto f = make_shared(r_6, ParameterVector{A}); - return f; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - // pass_manager.register_pass( - // "before_recurrent_reshapes_multiple_fusions.png"); - pass_manager.register_pass(); - // pass_manager.register_pass( - // "after_recurrent_reshapes_multiple_fusions.png"); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - ASSERT_EQ(num_reshapes_optimized, 2); -} - -TEST(reshape_elimination, nonrecurrent_reshapes) -{ - Shape shape_a{8, 6, 1, 1}; - Shape shape_r{2, 24}; - auto generate_func = [shape_a, shape_r]() { - auto A = make_shared(element::f32, shape_a); - - auto reshape_1 = make_shared(A, AxisVector{3, 0, 2, 1}, shape_r); - auto abs_1 = make_shared(reshape_1); - auto reshape_2 = make_shared(abs_1, AxisVector{0, 1}, shape_a); - auto abs_2 = make_shared(reshape_2); - auto reshape_3 = make_shared(abs_2, AxisVector{0, 1, 2, 3}, shape_a); - auto f_ = make_shared(NodeVector{reshape_3}, ParameterVector{A}); - return f_; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - // pass_manager.register_pass("before_nonrecurrent_reshapes.png"); - pass_manager.register_pass(); - // pass_manager.register_pass("after_nonrecurrent_reshapes.png"); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - ASSERT_EQ(num_reshapes_optimized, 3); -} - -TEST(reshape_elimination, recurrent_reshapes_multiple_branches) -{ - Shape shape_a{2, 2, 3, 3, 2, 4}; - auto generate_func = [shape_a]() { - auto A = make_shared(element::f32, shape_a); - Shape shape_r_1{3, 2, 2, 4, 6}; - Shape shape_r_2{6, 8, 3, 2}; - Shape shape_r_3{6, 8, 6}; - Shape shape_r_4{6, 2, 2, 2, 6}; - Shape shape_r_5{2, 3, 2, 2, 2, 3, 2}; - Shape shape_r_6{48, 6}; - - auto r_1 = make_shared(A, AxisVector{2, 4, 0, 5, 3, 1}, shape_r_1); - auto r_2 = make_shared(r_1, AxisVector{0, 1, 2, 3, 4}, shape_r_2); - auto r_3 = make_shared(r_2, AxisVector{0, 1, 2, 3}, shape_r_3); - auto r_4 = make_shared(r_3, AxisVector{0, 1, 2}, shape_r_4); - auto r_5 = make_shared(r_4, AxisVector{0, 1, 2, 3, 4}, shape_r_5); - auto r_6 = make_shared(r_5, AxisVector{0, 1, 2, 3, 4, 5, 6}, shape_r_6); - - auto r_7 = make_shared(A, AxisVector{2, 4, 0, 5, 3, 1}, shape_r_2); - auto r_8 = make_shared(r_7, AxisVector{0, 1, 2, 3}, shape_r_3); - - auto f = make_shared(NodeVector{r_6, r_8}, ParameterVector{A}); - return f; - }; - - auto baseline_f = generate_func(); - auto optimized_f = generate_func(); - auto baseline_input_shape = baseline_f->get_parameters().at(0)->get_shape(); - - pass::Manager pass_manager; - // pass_manager.register_pass( - // "before_recurrent_reshapes_multiple_branches.png"); - pass_manager.register_pass(); - // pass_manager.register_pass( - // "after_recurrent_reshapes_multiple_branches.png"); - pass_manager.run_passes(optimized_f); - - test::Uniform rng(0.0f, 100.0f); - vector> args; - vector tensor_val(shape_size(baseline_input_shape)); - rng.initialize(tensor_val); - args.push_back(tensor_val); - - auto baseline_results = execute(baseline_f, args, "INTERPRETER"); - auto optimized_results = execute(optimized_f, args, "INTERPRETER"); - - EXPECT_TRUE(test::all_close(baseline_results.at(0), optimized_results.at(0))); - - size_t num_reshapes_optimized = count_ops_of_type(optimized_f); - ASSERT_EQ(num_reshapes_optimized, 2); -} -#endif - -TEST(reshape_elimination, pass_property) -{ - { - auto pass = std::make_shared(); - ASSERT_FALSE(pass->get_property(pass::PassProperty::REQUIRE_STATIC_SHAPE)); - ASSERT_FALSE(pass->get_property(pass::PassProperty::CHANGE_DYNAMIC_STATE)); - } - { - auto pass = std::make_shared(); - ASSERT_FALSE(pass->get_property(pass::PassProperty::REQUIRE_STATIC_SHAPE)); - ASSERT_FALSE(pass->get_property(pass::PassProperty::CHANGE_DYNAMIC_STATE)); - } -} diff --git a/ngraph/test/reshape_sinking.cpp b/ngraph/test/reshape_sinking.cpp deleted file mode 100644 index 57928c8cfd9..00000000000 --- a/ngraph/test/reshape_sinking.cpp +++ /dev/null @@ -1,184 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include -#include -#include -#include -#include - -#include "gtest/gtest.h" -#include "ngraph/file_util.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/ngraph.hpp" -#include "ngraph/op/batch_norm.hpp" -#include "ngraph/op/get_output_element.hpp" -#include "ngraph/op/parameter.hpp" -#include "ngraph/pass/core_fusion.hpp" -#include "ngraph/pass/cse.hpp" -#include "ngraph/pass/manager.hpp" -#include "ngraph/pass/reshape_elimination.hpp" -#include "ngraph/pass/reshape_sinking.hpp" -#include "ngraph/pass/visualize_tree.hpp" -#include "ngraph/serializer.hpp" -#include "ngraph/util.hpp" -#include "util/all_close.hpp" -#include "util/ndarray.hpp" -#include "util/random.hpp" -#include "util/test_tools.hpp" - -using namespace ngraph; -using namespace std; - -TEST(reshape_sinking, edge_splitting) -{ - // checks if Reshapes are pushed through op::Abs, but stopped by Sum - Shape shape_nhwc{16, 28, 28, 1}; - Shape shape_nchw{16, 1, 28, 28}; - auto a = make_shared(element::i32, shape_nhwc); - auto reshape = make_shared(a, AxisVector{0, 3, 1, 2}, shape_nchw); - auto absn = make_shared(reshape); - auto absn2 = make_shared(absn); - auto sum = make_shared(reshape, AxisSet{0, 1, 2, 3}); - auto func = make_shared(NodeVector{absn2, sum}, ParameterVector{a}); - pass::Manager pass_manager; - // size_t before_count = count_ops_of_type(func); - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.run_passes(func); - ASSERT_EQ(func->get_results().at(1)->input_value(0).get_node_shared_ptr(), sum); - auto new_reshape = - as_type_ptr(func->get_results().at(0)->input_value(0).get_node_shared_ptr()); - ASSERT_TRUE(new_reshape); - ASSERT_EQ(new_reshape->get_shape(), shape_nchw); -} - -TEST(reshape_sinking, broadcast_swimming) -{ - Shape shape_nchw{1, 32, 536, 536}; - Shape shape_nhwc{1, 536, 536, 32}; - Shape shape_weights{16, 32, 3, 3}; - Shape conv_nhwc{1, 534, 534, 16}; - Shape conv_nchw{1, 16, 534, 534}; - AxisVector to_nhwc{0, 2, 3, 1}; - AxisVector to_nchw{0, 3, 1, 2}; - - size_t channel = 16; - auto bias = make_shared(element::i32, Shape{channel}); - auto bias_reshape = make_shared(bias, AxisVector{0}, Shape{1, channel}); - auto bias_broadcast = make_shared(bias_reshape, conv_nhwc, AxisSet{1, 2}); - - auto input = make_shared(element::i32, shape_nhwc); - auto reshape_input = make_shared(input, to_nchw, shape_nchw); - - auto weights = make_shared(element::i32, shape_weights); - auto conv = make_shared(reshape_input, weights); - auto conv_reshape = make_shared(conv, to_nhwc, conv_nhwc); - auto add = bias_broadcast + conv_reshape; - auto relu = make_shared(add); - - auto func = make_shared(NodeVector{relu}, ParameterVector{bias, input, weights}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.run_passes(func); - - ASSERT_EQ(add->get_shape(), conv_nchw); - ASSERT_EQ(add->get_input_shape(0), conv_nchw); - ASSERT_EQ(add->input_value(1).get_node_shared_ptr(), conv); -} - -TEST(reshape_sinking, concat) -{ - Shape shape{}; - Shape shape_w{1, 1, 1, 1}; - Shape shape_x{1, 3, 3, 1}; - Shape shape_b{1, 3, 3, 1}; - Shape r_shape{1, 3, 3, 2}; - - auto B_ = op::Constant::create(element::f32, shape_w, {3}); - auto B = make_shared(B_, AxisVector{3, 2, 0, 1}, Shape{1, 1, 1, 1}); /* nchw */ - auto A_ = make_shared(element::f32, shape_x); - auto A = make_shared(A_, AxisVector{0, 3, 1, 2}, Shape{1, 1, 3, 3}); /* nchw */ - auto C = op::Constant::create(element::f32, Shape{1}, {2}); - auto R = make_shared(element::f32, r_shape); - - auto conv = make_shared(A, - B, - Strides{1, 1}, - Strides{1, 1}, - CoordinateDiff{0, 0}, - CoordinateDiff{0, 0}, - Strides{1, 1}); - auto reshape_conv = - make_shared(conv, AxisVector{0, 2, 3, 1}, Shape{1, 3, 3, 1}); /* nhwc */ - auto broadcast = make_shared(C, reshape_conv->get_shape(), AxisSet{0, 1, 2}); - auto add = broadcast + reshape_conv; - - auto B1_ = op::Constant::create(element::f32, shape_w, {3}); - auto B1 = make_shared(B1_, AxisVector{3, 2, 0, 1}, Shape{1, 1, 1, 1}); - auto A1_ = make_shared(element::f32, shape_x); - auto A1 = make_shared(A1_, AxisVector{0, 3, 1, 2}, Shape{1, 1, 3, 3}); - auto C1 = op::Constant::create(element::f32, Shape{1}, {2}); - auto R1 = make_shared(element::f32, r_shape); - - auto conv1 = make_shared(A1, - B1, - Strides{1, 1}, - Strides{1, 1}, - CoordinateDiff{0, 0}, - CoordinateDiff{0, 0}, - Strides{1, 1}); - auto reshape_conv1 = make_shared(conv1, AxisVector{0, 2, 3, 1}, Shape{1, 3, 3, 1}); - auto broadcast1 = make_shared(C1, reshape_conv->get_shape(), AxisSet{0, 1, 2}); - auto add1 = broadcast1 + reshape_conv1; - - auto concat = make_shared(NodeVector{add, add1}, 3); - auto relu = make_shared(concat); - auto reshape_relu = - make_shared(relu, AxisVector{0, 3, 1, 2}, Shape{1, 2, 3, 3}); /* nchw */ - auto B2_ = op::Constant::create(element::f32, Shape{1, 1, 2, 1}, {2}); - auto B2 = make_shared(B2_, AxisVector{3, 2, 0, 1}, Shape{1, 2, 1, 1}); - auto conv2 = make_shared(reshape_relu, - B2, - Strides{1, 1}, - Strides{1, 1}, - CoordinateDiff{0, 0}, - CoordinateDiff{0, 0}, - Strides{1, 1}); - auto reshape_conv2 = - make_shared(conv2, AxisVector{0, 2, 3, 1}, Shape{1, 3, 3, 1}); /* nhwc */ - auto f = make_shared(reshape_conv2, ParameterVector{A_, A1_}); - pass::Manager pass_manager; - size_t before_count = count_ops_of_type(f); - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.register_pass(); - pass_manager.run_passes(f); - size_t before_after = count_ops_of_type(f); - ASSERT_LE(before_after, before_count); -} - -TEST(reshape_sinking, pass_property) -{ - auto pass = std::make_shared(); - ASSERT_TRUE(pass->get_property(pass::PassProperty::REQUIRE_STATIC_SHAPE)); - ASSERT_FALSE(pass->get_property(pass::PassProperty::CHANGE_DYNAMIC_STATE)); -} diff --git a/ngraph/test/runtime/CMakeLists.txt b/ngraph/test/runtime/CMakeLists.txt index 71e45a117ae..03cb43d30c1 100644 --- a/ngraph/test/runtime/CMakeLists.txt +++ b/ngraph/test/runtime/CMakeLists.txt @@ -33,6 +33,18 @@ set (SRC dynamic/dynamic_backend.hpp op/avg_pool.cpp op/avg_pool.hpp + pass/dyn_elimination.cpp + pass/dyn_elimination.hpp + pass/fused_op_decomposition.cpp + pass/fused_op_decomposition.hpp + pass/implicit_broadcast_elimination.cpp + pass/implicit_broadcast_elimination.hpp + pass/like_replacement.cpp + pass/like_replacement.hpp + pass/liveness.cpp + pass/liveness.hpp + pass/shape_relevance.cpp + pass/shape_relevance.hpp ) add_library(ngraph_backend SHARED ${SRC}) diff --git a/ngraph/test/runtime/dynamic/dynamic_backend.cpp b/ngraph/test/runtime/dynamic/dynamic_backend.cpp index 7941b48db8c..85edda65a02 100644 --- a/ngraph/test/runtime/dynamic/dynamic_backend.cpp +++ b/ngraph/test/runtime/dynamic/dynamic_backend.cpp @@ -23,13 +23,13 @@ #include "ngraph/op/reshape.hpp" #include "ngraph/op/transpose.hpp" #include "ngraph/pass/constant_folding.hpp" -#include "ngraph/pass/dyn_elimination.hpp" #include "ngraph/pass/manager.hpp" -#include "ngraph/pass/shape_relevance.hpp" #include "ngraph/specialize_function.hpp" #include "ngraph/util.hpp" #include "opset0_downgrade.hpp" #include "opset1_downgrade.hpp" +#include "pass/dyn_elimination.hpp" +#include "pass/shape_relevance.hpp" using namespace std; using namespace ngraph; diff --git a/ngraph/test/runtime/interpreter/int_executable.cpp b/ngraph/test/runtime/interpreter/int_executable.cpp index 457a55bf381..b363a42e076 100644 --- a/ngraph/test/runtime/interpreter/int_executable.cpp +++ b/ngraph/test/runtime/interpreter/int_executable.cpp @@ -22,16 +22,14 @@ #include "ngraph/except.hpp" #include "ngraph/op/util/op_types.hpp" #include "ngraph/ops.hpp" -#include "ngraph/pass/assign_layout.hpp" -#include "ngraph/pass/core_fusion.hpp" -#include "ngraph/pass/fused_op_decomposition.hpp" -#include "ngraph/pass/like_replacement.hpp" -#include "ngraph/pass/liveness.hpp" #include "ngraph/pass/manager.hpp" #include "ngraph/serializer.hpp" #include "ngraph/util.hpp" #include "opset0_downgrade.hpp" #include "opset1_downgrade.hpp" +#include "pass/fused_op_decomposition.hpp" +#include "pass/like_replacement.hpp" +#include "pass/liveness.hpp" using namespace std; using namespace ngraph; diff --git a/ngraph/test/runtime/opset0_downgrade.cpp b/ngraph/test/runtime/opset0_downgrade.cpp index 76e3bfed9cc..18fc7786e47 100644 --- a/ngraph/test/runtime/opset0_downgrade.cpp +++ b/ngraph/test/runtime/opset0_downgrade.cpp @@ -26,13 +26,13 @@ #include "ngraph/op/util/attr_types.hpp" #include "ngraph/op/util/op_types.hpp" #include "ngraph/ops.hpp" -#include "ngraph/pass/implicit_broadcast_elimination.hpp" #include "ngraph/provenance.hpp" #include "ngraph/slice_plan.hpp" #include "ngraph/type.hpp" #include "ngraph/validation_util.hpp" #include "op/avg_pool.hpp" #include "opset0_downgrade.hpp" +#include "pass/implicit_broadcast_elimination.hpp" using namespace std; using namespace ngraph; diff --git a/ngraph/src/ngraph/pass/dyn_elimination.cpp b/ngraph/test/runtime/pass/dyn_elimination.cpp similarity index 100% rename from ngraph/src/ngraph/pass/dyn_elimination.cpp rename to ngraph/test/runtime/pass/dyn_elimination.cpp diff --git a/ngraph/src/ngraph/pass/dyn_elimination.hpp b/ngraph/test/runtime/pass/dyn_elimination.hpp similarity index 96% rename from ngraph/src/ngraph/pass/dyn_elimination.hpp rename to ngraph/test/runtime/pass/dyn_elimination.hpp index 10811489ec2..62aa0ac64ac 100644 --- a/ngraph/src/ngraph/pass/dyn_elimination.hpp +++ b/ngraph/test/runtime/pass/dyn_elimination.hpp @@ -16,6 +16,7 @@ #pragma once +#include "backend_visibility.hpp" #include "ngraph/pass/graph_rewrite.hpp" #include "ngraph/util.hpp" @@ -50,7 +51,7 @@ namespace ngraph /// /// ///
opinfluence
" << exop->get_name() << "" << weight << "
\image html dyn_broadcast_post_dyneliminate.svg
- class NGRAPH_API DynElimination : public GraphRewrite + class BACKEND_API DynElimination : public GraphRewrite { public: DynElimination(); diff --git a/ngraph/src/ngraph/pass/fused_op_decomposition.cpp b/ngraph/test/runtime/pass/fused_op_decomposition.cpp similarity index 98% rename from ngraph/src/ngraph/pass/fused_op_decomposition.cpp rename to ngraph/test/runtime/pass/fused_op_decomposition.cpp index f42d42420be..b98d1828bfb 100644 --- a/ngraph/src/ngraph/pass/fused_op_decomposition.cpp +++ b/ngraph/test/runtime/pass/fused_op_decomposition.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. //***************************************************************************** -#include "ngraph/pass/fused_op_decomposition.hpp" +#include "fused_op_decomposition.hpp" #include "ngraph/graph_util.hpp" #include "ngraph/op/get_output_element.hpp" #include "ngraph/op/util/op_types.hpp" diff --git a/ngraph/src/ngraph/pass/fused_op_decomposition.hpp b/ngraph/test/runtime/pass/fused_op_decomposition.hpp similarity index 97% rename from ngraph/src/ngraph/pass/fused_op_decomposition.hpp rename to ngraph/test/runtime/pass/fused_op_decomposition.hpp index 1dae4937518..e8ab6caa8e6 100644 --- a/ngraph/src/ngraph/pass/fused_op_decomposition.hpp +++ b/ngraph/test/runtime/pass/fused_op_decomposition.hpp @@ -18,6 +18,7 @@ #include +#include "backend_visibility.hpp" #include "ngraph/op/util/fused_op.hpp" #include "ngraph/pass/pass.hpp" @@ -50,7 +51,7 @@ namespace ngraph /// \image html decompose_gelu_post.svg /// /// - class NGRAPH_API FusedOpDecomposition : public NodePass + class BACKEND_API FusedOpDecomposition : public NodePass { public: /// \brief Function signature type for callback used to check whether provided node diff --git a/ngraph/src/ngraph/pass/implicit_broadcast_elimination.cpp b/ngraph/test/runtime/pass/implicit_broadcast_elimination.cpp similarity index 97% rename from ngraph/src/ngraph/pass/implicit_broadcast_elimination.cpp rename to ngraph/test/runtime/pass/implicit_broadcast_elimination.cpp index 05324ae8ed5..676fcdc5b97 100644 --- a/ngraph/src/ngraph/pass/implicit_broadcast_elimination.cpp +++ b/ngraph/test/runtime/pass/implicit_broadcast_elimination.cpp @@ -14,7 +14,7 @@ // limitations under the License. //***************************************************************************** -#include "ngraph/pass/implicit_broadcast_elimination.hpp" +#include "implicit_broadcast_elimination.hpp" #include "ngraph/builder/autobroadcast.hpp" #include "ngraph/graph_util.hpp" diff --git a/ngraph/src/ngraph/pass/implicit_broadcast_elimination.hpp b/ngraph/test/runtime/pass/implicit_broadcast_elimination.hpp similarity index 89% rename from ngraph/src/ngraph/pass/implicit_broadcast_elimination.hpp rename to ngraph/test/runtime/pass/implicit_broadcast_elimination.hpp index 26dac25366b..7c526e9c7b6 100644 --- a/ngraph/src/ngraph/pass/implicit_broadcast_elimination.hpp +++ b/ngraph/test/runtime/pass/implicit_broadcast_elimination.hpp @@ -16,6 +16,7 @@ #pragma once +#include "backend_visibility.hpp" #include "ngraph/node.hpp" #include "ngraph/pass/pass.hpp" @@ -28,7 +29,7 @@ namespace ngraph } } -class NGRAPH_API ngraph::pass::ImplicitBroadcastElimination : public ngraph::pass::NodePass +class BACKEND_API ngraph::pass::ImplicitBroadcastElimination : public ngraph::pass::NodePass { public: bool run_on_node(std::shared_ptr node) override; diff --git a/ngraph/src/ngraph/pass/like_replacement.cpp b/ngraph/test/runtime/pass/like_replacement.cpp similarity index 100% rename from ngraph/src/ngraph/pass/like_replacement.cpp rename to ngraph/test/runtime/pass/like_replacement.cpp diff --git a/ngraph/src/ngraph/pass/like_replacement.hpp b/ngraph/test/runtime/pass/like_replacement.hpp similarity index 90% rename from ngraph/src/ngraph/pass/like_replacement.hpp rename to ngraph/test/runtime/pass/like_replacement.hpp index a8e83cf8cbb..01656ee6783 100644 --- a/ngraph/src/ngraph/pass/like_replacement.hpp +++ b/ngraph/test/runtime/pass/like_replacement.hpp @@ -16,13 +16,14 @@ #pragma once +#include "backend_visibility.hpp" #include "ngraph/pass/pass.hpp" namespace ngraph { namespace pass { - class NGRAPH_API LikeReplacement : public FunctionPass + class BACKEND_API LikeReplacement : public FunctionPass { public: bool run_on_function(std::shared_ptr function) override; diff --git a/ngraph/src/ngraph/pass/liveness.cpp b/ngraph/test/runtime/pass/liveness.cpp similarity index 99% rename from ngraph/src/ngraph/pass/liveness.cpp rename to ngraph/test/runtime/pass/liveness.cpp index 4db5b156cc3..238046e5553 100644 --- a/ngraph/src/ngraph/pass/liveness.cpp +++ b/ngraph/test/runtime/pass/liveness.cpp @@ -18,6 +18,7 @@ #include #include +#include "liveness.hpp" #include "ngraph/descriptor/input.hpp" #include "ngraph/descriptor/output.hpp" #include "ngraph/function.hpp" @@ -27,7 +28,6 @@ #include "ngraph/op/constant.hpp" #include "ngraph/op/parameter.hpp" #include "ngraph/op/result.hpp" -#include "ngraph/pass/liveness.hpp" #include "ngraph/util.hpp" using namespace std; diff --git a/ngraph/src/ngraph/pass/liveness.hpp b/ngraph/test/runtime/pass/liveness.hpp similarity index 91% rename from ngraph/src/ngraph/pass/liveness.hpp rename to ngraph/test/runtime/pass/liveness.hpp index 8c214dea32f..7355e712c6c 100644 --- a/ngraph/src/ngraph/pass/liveness.hpp +++ b/ngraph/test/runtime/pass/liveness.hpp @@ -16,6 +16,7 @@ #pragma once +#include "backend_visibility.hpp" #include "ngraph/descriptor/tensor.hpp" #include "ngraph/pass/pass.hpp" @@ -27,7 +28,7 @@ namespace ngraph } } -class NGRAPH_API ngraph::pass::Liveness : public FunctionPass +class BACKEND_API ngraph::pass::Liveness : public FunctionPass { public: bool run_on_function(std::shared_ptr) override; diff --git a/ngraph/src/ngraph/pass/shape_relevance.cpp b/ngraph/test/runtime/pass/shape_relevance.cpp similarity index 98% rename from ngraph/src/ngraph/pass/shape_relevance.cpp rename to ngraph/test/runtime/pass/shape_relevance.cpp index 19f2cc007e3..e9d6786af63 100644 --- a/ngraph/src/ngraph/pass/shape_relevance.cpp +++ b/ngraph/test/runtime/pass/shape_relevance.cpp @@ -14,7 +14,7 @@ // limitations under the License. //***************************************************************************** -#include "ngraph/pass/shape_relevance.hpp" +#include "pass/shape_relevance.hpp" #include "ngraph/graph_util.hpp" #include "ngraph/op/constant.hpp" #include "ngraph/op/util/op_types.hpp" diff --git a/ngraph/src/ngraph/pass/shape_relevance.hpp b/ngraph/test/runtime/pass/shape_relevance.hpp similarity index 91% rename from ngraph/src/ngraph/pass/shape_relevance.hpp rename to ngraph/test/runtime/pass/shape_relevance.hpp index b5f0481e8af..e9ff9016d25 100644 --- a/ngraph/src/ngraph/pass/shape_relevance.hpp +++ b/ngraph/test/runtime/pass/shape_relevance.hpp @@ -16,13 +16,14 @@ #pragma once +#include "backend_visibility.hpp" #include "ngraph/pass/pass.hpp" namespace ngraph { namespace pass { - class NGRAPH_API ShapeRelevance : public FunctionPass + class BACKEND_API ShapeRelevance : public FunctionPass { public: ShapeRelevance() diff --git a/ngraph/test/tensor.cpp b/ngraph/test/tensor.cpp index b98b7a570fd..0cc9b758ac2 100644 --- a/ngraph/test/tensor.cpp +++ b/ngraph/test/tensor.cpp @@ -23,8 +23,8 @@ #include "gtest/gtest.h" #include "ngraph/function.hpp" #include "ngraph/ngraph.hpp" -#include "ngraph/pass/liveness.hpp" #include "ngraph/pass/manager.hpp" +#include "pass/liveness.hpp" #include "util/test_tools.hpp" using namespace std; diff --git a/ngraph/test/zero_dim_tensor_elimination.cpp b/ngraph/test/zero_dim_tensor_elimination.cpp deleted file mode 100644 index 4ddcb4fb0ea..00000000000 --- a/ngraph/test/zero_dim_tensor_elimination.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//***************************************************************************** -// Copyright 2017-2020 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//***************************************************************************** - -#include - -#include "gtest/gtest.h" -#include "ngraph/file_util.hpp" -#include "ngraph/graph_util.hpp" -#include "ngraph/log.hpp" -#include "ngraph/ngraph.hpp" -#include "ngraph/op/add.hpp" -#include "ngraph/op/constant.hpp" -#include "ngraph/op/divide.hpp" -#include "ngraph/op/multiply.hpp" -#include "ngraph/op/product.hpp" -#include "ngraph/op/sqrt.hpp" -#include "ngraph/op/subtract.hpp" -#include "ngraph/op/sum.hpp" -#include "ngraph/pass/manager.hpp" -#include "ngraph/pass/visualize_tree.hpp" -#include "ngraph/pass/zero_dim_tensor_elimination.hpp" -#include "util/test_tools.hpp" - -using namespace ngraph; -using namespace std; - -TEST(zero_dim_tensor_elimination, zero_sum) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto abs_node = std::make_shared(A); - auto sum_node = std::make_shared(abs_node, AxisSet{0}); - auto constant = std::make_shared(element::i32, zero_shape, std::vector{}); - auto f = std::make_shared(NodeVector{sum_node, constant}, ParameterVector{A}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - EXPECT_EQ(count_ops_of_type(f), 1); - pass_manager.run_passes(f); - EXPECT_EQ(count_ops_of_type(f), 0); -} - -TEST(zero_dim_tensor_elimination, zero_product) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto abs_node = std::make_shared(A); - auto product_node = std::make_shared(abs_node, AxisSet{0}); - auto constant = std::make_shared(element::i32, zero_shape, std::vector{}); - auto f = std::make_shared(NodeVector{product_node, constant}, ParameterVector{A}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - EXPECT_EQ(count_ops_of_type(f), 1); - pass_manager.run_passes(f); - EXPECT_EQ(count_ops_of_type(f), 0); -} - -TEST(zero_dim_tensor_elimination, zero_min) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto abs_node = std::make_shared(A); - auto min_node = std::make_shared(abs_node, AxisSet{0}); - auto constant = std::make_shared(element::i32, zero_shape, std::vector{}); - auto f = std::make_shared(NodeVector{min_node, constant}, ParameterVector{A}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - EXPECT_EQ(count_ops_of_type(f), 1); - pass_manager.run_passes(f); - EXPECT_EQ(count_ops_of_type(f), 0); -} - -TEST(zero_dim_tensor_elimination, zero_max) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::i32, zero_shape); - auto abs_node = std::make_shared(A); - auto max_node = std::make_shared(abs_node, AxisSet{0}); - auto constant = std::make_shared(element::i32, zero_shape, std::vector{}); - auto f = std::make_shared(NodeVector{max_node, constant}, ParameterVector{A}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - EXPECT_EQ(count_ops_of_type(f), 1); - pass_manager.run_passes(f); - EXPECT_EQ(count_ops_of_type(f), 0); -} - -TEST(zero_dim_tensor_elimination, zero_const_conv) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::f32, Shape{1, 1, 0}); - auto weights = std::make_shared(element::f32, Shape{1, 1, 4}); - auto convolution = std::make_shared( - A, weights, Strides{1}, Strides{1}, CoordinateDiff{2}, CoordinateDiff{2}); - auto abs_node = std::make_shared(convolution); - auto constant = std::make_shared(element::i32, zero_shape, std::vector{}); - auto f = - std::make_shared(NodeVector{abs_node, constant}, ParameterVector{A, weights}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - EXPECT_EQ(count_ops_of_type(f), 1); - pass_manager.run_passes(f); - EXPECT_EQ(count_ops_of_type(f), 0); -} - -TEST(zero_dim_tensor_elimination, zero_const_pad) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::f32, zero_shape); - auto B = std::make_shared(element::f32, Shape{}); - - auto pad = std::make_shared(A, B, CoordinateDiff{2}, CoordinateDiff{2}); - auto abs_node = std::make_shared(pad); - auto constant = std::make_shared(element::i32, zero_shape, std::vector{}); - auto f = std::make_shared(NodeVector{abs_node, constant}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - EXPECT_EQ(count_ops_of_type(f), 0); - pass_manager.run_passes(f); - EXPECT_EQ(count_ops_of_type(f), 1); -} - -TEST(zero_dim_tensor_elimination, zero_const_slice) -{ - Shape zero_shape{0}; - auto A = std::make_shared(element::f32, zero_shape); - auto B = std::make_shared(element::f32, Shape{}); - auto slice = make_shared(A, Coordinate{0}, Coordinate{0}); - auto pad = std::make_shared(A, B, CoordinateDiff{2}, CoordinateDiff{2}); - auto abs_node = std::make_shared(pad); - auto constant = std::make_shared(element::i32, zero_shape, std::vector{}); - auto f = std::make_shared(NodeVector{abs_node, constant}, ParameterVector{A, B}); - pass::Manager pass_manager; - - pass_manager.register_pass(); - EXPECT_EQ(count_ops_of_type(f), 0); - EXPECT_EQ(count_ops_of_type(f), 0); - pass_manager.run_passes(f); - EXPECT_EQ(count_ops_of_type(f), 1); - EXPECT_EQ(count_ops_of_type(f), 0); -} - -TEST(zero_dim_tensor_elimination, pass_property) -{ - auto pass = std::make_shared(); - ASSERT_TRUE(pass->get_property(pass::PassProperty::REQUIRE_STATIC_SHAPE)); - ASSERT_FALSE(pass->get_property(pass::PassProperty::CHANGE_DYNAMIC_STATE)); -}