From ce19e1fb9a120a2d64254c55a468b5eb3a3fc927 Mon Sep 17 00:00:00 2001 From: iliya mironov Date: Sat, 24 Oct 2020 12:51:15 +0300 Subject: [PATCH] Add hsigmoid fusing for MO (#2750) * Add hsigmoid fusing for MO * Update Bom file * Remove comments * Refactoring hsigmoid fusion according to review * Add div and mul patterns for hsigmoid fusion * Refactoring code according to review * Fix HSigmoid fusion transformation --- model-optimizer/automation/package_BOM.txt | 1 + .../extensions/front/HSigmoid_fusion.py | 181 +++++++++++ .../extensions/front/HSigmoid_fusion_test.py | 355 +++++++++++++++++++++ model-optimizer/extensions/ops/activation_ops.py | 6 + 4 files changed, 543 insertions(+) create mode 100644 model-optimizer/extensions/front/HSigmoid_fusion.py create mode 100644 model-optimizer/extensions/front/HSigmoid_fusion_test.py diff --git a/model-optimizer/automation/package_BOM.txt b/model-optimizer/automation/package_BOM.txt index 4990bd9..30a1591 100644 --- a/model-optimizer/automation/package_BOM.txt +++ b/model-optimizer/automation/package_BOM.txt @@ -127,6 +127,7 @@ extensions/front/freeze_placeholder_value.py extensions/front/GeLUMerger_Erf.py extensions/front/GeLUMerger_Tanh.py extensions/front/global_pooling_to_reduce.py +extensions/front/HSigmoid_fusion.py extensions/front/HSwish_fusion.py extensions/front/image_scaler.py extensions/front/input_cut.py diff --git a/model-optimizer/extensions/front/HSigmoid_fusion.py b/model-optimizer/extensions/front/HSigmoid_fusion.py new file mode 100644 index 0000000..96e310a --- /dev/null +++ b/model-optimizer/extensions/front/HSigmoid_fusion.py @@ -0,0 +1,181 @@ +""" + Copyright (C) 2018-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. +""" +import numpy as np + +from extensions.front.AttributedClampNormalizer import AttributedClampNormalizer +from extensions.ops.activation_ops import HSigmoid +from mo.front.common.replacement import FrontReplacementSubgraph +from mo.front.subgraph_matcher import SubgraphMatch +from mo.graph.graph import Graph, rename_nodes +from mo.utils.graph import Node + + +def replace_with_hsigmoid(graph: Graph, first_node: Node, last_node: Node): + # determine the input port of first and last nodes which gets the 'input' node output + add_input_port_idx = int(first_node.in_port(0).get_connection().get_source().node.soft_get('op') == 'Const') + last_node_name = last_node.soft_get('name', last_node.id) + + hsigmoid = HSigmoid(graph, {}).create_node() + hsigmoid.in_port(0).connect(first_node.in_port(add_input_port_idx).get_source()) + last_node.out_port(0).get_connection().set_source(hsigmoid.out_port(0)) + + rename_nodes([(last_node, last_node_name + '/TBR'), (hsigmoid, last_node_name)]) + + +class HSigmoidWithClamp(FrontReplacementSubgraph): + """ + The transformation looks for the pattern with ReLU6 (Clamp) defining the HSigmoid function: + HSigmoid(x) = Relu6(x + 3.0) / 6.0. + """ + enabled = True + + def run_after(self): + return [AttributedClampNormalizer] + + def pattern(self): + return dict( + nodes=[ + ('input', dict()), + ('add', dict(op='Add')), + ('const_0', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 0.0, atol=1e-6))), + ('const_3', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 3.0, atol=1e-6))), + ('const_6', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 6.0, atol=1e-6))), + ('const_1_6', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 1.0 / 6.0, atol=1e-6))), + ('clamp', dict(op='Clamp')), + ('mul_2', dict(op='Mul')), + ], + edges=[ + ('input', 'add', {}), + ('const_3', 'add', {}), + ('add', 'clamp', {'in': 0}), + ('const_0', 'clamp', {'in': 1}), + ('const_6', 'clamp', {'in': 2}), + ('clamp', 'mul_2', {}), + ('const_1_6', 'mul_2', {}), + ]) + + def replace_sub_graph(self, graph: Graph, match: [dict, SubgraphMatch]): + replace_with_hsigmoid(graph, match['add'], match['mul_2']) + + +class HSigmoidWithMinMax(FrontReplacementSubgraph): + """ + The transformation looks for the pattern with Min/Max defining the HSigmoid function: + HSigmoid(x) = Min(Max(x + 3.0, 0), 6.0) / 6.0. + """ + enabled = True + + def run_after(self): + return [AttributedClampNormalizer] + + def pattern(self): + return dict( + nodes=[ + ('input', dict()), + ('add', dict(op='Add')), + ('const_0', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 0.0, atol=1e-6))), + ('const_3', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 3.0, atol=1e-6))), + ('const_6', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 6.0, atol=1e-6))), + ('const_1_6', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 1.0 / 6.0, atol=1e-6))), + ('max', dict(op='Maximum')), + ('min', dict(op='Minimum')), + ('mul_2', dict(op='Mul')), + ], + edges=[ + ('input', 'add', {'out': 0}), + ('const_3', 'add', {}), + ('add', 'max', {}), + ('const_0', 'max', {}), + ('max', 'min', {}), + ('const_6', 'min', {}), + ('min', 'mul_2', {}), + ('const_1_6', 'mul_2', {}), + ]) + + def replace_sub_graph(self, graph: Graph, match: [dict, SubgraphMatch]): + replace_with_hsigmoid(graph, match['add'], match['mul_2']) + + +class HSigmoidWithReluDiv(FrontReplacementSubgraph): + """ + The transformation looks for the pattern with Relu/Div defining the HSigmoid function: + HSigmoid(x) = Min(Relu(x + 3.0), 6.0) / 6.0 + """ + enabled = True + + def run_after(self): + return [AttributedClampNormalizer] + + def pattern(self): + return dict( + nodes=[ + ('input', dict()), + ('add_const', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 3.0, atol=1e-6))), + ('add', dict(op='Add')), + ('relu', dict(op='ReLU')), + ('min_const', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 6.0, atol=1e-6))), + ('min', dict(op='Minimum')), + ('div_const', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 6.0, atol=1e-6))), + ('div', dict(op='Div')), + ], + edges=[ + ('input', 'add', {'out': 0}), + ('add_const', 'add', {}), + ('add', 'relu', {}), + ('relu', 'min', {}), + ('min_const', 'min', {}), + ('min', 'div', {}), + ('div_const', 'div', {}), + ]) + + def replace_sub_graph(self, graph: Graph, match: [dict, SubgraphMatch]): + replace_with_hsigmoid(graph, match['add'], match['div']) + + +class HSigmoidWithReluMul(FrontReplacementSubgraph): + """ + The transformation looks for the pattern with Relu/Mul defining the HSigmoid function: + HSigmoid(x) = Min(Relu(x + 3.0), 6.0) * 1.0/6.0 + """ + enabled = True + + def run_after(self): + return [AttributedClampNormalizer] + + def pattern(self): + return dict( + nodes=[ + ('input', dict()), + ('add_const', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 3.0, atol=1e-6))), + ('add', dict(op='Add')), + ('relu', dict(op='ReLU')), + ('min_const', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 6.0, atol=1e-6))), + ('min', dict(op='Minimum')), + ('mul_const', dict(op='Const', value=lambda v: v is not None and np.allclose(v, 1.0/6.0, atol=1e-6))), + ('mul', dict(op='Mul')), + ], + edges=[ + ('input', 'add', {'out': 0}), + ('add_const', 'add', {}), + ('add', 'relu', {}), + ('relu', 'min', {}), + ('min_const', 'min', {}), + ('min', 'mul', {}), + ('mul_const', 'mul', {}), + ]) + + def replace_sub_graph(self, graph: Graph, match: [dict, SubgraphMatch]): + replace_with_hsigmoid(graph, match['add'], match['mul']) diff --git a/model-optimizer/extensions/front/HSigmoid_fusion_test.py b/model-optimizer/extensions/front/HSigmoid_fusion_test.py new file mode 100644 index 0000000..6c6b996 --- /dev/null +++ b/model-optimizer/extensions/front/HSigmoid_fusion_test.py @@ -0,0 +1,355 @@ +""" + Copyright (C) 2018-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. +""" + +import unittest + +from extensions.front.HSigmoid_fusion import HSigmoidWithClamp, HSigmoidWithMinMax, HSigmoidWithReluDiv, \ + HSigmoidWithReluMul +from mo.front.common.partial_infer.utils import float_array +from mo.utils.ir_engine.compare_graphs import compare_graphs +from mo.utils.unittest.graph import build_graph, const, regular_op, result, build_graph_with_edge_attrs + +ref_nodes = {**regular_op('input', {'type': 'Parameter'}), + **regular_op('hsigmoid', {'type': 'HSigmoid', 'name': 'final_mul'}), + **result('result') + } +ref_edges = [('input', 'hsigmoid'), ('hsigmoid', 'result')] + + +class HSigmoidWithClampTest(unittest.TestCase): + nodes = { + **regular_op('input', {'type': 'Parameter'}), + **regular_op('add', {'op': 'Add'}), + **regular_op('relu6', {'op': 'Clamp'}), + **regular_op('mul_2', {'op': 'Mul', 'name': 'final_mul'}), + **const('const_0', float_array([0.0])), + **const('const_3', float_array([3.0])), + **const('const_6', float_array([6.0])), + **const('const_1_6', float_array([1.0 / 6.0])), + **result('result'), + } + + edges = [('input', 'add', {'in': 0, 'out': 0}), + ('const_3', 'add', {'in': 1, 'out': 0}), + ('add', 'relu6', {'in': 0, 'out': 0}), + ('const_0', 'relu6', {'in': 1, 'out': 0}), + ('const_6', 'relu6', {'in': 2, 'out': 0}), + ('relu6', 'mul_2', {'in': 1, 'out': 0}), + ('const_1_6', 'mul_2', {'in': 1, 'out': 0}), + ('mul_2', 'result', {'in': 0, 'out': 0})] + + def test_hsigmoid_with_clamp(self): + graph = build_graph_with_edge_attrs(self.nodes, self.edges, {}) + + graph_ref = build_graph(ref_nodes, ref_edges) + graph.stage = 'front' + + HSigmoidWithClamp().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + self.assertTrue(len(graph.get_op_nodes(name='final_mul')) == 1 and + graph.get_op_nodes(name='final_mul')[0].op == 'HSigmoid') + + def test_hsigmoid_with_clamp_wrong_constant(self): + graph = build_graph_with_edge_attrs(self.nodes, self.edges, {'const_0': {'value': float_array([0.00001])}}) + + graph_ref = graph.copy() + graph.stage = 'front' + + HSigmoidWithClamp().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + + def test_hsigmoid_with_clamp_different_tensors(self): + graph = build_graph_with_edge_attrs({ + **regular_op('input', {'type': 'Parameter'}), + **regular_op('input_2', {'type': 'Parameter'}), + **regular_op('add', {'op': 'Add'}), + **regular_op('relu6', {'op': 'Clamp'}), + **regular_op('mul', {'op': 'Mul'}), + **regular_op('mul_2', {'op': 'Mul', 'name': 'final_mul'}), + **const('const_0', float_array([0.0])), + **const('const_3', float_array([3.0])), + **const('const_6', float_array([6.0])), + **const('const_1_6', float_array([1.0 / 6.0])), + **result('result'), + }, [('input', 'mul', {'in': 0, 'out': 0}), + ('input_2', 'add', {'in': 0, 'out': 0}), + ('const_3', 'add', {'in': 1, 'out': 0}), + ('add', 'relu6', {'in': 0, 'out': 0}), + ('const_0', 'relu6', {'in': 1, 'out': 0}), + ('const_6', 'relu6', {'in': 2, 'out': 0}), + ('relu6', 'mul', {'in': 1, 'out': 0}), + ('mul', 'mul_2', {'in': 0, 'out': 0}), + ('const_1_6', 'mul_2', {'in': 1, 'out': 0}), + ('mul_2', 'result', {'in': 0, 'out': 0})]) + + graph_ref = graph.copy() + graph.stage = 'front' + + HSigmoidWithClamp().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + + +class HSigmoidWithMinMaxTest(unittest.TestCase): + nodes = { + **regular_op('input', {'type': 'Parameter'}), + **regular_op('add', {'op': 'Add'}), + **regular_op('max', {'op': 'Maximum'}), + **regular_op('min', {'op': 'Minimum'}), + **regular_op('mul_2', {'op': 'Mul', 'name': 'final_mul'}), + **const('const_0', float_array([0.0])), + **const('const_3', float_array([3.0])), + **const('const_6', float_array([6.0])), + **const('const_1_6', float_array([1.0 / 6.0])), + **result('result'), + } + + edges = [('input', 'add', {'in': 0, 'out': 0}), + ('const_3', 'add', {'in': 1, 'out': 0}), + ('add', 'max', {'in': 0, 'out': 0}), + ('const_0', 'max', {'in': 1, 'out': 0}), + ('max', 'min', {'in': 0, 'out': 0}), + ('const_6', 'min', {'in': 1, 'out': 0}), + ('min', 'mul_2', {'in': 0, 'out': 0}), + ('const_1_6', 'mul_2', {'in': 1, 'out': 0}), + ('mul_2', 'result', {'in': 0, 'out': 0})] + + def test_hsigmoid_with_min_max(self): + graph = build_graph_with_edge_attrs(self.nodes, self.edges, {}) + + graph_ref = build_graph(ref_nodes, ref_edges) + graph.stage = 'front' + + HSigmoidWithMinMax().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + self.assertTrue(len(graph.get_op_nodes(name='final_mul')) == 1 and + graph.get_op_nodes(name='final_mul')[0].op == 'HSigmoid') + + def test_hsigmoid_with_min_max_wrong_constant(self): + graph = build_graph_with_edge_attrs(self.nodes, self.edges, {'const_0': {'value': float_array([0.00001])}}) + + graph_ref = graph.copy() + graph.stage = 'front' + + HSigmoidWithMinMax().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + + def test_hsigmoid_with_min_max_different_tensors(self): + graph = build_graph_with_edge_attrs({ + **regular_op('input', {'type': 'Parameter'}), + **regular_op('input_2', {'type': 'Parameter'}), + **regular_op('add', {'op': 'Add'}), + **regular_op('max', {'op': 'Maximum'}), + **regular_op('min', {'op': 'Minimum'}), + **regular_op('mul', {'op': 'Mul'}), + **regular_op('mul_2', {'op': 'Mul', 'name': 'final_mul'}), + **const('const_0', float_array([0.0])), + **const('const_3', float_array([3.0])), + **const('const_6', float_array([6.0])), + **const('const_1_6', float_array([1.0 / 6.0])), + **result('result'), + }, [('input_2', 'mul', {'in': 1, 'out': 0}), + ('input', 'add', {'in': 0, 'out': 0}), + ('const_3', 'add', {'in': 1, 'out': 0}), + ('add', 'max', {'in': 0, 'out': 0}), + ('const_0', 'max', {'in': 1, 'out': 0}), + ('max', 'min', {'in': 0, 'out': 0}), + ('const_6', 'min', {'in': 1, 'out': 0}), + ('min', 'mul', {'in': 0, 'out': 0}), + ('mul', 'mul_2', {'in': 0, 'out': 0}), + ('const_1_6', 'mul_2', {'in': 1, 'out': 0}), + ('mul_2', 'result', {'in': 0, 'out': 0})]) + + graph_ref = graph.copy() + graph.stage = 'front' + + HSigmoidWithMinMax().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + + +class HSigmoidWithReluDivTest(unittest.TestCase): + nodes = { + **regular_op('input', {'type': 'Parameter'}), + **regular_op('add', {'op': 'Add'}), + **regular_op('relu', {'op': 'ReLU'}), + **regular_op('min', {'op': 'Minimum'}), + **regular_op('div', {'op': 'Div', 'name': 'final_div'}), + **const('add_const', float_array([3.0])), + **const('min_const', float_array([6.0])), + **const('div_const', float_array([6.0])), + **result('result'), + } + + edges = [('input', 'add', {'in': 0, 'out': 0}), + ('add_const', 'add', {'in': 1, 'out': 0}), + ('add', 'relu', {'in': 0, 'out': 0}), + ('relu', 'min', {'in': 0, 'out': 0}), + ('min_const', 'min', {'in': 1, 'out': 0}), + ('min', 'div', {'in': 0, 'out': 0}), + ('div_const', 'div', {'in': 1, 'out': 0}), + ('div', 'result', {'in': 0, 'out': 0})] + + def test_hsigmoid_with_relu_div(self): + graph = build_graph_with_edge_attrs(self.nodes, self.edges, {}) + + graph_ref = build_graph(ref_nodes, ref_edges) + graph.stage = 'front' + + HSigmoidWithReluDiv().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + self.assertTrue(len(graph.get_op_nodes(name='final_div')) == 1 and + graph.get_op_nodes(name='final_div')[0].op == 'HSigmoid') + self.assertTrue(graph.get_op_nodes(name='final_div')[0].out_nodes()[0].node == 'result') + + def test_hsigmoid_with_relu_div_wrong_constant(self): + graph = build_graph_with_edge_attrs(self.nodes, self.edges, {'add_const': {'value': float_array([0.00001])}}) + + graph_ref = graph.copy() + graph.stage = 'front' + + HSigmoidWithReluDiv().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + + def test_hsigmoid_with_relu_div_different_tensors(self): + graph = build_graph_with_edge_attrs({ + **regular_op('input', {'type': 'Parameter'}), + **regular_op('input_2', {'type': 'Parameter'}), + **regular_op('add', {'op': 'Add'}), + **regular_op('max', {'op': 'Maximum'}), + **regular_op('min', {'op': 'Minimum'}), + **regular_op('mul', {'op': 'Mul'}), + **regular_op('mul_2', {'op': 'Mul', 'name': 'final_mul'}), + **const('const_0', float_array([0.0])), + **const('const_3', float_array([3.0])), + **const('const_6', float_array([6.0])), + **const('const_1_6', float_array([1.0 / 6.0])), + **result('result'), + }, [('input_2', 'mul', {'in': 1, 'out': 0}), + ('input', 'add', {'in': 0, 'out': 0}), + ('const_3', 'add', {'in': 1, 'out': 0}), + ('add', 'max', {'in': 0, 'out': 0}), + ('const_0', 'max', {'in': 1, 'out': 0}), + ('max', 'min', {'in': 0, 'out': 0}), + ('const_6', 'min', {'in': 1, 'out': 0}), + ('min', 'mul', {'in': 0, 'out': 0}), + ('mul', 'mul_2', {'in': 0, 'out': 0}), + ('const_1_6', 'mul_2', {'in': 1, 'out': 0}), + ('mul_2', 'result', {'in': 0, 'out': 0})]) + + graph_ref = graph.copy() + graph.stage = 'front' + + HSigmoidWithReluDiv().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + + +class HSigmoidWithReluMulTest(unittest.TestCase): + nodes = { + **regular_op('input', {'type': 'Parameter'}), + **regular_op('add', {'op': 'Add'}), + **regular_op('relu', {'op': 'ReLU'}), + **regular_op('min', {'op': 'Minimum'}), + **regular_op('mul', {'op': 'Mul', 'name': 'final_mul'}), + **const('add_const', float_array([3.0])), + **const('min_const', float_array([6.0])), + **const('mul_const', float_array([1.0/6.0])), + **result('result'), + } + + edges = [('input', 'add', {'in': 0, 'out': 0}), + ('add_const', 'add', {'in': 1, 'out': 0}), + ('add', 'relu', {'in': 0, 'out': 0}), + ('relu', 'min', {'in': 0, 'out': 0}), + ('min_const', 'min', {'in': 1, 'out': 0}), + ('min', 'mul', {'in': 0, 'out': 0}), + ('mul_const', 'mul', {'in': 1, 'out': 0}), + ('mul', 'result', {'in': 0, 'out': 0})] + + def test_hsigmoid_with_relu_mul(self): + graph = build_graph_with_edge_attrs(self.nodes, self.edges, {}) + + graph_ref = build_graph(ref_nodes, ref_edges) + graph.stage = 'front' + + HSigmoidWithReluMul().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + self.assertTrue(len(graph.get_op_nodes(name='final_mul')) == 1 and + graph.get_op_nodes(name='final_mul')[0].op == 'HSigmoid') + self.assertTrue(graph.get_op_nodes(name='final_mul')[0].out_nodes()[0].node == 'result') + + def test_hsigmoid_with_relu_mul_wrong_constant(self): + graph = build_graph_with_edge_attrs(self.nodes, self.edges, {'add_const': {'value': float_array([0.00001])}}) + + graph_ref = graph.copy() + graph.stage = 'front' + + HSigmoidWithReluMul().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) + + def test_hsigmoid_with_relu_mul_different_tensors(self): + graph = build_graph_with_edge_attrs({ + **regular_op('input', {'type': 'Parameter'}), + **regular_op('input_2', {'type': 'Parameter'}), + **regular_op('add', {'op': 'Add'}), + **regular_op('max', {'op': 'Maximum'}), + **regular_op('min', {'op': 'Minimum'}), + **regular_op('mul', {'op': 'Mul'}), + **regular_op('mul_2', {'op': 'Mul', 'name': 'final_mul'}), + **const('const_0', float_array([0.0])), + **const('const_3', float_array([3.0])), + **const('const_6', float_array([6.0])), + **const('const_1_6', float_array([1.0 / 6.0])), + **result('result'), + }, [('input_2', 'mul', {'in': 1, 'out': 0}), + ('input', 'add', {'in': 0, 'out': 0}), + ('const_3', 'add', {'in': 1, 'out': 0}), + ('add', 'max', {'in': 0, 'out': 0}), + ('const_0', 'max', {'in': 1, 'out': 0}), + ('max', 'min', {'in': 0, 'out': 0}), + ('const_6', 'min', {'in': 1, 'out': 0}), + ('min', 'mul', {'in': 0, 'out': 0}), + ('mul', 'mul_2', {'in': 0, 'out': 0}), + ('const_1_6', 'mul_2', {'in': 1, 'out': 0}), + ('mul_2', 'result', {'in': 0, 'out': 0})]) + + graph_ref = graph.copy() + graph.stage = 'front' + + HSigmoidWithReluMul().find_and_replace_pattern(graph) + + (flag, resp) = compare_graphs(graph, graph_ref, 'result') + self.assertTrue(flag, resp) diff --git a/model-optimizer/extensions/ops/activation_ops.py b/model-optimizer/extensions/ops/activation_ops.py index 49396f4..c560f80 100644 --- a/model-optimizer/extensions/ops/activation_ops.py +++ b/model-optimizer/extensions/ops/activation_ops.py @@ -248,6 +248,12 @@ class HSwish(Activation): operation = staticmethod(lambda x: x * np.minimum(np.maximum(x + 3.0, 0.0), 6.0) / 6.0) +class HSigmoid(Activation): + op = 'HSigmoid' + version = 'opset5' + operation = staticmethod(lambda x: np.minimum(np.maximum(x + 3.0, 0.0), 6.0) / 6.0) + + class Swish(Op): op = 'Swish' -- 2.7.4