Transformations for hsigmoid op (#2531)
authoriliya mironov <iliya.mironov@intel.com>
Fri, 23 Oct 2020 09:35:56 +0000 (12:35 +0300)
committerGitHub <noreply@github.com>
Fri, 23 Oct 2020 09:35:56 +0000 (12:35 +0300)
* 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

15 files changed:
inference-engine/src/cldnn_engine/cldnn_engine.cpp
inference-engine/src/transformations/include/transformations/common_optimizations/hsigmoid_fusion.hpp [new file with mode: 0644]
inference-engine/src/transformations/include/transformations/op_conversions/hsigmoid_decomposition.hpp [new file with mode: 0644]
inference-engine/src/transformations/src/transformations/common_optimizations/common_optimizations.cpp
inference-engine/src/transformations/src/transformations/common_optimizations/hsigmoid_fusion.cpp [new file with mode: 0644]
inference-engine/src/transformations/src/transformations/op_conversions/hsigmoid_decomposition.cpp [new file with mode: 0644]
inference-engine/tests/functional/inference_engine/transformations/hsigmoid_decomposition_test.cpp [new file with mode: 0644]
inference-engine/tests/functional/inference_engine/transformations/hsigmoid_fusion_test.cpp [new file with mode: 0644]
ngraph/core/include/ngraph/op/hsigmoid.hpp
ngraph/python/src/ngraph/__init__.py
ngraph/python/src/ngraph/opset5/__init__.py
ngraph/python/src/ngraph/opset5/ops.py
ngraph/python/tests/test_ngraph/test_ops_unary.py
ngraph/test/CMakeLists.txt
ngraph/test/type_prop/hsigmoid.cpp [new file with mode: 0644]

index db16779..e99d24b 100644 (file)
@@ -24,6 +24,7 @@
 #include <ngraph/opsets/opset2.hpp>
 #include <ngraph/opsets/opset3.hpp>
 #include <ngraph/opsets/opset4.hpp>
+#include <ngraph/opsets/opset5.hpp>
 #include <ngraph/pass/manager.hpp>
 #include <generic_ie.hpp>
 #include <transformations/control_flow/unroll_tensor_iterator.hpp>
@@ -117,6 +118,7 @@ InferenceEngine::ICNNNetwork::Ptr clDNNEngine::CloneAndTransformNetwork(const In
                    std::dynamic_pointer_cast<const ::ngraph::opset2::BatchToSpace>(node) ||
                    std::dynamic_pointer_cast<const ::ngraph::opset2::SpaceToBatch>(node) ||
                    std::dynamic_pointer_cast<const ::ngraph::opset3::ExtractImagePatches>(node) ||
+                   std::dynamic_pointer_cast<const ::ngraph::opset5::HSigmoid>(node) ||
                    std::dynamic_pointer_cast<const ::ngraph::opset4::HSwish>(node) ||
                    std::dynamic_pointer_cast<const ::ngraph::opset4::ReduceL1>(node) ||
                    std::dynamic_pointer_cast<const ::ngraph::opset4::ReduceL2>(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 (file)
index 0000000..bfadc78
--- /dev/null
@@ -0,0 +1,79 @@
+// Copyright (C) 2018-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <memory>
+#include <utility>
+
+#include <transformations_visibility.hpp>
+#include <ngraph/pass/graph_rewrite.hpp>
+
+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<ngraph::pass::HSigmoidFusionWithReluDiv>();
+        add_matcher<ngraph::pass::HSigmoidFusionWithReluMul>();
+        add_matcher<ngraph::pass::HSigmoidFusionWithoutRelu>();
+        add_matcher<ngraph::pass::HSigmoidFusionWithClamp>();
+    }
+};
+
+/**
+ * @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 (file)
index 0000000..c03eadd
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (C) 2018-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <transformations_visibility.hpp>
+#include <ngraph/pass/graph_rewrite.hpp>
+
+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();
+};
index 7f2a835..ecce914 100644 (file)
@@ -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 <ngraph/pass/manager.hpp>
@@ -68,6 +70,7 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr<ngraph::
     manager.register_pass<ngraph::pass::SoftPlusFusion>();
     manager.register_pass<ngraph::pass::SoftPlusToMishFusion>();
     manager.register_pass<ngraph::pass::SwishFusion>();
+    manager.register_pass<ngraph::pass::HSigmoidFusion>();
     manager.register_pass<ngraph::pass::HSwishFusion>();
     manager.register_pass<ngraph::pass::ConvertPadToGroupConvolution, false>();
     manager.register_pass<ngraph::pass::NormalizeL2Fusion>();
@@ -78,6 +81,7 @@ bool ngraph::pass::CommonOptimizations::run_on_function(std::shared_ptr<ngraph::
     auto decomp = manager.register_pass<ngraph::pass::GraphRewrite>();
     decomp->add_matcher<ngraph::pass::ReduceL1Decomposition>();
     decomp->add_matcher<ngraph::pass::ReduceL2Decomposition>();
+    decomp->add_matcher<ngraph::pass::HSigmoidDecomposition>();
     decomp->add_matcher<ngraph::pass::HSwishDecomposition>();
     decomp->add_matcher<ngraph::pass::LogSoftmaxDecomposition>();
     decomp->add_matcher<ngraph::pass::ConvertReduceMeanToPooling>();
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 (file)
index 0000000..f19c91e
--- /dev/null
@@ -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 <memory>
+
+#include <ngraph/opsets/opset5.hpp>
+#include <ngraph/rt_info.hpp>
+#include <ngraph/pattern/op/wrap_type.hpp>
+
+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<ngraph::opset4::Constant>();
+    auto add = std::make_shared<ngraph::opset4::Add>(input, add_constant);
+    auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+    auto min_constant = ngraph::pattern::wrap_type<ngraph::opset4::Constant>();
+    auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+    auto div_constant = ngraph::pattern::wrap_type<ngraph::opset4::Constant>();
+    auto div = std::make_shared<ngraph::opset4::Divide>(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<ngraph::opset4::Constant>(pattern_to_output.at(add_constant).get_node_shared_ptr());
+        auto min_const_value = std::dynamic_pointer_cast<ngraph::opset4::Constant>(pattern_to_output.at(min_constant).get_node_shared_ptr());
+        auto div_const_value = std::dynamic_pointer_cast<ngraph::opset4::Constant>(pattern_to_output.at(div_constant).get_node_shared_ptr());
+
+        bool valid_constant_values = op::util::has_constant_value<float>(add_const_value, 3.0)
+                                        && op::util::has_constant_value<float>(min_const_value, 6.0)
+                                        && op::util::has_constant_value<float>(div_const_value, 6.0);
+
+        if (!valid_constant_values) {
+            return false;
+        }
+
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(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<ngraph::pattern::Matcher>(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<ngraph::opset4::Constant>();
+    auto add = std::make_shared<ngraph::opset4::Add>(input, add_constant);
+    auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+    auto min_constant = ngraph::pattern::wrap_type<ngraph::opset4::Constant>();
+    auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+    //auto mul_first = std::make_shared<ngraph::opset4::Multiply>(input, min);
+    auto mul_constant = ngraph::pattern::wrap_type<ngraph::opset4::Constant>();
+    auto mul_second = std::make_shared<ngraph::opset4::Multiply>(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<ngraph::opset4::Constant>(pattern_to_output.at(add_constant).get_node_shared_ptr());
+        auto min_const_value = std::dynamic_pointer_cast<ngraph::opset4::Constant>(pattern_to_output.at(min_constant).get_node_shared_ptr());
+        auto mul_const_value = std::dynamic_pointer_cast<ngraph::opset4::Constant>(pattern_to_output.at(mul_constant).get_node_shared_ptr());
+
+        bool valid_constant_values =  op::util::has_constant_value<float>(add_const_value, 3.0f)
+                                        &&  op::util::has_constant_value<float>(min_const_value, 6.0f)
+                                        &&  op::util::has_constant_value<float>(mul_const_value, (1.0f/6.0f), 0.0001f);
+
+        if (!valid_constant_values) {
+            return false;
+        }
+
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(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<ngraph::pattern::Matcher>(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<ngraph::opset4::Constant>();
+    auto add = std::make_shared<ngraph::opset4::Add>(input, add_constant);
+    auto max_constant = ngraph::pattern::wrap_type<ngraph::opset4::Constant>();
+    auto max = std::make_shared<ngraph::opset4::Maximum>(add, max_constant);
+    auto min_constant = ngraph::pattern::wrap_type<ngraph::opset4::Constant>();
+    auto min = std::make_shared<ngraph::opset4::Minimum>(max, min_constant);
+    auto div_constant = ngraph::pattern::wrap_type<ngraph::opset4::Constant>();
+    auto div = std::make_shared<ngraph::opset4::Divide>(min, div_constant);
+    auto mul = std::make_shared<ngraph::opset4::Multiply>(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<ngraph::opset4::Constant>(pattern_to_output.at(add_constant).get_node_shared_ptr());
+        auto max_const_value = std::dynamic_pointer_cast<ngraph::opset4::Constant>(pattern_to_output.at(max_constant).get_node_shared_ptr());
+        auto min_const_value = std::dynamic_pointer_cast<ngraph::opset4::Constant>(pattern_to_output.at(min_constant).get_node_shared_ptr());
+        auto div_const_value = std::dynamic_pointer_cast<ngraph::opset4::Constant>(pattern_to_output.at(div_constant).get_node_shared_ptr());
+
+        bool valid_constant_values = op::util::has_constant_value<float>(add_const_value, 3.0f)
+                                        && op::util::has_constant_value<float>(max_const_value, 0.0f)
+                                        && op::util::has_constant_value<float>(min_const_value, 6.0f)
+                                        && op::util::has_constant_value<float>(div_const_value, 6.0f);
+
+        if (!valid_constant_values) {
+            return false;
+        }
+
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(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<ngraph::pattern::Matcher>(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<ngraph::opset4::Constant>();
+    auto add = std::make_shared<ngraph::opset4::Add>(input, add_constant);
+    auto clamp = std::make_shared<ngraph::op::v0::Clamp>(add, 0.0f, 6.0f);
+    auto mul_constant = ngraph::pattern::wrap_type<ngraph::opset4::Constant>();
+    auto mul_first = std::make_shared<ngraph::opset4::Multiply>(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<ngraph::opset4::Constant>(pattern_to_output.at(add_constant).get_node_shared_ptr());
+        auto mul_const_value = std::dynamic_pointer_cast<ngraph::opset4::Constant>(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<ngraph::opset5::HSigmoid>(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<ngraph::pattern::Matcher>(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 (file)
index 0000000..6654e51
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright (C) 2018-2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "transformations/op_conversions/hsigmoid_decomposition.hpp"
+
+#include <memory>
+
+#include <ngraph/opsets/opset5.hpp>
+#include <ngraph/rt_info.hpp>
+#include <ngraph/pattern/op/wrap_type.hpp>
+
+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<opset5::HSigmoid>();
+
+    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<ngraph::opset5::Add>(hsigmoid_node->input_value(0), add_constant);
+        auto relu = std::make_shared<ngraph::opset5::Relu>(add);
+        auto min_constant = ngraph::opset5::Constant::create(input_type, ngraph::Shape{}, {6.0});
+        auto min = register_new_node<ngraph::opset5::Minimum>(relu, min_constant);
+        auto mul = std::make_shared<ngraph::opset5::Multiply>(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<ngraph::pattern::Matcher>(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 (file)
index 0000000..828c8d6
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <memory>
+
+#include <ngraph/function.hpp>
+#include <ngraph/opsets/opset5.hpp>
+#include <ngraph/pass/manager.hpp>
+#include <transformations/op_conversions/hsigmoid_decomposition.hpp>
+#include <transformations/init_node_info.hpp>
+#include <transformations/utils/utils.hpp>
+
+#include "common_test_utils/ngraph_test_utils.hpp"
+
+using namespace testing;
+
+TEST(TransformationTests, HSigmoidDecompositionTest) {
+    std::shared_ptr<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset5::Parameter>(ngraph::element::f32, ngraph::PartialShape::dynamic(1));
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(input);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{hsigmoid}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidDecomposition>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset5::Parameter>(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<ngraph::opset5::Add>(input, add_constant);
+        auto relu = std::make_shared<ngraph::opset5::Relu>(add);
+        auto min_constant = ngraph::opset5::Constant::create(ngraph::element::f32, ngraph::Shape{}, {6.0});
+        auto min = std::make_shared<ngraph::opset5::Minimum>(relu, min_constant);
+        auto mul = std::make_shared<ngraph::opset5::Multiply>(input, min);
+
+        f_ref = std::make_shared<ngraph::Function>(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 (file)
index 0000000..f2d36b4
--- /dev/null
@@ -0,0 +1,328 @@
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <memory>
+
+#include <ngraph/function.hpp>
+#include <ngraph/opsets/opset5.hpp>
+#include <ngraph/pass/manager.hpp>
+#include <transformations/common_optimizations/hsigmoid_fusion.hpp>
+#include <transformations/init_node_info.hpp>
+#include <transformations/utils/utils.hpp>
+
+#include "common_test_utils/ngraph_test_utils.hpp"
+
+using namespace testing;
+
+TEST(TransformationTests, HSigmoidFusionWithReluDivF16) {
+    std::shared_ptr<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+        auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0});
+        auto div = std::make_shared<ngraph::opset4::Divide>(min, div_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{div}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(ngraph::element::f16, ngraph::PartialShape::dynamic(1));
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(input);
+
+        f_ref = std::make_shared<ngraph::Function>(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<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(ngraph::element::f32, ngraph::Shape{});
+        auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {3.0});
+        auto add = std::make_shared<ngraph::opset4::Add>(input, add_constant);
+        auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {6.0});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+        auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f32, ngraph::Shape{}, {6.0});
+        auto div = std::make_shared<ngraph::opset4::Divide>(min, div_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{div}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(ngraph::element::f32, ngraph::Shape{});
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(input);
+
+        f_ref = std::make_shared<ngraph::Function>(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<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+        auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.1666666716});
+        auto mul_second = std::make_shared<ngraph::opset4::Multiply>(min, mul_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{mul_second}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(ngraph::element::f16, ngraph::PartialShape::dynamic(1));
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(input);
+
+        f_ref = std::make_shared<ngraph::Function>(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<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto max_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.0});
+        auto max = std::make_shared<ngraph::opset4::Maximum>(add, max_constant);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(max, min_constant);
+        auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0});
+        auto div = std::make_shared<ngraph::opset4::Divide>(min, div_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{div}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(ngraph::element::f16, ngraph::PartialShape::dynamic(1));
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(input);
+
+        f_ref = std::make_shared<ngraph::Function>(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<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto clamp = std::make_shared<ngraph::op::v0::Clamp>(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<ngraph::opset4::Multiply>(clamp, mul_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{mul_first}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(ngraph::element::f16, ngraph::PartialShape::dynamic(1));
+        auto hsigmoid = std::make_shared<ngraph::opset5::HSigmoid>(input);
+
+        f_ref = std::make_shared<ngraph::Function>(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<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+        auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.167});
+        auto mul_second = std::make_shared<ngraph::opset4::Multiply>(min, mul_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{mul_second}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.0});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+        auto mul_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.167});
+        auto mul_second = std::make_shared<ngraph::opset4::Multiply>(min, mul_constant);
+
+        f_ref = std::make_shared<ngraph::Function>(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<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(ngraph::element::f16, ngraph::Shape{});
+        auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.01});
+        auto add = std::make_shared<ngraph::opset4::Add>(input, add_constant);
+        auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.002});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+        auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.0});
+        auto div = std::make_shared<ngraph::opset4::Divide>(min, div_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{div}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(ngraph::element::f16, ngraph::Shape{});
+        auto add_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {3.01});
+        auto add = std::make_shared<ngraph::opset4::Add>(input, add_constant);
+        auto relu = std::make_shared<ngraph::opset4::Relu>(add);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.002});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(relu, min_constant);
+        auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.0});
+        auto div = std::make_shared<ngraph::opset4::Divide>(min, div_constant);
+
+        f_ref = std::make_shared<ngraph::Function>(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<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto max_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.22});
+        auto max = std::make_shared<ngraph::opset4::Maximum>(add, max_constant);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.01});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(max, min_constant);
+        auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.002});
+        auto div = std::make_shared<ngraph::opset4::Divide>(min, div_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{div}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto max_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {0.22});
+        auto max = std::make_shared<ngraph::opset4::Maximum>(add, max_constant);
+        auto min_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.01});
+        auto min = std::make_shared<ngraph::opset4::Minimum>(max, min_constant);
+        auto div_constant = ngraph::opset4::Constant::create(ngraph::element::f16, ngraph::Shape{}, {6.002});
+        auto div = std::make_shared<ngraph::opset4::Divide>(min, div_constant);
+
+        f_ref = std::make_shared<ngraph::Function>(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<ngraph::Function> f(nullptr), f_ref(nullptr);
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto clamp = std::make_shared<ngraph::op::v0::Clamp>(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<ngraph::opset4::Multiply>(clamp, mul_constant);
+
+        f = std::make_shared<ngraph::Function>(ngraph::NodeVector{mul_first}, ngraph::ParameterVector{input});
+
+        ngraph::pass::Manager manager;
+        manager.register_pass<ngraph::pass::InitNodeInfo>();
+        manager.register_pass<ngraph::pass::HSigmoidFusion>();
+        manager.run_passes(f);
+        ASSERT_NO_THROW(check_rt_info(f));
+    }
+
+    {
+        auto input = std::make_shared<ngraph::opset4::Parameter>(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<ngraph::opset4::Add>(input, add_constant);
+        auto clamp = std::make_shared<ngraph::op::v0::Clamp>(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<ngraph::opset4::Multiply>(clamp, mul_constant);
+
+        f_ref = std::make_shared<ngraph::Function>(ngraph::NodeVector{mul_first}, ngraph::ParameterVector{input});
+    }
+
+    auto res = compare_functions(f, f_ref);
+    ASSERT_TRUE(res.first) << res.second;
+}
index d8963f9..4783400 100644 (file)
@@ -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<Node>& arg);
index 03f5043..939475a 100644 (file)
@@ -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
index 0141b1e..413fa77 100644 (file)
@@ -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
index ab6f9c5..ded64ea 100644 (file)
@@ -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), {})
index 7594425..b58e280 100644 (file)
@@ -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
index fcfbe27..7abaff8 100644 (file)
@@ -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 (file)
index 0000000..9ef8e48
--- /dev/null
@@ -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<op::Parameter>(element::f32, Shape{1, 3, 6});
+    auto hsigmoid_func = make_shared<op::v5::HSigmoid>(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<op::Parameter>(element::f32, PartialShape{1, Dimension::dynamic(), 6});
+    auto hsigmoid_func = make_shared<op::v5::HSigmoid>(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<op::v5::HSigmoid>(
+        make_shared<op::Parameter>(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<op::Parameter>(element::f32, PartialShape{1, Dimension::dynamic(), 6});
+    auto hsigmoid_func = make_shared<op::v5::HSigmoid>(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());
+}