[MO MXNET] Fixed spatial reshape on GluonCV models (#587)
authorYegor Kruglov <yegor.kruglov@intel.com>
Tue, 30 Jun 2020 19:32:13 +0000 (22:32 +0300)
committerGitHub <noreply@github.com>
Tue, 30 Jun 2020 19:32:13 +0000 (22:32 +0300)
* added value propagation for slice_like op

* Mark slice_lice as undead node

* fixes in mark_undead_nodes and unittests update

23 files changed:
model-optimizer/automation/package_BOM.txt
model-optimizer/extensions/back/ConvolutionNormalizer_test.py
model-optimizer/extensions/back/FuseTransposesSequence_test.py
model-optimizer/extensions/back/InterpolateReshape_test.py
model-optimizer/extensions/back/compress_quantized_weights_test.py
model-optimizer/extensions/front/interpolate_reshape_test.py
model-optimizer/extensions/front/mxnet/gluoncv_ssd_anchors.py [new file with mode: 0644]
model-optimizer/extensions/front/mxnet/gluoncv_ssd_anchors_test.py [new file with mode: 0644]
model-optimizer/extensions/front/mxnet/ssd_anchor_reshape.py
model-optimizer/extensions/front/mxnet/ssd_detection_output_replacer.py
model-optimizer/extensions/middle/AnchorToPriorBox.py [deleted file]
model-optimizer/extensions/middle/FakeSplitOutputs_test.py
model-optimizer/extensions/middle/ssd_anchors_to_const.py [deleted file]
model-optimizer/extensions/ops/slice_like.py
model-optimizer/extensions/ops/slice_like_test.py
model-optimizer/mo/front/extractor_test.py
model-optimizer/mo/graph/graph.py
model-optimizer/mo/middle/passes/eliminate.py
model-optimizer/mo/middle/passes/eliminate_test.py
model-optimizer/mo/middle/passes/fusing/decomposition_test.py
model-optimizer/mo/middle/passes/fusing/fuse_linear_ops_test.py
model-optimizer/mo/middle/passes/fusing/fuse_linear_seq_test.py
model-optimizer/mo/utils/unittest/graph.py

index 73d5acc..1fda288 100644 (file)
@@ -178,6 +178,7 @@ extensions/front/mxnet/flatten_ext.py
 extensions/front/mxnet/fully_connected_ext.py
 extensions/front/mxnet/gather.py
 extensions/front/mxnet/gather_ext.py
+extensions/front/mxnet/gluoncv_ssd_anchors.py
 extensions/front/mxnet/instance_norm_ext.py
 extensions/front/mxnet/leaky_relu.py
 extensions/front/mxnet/lrn_ext.py
@@ -481,7 +482,6 @@ extensions/middle/__init__.py
 extensions/middle/AddFakeQuantizeFuse.py
 extensions/middle/AddIsCyclicAttribute.py
 extensions/middle/AddMeanScaleValues.py
-extensions/middle/AnchorToPriorBox.py
 extensions/middle/ApplyNHWCtoNCHWpermutation.py
 extensions/middle/ApplyPermutations.py
 extensions/middle/ArgMaxToTopK.py
@@ -556,7 +556,6 @@ extensions/middle/SliceConverter.py
 extensions/middle/SliceLikeToStridedSlice.py
 extensions/middle/sparse_reshape.py
 extensions/middle/SplitConcatPairToInterpolate.py
-extensions/middle/ssd_anchors_to_const.py
 extensions/middle/SwapAxesMiddleReplacer.py
 extensions/middle/TensorIterator_utils.py
 extensions/middle/TensorIteratorBackEdge.py
index 1386edf..302b880 100644 (file)
@@ -36,12 +36,12 @@ def graph_template(weights_initial_shape, new_reshape_shape, limits_initial_shap
     ]
 
     core_nodes = lambda weights_shape, limit_shape, reshape_shape: {
-        **regular_op_with_shaped_data('input', None, {'type': 'Parameter'}),
+        **regular_op_with_shaped_data('input', None, {'type': 'Parameter', 'op': 'Parameter'}),
 
         **valued_const_with_data('weights', np.ones(weights_shape)),
 
         **const_with_data('dim', int64_array(reshape_shape)),
-        **regular_op_with_shaped_data('reshape', reshape_shape, {'type': 'Reshape', 'infer': Reshape.infer}),
+        **regular_op_with_shaped_data('reshape', reshape_shape, {'type': 'Reshape', 'infer': Reshape.infer, 'op': 'Reshape'}),
 
         **valued_const_with_data('il', np.ones(limit_shape)),
         **valued_const_with_data('ih', np.ones(limit_shape)),
@@ -49,9 +49,9 @@ def graph_template(weights_initial_shape, new_reshape_shape, limits_initial_shap
         **valued_const_with_data('oh', np.ones(limit_shape)),
 
         **regular_op_with_shaped_data('FQ', weights_shape, {'type': 'FakeQuantize', 'infer': FakeQuantize.infer,
-                                                            'stop_value_propagation': True, 'levels': 2}),
+                                                            'stop_value_propagation': True, 'levels': 2, 'op': 'FakeQuantize'}),
 
-        **regular_op_with_shaped_data('convolution', None, {'type': 'Convolution'}),
+        **regular_op_with_shaped_data('convolution', None, {'type': 'Convolution', 'op': 'Convolution'}),
 
         **result(),
     }
index 6dfbe94..3d33946 100644 (file)
@@ -31,24 +31,24 @@ nodes_attributes = {
     'placeholder_1_data': {'name': 'placeholder_1_data', 'value': None, 'shape': None, 'kind': 'data',
                            'data_type': None},
     # Transpose layers
-    'const_1': {'value': None, 'kind': 'op', 'type': 'Const'},
+    'const_1': {'value': None, 'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'const_1_data': {'value': None, 'shape': None, 'kind': 'data'},
 
     'permute_1': {'type': 'Transpose', 'value': None, 'kind': 'op', 'op': 'Transpose'},
     'permute_1_data': {'value': None, 'shape': None, 'kind': 'data'},
 
-    'const_2': {'value': None, 'kind': 'op', 'type': 'Const'},
+    'const_2': {'value': None, 'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'const_2_data': {'value': None, 'shape': None, 'kind': 'data'},
 
     'permute_2': {'type': 'Transpose', 'value': None, 'kind': 'op', 'op': 'Transpose'},
     'permute_2_data': {'value': None, 'shape': None, 'kind': 'data'},
 
-    'const_3': {'value': None, 'kind': 'op', 'type': 'Const'},
+    'const_3': {'value': None, 'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'const_3_data': {'value': None, 'shape': None, 'kind': 'data'},
 
     'permute_3': {'type': 'Transpose', 'value': None, 'kind': 'op', 'op': 'Transpose'},
     'permute_3_data': {'value': None, 'shape': None, 'kind': 'data'},
-    'op_output': { 'op': 'Result', 'kind': 'op'}
+    'op_output': {'op': 'Result', 'kind': 'op'}
 }
 
 
index f793a4b..cba8369 100644 (file)
@@ -25,21 +25,22 @@ from mo.utils.unittest.graph import build_graph, result, regular_op_with_shaped_
     connect_data
 
 nodes = {
-    **regular_op_with_shaped_data('placeholder', [1, 3, 30, 40], {'type': 'Parameter'}),
+    **regular_op_with_shaped_data('placeholder', [1, 3, 30, 40], {'type': 'Parameter', 'op': 'Parameter'}),
     **valued_const_with_data('out_shape', np.array([60, 160])),
 
-    **regular_op_with_shaped_data('interpolate', [1, 3, 60, 160], {'type': 'Interpolate', 'axes': [2, 3]}),
+    **regular_op_with_shaped_data('interpolate', [1, 3, 60, 160], {'type': 'Interpolate', 'axes': [2, 3],
+                                                                   'op': 'Interpolate'}),
 
-    **regular_op_with_shaped_data('shape', [4], {'type': 'ShapeOf'}),
+    **regular_op_with_shaped_data('shape', [4], {'type': 'ShapeOf', 'op': 'ShapeOf'}),
     **valued_const_with_data('indices', np.array([2, 3])),
     **valued_const_with_data('axis', np.array(0)),
-    **regular_op_with_shaped_data('gather', [2], {'type': 'Gather'}),
+    **regular_op_with_shaped_data('gather', [2], {'type': 'Gather', 'op': 'Gather'}),
 
     **valued_const_with_data('multiplier', np.array([2, 4])),
-    **regular_op_with_shaped_data('mul', [2], {'type': 'Multiply'}),
+    **regular_op_with_shaped_data('mul', [2], {'type': 'Multiply', 'op': 'Mul'}),
 
-    **regular_op_with_shaped_data('placeholder_1', [1, 3, 60, 160], {'type': 'Parameter'}),
-    **regular_op_with_shaped_data('concat', [1, 7, 60, 160], {'type': 'Concat', 'axis': 1}),
+    **regular_op_with_shaped_data('placeholder_1', [1, 3, 60, 160], {'type': 'Parameter', 'op': 'Parameter'}),
+    **regular_op_with_shaped_data('concat', [1, 7, 60, 160], {'type': 'Concat', 'axis': 1, 'op': 'Concat'}),
 
     **result(),
 }
index dedd4ea..8465a44 100644 (file)
@@ -34,36 +34,36 @@ nodes_attributes = {
     'placeholder_data': {'kind': 'data'},
 
     # weights
-    'weights_const': {'type': 'Const', 'kind': 'op', 'value': np.array([], dtype=np.float32)},
+    'weights_const': {'type': 'Const', 'kind': 'op', 'value': np.array([], dtype=np.float32), 'op': 'Const'},
     'weights_data': {'kind': 'data'},
 
     # quantize
-    'quantize1': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 5},
-    'quantize2': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 2},
-    'quantize3': {'type': 'FakeQuantize', 'kind': 'op', 'levels': None},
-    'quantize4': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 122},
-    'quantize5': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 202},
-    'quantize6': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 257},
+    'quantize1': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 5, 'op': 'FakeQuantize'},
+    'quantize2': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 2, 'op': 'FakeQuantize'},
+    'quantize3': {'type': 'FakeQuantize', 'kind': 'op', 'levels': None, 'op': 'FakeQuantize'},
+    'quantize4': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 122, 'op': 'FakeQuantize'},
+    'quantize5': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 202, 'op': 'FakeQuantize'},
+    'quantize6': {'type': 'FakeQuantize', 'kind': 'op', 'levels': 257, 'op': 'FakeQuantize'},
     'quantize_data': {'kind': 'data'},
