[MO] fix MarkNodesWithShapeValues (#5808)
* fix marking of nodes with shape values: corrected 'leaky' starting condition
* cleaned up code
* fixed t2t type collision error: removed strict assert from Pow; now type_infer is same as for other eltwise ops; added warnings about type alignment
* type cast for Pow according to ONNX spec
* fix highlight in dump_graph_for_graphviz
* soft_get('op')
* Revert "soft_get('op')"
This reverts commit cadfe18f
* Revert "type cast for Pow according to ONNX spec"
This reverts commit bf85ebf8
* applied review comments
* comment for ShapeOf bfs, removed Error from elementwise op
* reverted back dump_graph_for_graphviz: fill_color -> node_attrs
* applied last review comments: returned back Error, added type_infer into unit-test utils
This commit is contained in:
1 parent
06811924f4
commit
d9d63d0d7e
5 files changed
+193
-63
No files matched your search
@@ -2,12 +2,30 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import logging as log
|
||||
from typing import List
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.middle.MarkSubgraphsWithCorrectLayout import MarkSubGraphsWithCorrectLayout
|
||||
from mo.back.replacement import BackReplacementPattern
|
||||
from mo.graph.graph import Graph
|
||||
from mo.graph.graph import Graph, Node
|
||||
|
||||
shape_accepting_ops = {
|
||||
'Interpolate': [1, 2], # sizes, scales inputs
|
||||
'Reshape': [1], # shape
|
||||
'Broadcast': [1], # target_shape
|
||||
'ConvBackPropData ': [2], # output_shape
|
||||
'GroupConvolutionBackpropData ': [2], # output_shape
|
||||
'BatchToSpace': [1, 2, 3], # block_shape, crops_begin, crops_end
|
||||
'SpaceToBatch': [1, 2, 3], # block_shape, pads_begin, pads_end
|
||||
'StridedSlice': [1, 2, 3], # begin, end, strides
|
||||
'VariadicSplit': [2], # split_lengths
|
||||
'Tile': [1], # repeats input
|
||||
'TopK': [1], # K input
|
||||
'Pad': [1, 2], # pads_begin, pads_end
|
||||
'Range': [0, 1, 2], # start, stop, step inputs
|
||||
'OneHot': [1], # depth input
|
||||
}
|
||||
|
||||
|
||||
class MarkNodesWithShapeValues(BackReplacementPattern):
|
||||
@@ -34,45 +52,44 @@ class MarkNodesWithShapeValues(BackReplacementPattern):
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def get_operations_with_shape_inputs():
|
||||
return {
|
||||
'Interpolate': [1, 2], # sizes, scales inputs
|
||||
'Reshape': [1], # shape
|
||||
'Broadcast': [1], # target_shape
|
||||
'ConvBackPropData ': [2], # output_shape
|
||||
'GroupConvolutionBackpropData ': [2], # output_shape
|
||||
'BatchToSpace': [1, 2, 3], # block_shape, crops_begin, crops_end
|
||||
'SpaceToBatch': [1, 2, 3], # block_shape, pads_begin, pads_end
|
||||
'StridedSlice': [1, 2, 3], # begin, end, strides
|
||||
'VariadicSplit': [2], # split_lengths
|
||||
'Tile': [1], # repeats input
|
||||
'TopK': [1], # K input
|
||||
'Pad': [1, 2], # pads_begin, pads_end
|
||||
'Range': [0, 1, 2], # start, stop, step inputs
|
||||
'OneHot': [1], # depth input
|
||||
}
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
shape_input_ops_map = self.get_operations_with_shape_inputs()
|
||||
|
||||
nodes_with_shape_inputs = []
|
||||
def get_nodes_with_shape_inputs(graph: Graph) -> List[Node]:
|
||||
shape_accepting_nodes = []
|
||||
for node in graph.get_op_nodes():
|
||||
if node.soft_get('type') in shape_input_ops_map:
|
||||
nodes_with_shape_inputs.append(node)
|
||||
if node.soft_get('type') in shape_accepting_ops:
|
||||
shape_accepting_nodes.append(node)
|
||||
return shape_accepting_nodes
|
||||
|
||||
start_nodes = []
|
||||
@staticmethod
|
||||
def get_shape_returning_start_nodes(nodes_with_shape_inputs: List[Node]) -> List[Node]:
|
||||
sources = []
|
||||
for node in nodes_with_shape_inputs:
|
||||
start_nodes.extend(
|
||||
[node.in_port(port_idx).get_source().node for port_idx in shape_input_ops_map[node.type] if
|
||||
node.is_in_port_connected(port_idx)])
|
||||
assert node.soft_get('type') in shape_accepting_ops
|
||||
for port_idx in shape_accepting_ops[node.soft_get('type')]:
|
||||
if not node.is_in_port_connected(port_idx):
|
||||
continue
|
||||
source_node = node.in_port(port_idx).get_source().node
|
||||
# no need to start BFS for ShapeOf nodes, indeed if there is a ShapeOf it's an end of BFS
|
||||
if source_node.soft_get('type') != 'ShapeOf':
|
||||
sources.append(source_node)
|
||||
return sources
|
||||
|
||||
condition = lambda node: node.soft_get('type') != 'ShapeOf'
|
||||
nodes_with_shape_values = MarkSubGraphsWithCorrectLayout.bfs(start_nodes, set(), condition, forward=False)
|
||||
for node in nodes_with_shape_values:
|
||||
@staticmethod
|
||||
def mark_nodes(shape_returning_nodes: List[Node]):
|
||||
for node in shape_returning_nodes:
|
||||
node['returns_shape_value'] = True
|
||||
if node.soft_get('type') == 'Const':
|
||||
if node.value.dtype == np.float32:
|
||||
node.out_node(0)['correct_data_type'] = True
|
||||
elif node.value.dtype in [np.float16, np.float64]:
|
||||
log.debug('Const nodes {} with shape values have {} type'.format(node.soft_get('name', node.id),
|
||||
node.value.dtype))
|
||||
log.error("Const node '{}' returns shape values of '{}' type but it must be integer or float32. "
|
||||
"During Elementwise type inference will attempt to cast to float32".
|
||||
format(node.soft_get('name', node.id), node.value.dtype), extra={'is_warning': True})
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
shape_accepting_nodes = self.get_nodes_with_shape_inputs(graph)
|
||||
|
||||
condition = lambda node: node.soft_get('type') != 'ShapeOf'
|
||||
shape_returning_start_nodes = self.get_shape_returning_start_nodes(shape_accepting_nodes)
|
||||
shape_returning_nodes = MarkSubGraphsWithCorrectLayout.bfs(shape_returning_start_nodes, set(),
|
||||
condition, forward=False)
|
||||
self.mark_nodes(shape_returning_nodes)
|
||||
@@ -10,6 +10,7 @@ from mo.graph.graph import Graph, Node
|
||||
from mo.middle.passes.infer import copy_type_infer
|
||||
from mo.ops.op import Op
|
||||
from mo.pipeline.common import convert_const_node_value_type
|
||||
from mo.utils.error import Error
|
||||
|
||||
|
||||
def override_data_type_of_constant(node: Node):
|
||||
@@ -22,13 +23,19 @@ def override_data_type_of_constant(node: Node):
|
||||
# power value 2, or when replacing Neg operation with Mul with -1 as second input.
|
||||
in_node_0 = node.in_port(0).get_source().node
|
||||
in_node_1 = node.in_port(1).get_source().node
|
||||
|
||||
if in_node_0.op != 'Const' and in_node_1.op != 'Const':
|
||||
raise Error("Elementwise operation '{}' has inputs of different data types: '{}' and '{}' "
|
||||
"that cannot be aligned".format(node.soft_get('name'), in_type_0, in_type_1))
|
||||
|
||||
if in_node_0.op == 'Const':
|
||||
convert_const_node_value_type(in_node_0, in_type_1)
|
||||
elif in_node_1.op == 'Const':
|
||||
convert_const_node_value_type(in_node_1, in_type_0)
|
||||
node_to_convert, src_type, dst_type = in_node_0, in_type_0, in_type_1
|
||||
else:
|
||||
log.error('Elementwise operation {} has inputs of different data types: {} and {}'.format(
|
||||
node.soft_get('name'), in_type_0, in_type_1))
|
||||
node_to_convert, src_type, dst_type = in_node_1, in_type_1, in_type_0
|
||||
log.error("Changing Const node '{}' data type from {} to {} for Elementwise operation".format(
|
||||
node_to_convert.soft_get('name', node_to_convert.id), src_type, dst_type),
|
||||
extra={'is_warning': True})
|
||||
convert_const_node_value_type(node_to_convert, dst_type)
|
||||
|
||||
|
||||
class Elementwise(Op):
|
||||
@@ -129,15 +136,6 @@ class Pow(Elementwise):
|
||||
return np.array(a.astype(np.float32) ** b, dtype=np.float32)
|
||||
return a ** b
|
||||
|
||||
@staticmethod
|
||||
def type_infer(node):
|
||||
in_type_0 = node.in_port(0).get_data_type()
|
||||
in_type_1 = node.in_port(1).get_data_type()
|
||||
assert in_type_0 == in_type_1, \
|
||||
'Power operation {} has inputs of different data types: {} and {}'.format(
|
||||
node.soft_get('name'), in_type_0, in_type_1)
|
||||
node.out_port(0).set_data_type(in_type_0)
|
||||
|
||||
|
||||
class LogicalElementwise(Elementwise):
|
||||
@staticmethod
|
||||
|
||||
Reference in new issue
Block a user