Add ShapeOfConstFolding transform (#5858)

* Add ShapeOfConstFolding transform

* Add unit tests

* Update bom file

* Update transform file

* Hot fix

* Fix midle replaser

* Update unit tests

* Fix get value

* Refactoring Const Folding transformation. Move to back

* Update bom file

* Remove unuse code

* Add some unit tests

* Refactoring unit test

* Hot fix
This commit is contained in:
iliya mironov authored and GitHub committed 2021-06-09 12:14:39 +03:00
1 parent cbd48cf15f
commit 421465adc1
3 files changed
+200

No files matched your search

@@ -57,6 +57,7 @@ extensions/back/ReverseInputChannels.py
extensions/back/RNNSequenceTypeRename.py
extensions/back/ScalarConstNormalize.py
extensions/back/SelectBroadcast.py
extensions/back/ShapeOfConstFolding.py
extensions/back/ShuffleChannelPatternOptimization.py
extensions/back/ShufflenetReLUReorder.py
extensions/back/SpecialNodesFinalization.py
@@ -0,0 +1,29 @@
# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
from mo.back.replacement import BackReplacementPattern
from mo.graph.graph import Graph, rename_nodes
from mo.ops.const import Const
class ShapeOfConstFolding(BackReplacementPattern):
"""
The transformation folds ShapeOf(Const) -> Const
"""
enabled = True
def run_after(self):
from extensions.back.MatMulNormalizer import SmartReshape_HC_Reshape_MatMul
return [SmartReshape_HC_Reshape_MatMul]
def find_and_replace_pattern(self, graph: Graph):
for shapeof_node in graph.get_op_nodes(op='ShapeOf'):
in_node = shapeof_node.in_port(0).get_source().node
if in_node.op == 'Const':
shapeof_node.in_port(0).disconnect()
shape_name = shapeof_node.soft_get('name', shapeof_node.id)
shape_value = shapeof_node.out_port(0).data.get_value()
shape_const_node = Const(graph, {'name': shape_name + '/ExecutionConstValue',
'value': shape_value}).create_node()
shapeof_node.out_port(0).get_connection().set_source(shape_const_node.out_port(0))
rename_nodes([(shapeof_node, shape_name + '/TBD'), (shape_const_node, shape_name)])
@@ -0,0 +1,170 @@
# Copyright (C) 2018-2021 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import unittest
import numpy as np
from extensions.back.ShapeOfConstFolding import ShapeOfConstFolding
from mo.front.common.partial_infer.eltwise import eltwise_infer
from mo.front.common.partial_infer.utils import int64_array
from mo.utils.ir_engine.compare_graphs import compare_graphs
from unit_tests.utils.graph import build_graph
const_value = np.random.rand(1, 3, 30, 30)
nodes_attributes = {'input': {'shape': int64_array([1, 3, 30, 30]), 'type': 'Parameter', 'kind': 'op',
'op': 'Parameter'},
'input_data': {'value': None, 'shape': int64_array([1, 3, 30, 30]), 'kind': 'data'},
'const': {'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': const_value},
'const_data': {'kind': 'data', 'value': const_value},
'shapeof_input': {'kind': 'op', 'op': 'ShapeOf', 'value': int64_array([1, 3, 30, 30])},
'shapeof_input_data': {'value': None, 'shape': None, 'kind': 'data',
'value': int64_array([1, 3, 30, 30])},
'shapeof_const': {'kind': 'op', 'op': 'ShapeOf', 'value': int64_array([1, 3, 30, 30])},
'shapeof_const_data': {'value': None, 'shape': None, 'kind': 'data',
'value': int64_array([1, 3, 30, 30])},
'mul': {'kind': 'op', 'op': 'Mul', 'infer': lambda node: eltwise_infer(node, lambda a, b: a * b)},
'mul_data': {'kind': 'data', 'value': np.array([1, 9, 900, 900])},
'last': {'kind': 'op', 'op': 'Result'},
# new nodes
'new_const_shapeof': {'type': 'Const', 'kind': 'op', 'op': 'Const',
'value': int64_array([1, 3, 30, 30])}
}
const_value2 = np.random.rand(30, 30)
nodes_attributes2 = {'input': {'shape': int64_array([1, 3, 30, 30]), 'type': 'Parameter', 'kind': 'op',
'op': 'Parameter'},
'input_data': {'value': None, 'shape': int64_array([1, 3, 30, 30]), 'kind': 'data'},
'const': {'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': const_value2},
'const_data': {'kind': 'data', 'value': const_value2},
'shapeof_const': {'kind': 'op', 'op': 'ShapeOf', 'value': int64_array([2700, 30])},
'shapeof_const_data': {'value': int64_array([2700, 30]), 'shape': None, 'kind': 'data'},
'gather': {'kind': 'op', 'op': 'Gather', 'batch_dims': 0},
'gather_data': {'kind': 'data'},
'const_concat': {'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': [1]},
'const_concat_data': {'kind': 'data', 'value': [1]},
'concat': {'kind': 'op', 'op': 'Concat'},
'concat_data': {'kind': 'data'},
'reshape': {'kind': 'op', 'op': 'Reshape'},
'reshape_data': {'kind': 'data'},
'matmul': {'kind': 'op', 'op': 'MatMul'},
'matmul_data': {'kind': 'data'},
'last': {'kind': 'op', 'op': 'Result'},
# new nodes
'new_const_shapeof': {'type': 'Const', 'kind': 'op', 'op': 'Const',
'value': int64_array([2700, 30])},
}
class ShapeOfConstFoldingTests(unittest.TestCase):
def test_const_with_one_output(self):
graph = build_graph(nodes_attributes,
[('input', 'input_data'),
('input_data', 'shapeof_input'),
('shapeof_input', 'shapeof_input_data'),
('shapeof_input_data', 'mul'),
('const', 'const_data'),
('const_data', 'shapeof_const'),
('shapeof_const', 'shapeof_const_data'),
('shapeof_const_data', 'mul'),
('mul', 'mul_data'),
('mul_data', 'last')],
{
'input': {'shape': int64_array([1, 3, 30, 30])},
'input_data': {'shape': int64_array([1, 3, 30, 30])},
'shapeof_input': {'value': int64_array([1, 3, 30, 30])},
'shapeof_input_data': {'value': int64_array([1, 3, 30, 30])},
'const': {'value': const_value},
'const_data': {'value': const_value},
'shapeof_const': {'value': int64_array([1, 3, 30, 30])},
'shapeof_const_data': {'value': int64_array([1, 3, 30, 30])},
'mul_data': {'value': int64_array([1, 9, 900, 900])},
},
nodes_with_edges_only=True)
graph_ref = build_graph(nodes_attributes,
[('input', 'input_data'),
('input_data', 'shapeof_input'),
('shapeof_input', 'shapeof_input_data'),
('shapeof_input_data', 'mul'),
('new_const_shapeof', 'shapeof_const_data'),
('shapeof_const_data', 'mul'),
('mul', 'mul_data'),
('mul_data', 'last')],
{
'input': {'shape': int64_array([1, 3, 30, 30])},
'input_data': {'shape': int64_array([1, 3, 30, 30])},
'shapeof_input': {'value': int64_array([1, 3, 30, 30])},
'shapeof_input_data': {'value': int64_array([1, 3, 30, 30])},
'new_const_shapeof': {'value': int64_array([1, 3, 30, 30])},
'shapeof_const_data': {'value': int64_array([1, 3, 30, 30])},
'mul_data': {'value': int64_array([1, 9, 900, 900])},
},
nodes_with_edges_only=True)
ShapeOfConstFolding().find_and_replace_pattern(graph)
(flag, resp) = compare_graphs(graph, graph_ref, 'last')
self.assertTrue(flag, resp)
def test_const_with_two_outputs(self):
graph = build_graph(nodes_attributes2,
[('input', 'input_data'),
('input_data', 'reshape'),
('const', 'const_data'),
('const_data', 'shapeof_const'),
('shapeof_const', 'shapeof_const_data'),
('shapeof_const_data', 'gather'),
('gather', 'gather_data'),
('const_concat', 'const_concat_data'),
('const_concat_data', 'concat'),
('gather_data', 'concat'),
('concat', 'reshape'),
('reshape', 'reshape_data'),
('reshape_data', 'matmul'),
('const_data', 'matmul'),
('matmul', 'matmul_data'),
('matmul_data', 'last')
],
{
'input': {'shape': int64_array([1, 3, 30, 30])},
'input_data': {'shape': int64_array([1, 3, 30, 30])},
'shapeof_const': {'value': int64_array([2700, 30])},
'shapeof_const_data': {'value': int64_array([2700, 30])},
},
nodes_with_edges_only=True)
graph_ref = build_graph(nodes_attributes2,
[('input', 'input_data'),
('input_data', 'reshape'),
('new_const_shapeof', 'shapeof_const_data'),
('shapeof_const_data', 'gather'),
('gather', 'gather_data'),
('const_concat', 'const_concat_data'),
('const_concat_data', 'concat'),
('gather_data', 'concat'),
('concat', 'reshape'),
('reshape', 'reshape_data'),
('reshape_data', 'matmul'),
('const', 'const_data'),
('const_data', 'matmul'),
('matmul', 'matmul_data'),
('matmul_data', 'last')],
{
'input': {'shape': int64_array([1, 3, 30, 30])},
'input_data': {'shape': int64_array([1, 3, 30, 30])},
'new_const_shapeof': {'value': int64_array([2700, 30])},
'shapeof_const_data': {'value': int64_array([2700, 30])},
},
nodes_with_edges_only=True)
ShapeOfConstFolding().find_and_replace_pattern(graph)
(flag, resp) = compare_graphs(graph, graph_ref, 'last')
self.assertTrue(flag, resp)