-    'new_quantize1': {'kind': 'op', 'type': 'FakeQuantize', 'levels': 5},
-    'new_quantize4': {'kind': 'op', 'type': 'FakeQuantize', 'levels': 122},
-    'new_quantize5': {'kind': 'op', 'type': 'FakeQuantize', 'levels': 202},
+    'new_quantize1': {'kind': 'op', 'type': 'FakeQuantize', 'levels': 5, 'op': 'FakeQuantize'},
+    'new_quantize4': {'kind': 'op', 'type': 'FakeQuantize', 'levels': 122, 'op': 'FakeQuantize'},
+    'new_quantize5': {'kind': 'op', 'type': 'FakeQuantize', 'levels': 202, 'op': 'FakeQuantize'},
     'new_quantize_data': {'kind': 'data'},
 
     #  quantize input/output
-    'output_high_init': {'kind': 'op', 'type': 'Const'},
+    'output_high_init': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'output_high_init_data': {'kind': 'data', 'value': 3},
-    'output_low_init': {'kind': 'op', 'type': 'Const'},
+    'output_low_init': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'output_low_init_data': {'kind': 'data', 'value': -1.5},
 
-    'input_low': {'kind': 'op', 'type': 'Const'},
+    'input_low': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'input_low_data': {'kind': 'data'},
-    'input_high': {'kind': 'op', 'type': 'Const'},
+    'input_high': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'input_high_data': {'kind': 'data'},
 
-    'output_low': {'kind': 'op', 'type': 'Const'},
+    'output_low': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'output_low_data': {'kind': 'data'},
-    'output_high': {'kind': 'op', 'type': 'Const'},
+    'output_high': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
     'output_high_data': {'kind': 'data'},
 
     'output_high_init_data1': {'kind': 'data', 'value': 256.1},
@@ -76,58 +76,58 @@ nodes_attributes = {
     'mul': {'kind': 'op', 'op': 'Mul'},
     'add': {'kind': 'op', 'op': 'Add'},
 
-    'scale': {'kind': 'op', 'type': 'Const', 'value': 1.125},
-    'shift': {'kind': 'op', 'type': 'Const', 'value': -1.5},
-    'scale1': {'kind': 'op', 'type': 'Const', 'value': 1.9735537190082646},
-    'shift1': {'kind': 'op', 'type': 'Const', 'value': 17.3},
-    'scale2': {'kind': 'op', 'type': 'Const', 'value': 0.010711442786069652},
-    'shift2': {'kind': 'op', 'type': 'Const', 'value': -2.573},
+    'scale': {'kind': 'op', 'type': 'Const', 'value': 1.125, 'op': 'Const'},
+    'shift': {'kind': 'op', 'type': 'Const', 'value': -1.5, 'op': 'Const'},
+    'scale1': {'kind': 'op', 'type': 'Const', 'value': 1.9735537190082646, 'op': 'Const'},
+    'shift1': {'kind': 'op', 'type': 'Const', 'value': 17.3, 'op': 'Const'},
+    'scale2': {'kind': 'op', 'type': 'Const', 'value': 0.010711442786069652, 'op': 'Const'},
+    'shift2': {'kind': 'op', 'type': 'Const', 'value': -2.573, 'op': 'Const'},
 
     'shift_data': {'kind': 'data'},
     'scale_data': {'kind': 'data'},
     'mul_data': {'kind': 'data'},
     'add_data': {'kind': 'data'},
 
-    'convolution': {'type': 'Convolution', 'kind': 'op'},
-    'convert': {'type': 'Convert', 'kind': 'op', 'dst_type': np.float32},
+    'convolution': {'type': 'Convolution', 'kind': 'op', 'op': 'Convolution'},
+    'convert': {'type': 'Convert', 'kind': 'op', 'dst_type': np.float32, 'op': 'Cast'},
     'convert_data': {'kind': 'data'},
 
-    'result_data': {'kind':'data'},
+    'result_data': {'kind': 'data'},
     'result': {'kind': 'op', 'op': 'Result'},
 
     # accuracy test
     'ac_weights': {'kind': 'op', 'op': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
     'ac_weights_data': {'kind': 'data', 'shape': None, 'value': None},
 
-    'ac_input_low': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
+    'ac_input_low': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer, 'op': 'Const'},
     'ac_input_low_data': {'kind': 'data', 'value': None, 'shape': None},
-    'ac_input_high': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
+    'ac_input_high': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer, 'op': 'Const'},
     'ac_input_high_data': {'kind': 'data', 'value': None, 'shape': None},
-    'ac_output_low': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
+    'ac_output_low': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer, 'op': 'Const'},
     'ac_output_low_data': {'kind': 'data', 'value': None, 'shape': None},
-    'ac_output_high': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
+    'ac_output_high': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer, 'op': 'Const'},
     'ac_output_high_data': {'kind': 'data', 'value': None, 'shape': None},
 
-    'ac_fakeQuantize': {'kind': 'op', 'type': 'FakeQuantize', 'levels': None, 'infer': FakeQuantize.infer},
+    'ac_fakeQuantize': {'kind': 'op', 'type': 'FakeQuantize', 'levels': None, 'infer': FakeQuantize.infer, 'op': 'FakeQuantize'},
     'ac_fakeQuantize_data': {'kind': 'data', 'shape': None, 'value': None},
-    'ac_quantize': {'kind': 'op', 'type': 'fakeQuantize', 'levels': None, 'infer': FakeQuantize.infer},
+    'ac_quantize': {'kind': 'op', 'type': 'fakeQuantize', 'levels': None, 'infer': FakeQuantize.infer, 'op': 'FakeQuantize'},
     'ac_quantize_data': {'kind': 'data', 'shape': None, 'value': None},
 
