XLNET models bugs (#1199)

* Started to write equality comparator for StridedSlice layers.

* Now considered only unique StridedSlice consumers of non-constant data nodes.

* Fixed test for the transformation ConvertGroupedStridedSlice.

* Deleted commented code.

* Small fixes.

* Moved functions unique_by and group_by_with_binary_predicate to mo/utils/utils.py.

* Deleted function collect_sequences.

* Added asserts into the constructor of StridedSlice.

* Written test for the case when 1) there are 4 StridedSlice operations; 2) 2 of StridedSlice have the same data; 3) 2 others StridedSlice have the same data; 4) all StridedSlice operations outputs are consumed by different operations.

* Added some comments.
This commit is contained in:
Vladimir Gavrilov authored and GitHub committed 2020-11-19 10:07:30 +03:00
1 parent 2ec0904d40
commit 3aed19a46a
5 files changed
+258 -91

No files matched your search

@@ -16,6 +16,7 @@
import logging as log
from copy import deepcopy
from typing import Callable
import numpy as np
@@ -28,6 +29,21 @@ from mo.ops.const import Const
from mo.ops.op import Op
from mo.ops.squeeze import Squeeze
from mo.ops.unsqueeze import Unsqueeze
from mo.utils.utils import unique_by
def strided_slices_equality(lhs: Node, rhs: Node) -> bool:
"""
Equality criterion for StridedSlice layers.
:param lhs: the first StridedSlice layer
:param rhs: the second StridedSlice layer
:return: True, if lhs and rhs have identical attributes 'slices', 'begin_mask', 'end_mask', 'ellipsis_mask',
'new_axis_mask', 'shrink_axis_mask', and False otherwise.
"""
for attr in ['slices', 'new_axis_mask', 'shrink_axis_mask', 'begin_mask', 'end_mask', 'ellipsis_mask']:
if not np.array_equal(lhs[attr], rhs[attr]):
return False
return True
class ConvertGroupedStridedSlice(MiddleReplacementPattern):
@@ -68,8 +84,10 @@ class ConvertGroupedStridedSlice(MiddleReplacementPattern):
input_shape = np.array(input_data.shape)
# Get all StridedSlice consumers
# Get all unique StridedSlice consumers
out_nodes = [node for node in input_data.out_nodes() if node.op == 'StridedSlice' and node.in_node(0).name == input_data.name]
sorted_out_nodes = sorted(out_nodes, key=lambda n: list(n.slices))
out_nodes = unique_by(sorted_out_nodes, strided_slices_equality)
if len(out_nodes) <= 1:
continue
@@ -36,14 +36,25 @@ nodes_attributes = {
# StridedSlice layers
'sslice_1': {'type': None, 'kind': 'op', 'op': 'StridedSlice', 'slices': None,
'shrink_axis_mask': np.array([0, 0, 0, 0])},
'shrink_axis_mask': np.array([0, 0, 0, 0]), 'begin_mask': int64_array([1, 1, 1, 1]),
'end_mask': int64_array([1, 1, 1, 1]), 'new_axis_mask': int64_array([0, 0, 0, 0]),
'ellipsis_mask': int64_array([0])},
'sslice_1_data': {'value': None, 'shape': None, 'kind': 'data'},
'sslice_2': {'type': None, 'kind': 'op', 'op': 'StridedSlice', 'slices': None,
'shrink_axis_mask': np.array([0, 0, 0, 0])},
'shrink_axis_mask': np.array([0, 0, 0, 0]), 'begin_mask': int64_array([1, 1, 1, 1]),
'end_mask': int64_array([1, 1, 1, 1]), 'new_axis_mask': int64_array([0, 0, 0, 0]),
'ellipsis_mask': int64_array([0])},
'sslice_2_data': {'value': None, 'shape': None, 'kind': 'data'},
'sslice_3': {'type': None, 'kind': 'op', 'op': 'StridedSlice', 'slices': None,
'shrink_axis_mask': np.array([0, 0, 0, 0])},
'shrink_axis_mask': np.array([0, 0, 0, 0]), 'begin_mask': int64_array([1, 1, 1, 1]),
'end_mask': int64_array([1, 1, 1, 1]), 'new_axis_mask': int64_array([0, 0, 0, 0]),
'ellipsis_mask': int64_array([0])},
'sslice_3_data': {'value': None, 'shape': None, 'kind': 'data'},
'sslice_4': {'type': None, 'kind': 'op', 'op': 'StridedSlice', 'slices': None,
'shrink_axis_mask': np.array([0, 0, 0, 0]), 'begin_mask': int64_array([1, 1, 1, 1]),
'end_mask': int64_array([1, 1, 1, 1]), 'new_axis_mask': int64_array([0, 0, 0, 0]),
'ellipsis_mask': int64_array([0])},
'sslice_4_data': {'value': None, 'shape': None, 'kind': 'data'},
# Split layer
'axis_const': {'kind': 'op'},
@@ -81,6 +92,16 @@ nodes_attributes = {
'sslice_2/Unsqueeze_new_data': {'value': None, 'shape': None, 'kind': 'data'},
'sslice_2/unsqueeze_const': {'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': int64_array([2])},
'sslice_2/unsqueeze_const_data': {'kind': 'data', 'value': None, 'shape': None},
# Activations
'abs': {'type': None, 'value': None, 'kind': 'op', 'op': 'Abs'},
'abs_data': {'value': None, 'shape': None, 'kind': 'data'},
'relu': {'type': None, 'value': None, 'kind': 'op', 'op': 'ReLU'},
'relu_data': {'value': None, 'shape': None, 'kind': 'data'},
'erf': {'type': None, 'value': None, 'kind': 'op', 'op': 'Erf'},
'erf_data': {'value': None, 'shape': None, 'kind': 'data'},
'gelu': {'type': None, 'value': None, 'kind': 'op', 'op': 'Gelu'},
'gelu_data': {'value': None, 'shape': None, 'kind': 'data'},
}
one_strided_slice_case_node_attributes = {
@@ -653,6 +674,110 @@ class ConvertGroupedStridedSliceTests(unittest.TestCase):
(flag, resp) = compare_graphs(graph, graph_ref, 'op_output', check_op_attrs=True)
self.assertTrue(flag, resp)
# Test for case when
# 1) There are 4 StridedSlice operations.
# 2) 2 of StridedSlice have the same data.
# 3) 2 others StridedSlice have the same data.
# 4) All StridedSlice operations outputs are consumed by different operations.
def test_10(self):
graph = build_graph(nodes_attributes,
[('placeholder_1', 'placeholder_1_data'),
('placeholder_1_data', 'sslice_1'),
('sslice_1', 'sslice_1_data'),
('placeholder_1_data', 'sslice_2'),
('sslice_2', 'sslice_2_data'),
('placeholder_1_data', 'sslice_3'),
('sslice_3', 'sslice_3_data'),
('placeholder_1_data', 'sslice_4'),
('sslice_4', 'sslice_4_data'),
('sslice_1_data', 'abs'),
('abs', 'abs_data'),
('sslice_2_data', 'relu'),
('relu', 'relu_data'),
('sslice_3_data', 'erf'),
('erf', 'erf_data'),
('sslice_4_data', 'gelu'),
('gelu', 'gelu_data'),
('abs_data', 'concat_1'),
('relu_data', 'concat_1'),
('erf_data', 'concat_1'),
('gelu_data', 'concat_1'),
('concat_1', 'concat_1_data'),
('concat_1_data', 'op_output')
],
{'placeholder_1_data': {'shape': np.array([1, 54, 54, 3])},
'sslice_1': {'slices': np.array(
[slice(0, 1, 1), slice(0, 30, 1), slice(0, 54, 1), slice(0, 3, 1)])},
'sslice_1_data': {'shape': np.array([1, 30, 54, 3])},
'sslice_2': {'slices': np.array(
[slice(0, 1, 1), slice(30, 54, 1), slice(0, 54, 1), slice(0, 3, 1)])},
'sslice_2_data': {'shape': np.array([1, 24, 54, 3])},
'sslice_3': {'slices': np.array(
[slice(0, 1, 1), slice(0, 30, 1), slice(0, 54, 1), slice(0, 3, 1)])},
'sslice_3_data': {'shape': np.array([1, 30, 54, 3])},
'sslice_4': {'slices': np.array(
[slice(0, 1, 1), slice(30, 54, 1), slice(0, 54, 1), slice(0, 3, 1)])},
'sslice_4_data': {'shape': np.array([1, 24, 54, 3])},
'concat_1_data': {'shape': np.array([1, 108, 54, 3])},
'abs_data': {'shape': np.array([1, 30, 54, 3])},
'relu_data': {'shape': np.array([1, 24, 54, 3])},
'erf_data': {'shape': np.array([1, 30, 54, 3])},
'gelu_data': {'shape': np.array([1, 24, 54, 3])},
})
graph.graph['layout'] = 'NHWC'
graph_ref = build_graph(nodes_attributes,
[('placeholder_1', 'placeholder_1_data'),
('placeholder_1_data', 'split_1'),
('split_1', 'split_1_data'),
('split_1', 'split_2_data'),
('placeholder_1_data', 'sslice_3'),
('sslice_3', 'sslice_3_data'),
('placeholder_1_data', 'sslice_4'),
('sslice_4', 'sslice_4_data'),
('split_1_data', 'abs'),
('abs', 'abs_data'),
('split_2_data', 'relu'),
('relu', 'relu_data'),
('sslice_3_data', 'erf'),
('erf', 'erf_data'),
('sslice_4_data', 'gelu'),
('gelu', 'gelu_data'),
('abs_data', 'concat_1'),
('relu_data', 'concat_1'),
('erf_data', 'concat_1'),
('gelu_data', 'concat_1'),
('concat_1', 'concat_1_data'),
('axis_const', 'axis_const_data'),
('split_dim_const', 'split_dim_const_data'),
('axis_const_data', 'split_1', {'in': 1}),
('split_dim_const_data', 'split_1', {'in': 2}),
('concat_1_data', 'op_output')
],
{'placeholder_1_data': {'shape': np.array([1, 54, 54, 3])},
'split_1_data': {'shape': np.array([1, 30, 54, 3])},
'split_2_data': {'shape': np.array([1, 24, 54, 3])},
'sslice_3': {'slices': np.array(
[slice(0, 1, 1), slice(0, 30, 1), slice(0, 54, 1), slice(0, 3, 1)])},
'sslice_3_data': {'shape': np.array([1, 30, 54, 3])},
'sslice_4': {'slices': np.array(
[slice(0, 1, 1), slice(30, 54, 1), slice(0, 54, 1), slice(0, 3, 1)])},
'sslice_4_data': {'shape': np.array([1, 24, 54, 3])},
'abs_data': {'shape': np.array([1, 30, 54, 3])},
'relu_data': {'shape': np.array([1, 24, 54, 3])},
'erf_data': {'shape': np.array([1, 30, 54, 3])},
'gelu_data': {'shape': np.array([1, 24, 54, 3])},
'axis_const': {'value': 1},
'concat_1_data': {'shape': np.array([1, 108, 54, 3])},
})
pattern = ConvertGroupedStridedSlice()
pattern.find_and_replace_pattern(graph)
(flag, resp) = compare_graphs(graph, graph_ref, 'concat_1_data', check_op_attrs=True)
self.assertTrue(flag, resp)
class AddReshapeAfterStridedSliceTests(unittest.TestCase):
def test_ss_1_shrink_last(self):
@@ -987,69 +1112,75 @@ class AddReshapeAfterStridedSliceTests(unittest.TestCase):
(flag, resp) = compare_graphs(graph, graph_ref, 'sslice_2_data', check_op_attrs=True)
self.assertTrue(flag, resp)
# test case with 2 strided slices with the same parameters but different outputs
# test case when
# 1) There are 3 StridedSlice operations;
# 2) 2 of StridedSlice have the same attributes;
# 3) other StridedSlice have different attributes;
# 4) pair (some StridedSlice from the item 2, StridedSlice from the item 3) can be replaced by VariadicSplit.
def test_1(self):
graph = build_graph(nodes_attributes,
[('placeholder_1', 'placeholder_1_data'),
('placeholder_1_data', 'sslice_1'),
('sslice_1', 'sslice_1_data'),
('placeholder_1_data', 'sslice_2'),
('sslice_2', 'sslice_2_data'),
('placeholder_1_data', 'sslice_3'),
('sslice_3', 'sslice_3_data'),
('sslice_1_data', 'concat_1'),
('sslice_2_data', 'concat_1'),
('sslice_3_data', 'placeholder_2'),
('placeholder_2', 'placeholder_2_data'),
('concat_1', 'concat_1_data'),
('concat_1_data', 'op_output'),
('placeholder_2_data', 'op_output')
],
{'placeholder_1_data': {'shape': np.array([1, 227, 227, 54])},
'sslice_1': {'slices': np.array(
[slice(0, 1, 1), slice(0, 227, 1), slice(0, 227, 1), slice(0, 27, 1)])},
'sslice_1_data': {'shape': np.array([1, 227, 227, 27])},
'sslice_2': {'slices': np.array(
[slice(0, 1, 1), slice(0, 227, 1), slice(0, 227, 1), slice(27, 54, 1)])},
'sslice_2_data': {'shape': np.array([1, 227, 227, 27])},
'sslice_3': {'slices': np.array(
[slice(0, 1, 1), slice(0, 227, 1), slice(0, 227, 1), slice(0, 27, 1)])},
'sslice_3_data': {'shape': np.array([1, 227, 227, 27])},
'concat_1_data': {'shape': np.array([1, 227, 227, 54])},
}, nodes_with_edges_only=True)
[
('placeholder_1', 'placeholder_1_data'),
('placeholder_1_data', 'sslice_1'),
('sslice_1', 'sslice_1_data'),
('placeholder_1_data', 'sslice_2'),
('sslice_2', 'sslice_2_data'),
('placeholder_1_data', 'sslice_3'),
('sslice_3', 'sslice_3_data'),
('sslice_1_data', 'concat_1'),
('sslice_2_data', 'concat_1'),
('sslice_3_data', 'concat_1'),
('concat_1', 'concat_1_data'),
('concat_1_data', 'op_output'),
],
{
'placeholder_1_data': {'shape': np.array([1, 227, 227, 54])},
'sslice_1': {'slices': np.array([slice(0, 1, 1), slice(0, 227, 1), slice(0, 227, 1),
slice(0, 27, 1)])},
'sslice_1_data': {'shape': np.array([1, 227, 227, 27])},
'sslice_2': {'slices': np.array([slice(0, 1, 1), slice(0, 227, 1), slice(0, 227, 1),
slice(27, 54, 1)])},
'sslice_2_data': {'shape': np.array([1, 227, 227, 27])},
'sslice_3': {'slices': np.array([slice(0, 1, 1), slice(0, 227, 1), slice(0, 227, 1),
slice(0, 27, 1)])},
'sslice_3_data': {'shape': np.array([1, 227, 227, 27])},
'concat_1': {'axis': 3},
'concat_1_data': {'shape': np.array([1, 227, 227, 81])},
})
graph.graph['layout'] = 'NHWC'
graph_ref = build_graph(nodes_attributes,
[('placeholder_1', 'placeholder_1_data'),
('placeholder_1_data', 'split_1'),
('split_1', 'split_1_data'),
('split_1', 'split_2_data'),
('split_1_data', 'concat_1'),
('split_2_data', 'concat_1'),
('split_1_data', 'placeholder_2'),
('placeholder_2', 'placeholder_2_data'),
('concat_1', 'concat_1_data'),
('concat_1_data', 'op_output'),
('placeholder_2_data', 'op_output'),
('axis_const', 'axis_const_data'),
('split_dim_const', 'split_dim_const_data'),
('axis_const_data', 'split_1', {'in': 1}),
('split_dim_const_data', 'split_1', {'in': 2}),
],
{'placeholder_1_data': {'shape': np.array([1, 227, 227, 54])},
'axis_const': {'value': 3},
'split_1_data': {'shape': np.array([1, 227, 227, 27])},
'split_2_data': {'shape': np.array([1, 227, 227, 27])},
'concat_1_data': {'shape': np.array([1, 227, 227, 54])},
}, nodes_with_edges_only=True)
[
('placeholder_1', 'placeholder_1_data'),
('placeholder_1_data', 'sslice_3'),
('sslice_3', 'sslice_3_data'),
('placeholder_1_data', 'split_1'),
('split_1', 'split_1_data'),
('split_1', 'split_2_data'),
('axis_const', 'axis_const_data'),
('split_dim_const', 'split_dim_const_data'),
('axis_const_data', 'split_1', {'in': 1}),
('split_dim_const_data', 'split_1', {'in': 2}),
('split_1_data', 'concat_1'),
('split_2_data', 'concat_1'),
('sslice_3_data', 'concat_1'),
('concat_1', 'concat_1_data'),
('concat_1_data', 'op_output')
],
{
'placeholder_1_data': {'shape': np.array([1, 227, 227, 54])},
'sslice_3': {'slices': np.array([slice(0, 1, 1), slice(0, 227, 1), slice(0, 227, 1),
slice(0, 27, 1)])},
'sslice_3_data': {'shape': np.array([1, 227, 227, 27])},
'split_1_data': {'shape': np.array([1, 227, 227, 27])},
'split_2_data': {'shape': np.array([1, 227, 227, 27])},
'axis_const': {'op': 'Const', 'type': 'Const', 'value': 3, 'shape': []},
'axis_const_data': {'value': 3, 'shape': []},
'split_dim_const': {'op': 'Const', 'type': 'Const', 'value': np.array([27, 27])},
'split_dim_const_data': {'value': np.array([27, 27])},
'concat_1': {'axis': 3},
'concat_1_data': {'shape': np.array([1, 227, 227, 81])}
})
ConvertGroupedStridedSlice().find_and_replace_pattern(graph)
(flag, resp) = compare_graphs(graph, graph_ref, 'concat_1_data', check_op_attrs=True)
self.assertTrue(flag, resp)
@@ -24,6 +24,7 @@ from mo.front.tf.graph_utils import create_op_with_const_inputs
from mo.graph.graph import Graph, Node, rename_nodes
from mo.middle.replacement import MiddleReplacementPattern
from mo.utils.error import Error
from mo.utils.utils import group_by_with_binary_predicate
def node_has_one_consumer(node: Node) -> bool:
@@ -148,34 +149,6 @@ class CanBeFused:
return False
def collect_sequences(xs: List[Node]) -> List[List[Node]]:
"""
This function receive a list of Interpolate layers, and returns a list of sequences
of Interpolate layers. Two Interpolate layers, 'first' and 'second' are called to be
a consecutive, if an output of 'first' is an input of 'second', and number of destinations
of 'first' is equal to 1.
:param xs: list of Interpolate layers
:return: list of sequences of consecutive Interpolate layers
"""
fuser = CanBeFused()
if not xs:
return []
prev = xs[0]
sequence = [prev]
result = []
for x in xs[1:]:
if is_next(prev, x) and fuser(prev, x):
sequence.append(x)
prev = x
else:
result.append(sequence)
prev = x
sequence = [prev]
result.append(sequence)
return result
def get_interpolate_attributes(node: Node) -> dict:
opset_to_default_values = {
'opset1': {
@@ -293,6 +266,7 @@ class InterpolateSequenceToInterpolate(MiddleReplacementPattern):
def find_and_replace_pattern(self, graph: Graph):
log.debug('Enabled replacement of a sequence of Interpolate layers with one Interpolate layer.')
interps = [n for n in graph.pseudo_topological_sort() if n.kind == 'op' and n.op == 'Interpolate']
sequences = collect_sequences(interps)
fuser = CanBeFused()
sequences = group_by_with_binary_predicate(interps, lambda prev, x: is_next(prev, x) and fuser(prev, x))
for seq in sequences:
replace_sequence(seq, graph)