From 0a59be6f1ec0d2d3f186121f94f2338d346e2d8f Mon Sep 17 00:00:00 2001 From: iliya mironov Date: Fri, 23 Oct 2020 12:35:56 +0300 Subject: [PATCH] Transformations for hsigmoid op (#2531) * Add hsigmoid op * Add tests for hsigmoid * Add fusion hsigmoid * Add unit tests for fuse hsigmoid * Add python api for hsigmoid. Update opset 5 * Update opset5 file * Add hsigmoid decomposition transformation * fix * Move transformations for hsigmoid * Hot fix * Fix unit tests * fix unit tests * Fix unit test * Fix code style * Reverse changes * Add includes for hsigmoid transformations * Enable in cldnn * Refactoring hsigmoid fusion * Move hsigmoid transforms patterns to cpp file * Reverse hsigmoid fusion refactoring * Fix according to code review * Refactoring transformation * Hot fix --- inference-engine/src/cldnn_engine/cldnn_engine.cpp | 2 + .../common_optimizations/hsigmoid_fusion.hpp | 79 +++++ .../op_conversions/hsigmoid_decomposition.hpp | 26 ++ .../common_optimizations/common_optimizations.cpp | 4 + .../common_optimizations/hsigmoid_fusion.cpp | 198 +++++++++++++ .../op_conversions/hsigmoid_decomposition.cpp | 44 +++ .../hsigmoid_decomposition_test.cpp | 50 ++++ .../transformations/hsigmoid_fusion_test.cpp | 328 +++++++++++++++++++++ ngraph/core/include/ngraph/op/hsigmoid.hpp | 2 +- ngraph/python/src/ngraph/__init__.py | 1 + ngraph/python/src/ngraph/opset5/__init__.py | 1 + ngraph/python/src/ngraph/opset5/ops.py | 10 + ngraph/python/tests/test_ngraph/test_ops_unary.py | 11 + ngraph/test/CMakeLists.txt | 1 + ngraph/test/type_prop/hsigmoid.cpp | 54 ++++ 15 files changed, 810 insertions(+), 1 deletion(-) create mode 100644 inference-engine/src/transformations/include/transformations/common_optimizations/hsigmoid_fusion.hpp create mode 100644 inference-engine/src/transformations/include/transformations/op_conversions/hsigmoid_decomposition.hpp create mode 100644 inference-engine/src/transformations/src/transformations/common_optimizations/hsigmoid_fusion.cpp create mode 100644 inference-engine/src/transformations/src/transformations/op_conversions/hsigmoid_decomposition.cpp create mode 100644 inference-engine/tests/functional/inference_engine/transformations/hsigmoid_decomposition_test.cpp create mode 100644 inference-engine/tests/functional/inference_engine/transformations/hsigmoid_fusion_test.cpp create mode 100644 ngraph/test/type_prop/hsigmoid.cpp diff --git a/inference-engine/src/cldnn_engine/cldnn_engine.cpp b/inference-engine/src/cldnn_engine/cldnn_engine.cpp index db16779..e99d24b 100644 --- a/inference-engine/src/cldnn_engine/cldnn_engine.cpp +++ b/inference-engine/src/cldnn_engine/cldnn_engine.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +118,7 @@ InferenceEngine::ICNNNetwork::Ptr clDNNEngine::CloneAndTransformNetwork(const In std::dynamic_pointer_cast(node) || std::dynamic_pointer_cast(node) || std::dynamic_pointer_cast(node) || + std::dynamic_pointer_cast(node) || std::dynamic_pointer_cast(node) || std::dynamic_pointer_cast(node) || std::dynamic_pointer_cast(node) || diff --git a/inference-engine/src/transformations/include/transformations/common_optimizations/hsigmoid_fusion.hpp b/inference-engine/src/transformations/include/transformations/common_optimizations/hsigmoid_fusion.hpp new file mode 100644 index 0000000..bfadc78 --- /dev/null +++ b/inference-engine/src/transformations/include/transformations/common_optimizations/hsigmoid_fusion.hpp @@ -0,0 +1,79 @@ +// Copyright (C) 2018-2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +#include +#include + +namespace ngraph { +namespace pass { + +class TRANSFORMATIONS_API HSigmoidFusion; +class TRANSFORMATIONS_API HSigmoidFusionWithReluDiv; +class TRANSFORMATIONS_API HSigmoidFusionWithReluMul; +class TRANSFORMATIONS_API HSigmoidFusionWithoutRelu; +class TRANSFORMATIONS_API HSigmoidFusionWithClamp; + + +} // namespace pass +} // namespace ngraph + +/** + * @ingroup ie_transformation_common_api + * @brief HSigmoidFusion transformation replaces various sub-graphs with a HSigmoid op. + */ +class ngraph::pass::HSigmoidFusion: public ngraph::pass::GraphRewrite { +public: + NGRAPH_RTTI_DECLARATION; + HSigmoidFusion() { + add_matcher(); + add_matcher(); + add_matcher(); + add_matcher(); + } +}; + +/** + * @ingroup ie_transformation_common_api + * @brief HSigmoidFusion transformation replaces a sub-graph (x * (min(Relu(x + 3), 6))) / 6 with a HSigmoid op. + */ +class ngraph::pass::HSigmoidFusionWithReluDiv: public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + HSigmoidFusionWithReluDiv(); +}; + +/** + * @ingroup ie_transformation_common_api + * @brief HSigmoidFusion transformation replaces a sub-graph (x * (min(Relu(x + 3), 6)) * const(1/6) with a HSigmoid op. + */ +class ngraph::pass::HSigmoidFusionWithReluMul: public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + HSigmoidFusionWithReluMul(); +}; + +/** + * @ingroup ie_transformation_common_api + * @brief HSigmoidFusion transformation replaces a sub-graph x * (min(max(x + 3, 0), 6) / 6) with a HSigmoid op. + */ +class ngraph::pass::HSigmoidFusionWithoutRelu: public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + HSigmoidFusionWithoutRelu(); +}; + +/** + * @ingroup ie_transformation_common_api + * @brief HSigmoidFusion transformation replaces a sub-graph x * (Clamp(x + 3, 0, 6) * const(1/6)) with a HSigmoid op. + */ +class ngraph::pass::HSigmoidFusionWithClamp: public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + HSigmoidFusionWithClamp(); +}; diff --git a/inference-engine/src/transformations/include/transformations/op_conversions/hsigmoid_decomposition.hpp b/inference-engine/src/transformations/include/transformations/op_conversions/hsigmoid_decomposition.hpp new file mode 100644 index 0000000..c03eadd --- /dev/null +++ b/inference-engine/src/transformations/include/transformations/op_conversions/hsigmoid_decomposition.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2018-2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include + +namespace ngraph { +namespace pass { + +class TRANSFORMATIONS_API HSigmoidDecomposition; + +} // namespace pass +} // namespace ngraph + +/** + * @ingroup ie_transformation_common_api + * @brief HSigmoidDecomposition transformation into sub-graph (min(Relu(x + 3), 6) * const(1/6). + */ +class ngraph::pass::HSigmoidDecomposition: public ngraph::pass::MatcherPass { +public: + NGRAPH_RTTI_DECLARATION; + HSigmoidDecomposition(); +}; diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp index 7f2a835..ecce914 100644 --- a/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp @@ -22,6 +22,7 @@ #include "transformations/common_optimizations/pull_transpose_through_fq.hpp" #include "transformations/common_optimizations/lin_op_sequence_fusion.hpp" #include "transformations/common_optimizations/remove_filtering_boxes_by_size.hpp" +#include "transformations/common_optimizations/hsigmoid_fusion.hpp" #include "transformations/common_optimizations/hswish_fusion.hpp" #include "transformations/common_optimizations/convert_quantize_dequantize.hpp" #include "transformations/op_conversions/bidirectional_sequences_decomposition.hpp" @@ -41,6 +42,7 @@ #include "transformations/op_conversions/reduce_l1_decomposition.hpp" #include "transformations/op_conversions/reduce_l2_decomposition.hpp" #include "transformations/op_conversions/hswish_decomposition.hpp" +#include "transformations/op_conversions/hsigmoid_decomposition.hpp" #include "transformations/op_conversions/log_softmax_decomposition.hpp" #include @@ -68,6 +70,7 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr(); manager.register_pass(); manager.register_pass(); + manager.register_pass(); manager.register_pass(); manager.register_pass(); manager.register_pass(); @@ -78,6 +81,7 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr(); decomp->add_matcher(); decomp->add_matcher(); + decomp->add_matcher(); decomp->add_matcher(); decomp->add_matcher(); decomp->add_matcher(); diff --git a/inference-engine/src/transformations/src/transformations/common_optimizations/hsigmoid_fusion.cpp b/inference-engine/src/transformations/src/transformations/common_optimizations/hsigmoid_fusion.cpp new file mode 100644 index 0000000..f19c91e --- /dev/null +++ b/inference-engine/src/transformations/src/transformations/common_optimizations/hsigmoid_fusion.cpp @@ -0,0 +1,198 @@ +// Copyright (C) 2018-2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/common_optimizations/hsigmoid_fusion.hpp" +#include "transformations/utils/utils.hpp" + +#include + +#include +#include +#include + +NGRAPH_RTTI_DEFINITION(ngraph::pass::HSigmoidFusion, "HSigmoidFusion", 0); + +NGRAPH_RTTI_DEFINITION(ngraph::pass::HSigmoidFusionWithReluDiv, "HSigmoidFusionWithReluDiv", 0); + +ngraph::pass::HSigmoidFusionWithReluDiv::HSigmoidFusionWithReluDiv() { + // Replaces a sub-graph ((min(Relu(x + 3), 6)) / 6 with a HSigmoid op. + auto input = ngraph::pattern::any_input(); + auto add_constant = ngraph::pattern::wrap_type(); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::pattern::wrap_type(); + auto min = std::make_shared(relu, min_constant); + auto div_constant = ngraph::pattern::wrap_type(); + auto div = std::make_shared(min, div_constant); + + ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher &m) { + auto &pattern_to_output = m.get_pattern_value_map(); + auto x_output = pattern_to_output.at(input); + + auto add_const_value = std::dynamic_pointer_cast(pattern_to_output.at(add_constant).get_node_shared_ptr()); + auto min_const_value = std::dynamic_pointer_cast(pattern_to_output.at(min_constant).get_node_shared_ptr()); + auto div_const_value = std::dynamic_pointer_cast(pattern_to_output.at(div_constant).get_node_shared_ptr()); + + bool valid_constant_values = op::util::has_constant_value(add_const_value, 3.0) + && op::util::has_constant_value(min_const_value, 6.0) + && op::util::has_constant_value(div_const_value, 6.0); + + if (!valid_constant_values) { + return false; + } + + auto hsigmoid = std::make_shared(x_output); + + hsigmoid->set_friendly_name(m.get_match_root()->get_friendly_name()); + ngraph::copy_runtime_info({ pattern_to_output.at(add).get_node_shared_ptr(), + pattern_to_output.at(relu).get_node_shared_ptr(), + pattern_to_output.at(min).get_node_shared_ptr(), + pattern_to_output.at(div).get_node_shared_ptr(), + }, + hsigmoid); + ngraph::replace_node(m.get_match_root(), hsigmoid); + return true; + }; + + auto m = std::make_shared(div, "HSigmoidWithReluDivFusion"); + register_matcher(m, callback); +} + +NGRAPH_RTTI_DEFINITION(ngraph::pass::HSigmoidFusionWithReluMul, "HSigmoidFusionWithReluMul", 0); + +ngraph::pass::HSigmoidFusionWithReluMul::HSigmoidFusionWithReluMul() { + // Replaces a sub-graph ((min(Relu(x + 3), 6)) * const(1/6) with a HSigmoid op. + auto input = ngraph::pattern::any_input(); + auto add_constant = ngraph::pattern::wrap_type(); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::pattern::wrap_type(); + auto min = std::make_shared(relu, min_constant); + //auto mul_first = std::make_shared(input, min); + auto mul_constant = ngraph::pattern::wrap_type(); + auto mul_second = std::make_shared(min, mul_constant); + + ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher &m) { + auto &pattern_to_output = m.get_pattern_value_map(); + auto x_output = pattern_to_output.at(input); + + auto add_const_value = std::dynamic_pointer_cast(pattern_to_output.at(add_constant).get_node_shared_ptr()); + auto min_const_value = std::dynamic_pointer_cast(pattern_to_output.at(min_constant).get_node_shared_ptr()); + auto mul_const_value = std::dynamic_pointer_cast(pattern_to_output.at(mul_constant).get_node_shared_ptr()); + + bool valid_constant_values = op::util::has_constant_value(add_const_value, 3.0f) + && op::util::has_constant_value(min_const_value, 6.0f) + && op::util::has_constant_value(mul_const_value, (1.0f/6.0f), 0.0001f); + + if (!valid_constant_values) { + return false; + } + + auto hsigmoid = std::make_shared(x_output); + + hsigmoid->set_friendly_name(m.get_match_root()->get_friendly_name()); + ngraph::copy_runtime_info({ pattern_to_output.at(add).get_node_shared_ptr(), + pattern_to_output.at(relu).get_node_shared_ptr(), + pattern_to_output.at(min).get_node_shared_ptr(), + pattern_to_output.at(mul_second).get_node_shared_ptr() + }, + hsigmoid); + ngraph::replace_node(m.get_match_root(), hsigmoid); + return true; + }; + + auto m = std::make_shared(mul_second, "HSigmoidWithReluMulFusion"); + register_matcher(m, callback); +} + +NGRAPH_RTTI_DEFINITION(ngraph::pass::HSigmoidFusionWithoutRelu, "HSigmoidFusionWithoutRelu", 0); + +ngraph::pass::HSigmoidFusionWithoutRelu::HSigmoidFusionWithoutRelu() { + // Replaces a sub-graph (min(max(x + 3, 0), 6) / 6) with a HSigmoid op. + auto input = ngraph::pattern::any_input(); + auto add_constant = ngraph::pattern::wrap_type(); + auto add = std::make_shared(input, add_constant); + auto max_constant = ngraph::pattern::wrap_type(); + auto max = std::make_shared(add, max_constant); + auto min_constant = ngraph::pattern::wrap_type(); + auto min = std::make_shared(max, min_constant); + auto div_constant = ngraph::pattern::wrap_type(); + auto div = std::make_shared(min, div_constant); + auto mul = std::make_shared(input, div); + + ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher &m) { + auto &pattern_to_output = m.get_pattern_value_map(); + auto x_output = pattern_to_output.at(input); + + auto add_const_value = std::dynamic_pointer_cast(pattern_to_output.at(add_constant).get_node_shared_ptr()); + auto max_const_value = std::dynamic_pointer_cast(pattern_to_output.at(max_constant).get_node_shared_ptr()); + auto min_const_value = std::dynamic_pointer_cast(pattern_to_output.at(min_constant).get_node_shared_ptr()); + auto div_const_value = std::dynamic_pointer_cast(pattern_to_output.at(div_constant).get_node_shared_ptr()); + + bool valid_constant_values = op::util::has_constant_value(add_const_value, 3.0f) + && op::util::has_constant_value(max_const_value, 0.0f) + && op::util::has_constant_value(min_const_value, 6.0f) + && op::util::has_constant_value(div_const_value, 6.0f); + + if (!valid_constant_values) { + return false; + } + + auto hsigmoid = std::make_shared(x_output); + + hsigmoid->set_friendly_name(m.get_match_root()->get_friendly_name()); + ngraph::copy_runtime_info({ pattern_to_output.at(add).get_node_shared_ptr(), + pattern_to_output.at(max).get_node_shared_ptr(), + pattern_to_output.at(min).get_node_shared_ptr(), + pattern_to_output.at(div).get_node_shared_ptr() + }, + hsigmoid); + ngraph::replace_node(m.get_match_root(), hsigmoid); + return true; + }; + + auto m = std::make_shared(div, "HSigmoidWithoutReluFusion"); + register_matcher(m, callback); +} + +NGRAPH_RTTI_DEFINITION(ngraph::pass::HSigmoidFusionWithClamp, "HSigmoidFusionWithClamp", 0); + +ngraph::pass::HSigmoidFusionWithClamp::HSigmoidFusionWithClamp() { + // Replaces a sub-graph (Clamp(x + 3, 0, 6) * const(1/6)) with a HSigmoid op. + auto input = ngraph::pattern::any_input(); + auto add_constant = ngraph::pattern::wrap_type(); + auto add = std::make_shared(input, add_constant); + auto clamp = std::make_shared(add, 0.0f, 6.0f); + auto mul_constant = ngraph::pattern::wrap_type(); + auto mul_first = std::make_shared(clamp, mul_constant); + + ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher &m) { + auto &pattern_to_output = m.get_pattern_value_map(); + auto x_output = pattern_to_output.at(input); + + auto add_const_value = std::dynamic_pointer_cast(pattern_to_output.at(add_constant).get_node_shared_ptr()); + auto mul_const_value = std::dynamic_pointer_cast(pattern_to_output.at(mul_constant).get_node_shared_ptr()); + + bool valid_constant_values = op::util::has_constant_value(add_const_value, 3.0) + && op::util::has_constant_value(mul_const_value, (1.0/6.0), 0.0001); + + if (!valid_constant_values) { + return false; + } + + auto hsigmoid = std::make_shared(x_output); + + hsigmoid->set_friendly_name(m.get_match_root()->get_friendly_name()); + ngraph::copy_runtime_info({ pattern_to_output.at(add).get_node_shared_ptr(), + pattern_to_output.at(clamp).get_node_shared_ptr(), + pattern_to_output.at(mul_first).get_node_shared_ptr() + }, + hsigmoid); + ngraph::replace_node(m.get_match_root(), hsigmoid); + return true; + }; + + auto m = std::make_shared(mul_first, "HSigmoidWithClampFusion"); + register_matcher(m, callback); +} diff --git a/inference-engine/src/transformations/src/transformations/op_conversions/hsigmoid_decomposition.cpp b/inference-engine/src/transformations/src/transformations/op_conversions/hsigmoid_decomposition.cpp new file mode 100644 index 0000000..6654e51 --- /dev/null +++ b/inference-engine/src/transformations/src/transformations/op_conversions/hsigmoid_decomposition.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2018-2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/op_conversions/hsigmoid_decomposition.hpp" + +#include + +#include +#include +#include + +NGRAPH_RTTI_DEFINITION(ngraph::pass::HSigmoidDecomposition, "HSigmoidDecomposition", 0); + +ngraph::pass::HSigmoidDecomposition::HSigmoidDecomposition() { + // Decomposes HSigmoid(x) op into sub-graph (min(Relu(x + 3), 6) * const(1/6) + auto hsigmoid = ngraph::pattern::wrap_type(); + + ngraph::matcher_pass_callback callback = [=](ngraph::pattern::Matcher &m) { + auto &pattern_to_output = m.get_pattern_value_map(); + auto hsigmoid_node = pattern_to_output.at(hsigmoid).get_node_shared_ptr(); + + if (m_transformation_callback(hsigmoid_node)) { + return false; + } + + auto input_type = hsigmoid_node->input_value(0).get_element_type(); + auto add_constant = ngraph::opset5::Constant::create(input_type, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(hsigmoid_node->input_value(0), add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset5::Constant::create(input_type, ngraph::Shape{}, {6.0}); + auto min = register_new_node(relu, min_constant); + auto mul = std::make_shared(hsigmoid_node->input_value(0), min); + + mul->set_friendly_name(m.get_match_root()->get_friendly_name()); + ngraph::copy_runtime_info(hsigmoid_node, + {add_constant, add, relu, min_constant, min, mul}); + ngraph::replace_node(m.get_match_root(), mul); + return true; + }; + + auto m = std::make_shared(hsigmoid, "HSigmoidDecomposition"); + register_matcher(m, callback); +} diff --git a/inference-engine/tests/functional/inference_engine/transformations/hsigmoid_decomposition_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/hsigmoid_decomposition_test.cpp new file mode 100644 index 0000000..828c8d6 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/transformations/hsigmoid_decomposition_test.cpp @@ -0,0 +1,50 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "common_test_utils/ngraph_test_utils.hpp" + +using namespace testing; + +TEST(TransformationTests, HSigmoidDecompositionTest) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::PartialShape::dynamic(1)); + auto hsigmoid = std::make_shared(input); + + f = std::make_shared(ngraph::NodeVector{hsigmoid}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f32, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset5::Constant::create(ngraph::element::f32, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset5::Constant::create(ngraph::element::f32, ngraph::Shape{}, {6.0}); + auto min = std::make_shared(relu, min_constant); + auto mul = std::make_shared(input, min); + + f_ref = std::make_shared(ngraph::NodeVector{mul}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} diff --git a/inference-engine/tests/functional/inference_engine/transformations/hsigmoid_fusion_test.cpp b/inference-engine/tests/functional/inference_engine/transformations/hsigmoid_fusion_test.cpp new file mode 100644 index 0000000..f2d36b4 --- /dev/null +++ b/inference-engine/tests/functional/inference_engine/transformations/hsigmoid_fusion_test.cpp @@ -0,0 +1,328 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "common_test_utils/ngraph_test_utils.hpp" + +using namespace testing; + +TEST(TransformationTests, HSigmoidFusionWithReluDivF16) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0}); + auto min = std::make_shared(relu, min_constant); + auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0}); + auto div = std::make_shared(min, div_constant); + + f = std::make_shared(ngraph::NodeVector{div}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto hsigmoid = std::make_shared(input); + + f_ref = std::make_shared(ngraph::NodeVector{hsigmoid}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, HSigmoidFusionWithReluDivF32) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{}); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {6.0}); + auto min = std::make_shared(relu, min_constant); + auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {6.0}); + auto div = std::make_shared(min, div_constant); + + f = std::make_shared(ngraph::NodeVector{div}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f32, ngraph::Shape{}); + auto hsigmoid = std::make_shared(input); + + f_ref = std::make_shared(ngraph::NodeVector{hsigmoid}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, HSigmoidFusionWithReluMul) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0}); + auto min = std::make_shared(relu, min_constant); + auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.1666666716}); + auto mul_second = std::make_shared(min, mul_constant); + + f = std::make_shared(ngraph::NodeVector{mul_second}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto hsigmoid = std::make_shared(input); + + f_ref = std::make_shared(ngraph::NodeVector{hsigmoid}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, HSigmoidFusionWithoutRelu) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(input, add_constant); + auto max_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.0}); + auto max = std::make_shared(add, max_constant); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0}); + auto min = std::make_shared(max, min_constant); + auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0}); + auto div = std::make_shared(min, div_constant); + + f = std::make_shared(ngraph::NodeVector{div}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto hsigmoid = std::make_shared(input); + + f_ref = std::make_shared(ngraph::NodeVector{hsigmoid}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, HSigmoidFusionWithClamp) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(input, add_constant); + auto clamp = std::make_shared(add, 0.0f, 6.0f); + auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {1.0 / 6.0}); + auto mul_first = std::make_shared(clamp, mul_constant); + + f = std::make_shared(ngraph::NodeVector{mul_first}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto hsigmoid = std::make_shared(input); + + f_ref = std::make_shared(ngraph::NodeVector{hsigmoid}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, HSigmoidFusionWithReluMulWrongConstValue) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0}); + auto min = std::make_shared(relu, min_constant); + auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.167}); + auto mul_second = std::make_shared(min, mul_constant); + + f = std::make_shared(ngraph::NodeVector{mul_second}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.0}); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0}); + auto min = std::make_shared(relu, min_constant); + auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.167}); + auto mul_second = std::make_shared(min, mul_constant); + + f_ref = std::make_shared(ngraph::NodeVector{mul_second}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, HSigmoidFusionWithReluDivWrongConstValue) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f16, ngraph::Shape{}); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.01}); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.002}); + auto min = std::make_shared(relu, min_constant); + auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.0}); + auto div = std::make_shared(min, div_constant); + + f = std::make_shared(ngraph::NodeVector{div}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f16, ngraph::Shape{}); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.01}); + auto add = std::make_shared(input, add_constant); + auto relu = std::make_shared(add); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.002}); + auto min = std::make_shared(relu, min_constant); + auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.0}); + auto div = std::make_shared(min, div_constant); + + f_ref = std::make_shared(ngraph::NodeVector{div}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, HSigmoidFusionWithoutReluWrongConstValue) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.11}); + auto add = std::make_shared(input, add_constant); + auto max_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.22}); + auto max = std::make_shared(add, max_constant); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.01}); + auto min = std::make_shared(max, min_constant); + auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.002}); + auto div = std::make_shared(min, div_constant); + + f = std::make_shared(ngraph::NodeVector{div}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.11}); + auto add = std::make_shared(input, add_constant); + auto max_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.22}); + auto max = std::make_shared(add, max_constant); + auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.01}); + auto min = std::make_shared(max, min_constant); + auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.002}); + auto div = std::make_shared(min, div_constant); + + f_ref = std::make_shared(ngraph::NodeVector{div}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} + +TEST(TransformationTests, HSigmoidFusionWithClampWrongConstValue) { + std::shared_ptr f(nullptr), f_ref(nullptr); + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.11}); + auto add = std::make_shared(input, add_constant); + auto clamp = std::make_shared(add, 0.11f, 6.02f); + auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.98 / 6.15}); + auto mul_first = std::make_shared(clamp, mul_constant); + + f = std::make_shared(ngraph::NodeVector{mul_first}, ngraph::ParameterVector{input}); + + ngraph::pass::Manager manager; + manager.register_pass(); + manager.register_pass(); + manager.run_passes(f); + ASSERT_NO_THROW(check_rt_info(f)); + } + + { + auto input = std::make_shared(ngraph::element::f16, ngraph::PartialShape::dynamic(1)); + auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.11}); + auto add = std::make_shared(input, add_constant); + auto clamp = std::make_shared(add, 0.11f, 6.02f); + auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.98 / 6.15}); + auto mul_first = std::make_shared(clamp, mul_constant); + + f_ref = std::make_shared(ngraph::NodeVector{mul_first}, ngraph::ParameterVector{input}); + } + + auto res = compare_functions(f, f_ref); + ASSERT_TRUE(res.first) << res.second; +} diff --git a/ngraph/core/include/ngraph/op/hsigmoid.hpp b/ngraph/core/include/ngraph/op/hsigmoid.hpp index d8963f9..4783400 100644 --- a/ngraph/core/include/ngraph/op/hsigmoid.hpp +++ b/ngraph/core/include/ngraph/op/hsigmoid.hpp @@ -36,7 +36,7 @@ namespace ngraph NGRAPH_RTTI_DECLARATION; HSigmoid() = default; - /// \brief Constructs a HSigmoid (hard version of Swish) operation. + /// \brief Constructs a HSigmoid operation. /// /// \param data Input tensor HSigmoid(const Output& arg); diff --git a/ngraph/python/src/ngraph/__init__.py b/ngraph/python/src/ngraph/__init__.py index 03f5043..939475a 100644 --- a/ngraph/python/src/ngraph/__init__.py +++ b/ngraph/python/src/ngraph/__init__.py @@ -86,6 +86,7 @@ from ngraph.opset5 import group_convolution from ngraph.opset5 import group_convolution_backprop_data from ngraph.opset5 import gru_cell from ngraph.opset5 import hard_sigmoid +from ngraph.opset5 import hsigmoid from ngraph.opset5 import hswish from ngraph.opset5 import interpolate from ngraph.opset5 import less diff --git a/ngraph/python/src/ngraph/opset5/__init__.py b/ngraph/python/src/ngraph/opset5/__init__.py index 0141b1e..413fa77 100644 --- a/ngraph/python/src/ngraph/opset5/__init__.py +++ b/ngraph/python/src/ngraph/opset5/__init__.py @@ -73,6 +73,7 @@ from ngraph.opset1.ops import group_convolution from ngraph.opset1.ops import group_convolution_backprop_data from ngraph.opset3.ops import gru_cell from ngraph.opset1.ops import hard_sigmoid +from ngraph.opset5.ops import hsigmoid from ngraph.opset4.ops import hswish from ngraph.opset1.ops import interpolate from ngraph.opset1.ops import less diff --git a/ngraph/python/src/ngraph/opset5/ops.py b/ngraph/python/src/ngraph/opset5/ops.py index ab6f9c5..ded64ea 100644 --- a/ngraph/python/src/ngraph/opset5/ops.py +++ b/ngraph/python/src/ngraph/opset5/ops.py @@ -130,3 +130,13 @@ def round(data: NodeInput, mode: str = "half_to_even", name: Optional[str] = Non :return: The new node with Round operation applied on each element. """ return _get_node_factory_opset5().create("Round", as_nodes(data), {"mode": mode.upper()}) + + +@nameable_op +def hsigmoid(data: NodeInput, name: Optional[str] = None,) -> Node: + """Return a node which performs HSigmoid. + + :param data: Tensor with input data floating point type. + :return: The new node which performs HSigmoid + """ + return _get_node_factory_opset5().create("HSigmoid", as_nodes(data), {}) diff --git a/ngraph/python/tests/test_ngraph/test_ops_unary.py b/ngraph/python/tests/test_ngraph/test_ops_unary.py index 7594425..b58e280 100644 --- a/ngraph/python/tests/test_ngraph/test_ops_unary.py +++ b/ngraph/python/tests/test_ngraph/test_ops_unary.py @@ -179,3 +179,14 @@ def test_round_away(): # result = run_op_node([input_tensor], ng.round, "HALF_AWAY_FROM_ZERO") # assert np.allclose(result, expected) + + +def test_hsigmoid(): + float_dtype = np.float32 + data = ng.parameter(Shape([3, 10]), dtype=float_dtype, name="data") + + node = ng.hsigmoid(data) + assert node.get_type_name() == "HSigmoid" + assert node.get_output_size() == 1 + assert list(node.get_output_shape(0)) == [3, 10] + assert node.get_output_element_type(0) == Type.f32 diff --git a/ngraph/test/CMakeLists.txt b/ngraph/test/CMakeLists.txt index fcfbe27..7abaff8 100644 --- a/ngraph/test/CMakeLists.txt +++ b/ngraph/test/CMakeLists.txt @@ -132,6 +132,7 @@ set(SRC type_prop/gru_cell.cpp type_prop/gru_sequence.cpp type_prop/hard_sigmoid.cpp + type_prop/hsigmoid.cpp type_prop/hswish.cpp type_prop/interpolate.cpp type_prop/lrn.cpp diff --git a/ngraph/test/type_prop/hsigmoid.cpp b/ngraph/test/type_prop/hsigmoid.cpp new file mode 100644 index 0000000..9ef8e48 --- /dev/null +++ b/ngraph/test/type_prop/hsigmoid.cpp @@ -0,0 +1,54 @@ +//***************************************************************************** +// 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 "gtest/gtest.h" +#include "ngraph/ngraph.hpp" +#include "util/type_prop.hpp" + +using namespace std; +using namespace ngraph; + +TEST(type_prop, hsigmoid) +{ + auto data = make_shared(element::f32, Shape{1, 3, 6}); + auto hsigmoid_func = make_shared(data); + EXPECT_EQ(hsigmoid_func->get_element_type(), element::f32); + EXPECT_EQ(hsigmoid_func->get_shape(), data->get_output_shape(0)); +} + +TEST(type_prop, hsigmoid_partial) +{ + auto data = make_shared(element::f32, PartialShape{1, Dimension::dynamic(), 6}); + auto hsigmoid_func = make_shared(data); + EXPECT_EQ(hsigmoid_func->get_element_type(), element::f32); + ASSERT_TRUE( + hsigmoid_func->get_output_partial_shape(0).same_scheme(data->get_output_partial_shape(0))); + + // rank unknown + auto hsigmoid_partial = make_shared( + make_shared(element::f32, PartialShape::dynamic())); + ASSERT_TRUE(hsigmoid_partial->get_output_partial_shape(0).same_scheme(PartialShape::dynamic())); +} + +TEST(type_prop, hsigmoid_partial_static_rank) +{ + auto data = make_shared(element::f32, PartialShape{1, Dimension::dynamic(), 6}); + auto hsigmoid_func = make_shared(data); + EXPECT_EQ(hsigmoid_func->get_element_type(), element::f32); + ASSERT_TRUE( + hsigmoid_func->get_output_partial_shape(0).same_scheme(data->get_output_partial_shape(0))); + ASSERT_TRUE(hsigmoid_func->get_output_partial_shape(0).rank().is_static()); +} -- 2.7.4