-    'ac_convolution': {'kind': 'op', 'type': 'Convolution'},
+    'ac_convolution': {'kind': 'op', 'type': 'Convolution', 'op': 'Convolution'},
 
     'ac_mul': {'kind': 'op', 'op': 'Mul', 'infer': lambda node: eltwise_infer(node, lambda a, b: a * b)},
     'ac_mul_data': {'kind': 'data', 'shape': None, 'value': None},
     'ac_add': {'kind': 'op', 'op': 'Add', 'infer': lambda node: eltwise_infer(node, lambda a, b: a + b)},
     'ac_add_data': {'kind': 'data', 'shape': None, 'value': None},
 
-    'ac_scale': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
+    'ac_scale': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer, 'op': 'Const'},
     'ac_scale_data': {'kind': 'data', 'shape': None, 'value': None},
-    'ac_shift': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
+    'ac_shift': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer, 'op': 'Const'},
     'ac_shift_data': {'kind': 'data', 'shape': None, 'value': None},
 
-    'ac_output_low_ref': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
+    'ac_output_low_ref': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer, 'op': 'Const'},
     'ac_output_low_ref_data': {'kind': 'data', 'shape': None, 'value': None},
-    'ac_output_high_ref': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer},
+    'ac_output_high_ref': {'kind': 'op', 'type': 'Const', 'shape': None, 'value': None, 'infer': Const.infer, 'op': 'Const'},
     'ac_output_high_ref_data': {'kind': 'data', 'shape': None, 'value': None}
 }
 
@@ -838,7 +838,8 @@ class CompressionDataTypeTest(unittest.TestCase):
             **valued_const_with_data('weights', np.ones([1, 2, 3, 4], dtype=original)),
 
             **valued_const_with_data('int_weights', np.ones([1, 2, 3, 4], dtype=np.uint8)),
-            **regular_op_with_shaped_data('cast', [1, 2, 3, 4], {'type': 'Convert', 'dst_type': transformed}),
+            **regular_op_with_shaped_data('cast', [1, 2, 3, 4], {'type': 'Convert', 'dst_type': transformed,
+                                                                 'op': 'Cast'}),
 
             **valued_const_with_data('il', np.array([0])),
             **valued_const_with_data('ih', np.array([254])),
@@ -846,7 +847,8 @@ class CompressionDataTypeTest(unittest.TestCase):
             **valued_const_with_data('oh', np.array([254])),
 
             **regular_op_with_shaped_data('FQ', [1, 2, 3, 4], {'type': 'FakeQuantize', 'infer': FakeQuantize.infer,
-                                                               'stop_value_propagation': True, 'levels': 255}),
+                                                               'stop_value_propagation': True, 'levels': 255,
+                                                               'op': 'FakeQuantize'}),
             **result()
         }
 
index 4f45da8..1a23695 100644 (file)
@@ -26,23 +26,23 @@ from mo.utils.unittest.graph import build_graph, result, regular_op_with_shaped_
     connect_data
 
 nodes = {
-    **regular_op_with_shaped_data('placeholder', [1, 3, 30, 40], {'type': 'Parameter'}),
+    **regular_op_with_shaped_data('placeholder', [1, 3, 30, 40], {'type': 'Parameter', 'op': 'Parameter'}),
     **valued_const_with_data('out_shape', np.array([60, 160])),
 
     **regular_op_with_shaped_data('interpolate', [1, 3, 60, 160],
-                                  {'type': 'Interpolate', 'axes': int64_array([2, 3])}),
-    **regular_op_with_shaped_data('identity_00', [1, 3, 60, 160], {'identity': True}),
-    **regular_op_with_shaped_data('identity_01', [1, 3, 60, 160], {'identity': True}),
+                                  {'type': 'Interpolate', 'axes': int64_array([2, 3]), 'op': 'Interpolate'}),
+    **regular_op_with_shaped_data('identity_00', [1, 3, 60, 160], {'identity': True, 'op': 'Identity'}),
+    **regular_op_with_shaped_data('identity_01', [1, 3, 60, 160], {'identity': True, 'op': 'Identity'}),
 
-    **regular_op_with_shaped_data('shape', [4], {'type': 'ShapeOf'}),
+    **regular_op_with_shaped_data('shape', [4], {'type': 'ShapeOf', 'op': 'ShapeOf'}),
     **valued_const_with_data('indices', np.array([2, 3])),
     **valued_const_with_data('axis', np.array(0)),
-    **regular_op_with_shaped_data('gather', [2], {'type': 'Gather'}),
+    **regular_op_with_shaped_data('gather', [2], {'type': 'Gather', 'op': 'Gather'}),
 
-    **regular_op_with_shaped_data('placeholder_1', [1, 3, 60, 160], {'type': 'Parameter'}),
-    **regular_op_with_shaped_data('identity_10', [1, 3, 60, 160], {'identity': True}),
-    **regular_op_with_shaped_data('identity_11', [1, 3, 60, 160], {'identity': True}),
-    **regular_op_with_shaped_data('concat', [1, 7, 60, 160], {'type': 'Concat', 'axis': 1}),
+    **regular_op_with_shaped_data('placeholder_1', [1, 3, 60, 160], {'type': 'Parameter', 'op': 'Parameter'}),
+    **regular_op_with_shaped_data('identity_10', [1, 3, 60, 160], {'identity': True, 'op': 'Identity'}),
+    **regular_op_with_shaped_data('identity_11', [1, 3, 60, 160], {'identity': True, 'op': 'Identity'}),
+    **regular_op_with_shaped_data('concat', [1, 7, 60, 160], {'type': 'Concat', 'axis': 1, 'op': 'Concat'}),
 
     **result(),
 }
diff --git a/model-optimizer/extensions/front/mxnet/gluoncv_ssd_anchors.py b/model-optimizer/extensions/front/mxnet/gluoncv_ssd_anchors.py
new file mode 100644 (file)
index 0000000..e357e1c
--- /dev/null
@@ -0,0 +1,126 @@
+"""
+ 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 typing import Dict
+
+from extensions.front.mxnet.mx_reshape_to_reshape import MXReshapeToReshape
+from extensions.front.mxnet.ssd_detection_output_replacer import SsdPatternDetectionOutputReplacer
+from extensions.ops.elementwise import Div, Add, Sub
+from extensions.ops.split import Split
+from mo.front.common.partial_infer.utils import int64_array
+from mo.front.common.replacement import FrontReplacementPattern
+from mo.front.tf.graph_utils import create_op_node_with_second_input
+from mo.graph.graph import Graph, Node
+from mo.graph.port import Port
+from mo.middle.passes.convert_data_type import data_type_str_to_np
+from mo.ops.concat import Concat
+from mo.ops.reshape import Reshape
+
+
+def calculate_prior_box_value(value: Node, value_to_div: Port, value_to_add: Port):
+    """
+    :param value: Node with value. Here is supposed the node with op='Split'
+    :param value_to_div: Output port with values to be divided by 2
+    :param value_to_add: Output port with values to be added to values from value_to_div port
+    :return: Sub and Add nodes
+
+    The sub-graph can be described by formulas:
+    min = value[value_to_add] - (value[value_to_div] / 2)
+    max = value[value_to_add] + (value[value_to_div] / 2)
+    """
+    graph = value.graph
+    dtype = data_type_str_to_np(graph.graph['cmd_params'].data_type)
+    _min = Sub(graph, dict(name=value.name + '/Sub')).create_node()
+    div = create_op_node_with_second_input(graph, Div, np.array([2], dtype=dtype), op_attrs=dict(name=value.name + '/Div'))
+    div.in_port(0).connect(value_to_div)
+    _min.in_port(0).connect(value_to_add)
+    _min.in_port(1).connect(div.out_port(0))
+
+    _max = Add(graph, dict(name=value.name + '/Add')).create_node()
+    _max.in_port(0).connect(div.out_port(0))
+    _max.in_port(1).connect(value_to_add)
+
+    return _min, _max
+
+
+class SsdAnchorsReplacer(FrontReplacementPattern):
+    """
+    Replacing sub-graph with all anchors to sub-graph which calculates prior boxes values by formulas:
+
+    value[i] = xmin = value[i] - (value[i + 2] / 2)
+    value[i + 1] = ymin = value[i + 1] - (value[i + 3] / 2)
+    value[i + 2] = xmax = value[i] + (value[i + 2] / 2)
+    value[i + 3] = ymax = value[i + 1] + (value[i + 3] / 2)
+    """
+
+    enabled = True
+    graph_condition = [lambda graph: graph.graph['cmd_params'].enable_ssd_gluoncv]
+
+    def run_after(self):
+        return [SsdPatternDetectionOutputReplacer, MXReshapeToReshape]
+
+    def pattern(self):
+        return dict(
+            nodes=[
+                ('slice_like', dict(op='slice_like')),
+                ('reshape0', dict(op='Reshape')),
+                ('reshape1', dict(op='Reshape')),
+                ('reshape2', dict(op='Reshape')),
+                ('reshape3', dict(op='Reshape')),
+                ('concat', dict(op='Concat')),
+                ('detection_output', dict(op='DetectionOutput'))
+            ],
+            edges=[
+                ('slice_like', 'reshape0'),
+                ('reshape0', 'reshape1'),
+                ('reshape1', 'reshape2'),
+                ('reshape2', 'reshape3'),
+                ('reshape3', 'concat', {'in': 0}),
+                ('concat', 'detection_output', {'in': 2})
+            ])
+
+    def replace_pattern(self, graph: Graph, match: Dict[str, Node]):
+        concat_node = match['concat']
+        concat_node['axis'] = 1
+        concat_name = concat_node.soft_get('name', concat_node.id)
+
+        concat_reshape = create_op_node_with_second_input(graph, Reshape, int64_array([1, 2, -1]), op_attrs=dict(
+            name=concat_name + '/Reshape'))
+        split_node = create_op_node_with_second_input(graph, Split, int64_array(1), op_attrs=dict(
+            name=concat_name + '/Split', num_splits=2), input_node=concat_reshape)
+        split_node_reshape = create_op_node_with_second_input(graph, Reshape, int64_array([-1, 4]), op_attrs=dict(
+            name=split_node.name + '/Reshape'))
+        split_node.out_port(0).connect(split_node_reshape.in_port(0))
+        value = create_op_node_with_second_input(graph, Split, int64_array(1), op_attrs=dict(
+            name=split_node_reshape.name + '/Split', num_splits=4), input_node=split_node_reshape)
+
+        xmin, xmax = calculate_prior_box_value(value, value_to_div=value.out_port(2), value_to_add=value.out_port(0))
+        ymin, ymax = calculate_prior_box_value(value, value_to_div=value.out_port(3), value_to_add=value.out_port(1))
+
+        concat_slice_value = Concat(graph, dict(name=value.name + '/Concat', in_ports_count=4, axis=1)).create_node()
+        for ind, node in enumerate([xmin, ymin, xmax, ymax]):
+            concat_slice_value.in_port(ind).connect(node.out_port(0))
+
+        reshape_concat_values = create_op_node_with_second_input(graph, Reshape, int64_array([1, 1, -1]),
+                                                                 op_attrs=dict(name=concat_slice_value.name + '/Reshape'),
+                                                                 input_node=concat_slice_value)
+        concat = Concat(graph, dict(name=reshape_concat_values.name + '/Concat', in_ports_count=2, axis=1)).create_node()
+        concat.in_port(0).connect(reshape_concat_values.out_port(0))
+        concat.in_port(1).connect(split_node.out_port(1))
+
+        match['detection_output'].in_port(2).get_connection().set_source(concat.out_port(0))
+        concat_node.out_port(0).get_connection().set_destination(concat_reshape.in_port(0))
diff --git a/model-optimizer/extensions/front/mxnet/gluoncv_ssd_anchors_test.py b/model-optimizer/extensions/front/mxnet/gluoncv_ssd_anchors_test.py
new file mode 100644 (file)
index 0000000..c1ec541
--- /dev/null
@@ -0,0 +1,130 @@
+"""
+ 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
+import unittest
+
+from extensions.front.mxnet.gluoncv_ssd_anchors import SsdAnchorsReplacer
+from mo.front.common.partial_infer.utils import int64_array
+from mo.utils.ir_engine.compare_graphs import compare_graphs
+from mo.utils.unittest.graph import build_graph
+
+nodes_attributes = {
+    'slice_like': {'kind': 'op', 'op': 'slice_like'},
+    'model_reshape0': {'kind': 'op', 'op': 'Reshape'},
+    'model_reshape0_const': {'kind': 'op', 'op': 'Const', 'value': int64_array([1, -1, 4])},
+    'model_reshape1': {'kind': 'op', 'op': 'Reshape'},
+    'model_reshape1_const': {'kind': 'op', 'op': 'Const', 'value': int64_array([1, -1, 4])},
+    'model_reshape2': {'kind': 'op', 'op': 'Reshape'},
+    'model_reshape2_const': {'kind': 'op', 'op': 'Const', 'value': int64_array([1, -1])},
+    'reshape0': {'kind': 'op', 'op': 'Reshape'},
+    'reshape0_const': {'kind': 'op', 'op': 'Const', 'value': int64_array([1, -1])},
+    'concat': {'kind': 'op', 'op': 'Concat'},
+    'reshape1': {'kind': 'op', 'op': 'Reshape'},
+    'reshape1_const': {'kind': 'op', 'op': 'Const', 'value': int64_array([1, 2, -1])},
+    'split': {'kind': 'op', 'op': 'Split', 'num_splits': 2},
+    'split_const': {'kind': 'op', 'op': 'Const', 'value': int64_array(1)},
+    'reshape2': {'kind': 'op', 'op': 'Reshape'},
+    'reshape2_const': {'kind': 'op', 'op': 'Const', 'value': int64_array([-1, 4])},
+    'value': {'kind': 'op', 'op': 'Split', 'num_splits': 4},
+    'value_const': {'kind': 'op', 'op': 'Const', 'value': int64_array(1)},
+    'div_1': {'kind': 'op', 'op': 'Div'},
+    'div_1_const': {'kind': 'op', 'op': 'Const', 'value': np.array([2], dtype=np.float32)},
+    'div_2': {'kind': 'op', 'op': 'Div'},
+    'div_2_const': {'kind': 'op', 'op': 'Const', 'value': np.array([2], dtype=np.float32)},
+    'xmin': {'kind': 'op', 'op': 'Sub'},
+    'ymin': {'kind': 'op', 'op': 'Sub'},
+    'xmax': {'kind': 'op', 'op': 'Add'},
+    'ymax': {'kind': 'op', 'op': 'Add'},
+    'concat_value': {'kind': 'op', 'op': 'Concat', 'axis': 1},
+    'reshape3': {'kind': 'op', 'op': 'Reshape'},
+    'reshape3_const': {'kind': 'op', 'op': 'Const', 'value': int64_array([1, 1, -1])},
+    'end_concat': {'kind': 'op', 'op': 'Concat'},
+    'detection_output': {'kind': 'op', 'op': 'DetectionOutput'}
+}
+
+
+class SsdAnchorsReplacerTest(unittest.TestCase):
+
+    def test_replacer(self):
+        graph = build_graph(
+            nodes_attrs=nodes_attributes,
+            edges=[
+                ('slice_like', 'model_reshape0', {'in': 0}),
+                ('model_reshape0_const', 'model_reshape0', {'in': 1}),
+                ('model_reshape0', 'model_reshape1', {'in': 0}),
+                ('model_reshape1_const', 'model_reshape1', {'in': 1}),
+                ('model_reshape1', 'model_reshape2', {'in': 0}),
+                ('model_reshape2_const', 'model_reshape2', {'in': 1}),
+                ('model_reshape2', 'reshape0', {'in': 0}),
+                ('reshape0_const', 'reshape0', {'in': 1}),
+                ('reshape0', 'concat'),
+                ('concat', 'detection_output', {'in': 2})
+            ],
+            nodes_with_edges_only=True
+        )
+
+        ref_graph = build_graph(
+            nodes_attrs=nodes_attributes,
+            edges=[
+                ('slice_like', 'model_reshape0', {'in': 0}),
+                ('model_reshape0_const', 'model_reshape0', {'in': 1}),
+                ('model_reshape0', 'model_reshape1', {'in': 0}),
+                ('model_reshape1_const', 'model_reshape1', {'in': 1}),
+                ('model_reshape1', 'model_reshape2', {'in': 0}),
+                ('model_reshape2_const', 'model_reshape2', {'in': 1}),
+                ('model_reshape2', 'reshape0', {'in': 0}),
+                ('reshape0_const', 'reshape0', {'in': 1}),
+                ('reshape0', 'concat'),
+                ('concat', 'reshape1', {'in': 0}),
+                ('reshape1_const', 'reshape1', {'in': 1}),
+                ('reshape1', 'split', {'in': 0}),
+                ('split_const', 'split', {'in': 1}),
+                ('split', 'reshape2', {'out': 0, 'in': 0}),
+                ('reshape2_const', 'reshape2', {'in': 1}),
+                ('reshape2', 'value', {'in': 0}),
+                ('value_const', 'value', {'in': 1}),
+                ('value', 'xmin', {'out': 0, 'in': 0}),
+                ('value', 'ymin', {'out': 1, 'in': 0}),
+                ('value', 'xmax', {'out': 0, 'in': 1}),
+                ('value', 'ymax', {'out': 1, 'in': 1}),
+                ('value', 'div_1', {'out': 2, 'in': 0}),
+                ('value', 'div_2', {'out': 3, 'in': 0}),
+                ('div_1_const', 'div_1', {'in': 1}),
+                ('div_2_const', 'div_2', {'in': 1}),
+                ('div_1', 'xmin', {'in': 1, 'out': 0}),
+                ('div_1', 'xmax', {'in': 0, 'out': 0}),
+                ('div_2', 'ymin', {'in': 1, 'out': 0}),
+                ('div_2', 'ymax', {'in': 0, 'out': 0}),
+                ('xmin', 'concat_value', {'in': 0}),
+                ('ymin', 'concat_value', {'in': 1}),
+                ('xmax', 'concat_value', {'in': 2}),
+                ('ymax', 'concat_value', {'in': 3}),
+                ('concat_value', 'reshape3', {'in': 0}),
+                ('reshape3_const', 'reshape3', {'in': 1}),
+                ('reshape3', 'end_concat', {'in': 0}),
+                ('split', 'end_concat', {'in': 1}),
+                ('end_concat', 'detection_output', {'in': 2})
+            ],
+            update_attributes={
+                'concat': {'axis': 1}
+            },
+            nodes_with_edges_only=True
+        )
+        graph.stage = 'front'
+        graph.graph['cmd_params'].data_type = 'FP32'
+        SsdAnchorsReplacer().find_and_replace_pattern(graph)
+        flag, resp = compare_graphs(graph, ref_graph, 'detection_output', check_op_attrs=True)
+        self.assertTrue(flag, resp)
index a1f7350..c109102 100644 (file)
@@ -24,7 +24,6 @@ from mo.front.common.replacement import FrontReplacementSubgraph
 from mo.graph.graph import Graph, Node
 from mo.middle.pattern_match import find_pattern_matches
 from mo.ops.const import Const
-from mo.ops.crop import Crop
 
 
 class SsdPatternAnchorReshape(FrontReplacementSubgraph):
index 0033a49..1bef8e9 100644 (file)
@@ -103,7 +103,7 @@ class SsdPatternDetectionOutputReplacer(FrontReplacementSubgraph):
 
     def reshape_priorboxes(self, concat):
         for i, node in concat.in_nodes().items():
-            reshape_node = create_op_node_with_second_input(concat.graph, Reshape, int64_array([0, 2, -1]),
+            reshape_node = create_op_node_with_second_input(concat.graph, Reshape, int64_array([1, -1]),
                                                             dict(name=concat.name + str(i) + '/PriorBoxReshape_'))
             node.out_port(0).disconnect()
             node.out_port(0).connect(reshape_node.in_port(0))
diff --git a/model-optimizer/extensions/middle/AnchorToPriorBox.py b/model-optimizer/extensions/middle/AnchorToPriorBox.py
deleted file mode 100644 (file)
index 30dbf2a..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-"""
- 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.middle.SliceLikeToStridedSlice import SliceLikeToStridedSlice
-from mo.graph.graph import Graph
-from mo.middle.replacement import MiddleReplacementPattern
-from mo.ops.const import Const
-
-
-class AnchorToPriorBoxes(MiddleReplacementPattern):
-    """
-    Crop anchors consts before replacing subgraph with all anchors
-    """
-    enabled = True
-    force_clean_up = True
-    graph_condition = [lambda graph: graph.graph['fw'] == 'mxnet' and graph.graph['cmd_params'].enable_ssd_gluoncv]
-
-    def run_after(self):
-        from extensions.middle.pass_separator import MiddleStart
-        return [MiddleStart]
-
-    def run_before(self):
-        return [SliceLikeToStridedSlice]
-
-    def pattern(self):
-        return dict(
-            nodes=[
-                ('const', dict(op='Const')),
-                ('const_data', dict(kind='data')),
-                ('slice_like', dict(op='slice_like')),
-                ('slice_like_out', dict(kind='data')),
-                ('reshape', dict(op='Reshape')),
-            ],
-            edges=[
-                ('const', 'const_data'),
-                ('const_data', 'slice_like', {'in': 0}),
-                ('slice_like', 'slice_like_out'),
-                ('slice_like_out', 'reshape'),
-            ]
-        )
-
-    def replace_pattern(self, graph: Graph, match: dict):
-        slice_like = match['slice_like']
-        anchor_node = slice_like.in_port(0).get_source().node
-        reshape = slice_like.out_nodes()[0].out_node()
-        slice_shape = slice_like.out_nodes()[0].shape
-        anchor_node.value = np.copy(anchor_node.value[:slice_shape[0], :slice_shape[1],
-                                         :slice_shape[2], :slice_shape[3], :slice_shape[4]])
-        anchor_node.shape = slice_shape
-
-        val_node = Const(graph, {'name': slice_like.name +'/croped_', 'value': anchor_node.value[:slice_shape[0], :slice_shape[1],
-                                         :slice_shape[2], :slice_shape[3], :slice_shape[4]], 'shape': slice_shape}).create_node_with_data()
-        slice_like.in_port(0).disconnect()
-        slice_like.in_port(1).disconnect()
-        slice_like.out_port(0).disconnect()
-        reshape.in_port(0).connect(val_node.in_node().out_port(0))
index c176e34..d24e30e 100644 (file)
@@ -38,9 +38,9 @@ nodes_attributes = {
     'split_data_1': {'kind': 'data', 'value': None, 'shape': np.array([1, 227, 227, 1])},
     'last_data': {'kind': 'data', 'value': None, 'shape': np.array([1, 227, 227, 3])},
 
-    'axis_const': {'kind': 'op'},
+    'axis_const': {'kind': 'op', 'op': 'Const'},
     'axis_const_data': {'value': np.int64(1), 'shape': None, 'kind': 'data'},
-    'split_dim_const': {'kind': 'op'},
+    'split_dim_const': {'kind': 'op', 'op': 'Const'},
     'split_dim_const_data': {'value': np.array([1, 2, 3]), 'shape': None, 'kind': 'data'},
 
 }
diff --git a/model-optimizer/extensions/middle/ssd_anchors_to_const.py b/model-optimizer/extensions/middle/ssd_anchors_to_const.py
deleted file mode 100644 (file)
index a6896ca..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-"""
- 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.middle.AnchorToPriorBox import AnchorToPriorBoxes
-from extensions.middle.SliceLikeToStridedSlice import SliceLikeToStridedSlice
-from mo.graph.graph import Graph
-from mo.middle.replacement import MiddleReplacementPattern
-from mo.ops.const import Const
-
-
-class SsdAnchorsMiddleReplacer(MiddleReplacementPattern):
-    """
-    Replacing subgraph with all anchors constant to constant op with pre calculated prior boxes values.
-    """
-    enabled = True
-    force_clean_up = True
-    graph_condition = [lambda graph: graph.graph['fw'] == 'mxnet' and graph.graph['cmd_params'].enable_ssd_gluoncv]
-
-    def run_after(self):
-        return [AnchorToPriorBoxes]
-
-    def run_before(self):
-        return [SliceLikeToStridedSlice]
-
-
-    def pattern(self):
-        return dict(
-            nodes=[
-                ('const', dict(op='Const')),
-                ('const_data', dict(kind='data')),
-                ('reshape0', dict(op='Reshape')),
-                ('reshape0_data', dict(kind='data')),
-                ('reshape1', dict(op='Reshape')),
-                ('reshape1_data', dict(kind='data')),
-                ('reshape2', dict(op='Reshape')),
-                ('reshape2_data', dict(kind='data')),
-                ('reshape3', dict(op='Reshape')),
-                ('reshape3_data', dict(kind='data')),
-                ('concat', dict(op='Concat')),
-            ],
-            edges=[
-                ('const', 'const_data'),
-                ('const_data', 'reshape0'),
-                ('reshape0', 'reshape0_data'),
-                ('reshape0_data', 'reshape1'),
-                ('reshape1', 'reshape1_data'),
-                ('reshape1_data', 'reshape2'),
-                ('reshape2', 'reshape2_data'),
-                ('reshape2_data', 'reshape3'),
-                ('reshape3', 'reshape3_data'),
-                ('reshape3_data', 'concat'),
-        ])
-
-    def replace_pattern(self, graph: Graph, match: dict):
-        #self.pattern()['nodes']
-        concat_node = match['concat']
-        if len(concat_node.out_nodes()[0].out_nodes()) == 0:
-            return
-        const_values = []
-        for in_node_index in concat_node.in_nodes():
-            current_node = concat_node.in_port(in_node_index).get_source().node
-            for k, v in reversed(self.pattern()['nodes'][:-1]):
-                if 'op' in v:
-                    assert current_node.op == v['op']
-                    current_node = current_node.in_port(0).get_source().node
-                    if current_node.op == 'Const':
-                        crop_value = current_node.value
-                        crop_value = np.reshape(crop_value, (1, -1))
-                        const_values.append(crop_value)
-                        break
-        concat_value = np.concatenate(tuple(const_values), axis=1)
-        concat_value = np.reshape(concat_value, (1, 2, -1))
-        slice_value = concat_value[0][0]
-        for i in range(int(concat_value[0][0].size / 4)):
-            index = i * 4
-            xmin = slice_value[index] - (slice_value[index+2] / 2)
-            ymin = slice_value[index + 1] - (slice_value[index + 3] / 2)
-            xmax = slice_value[index] + (slice_value[index + 2] / 2)
-            ymax = slice_value[index + 1] + (slice_value[index + 3] / 2)
-            slice_value[index] = xmin
-            slice_value[index + 1] = ymin
-            slice_value[index + 2] = xmax
-            slice_value[index + 3] = ymax
-
-        val_node = Const(graph, {'name': concat_node.name + '/const_',
-                                 'value': concat_value}).create_node_with_data()
-        out_node = concat_node.out_port(0).get_destination().node
-        concat_node.out_port(0).disconnect()
-        out_node.in_port(2).connect(val_node.in_node().out_port(0))
index ed02881..7d6ae78 100644 (file)
@@ -50,5 +50,16 @@ class SliceLike(Op):
                 'Input shape ranks are inconsistent: {} and {}'.format(input_shape.size, shape_like.size)
             node.axes = int64_array(range(shape_like.size))
             new_shape = np.copy(shape_like)
-
         node.out_port(0).data.set_shape(new_shape)
+
+        if node.in_port(0).get_connection().data.get_value() is not None:
+            out_value = np.copy(node.in_port(0).data.get_value())
+
+            slice_indexes = []
+            for s in out_value.shape:
+                slice_indexes.append(slice(0, s))
+
+            for axis in node.axes:
+                slice_indexes[axis] = slice(0, new_shape[axis])
+                out_value = out_value[tuple(slice_indexes)]
+            node.out_port(0).data.set_value(out_value)
index dc1abd8..156fa37 100644 (file)
@@ -23,14 +23,18 @@ from mo.graph.graph import Node
 from mo.utils.unittest.graph import build_graph
 
 nodes_attributes = {
-    'input_data': {'kind': 'data', 'shape': int64_array([3, 4]), 'value': None},
+    'input': {'kind': 'op', 'op': 'Const'},
+    'input_data': {'kind': 'data', 'shape': int64_array([3, 4]), 'value': np.arange(1, 13).reshape([3, 4])},
+    'shape_like': {'kind': 'op', 'op': 'Const', 'shape': int64_array([2, 3]), 'value': None},
     'shape_like_data': {'kind': 'data', 'shape': int64_array([2, 3]), 'value': None},
     'slice_like': {'kind': 'op', 'op': 'slice_data'},
     'out_data': {'kind': 'data', 'shape': None, 'value': None}
 }
 
 edges = [
+    ('input', 'input_data'),
     ('input_data', 'slice_like', {'in': 0}),
+    ('shape_like', 'shape_like_data'),
     ('shape_like_data', 'slice_like', {'in': 1}),
     ('slice_like', 'out_data')
 ]
@@ -43,29 +47,41 @@ class SliceLikeTest(unittest.TestCase):
         slice_like = Node(graph, 'slice_like')
         SliceLike.infer(slice_like)
         ref_shape = int64_array([2, 3])
+        ref_value = np.array([[1, 2, 3], [5, 6, 7]])
         res_shape = graph.node['out_data']['shape']
+        res_value = graph.node['out_data']['value']
         self.assertTrue(np.array_equal(res_shape, ref_shape))
+        self.assertTrue(np.array_equal(res_value, ref_value))
 
     def test_2(self):
         graph = build_graph(nodes_attributes, edges, {'slice_like': {'axes': (0, 1)}})
         slice_like = Node(graph, 'slice_like')
         SliceLike.infer(slice_like)
         ref_shape = int64_array([2, 3])
+        ref_value = np.array([[1, 2, 3], [5, 6, 7]])
         res_shape = graph.node['out_data']['shape']
+        res_value = graph.node['out_data']['value']
         self.assertTrue(np.array_equal(res_shape, ref_shape))
+        self.assertTrue(np.array_equal(res_value, ref_value))
 
     def test_3(self):
         graph = build_graph(nodes_attributes, edges, {'slice_like': {'axes': (0,)}})
         slice_like = Node(graph, 'slice_like')
         SliceLike.infer(slice_like)
         ref_shape = int64_array([2, 4])
+        ref_value = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
         res_shape = graph.node['out_data']['shape']
+        res_value = graph.node['out_data']['value']
         self.assertTrue(np.array_equal(res_shape, ref_shape))
+        self.assertTrue(np.array_equal(res_value, ref_value))
 
     def test_4(self):
         graph = build_graph(nodes_attributes, edges, {'slice_like': {'axes': (-1,)}})
         slice_like = Node(graph, 'slice_like')
         SliceLike.infer(slice_like)
         ref_shape = int64_array([3, 3])
+        ref_value = np.array([[1, 2, 3], [5, 6, 7], [9, 10, 11]])
         res_shape = graph.node['out_data']['shape']
+        res_value = graph.node['out_data']['value']
         self.assertTrue(np.array_equal(res_shape, ref_shape))
+        self.assertTrue(np.array_equal(res_value, ref_value))
index 1ade5f6..d04107e 100644 (file)
@@ -448,11 +448,11 @@ class TestOutputCut(unittest.TestCase):
     # {'embeddings': [{'port': None}]}
     @generate({'C': [{'port': None}]}, {'C': [{'out': 0}]}, {'C': [{'out': 1}]})
     def test_output_port_cut(self, output):
-        nodes = {'A': {'type': 'Identity', 'kind': 'op'},
-                 'B': {'type': 'Identity', 'kind': 'op'},
-                 'C': {'type': 'Identity', 'kind': 'op'},
-                 'D': {'type': 'Identity', 'kind': 'op'},
-                 'E': {'type': 'Identity', 'kind': 'op'},
+        nodes = {'A': {'type': 'Identity', 'kind': 'op', 'op': 'Identity'},
+                 'B': {'type': 'Identity', 'kind': 'op', 'op': 'Identity'},
+                 'C': {'type': 'Identity', 'kind': 'op', 'op': 'Identity'},
+                 'D': {'type': 'Identity', 'kind': 'op', 'op': 'Identity'},
+                 'E': {'type': 'Identity', 'kind': 'op', 'op': 'Identity'},
                  }
         edges = [
             ('A', 'C', {'in': 0, 'out': 0}),
@@ -470,9 +470,9 @@ class TestOutputCut(unittest.TestCase):
     def test_output_port_cut(self, output):
         nodes = {'A': {'op': 'Parameter', 'kind': 'op'},
                  'B': {'op': 'Parameter', 'kind': 'op'},
-                 'C': {'type': 'Identity', 'kind': 'op'},
-                 'D': {'type': 'Identity', 'kind': 'op'},
-                 'E': {'type': 'Identity', 'kind': 'op'},
+                 'C': {'type': 'Identity', 'kind': 'op', 'op': 'Identity'},
+                 'D': {'type': 'Identity', 'kind': 'op', 'op': 'Identity'},
+                 'E': {'type': 'Identity', 'kind': 'op', 'op': 'Identity'},
                  }
         edges = [
             ('A', 'C', {'in': 0, 'out': 0}),
@@ -489,9 +489,9 @@ class TestOutputCut(unittest.TestCase):
 class TestUserDataRepack(unittest.TestCase):
     nodes = {'A': {'name': 'Aa', 'op': 'Parameter', 'kind': 'op'},
              'B': {'name': 'Bb', 'op': 'Parameter', 'kind': 'op'},
-             'C': {'name': 'Cc', 'type': 'Identity', 'value': None, 'kind': 'op'},
-             'D': {'name': 'Dd', 'type': 'Identity', 'value': None, 'kind': 'op'},
-             'E': {'name': 'Ee', 'type': 'Identity', 'value': None, 'kind': 'op'},
+             'C': {'name': 'Cc', 'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
+             'D': {'name': 'Dd', 'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
+             'E': {'name': 'Ee', 'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
              }
     edges = [
         ('A', 'C', {'in': 0, 'out': 0}),
index e79eb12..3481180 100644 (file)
@@ -979,7 +979,7 @@ class Graph(nx.MultiDiGraph):
             undead_node_types.append('TFCustomSubgraphCall')
 
         if 'cmd_params' in self.graph and getattr(self.graph['cmd_params'], 'keep_shape_ops'):
-            undead_node_types.extend(['ShapeOf', 'Shape'])
+            undead_node_types.extend(['ShapeOf', 'Shape', 'slice_like'])
 
         mark_output_reachable_nodes(self)
         shape_inference(self)
index a2ead94..f0b373b 100644 (file)
@@ -83,16 +83,14 @@ def mark_undead_nodes(graph, undead_types: list):
 
     nx.set_node_attributes(G=graph, name='is_undead', values=False)
 
-    # mark output nodes as undead
-    outputs = graph.get_nodes_with_attributes(op='Result')
-    nx.set_node_attributes(G=graph, name='is_undead', values={n: True for n in outputs})
-
-    # mark specifically defined with node type set of nodes
-    for type in undead_types:
-        node_of_specific_type = graph.get_nodes_with_attributes(type=type)
-        nx.set_node_attributes(G=graph, name='is_undead', values={n: True for n in node_of_specific_type})
-
-    undead_nodes = graph.get_nodes_with_attributes(is_undead=True)
+    undead_types_with_result = undead_types + ['Result']
+    undead_nodes = []
+    for node in graph.get_op_nodes():
+        node_type = node.soft_get('type', node.op)
+        if node_type in undead_types_with_result:
+            undead_nodes.append(node.id)
+
+    nx.set_node_attributes(G=graph, name='is_undead', values={n: True for n in undead_nodes})
     # propagate 'undead' attribute to children nodes of undead nodes if the node produces constant value
     for node_name in bfs_search(graph, undead_nodes):
         if graph.node[node_name]['is_undead']:
index 0b0159a..693c8fd 100644 (file)
@@ -22,14 +22,14 @@ from mo.graph.graph import Node
 from mo.middle.passes.eliminate import mark_output_reachable_nodes, mark_const_producer_nodes
 from mo.utils.unittest.graph import build_graph
 
-nodes_attributes = {'placeholder_1': {'type': 'Parameter', 'kind': 'op'},
-                    'placeholder_2': {'type': 'Parameter', 'kind': 'op'},
-                    'node_1': {'type': 'Identity', 'value': None, 'kind': 'op'},
-                    'node_2': {'type': 'Identity', 'value': None, 'kind': 'op'},
-                    'node_3': {'type': 'Identity', 'value': None, 'kind': 'op'},
-                    'node_4': {'type': 'Identity', 'value': None, 'kind': 'op'},
-                    'node_5': {'type': 'Identity', 'value': None, 'kind': 'op'},
-                    'node_6': {'type': 'Identity', 'value': None, 'kind': 'op'},
+nodes_attributes = {'placeholder_1': {'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
+                    'placeholder_2': {'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
+                    'node_1': {'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
+                    'node_2': {'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
+                    'node_3': {'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
+                    'node_4': {'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
+                    'node_5': {'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
+                    'node_6': {'type': 'Identity', 'value': None, 'kind': 'op', 'op': 'Identity'},
                     'placeholder_1_data_node': {'value': None, 'kind': 'data'},
                     'placeholder_2_data_node': {'value': None, 'kind': 'data'},
                     'data_node_1': {'value': None, 'kind': 'data'},
@@ -39,9 +39,9 @@ nodes_attributes = {'placeholder_1': {'type': 'Parameter', 'kind': 'op'},
                     'data_node_4': {'value': None, 'kind': 'data'},
                     'data_node_5': {'value': None, 'shape': None, 'kind': 'data'},
                     'data_node_6': {'value': None, 'shape': None, 'kind': 'data'},
-                    'tf_call_1': {'type': 'TFCustomSubgraphCall', 'kind': 'op'},
-                    'tf_call_2': {'type': 'TFCustomSubgraphCall', 'kind': 'op'},
-                    'tf_call_3': {'type': 'TFCustomSubgraphCall', 'kind': 'op'},
+                    'tf_call_1': {'type': 'TFCustomSubgraphCall', 'kind': 'op', 'op': 'TFCustomSubgraphCall'},
+                    'tf_call_2': {'type': 'TFCustomSubgraphCall', 'kind': 'op', 'op': 'TFCustomSubgraphCall'},
+                    'tf_call_3': {'type': 'TFCustomSubgraphCall', 'kind': 'op', 'op': 'TFCustomSubgraphCall'},
                     'op_output': {'kind': 'op', 'op': 'Result'},
                     'op_output_1': {'kind': 'op', 'op': 'Result'},
                     'op_output_2': {'kind': 'op', 'op': 'Result'}
index f72f653..5f32105 100644 (file)
@@ -29,27 +29,27 @@ nodes_attributes = {
     'placeholder_2_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     # ScaleShift layer
     'scaleshift_1': {'type': 'ScaleShift', 'kind': 'op', 'op': 'ScaleShift', 'axis': 0},
-    'const_scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'data'},
     'scaleshift_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Mul and Add operations
     'mul_1': {'type': None, 'value': None, 'kind': 'op', 'op': 'Mul'},
-    'const_mul_1_w': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_mul_1_w': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'mul_1_w': {'value': None, 'shape': None, 'kind': 'data'},
     'mul_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     'add_1': {'type': None, 'kind': 'op', 'op': 'Add'},
-    'const_add_1_w': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_add_1_w': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'add_1_w': {'value': None, 'shape': None, 'kind': 'data'},
     'add_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Mul and Add operations
     'mul_2': {'type': None, 'kind': 'op', 'op': 'Mul'},
-    'const_mul_2_w': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_mul_2_w': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'mul_2_w': {'value': None, 'shape': None, 'kind': 'data'},
     'mul_2_data': {'value': None, 'shape': None, 'kind': 'data'},
     'add_2': {'type': None, 'kind': 'op', 'op': 'Add'},
-    'const_add_2_w': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_add_2_w': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'add_2_w': {'value': None, 'shape': None, 'kind': 'data'},
     'add_2_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Reshape
@@ -59,13 +59,13 @@ nodes_attributes = {
     'placeholder_2/Reshape_const_data': {'kind': 'data', 'value': None, 'shape': None},
     # BatchNorm operation
     'bn_op': {'type': None, 'kind': 'op', 'op': 'BatchNorm', 'can_be_fused': True},
-    'const_bn_const': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_bn_const': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'bn_const': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_bn_beta': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_bn_beta': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'bn_beta': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_bn_mean': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_bn_mean': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'bn_mean': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_bn_var': {'value': None, 'shape': None, 'kind': 'op'},
+    'const_bn_var': {'value': None, 'shape': None, 'kind': 'op', 'op': 'Const'},
     'bn_var': {'value': None, 'shape': None, 'kind': 'data'},
     'bn_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Concat1 operation
index 5bc4f33..23b8d07 100644 (file)
@@ -31,27 +31,27 @@ nodes_attributes = {
     'scaleshift_1': {'type': 'ScaleShift', 'kind': 'op', 'op': 'ScaleShift'},
     'scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'data'},
     'scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
-    'const_scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
+    'const_scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'scaleshift_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Mul and Add operations
     'mul_1': {'type': 'Mul', 'kind': 'op', 'op': 'Mul', 'can_be_fused': True,
               'infer': lambda node: eltwise_infer(node, lambda a, b: a*b)},
     'mul_1_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
-    'const_mul_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_mul_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'mul_1_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_1': {'type': 'Add', 'kind': 'op', 'op': 'Add', 'can_be_fused': True},
     'add_1_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
-    'const_add_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_add_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'add_1_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     # Mul2 and Add2 operations
     'mul_2': {'type': 'Mul', 'kind': 'op', 'op': 'Mul', 'can_be_fused': True},
     'mul_2_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
-    'const_mul_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_mul_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'mul_2_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_2': {'type': 'Add', 'kind': 'op', 'op': 'Add', 'can_be_fused': True},
     'add_2_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
-    'const_add_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_add_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'add_2_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     # Concat1 operation
     'concat_1': {'type': 'Concat', 'kind': 'op', 'op': 'Concat'},
@@ -60,21 +60,21 @@ nodes_attributes = {
     'conv_1': {'type': 'Convolution', 'kind': 'op', 'op': 'Conv2D', 'layout': 'NHWC'},
     'conv_1_w': {'value': None, 'shape': None, 'kind': 'data'},
     'conv_1_b': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_conv_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
-    'const_conv_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_conv_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
+    'const_conv_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'conv_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     'conv_2': {'type': 'Convolution', 'kind': 'op', 'op': 'Conv2D', 'layout': 'NHWC'},
     'conv_2_w': {'value': None, 'shape': None, 'kind': 'data'},
     'conv_2_b': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_conv_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
-    'const_conv_2_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_conv_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
+    'const_conv_2_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'conv_2_data': {'value': None, 'shape': None, 'kind': 'data'},
     # MatMul
-    'fc_1': {'type': 'MatMul', 'kind': 'op', 'layout': 'NHWC'},
+    'fc_1': {'type': 'MatMul', 'kind': 'op', 'layout': 'NHWC', 'op': 'MatMul'},
     'fc_1_w': {'value': None, 'shape': None, 'kind': 'data'},
     'fc_1_b': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_fc_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
-    'const_fc_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_fc_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
+    'const_fc_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'fc_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Placeholders
     'placeholder_2': {'shape': None, 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
index afa4a89..e256553 100644 (file)
@@ -27,45 +27,45 @@ nodes_attributes = {
     'placeholder_1_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     # ScaleShift layer
     'scaleshift_1': {'type': 'ScaleShift', 'kind': 'op', 'op': 'ScaleShift'},
-    'const_scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'scaleshift_1_w': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'scaleshift_1_b': {'value': None, 'shape': None, 'kind': 'data'},
     'scaleshift_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Mul and Add operations
     'mul_1': {'type': 'Mul', 'kind': 'op', 'op': 'Mul', 'can_be_fused': True},
-    'const_mul_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_mul_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'mul_1_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'mul_1_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_1': {'type': 'Add', 'kind': 'op', 'op': 'Add', 'can_be_fused': True},
-    'const_add_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_add_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'add_1_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_1_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     # Mul2 and Add2 operations
     'mul_2': {'type': 'Mul', 'kind': 'op', 'op': 'Mul', 'can_be_fused': True},
-    'const_mul_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_mul_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'mul_2_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'mul_2_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_2': {'type': 'Add', 'kind': 'op', 'op': 'Add', 'can_be_fused': True},
-    'const_add_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_add_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'add_2_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_2_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     # Mul3 and Add3 operations
     'mul_3': {'type': 'Mul', 'kind': 'op', 'op': 'Mul', 'can_be_fused': True},
-    'const_mul_3_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_mul_3_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'mul_3_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'mul_3_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_3': {'type': 'Add', 'kind': 'op', 'op': 'Add', 'can_be_fused': True},
-    'const_add_3_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_add_3_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'add_3_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_3_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     # Mul4 and Add4 operations
     'mul_4': {'type': 'Mul', 'kind': 'op', 'op': 'Mul', 'can_be_fused': True},
-    'const_mul_4_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_mul_4_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'mul_4_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'mul_4_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_4': {'type': 'Add', 'kind': 'op', 'op': 'Add', 'can_be_fused': True},
-    'const_add_4_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_add_4_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'add_4_w': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'add_4_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     # Concat1 operation
@@ -73,22 +73,22 @@ nodes_attributes = {
     'concat_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Convolutions
     'conv_1': {'type': 'Convolution', 'kind': 'op', 'op': 'Conv2D', 'layout': 'NHWC'},
-    'const_conv_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_conv_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'conv_1_w': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_conv_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_conv_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'conv_1_b': {'value': None, 'shape': None, 'kind': 'data'},
     'conv_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     'conv_2': {'type': 'Convolution', 'kind': 'op', 'op': 'Conv2D', 'layout': 'NHWC'},
-    'const_conv_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_conv_2_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'conv_2_w': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_conv_2_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_conv_2_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'conv_2_b': {'value': None, 'shape': None, 'kind': 'data'},
     'conv_2_data': {'value': None, 'shape': None, 'kind': 'data'},
     # FullyConnected
     'fc_1': {'type': 'MatMul', 'kind': 'op', 'op': 'FullyConnected', 'layout': 'NHWC'},
-    'const_fc_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_fc_1_w': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'fc_1_w': {'value': None, 'shape': None, 'kind': 'data'},
-    'const_fc_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None},
+    'const_fc_1_b': {'value': None, 'shape': None, 'kind': 'op', 'data_type': None, 'op': 'Const'},
     'fc_1_b': {'value': None, 'shape': None, 'kind': 'data'},
     'fc_1_data': {'value': None, 'shape': None, 'kind': 'data'},
     # Placeholders
@@ -96,7 +96,7 @@ nodes_attributes = {
     'placeholder_2_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
     'placeholder_3': {'shape': None, 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
     'placeholder_3_data': {'value': None, 'shape': None, 'kind': 'data', 'data_type': None},
-    'op_output': { 'kind': 'op', 'op': 'Result'}
+    'op_output': {'kind': 'op', 'op': 'Result'}
 }
 
 
index fd7d846..f76ca0d 100644 (file)
@@ -277,7 +277,7 @@ regular_op_with_empty_data = lambda name, kwargs: {**regular_op(name, kwargs), *
 
 # constants
 const = lambda name, value: {name: {'kind': 'op', 'value': value, 'shape': int64_array(value.shape),
-                                    'type': 'Const', 'infer': Const.infer}}
+                                    'type': 'Const', 'infer': Const.infer, 'op': 'Const'}}
 fake_const = lambda name, shape: {name: {'kind': 'op', 'value': None, 'infer': Const.infer,
                                          'shape': int64_array(shape) if shape is not None else None}}
 shaped_const_with_data = lambda name, shape: {**fake_const(name, shape), **shaped_data(name + '_d', shape)}