MO support for operations DFT and IDFT (#5197)
* Written MO classes for DFT and IDFT operations. * Added class to read TF (I)FFT operations. * Written extractors for TF operations FFT, FFT2D, FFT3D, IFFT, IFFT2D, IFFT3D. * Written MO Roll operation and TF Roll operation extractor. * Started to write needed transformations. * Written transformation StridedSlices + Complex + Roll + (i)FFTxD + Roll + (Imag, Real) + Pack -> Roll + (I)DFT + Roll. * Written transformation for Complex + ComplexAbs. * Written correction of axes of Roll. * Small fix. * Small fix. * Some fixes. * Some changes. * Now TF Roll is read as TFRoll. Written inserting Transposes before and after (I)DFT. * Small fix. * Written tests for the transformation TFRollToRoll. * Added comments to some transformations. * Deleted redundant import. * Written tests for the transformation TransposeDFT. * Fixes in MO IR Reader to read/write (I)DFT. * Fixes in the list of supported TF layers. * Started to write tests for SSliceComplexRolledFFTPackBlockReplacement transformation. * Written tests for the MO transformation SSliceComplexRolledFFTPackBlockReplacement. * Written tests for the MO transformation ComplexAbs. * Tests for transformations were moved into unit_tests directory. * All extractors for (I)FFTxD are in one file now. * Deleted redundant transformations. * Fixed extractor for TF Roll: now this operation is read as MO Roll. * Added comments to TFFFT operation. * The method insert_transpose of classes TransposeDFT and LayoutChangeForGatherND was moved into the separate function in the file model-optimizer/extensions/middle/InsertLayoutPropagationTransposes.py. * Fixed comment for the transformation TransposeDFT. * Small fix. * Some fixes. * Deleted shape infer function for the operation TFFFT. Sorted imports in complex_abs.py. * Small fixes. * Deleted redundant import. * Fixes in some asserts. * Small fix. * Added names for created nodes in the transformation ComplexAbs. * Added comments to the method canonicalize_axes. * The transformation SSliceComplexRolledFFTPackBlockReplacement was split into the sequence of transformations SSliceComplexRollReplacement -> RollRealImagPackReplacement -> TFFFTToDFT. * Written tests for the transformation SSliceComplexRollReplacement. * Written tests for the transformation RollRealImagPackReplacement. * Written tests for the transformation TFFFTToDFT. * Deleted commented code. * Fixed types of constants in the transformation ComplexAbs. * Written tests for canonicalization of signal_size value. * Deleted 'Replacement' from names of files and classes. * Used comarison of ids, not names. * replace_sub_graph was replaced with find_and_replace_pattern. * Now the transformation RollRealImagPack is executed before running transformation model-optimizer/extensions/front/Pack.py. * The body of the function create_dft_from_tffft is a part of the transformation TFFFTToDFT body now. * Now method correct_roll_axes of classes RollRealImagPack and SSliceComplexRoll is moved to the function in mo/front/tf/graph_utils.py. * Small changes. * Added comment before mark_input_as_in_correct_layout(roll, 2). * Now the functions correct_roll_axes generates sub-graph in the input port 2 of Roll. * Corrected tests for the transformation SSliceComplexRoll. * Corrected tests for the transformation RollRealImagPack. * Deleted commented code. * Some renaming. * Added decomposition of the separate operation ComplexAbs (without Complex before it). * Added comment to the transformation ComplexAbsAfterComplex. * Optimized imports for the transformation TFFFTToDFT. * The transformation SSliceComplexRoll was split into the sequence SSliceComplex -> CorrectRollAxes and disabled. * Written tests for the transformation ComplexAbs. * Written tests for the transformation SSliceComplex. * Written tests for the transformation CorrectRollAxes. * Deleted the transformation SSliceComplexRoll. * Deleted renaming nodes. * Fixed comment. * Small fixes. * Small fix. * The attribute need_correction was renamed as input_rank_changed. * Small fixes. * Deleted commented code. * Now we iterate over all complex_node.out_port(0).get_connection().get_destinations() input ports and mark the corresponding nodes with the marker attribute. * Added the attribute 'in_ports_count' into the class FFTBase. * Tests for the transformation TransposeDFT were rewritten using helper functions. * Now the transformation RollRealImagPack uses existing Roll node instead of creating new one. * Small fixes. * Fix in the documentation. * Written class to read MxNet (I)FFT operations. Written corresponding extractors. * Corrected shape infer function for MXFFT operation. Written transformation to convert MXFFT to (I)DFT. * Fixed shape infer function. * Fixed the conversion MXFFT to (I)DFT. * Written tests for the transformation MXFFTToDFT. * The function correct_roll_axes was replaced with more generic function add_constant_to_negative_values. * Fixes in classes TFFFT, FFTBase, DFT, IDFT, MXFFT. * Added asserts in constructors of operations TFFFT and MXFFT. * Refactored transformation MXFFTToDFT: conversion of DFT and IDFT were moved into separated functions. * Moved some commented code. * Fixed BOM file. * Written function convert_ifft_to_dft. * Started to rewrite tests for MXFFTToDFT transformations, in the case is_inverse=False. * Small fixes. * Fixes in the transformation RollRealImagPack. * Renaming tests class for the transformation SSliceComplex. * Fixes in the function compare_graphs. Now we get all output nodes of op node, and these output nodes are sorted by names. * Fixed tests for the transformation MXFFTToDFT. * Fix in the transformation ThresholdedReluDecomposition: added disconnect for trelu input port. * Fixes in test for the transformation TFSliceToSlice. * Small fix in the transformation ObjectDetectionAPIPreprocessor2Replacement. * Small fix in comment. * Optimized imports. * Used remove_node in the transformation ThresholdedReluDecomposition and remove_nodes_from in the transformation RollRealImagPack, instead of ports disconnection. * Deleted commented code. * Deleted test case test_slice_replacer_begin_with_2_inputs.
This commit is contained in:
1 parent
8645c08396
commit
0c288d506c
34 files changed
+1729
-77
No files matched your search
@@ -139,6 +139,8 @@ for more details and command line parameters used for the model conversion.
|
||||
```bash
|
||||
./<MO_INSTALL_DIR>/mo.py --input_model <PATH_TO_MODEL>/wnet_20.pb -b 1
|
||||
```
|
||||
> **NOTE:** This conversion guide is applicable for the 2021.3 release of OpenVINO and that starting from 2021.4
|
||||
> the OpenVINO supports this model out of the box.
|
||||
|
||||
Model Optimizer produces the following error:
|
||||
```bash
|
||||
|
||||
@@ -160,6 +160,9 @@ Standard TensorFlow\* operations:
|
||||
| EuclideanNorm | No |
|
||||
| FakeQuantWithMinMaxVars | No |
|
||||
| FakeQuantWithMinMaxVarsPerChannel | No |
|
||||
| FFT | Supported only when it is part of a sub-graph of the special form |
|
||||
| FFT2D | Supported only when it is part of a sub-graph of the special form |
|
||||
| FFT3D | Supported only when it is part of a sub-graph of the special form |
|
||||
| Fill | No |
|
||||
| Floor | No |
|
||||
| FloorDiv | No |
|
||||
@@ -172,6 +175,9 @@ Standard TensorFlow\* operations:
|
||||
| Greater | No |
|
||||
| GreaterEqual | No |
|
||||
| Identity | Not needed for shape inference |
|
||||
| IFFT | Supported only when it is part of a sub-graph of the special form |
|
||||
| IFFT2D | Supported only when it is part of a sub-graph of the special form |
|
||||
| IFFT3D | Supported only when it is part of a sub-graph of the special form |
|
||||
| LRN | No |
|
||||
| Less | No |
|
||||
| Log | No |
|
||||
|
||||
@@ -60,6 +60,7 @@ extensions/back/ShufflenetReLUReorder.py
|
||||
extensions/back/SpecialNodesFinalization.py
|
||||
extensions/back/StridedSliceMasksNormalizer.py
|
||||
extensions/back/TopKNormalizer.py
|
||||
extensions/back/TransposeDFT.py
|
||||
extensions/back/TransposeReduceFusing.py
|
||||
extensions/back/UselessConcatRemoval.py
|
||||
extensions/front/__init__.py
|
||||
@@ -196,6 +197,7 @@ extensions/front/mxnet/elementwise_ext.py
|
||||
extensions/front/mxnet/eltwise_scalar_replacers.py
|
||||
extensions/front/mxnet/exp_ext.py
|
||||
extensions/front/mxnet/expand_dims_ext.py
|
||||
extensions/front/mxnet/fft_ext.py
|
||||
extensions/front/mxnet/flatten_ext.py
|
||||
extensions/front/mxnet/fully_connected_ext.py
|
||||
extensions/front/mxnet/gather.py
|
||||
@@ -208,6 +210,7 @@ extensions/front/mxnet/max_ext.py
|
||||
extensions/front/mxnet/multibox_detection_ext.py
|
||||
extensions/front/mxnet/mx_reshape_reverse.py
|
||||
extensions/front/mxnet/mx_reshape_to_reshape.py
|
||||
extensions/front/mxnet/MXFFTToDFT.py
|
||||
extensions/front/mxnet/MXRepeatReplacer.py
|
||||
extensions/front/mxnet/null_ext.py
|
||||
extensions/front/mxnet/pad_ext.py
|
||||
@@ -383,10 +386,13 @@ extensions/front/tf/broadcast_ext.py
|
||||
extensions/front/tf/bucketize.py
|
||||
extensions/front/tf/bucketize_ext.py
|
||||
extensions/front/tf/Cast_ext.py
|
||||
extensions/front/tf/ComplexAbs.py
|
||||
extensions/front/tf/ComplexAbsAfterComplex.py
|
||||
extensions/front/tf/concat.py
|
||||
extensions/front/tf/concat_ext.py
|
||||
extensions/front/tf/const_ext.py
|
||||
extensions/front/tf/conv_ext.py
|
||||
extensions/front/tf/CorrectRollAxes.py
|
||||
extensions/front/tf/crop_and_resize_ext.py
|
||||
extensions/front/tf/CropAndResizeReplacement.py
|
||||
extensions/front/tf/CTCGreedyDecoder_ext.py
|
||||
@@ -413,6 +419,7 @@ extensions/front/tf/faster_rcnn_support_api_v1.15.json
|
||||
extensions/front/tf/faster_rcnn_support_api_v1.7.json
|
||||
extensions/front/tf/faster_rcnn_support_api_v2.0.json
|
||||
extensions/front/tf/faster_rcnn_support_api_v2.4.json
|
||||
extensions/front/tf/fft_ext.py
|
||||
extensions/front/tf/fifo_queue_v2_ext.py
|
||||
extensions/front/tf/fifo_replacer.py
|
||||
extensions/front/tf/fill_ext.py
|
||||
@@ -471,6 +478,7 @@ extensions/front/tf/rfcn_support_api_v1.10.json
|
||||
extensions/front/tf/rfcn_support_api_v1.13.json
|
||||
extensions/front/tf/rfcn_support_api_v1.14.json
|
||||
extensions/front/tf/roll_ext.py
|
||||
extensions/front/tf/RollRealImagPack.py
|
||||
extensions/front/tf/select_ext.py
|
||||
extensions/front/tf/sign_ext.py
|
||||
extensions/front/tf/SizeReplacer.py
|
||||
@@ -495,12 +503,14 @@ extensions/front/tf/ssd_toolbox_detection_output.json
|
||||
extensions/front/tf/ssd_toolbox_multihead_detection_output.json
|
||||
extensions/front/tf/ssd_v2_support.json
|
||||
extensions/front/tf/SSDToolboxDetectionOutput.py
|
||||
extensions/front/tf/SSliceComplex.py
|
||||
extensions/front/tf/swap_deconv_inputs.py
|
||||
extensions/front/tf/swish_ext.py
|
||||
extensions/front/tf/SwitchMergeOptimization.py
|
||||
extensions/front/tf/TensorArrayExtractors.py
|
||||
extensions/front/tf/TensorArrayGatherV3.py
|
||||
extensions/front/tf/tensorflow_custom_operations_config_update.py
|
||||
extensions/front/tf/TFFFTToDFT.py
|
||||
extensions/front/tf/TFResizeToInterpolate.py
|
||||
extensions/front/tf/TFSliceToSlice.py
|
||||
extensions/front/tf/tile_ext.py
|
||||
@@ -667,6 +677,7 @@ extensions/ops/depth_to_space.py
|
||||
extensions/ops/dequantize_linear.py
|
||||
extensions/ops/DetectionOutput.py
|
||||
extensions/ops/detectionoutput_onnx.py
|
||||
extensions/ops/dft.py
|
||||
extensions/ops/elementwise.py
|
||||
extensions/ops/embedding_bag.py
|
||||
extensions/ops/Enter.py
|
||||
@@ -695,6 +706,7 @@ extensions/ops/lstm_sequence.py
|
||||
extensions/ops/MatMul.py
|
||||
extensions/ops/merge.py
|
||||
extensions/ops/mvn.py
|
||||
extensions/ops/mxfft.py
|
||||
extensions/ops/mxrepeat.py
|
||||
extensions/ops/mxreshape.py
|
||||
extensions/ops/NextIteration.py
|
||||
@@ -760,6 +772,7 @@ extensions/ops/TensorArrayScatter.py
|
||||
extensions/ops/TensorArraySize.py
|
||||
extensions/ops/TensorArrayWrite.py
|
||||
extensions/ops/TensorIterator_ops.py
|
||||
extensions/ops/TFFFT.py
|
||||
extensions/ops/TFResize.py
|
||||
extensions/ops/topk.py
|
||||
extensions/ops/topkrois_onnx.py
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.ops.transpose import Transpose
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.graph.graph import Graph, Port
|
||||
from mo.back.replacement import BackReplacementPattern
|
||||
from mo.graph.graph import Graph
|
||||
|
||||
|
||||
class LayoutChangeForGatherND(BackReplacementPattern):
|
||||
@@ -19,31 +14,9 @@ class LayoutChangeForGatherND(BackReplacementPattern):
|
||||
force_shape_inference = True
|
||||
graph_condition = [lambda graph: graph.graph['fw'] == 'tf']
|
||||
|
||||
@staticmethod
|
||||
def insert_transpose(graph: Graph, input_port: Port, before_input=True):
|
||||
input_rank = len(input_port.data.get_shape())
|
||||
if input_rank > 3:
|
||||
if before_input:
|
||||
axis_order = np.concatenate((int64_array([0]),
|
||||
int64_array(list(range(2, input_rank))),
|
||||
int64_array([1])))
|
||||
source_node = input_port.get_source().node
|
||||
transpose_name = source_node.soft_get('name', source_node.id) + '/TransposeToNHWC'
|
||||
else:
|
||||
axis_order = np.concatenate(
|
||||
(int64_array([0]),
|
||||
int64_array([input_rank - 1]),
|
||||
int64_array(list(range(1, input_rank - 1)))))
|
||||
transpose_name = input_port.node.soft_get('name', input_port.node.id) + '/TransposeToNCHW'
|
||||
input_port.node['need_shape_inference'] = True
|
||||
input_port.node['override_output_shape'] = True
|
||||
transpose = create_op_with_const_inputs(graph, Transpose, {1: axis_order}, {'name': transpose_name})
|
||||
input_port.get_connection().insert_node(transpose)
|
||||
transpose['need_shape_inference'] = True
|
||||
transpose['override_output_shape'] = True
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
import extensions.middle.InsertLayoutPropagationTransposes as InsertTransposes
|
||||
for gathernd in graph.get_op_nodes(type='GatherND'):
|
||||
self.insert_transpose(graph, gathernd.in_port(0), before_input=True)
|
||||
self.insert_transpose(graph, gathernd.in_port(1), before_input=True)
|
||||
self.insert_transpose(graph, gathernd.out_port(0), before_input=False)
|
||||
InsertTransposes.insert_transpose(graph, gathernd.in_port(0), before_input=True)
|
||||
InsertTransposes.insert_transpose(graph, gathernd.in_port(1), before_input=True)
|
||||
InsertTransposes.insert_transpose(graph, gathernd.out_port(0), before_input=False)
|
||||
@@ -0,0 +1,34 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from mo.back.replacement import BackReplacementPattern
|
||||
from mo.graph.graph import Graph
|
||||
|
||||
|
||||
class TransposeDFT(BackReplacementPattern):
|
||||
"""
|
||||
In TF models, operation (I)FFTxD has some input shape, [N_0, ..., N_{r - 1}].
|
||||
|
||||
After the transformation SSliceComplexRolledFFTPackBlockReplacement, we have an input shape [N_0, ..., N_{r - 1}, 2]
|
||||
for operation DFT or IDFT.
|
||||
|
||||
If the input rank in the TF model was greater than 2, we have [N_0, 2, N_1, ..., N_{r - 1}] as the input shape of
|
||||
(I)DFT after the layout conversion, if the option '--disable_nhwc_to_nchw' is not specified.
|
||||
|
||||
But, generally speaking, according to DFT and IDFT specifications, the input shape [N_0, 2, N_1, ..., N_{r - 1}]
|
||||
is not correct input shape for DFT and IDFT. Hence, we need to insert Transpose operations before and after (I)DFT
|
||||
in such cases.
|
||||
|
||||
This transformation inserts such Transpose nodes, when the source model was the TF model, (I)DFT node has the
|
||||
attribute 'need_insert_transposes_for_dft', and this attribute is True.
|
||||
"""
|
||||
enabled = True
|
||||
force_shape_inference = True
|
||||
graph_condition = [lambda graph: graph.graph['fw'] == 'tf']
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
import extensions.middle.InsertLayoutPropagationTransposes as InsertTransposes
|
||||
for dft in graph.get_op_nodes(need_insert_transposes_for_dft=True):
|
||||
InsertTransposes.insert_transpose(graph, dft.in_port(0), before_input=True)
|
||||
InsertTransposes.insert_transpose(graph, dft.out_port(0), before_input=False)
|
||||
@@ -36,3 +36,4 @@ class ThresholdedReluDecomposition(FrontReplacementPattern):
|
||||
mul.in_port(1).connect(float_greater.out_port(0))
|
||||
|
||||
rename_nodes([(node, name + '/TBR'), (mul, name)])
|
||||
graph.remove_node(node.id)
|
||||
@@ -0,0 +1,140 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.ops.dft import DFT, IDFT
|
||||
from extensions.ops.elementwise import Add, Sub
|
||||
from extensions.ops.rank import Rank
|
||||
from extensions.ops.scatter import ScatterUpdate
|
||||
from extensions.ops.split import Split
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.graph.graph import Graph, Node, rename_nodes
|
||||
from mo.front.common.replacement import FrontReplacementSubgraph
|
||||
from mo.ops.broadcast import Broadcast
|
||||
from mo.ops.concat import Concat
|
||||
from mo.ops.pad import Pad
|
||||
from mo.ops.reshape import Reshape
|
||||
from mo.ops.squeeze import Squeeze
|
||||
from mo.ops.unsqueeze import Unsqueeze
|
||||
|
||||
|
||||
class MXFFTToDFT(FrontReplacementSubgraph):
|
||||
"""
|
||||
This transformation converts the operation MXFFT into OpenVINO DFT (if the attribute 'is_inverse' is False),
|
||||
or into OpenVINO IDFT (otherwise).
|
||||
|
||||
According to https://mxnet.apache.org/versions/1.0.0/api/python/symbol/contrib.html#mxnet.symbol.contrib.fft,
|
||||
MxNet operation FFT accept 2 input data shapes: [N, d] or [N_1, N_2, N_3, d], data can only be real numbers.
|
||||
The output data has shape: [N, 2*d] or [N_1, N_2, N_3, 2*d]. The format is: [real0, imag0, real1, imag1, ...].
|
||||
|
||||
Next, MxNet operation IFFT accept 2 input data shapes: [N, d] or [N_1, N_2, N_3, d]. Data is in format:
|
||||
[real0, imag0, real1, imag1, ...]. Last dimension must be an even number. The output data has shape: [N, d/2] or
|
||||
[N_1, N_2, N_3, d/2]. It is only the real part of the result.
|
||||
|
||||
But OpenVINO DFT and IDFT operations uses complex input data represented as real tensors of the shape
|
||||
[N_1, ..., N_r, 2]. Also, the result of OpenVINO DFT and IDFT operations is always complex but represented as
|
||||
a real tensor of the shape [M_1, ..., M_r, 2]. If OpenVINO DFT or IDFT have no input signal_size, the output shape
|
||||
and the input shape are the same.
|
||||
|
||||
Hence, to convert MxNet FFT to OpenVINO DFT, we need
|
||||
1) to convert input data from the shape [N, d] or [N_1, N_2, N_3, d] to shape [N, d, 1] or [N_1, N_2, N_3, d, 1]
|
||||
respectively;
|
||||
2) to pad converted data using pads_begin = [0, 0, 0] and pads_end = [0, 0, 1] for MxNet FFT input shape [N, d], or
|
||||
using pads_begin [0, 0, 0, 0, 0] and pads_end = [0, 0, 0, 0, 1] for MxNet FFT input shape [N_1, N_2, N_3, d],
|
||||
with mode=constant;
|
||||
3) to put padded data into DFT input 0, using (-1) in 'axes' input;
|
||||
4) to reshape calculated DFT output to the shape [N, 2 * d] for for MxNet FFT input shape [N, d], or to the shape
|
||||
[N_1, N_2, N_3, 2 * d]
|
||||
|
||||
Finally, to convert MxNet IFFT to OpenVINO IDFT, we need
|
||||
1) to reshape input data from the shape [N, d] or [N_1, N_2, N_3, d] to shape [N, d // 2, 2] or
|
||||
[N_1, N_2, N_3, d // 2, 2] respectively;
|
||||
2) to put reshaped input data to the input 0 of IDFT, using (-1) in 'axes' input;
|
||||
3) to get real parts using Split + Squeeze.
|
||||
"""
|
||||
enabled = True
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for mx_fft in graph.get_op_nodes(op='MXFFT'):
|
||||
if mx_fft.soft_get('is_inverse', False):
|
||||
self.convert_ifft_to_dft(graph, mx_fft)
|
||||
else:
|
||||
self.convert_fft_to_dft(graph, mx_fft)
|
||||
|
||||
def convert_fft_to_dft(self, graph: Graph, mx_fft: Node):
|
||||
mx_fft_name = mx_fft.soft_get('name', mx_fft.id)
|
||||
unsqueeze_node = create_op_with_const_inputs(graph, Unsqueeze, {1: int64_array([-1])},
|
||||
{'name': mx_fft_name + '/Unsqueeze'})
|
||||
rank_node = Rank(graph, {'name': mx_fft_name + '/Rank'}).create_node()
|
||||
|
||||
mx_fft_connection = mx_fft.in_port(0).get_connection()
|
||||
mx_fft_connection.set_destination(unsqueeze_node.in_port(0))
|
||||
mx_fft_connection.get_source().connect(rank_node.in_port(0))
|
||||
|
||||
add_node = create_op_with_const_inputs(graph, Add, {1: int64_array(1)},
|
||||
{'name': mx_fft_name + '/Add'}, rank_node)
|
||||
broadcast_node1 = create_op_with_const_inputs(graph, Broadcast, {0: int64_array(0)},
|
||||
{'name': mx_fft_name + '/Pad_broadcast'})
|
||||
add_node.out_port(0).connect(broadcast_node1.in_port(1))
|
||||
|
||||
scatter_node = create_op_with_const_inputs(graph, ScatterUpdate,
|
||||
{2: int64_array(1), 3: int64_array(0)},
|
||||
{'name': mx_fft_name + '/ScatterUpdate'})
|
||||
broadcast_node1.out_port(0).connect(scatter_node.in_port(0))
|
||||
rank_node.out_port(0).connect(scatter_node.in_port(1))
|
||||
|
||||
pad_node = Pad(graph, {'name': mx_fft_name + '/Pad', 'mode': 'constant'}).create_node([unsqueeze_node,
|
||||
broadcast_node1,
|
||||
scatter_node])
|
||||
|
||||
dft_node = create_op_with_const_inputs(graph, DFT, {1: int64_array([-1])},
|
||||
{'name': mx_fft_name + '/DFT', 'in_ports_count': 2},
|
||||
pad_node)
|
||||
|
||||
sub_node = create_op_with_const_inputs(graph, Sub, {1: int64_array(1)}, {'name': mx_fft_name + '/Sub'})
|
||||
rank_node.out_port(0).connect(sub_node.in_port(0))
|
||||
broadcast_node2 = create_op_with_const_inputs(graph, Broadcast, {0: int64_array(0)},
|
||||
{'name': mx_fft_name + '/Reshape_broadcast'})
|
||||
sub_node.out_port(0).connect(broadcast_node2.in_port(1))
|
||||
concat_node = create_op_with_const_inputs(graph, Concat, {1: int64_array([-1, 2])},
|
||||
{'name': mx_fft_name + '/New_shape', 'in_ports_count': 2, 'axis': 0},
|
||||
broadcast_node2)
|
||||
|
||||
reshape_node = Reshape(graph, {}).create_node([dft_node, concat_node])
|
||||
|
||||
mx_fft.out_port(0).get_connection().set_source(reshape_node.out_port(0))
|
||||
rename_nodes([(mx_fft, mx_fft_name + '/to_be_removed'), (reshape_node, mx_fft_name)])
|
||||
|
||||
def convert_ifft_to_dft(self, graph: Graph, mx_fft: Node):
|
||||
mx_fft_name = mx_fft.soft_get('name', mx_fft.id)
|
||||
|
||||
rank_node = Rank(graph, {'name': mx_fft_name + '/rank'}).create_node()
|
||||
sub_node = create_op_with_const_inputs(graph, Sub, {1: int64_array(1)}, {'name': mx_fft_name + '/Sub'})
|
||||
rank_node.out_port(0).connect(sub_node.in_port(0))
|
||||
broadcast_node0 = create_op_with_const_inputs(graph, Broadcast, {0: int64_array(0)},
|
||||
{'name': mx_fft_name + '/broadcast'})
|
||||
sub_node.out_port(0).connect(broadcast_node0.in_port(1))
|
||||
concat_node = create_op_with_const_inputs(graph, Concat, {1: int64_array([-1, 2])},
|
||||
{'name': mx_fft_name + '/new_shape', 'in_ports_count': 2, 'axis': 0},
|
||||
broadcast_node0)
|
||||
|
||||
reshape_node = Reshape(graph, {'name': mx_fft_name + '/reshape'}).create_node()
|
||||
concat_node.out_port(0).connect(reshape_node.in_port(1))
|
||||
|
||||
mx_fft_connection = mx_fft.in_port(0).get_connection()
|
||||
mx_fft_connection.set_destination(reshape_node.in_port(0))
|
||||
mx_fft_connection.get_source().connect(rank_node.in_port(0))
|
||||
|
||||
dft_node = create_op_with_const_inputs(graph, IDFT, {1: int64_array([-1])},
|
||||
{'name': mx_fft_name + '/idft', 'in_ports_count': 2},
|
||||
reshape_node)
|
||||
|
||||
split_node = create_op_with_const_inputs(graph, Split, {1: int64_array(-1)},
|
||||
{'name': mx_fft_name + '/split', 'num_splits': 2},
|
||||
dft_node)
|
||||
squeeze_node = create_op_with_const_inputs(graph, Squeeze, {1: int64_array([-1])}, {}, split_node)
|
||||
|
||||
mx_fft.out_port(0).get_connection().set_source(squeeze_node.out_port(0))
|
||||
rename_nodes([(mx_fft, mx_fft_name + '/to_be_removed'), (squeeze_node, mx_fft_name)])
|
||||
@@ -0,0 +1,25 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from extensions.ops.mxfft import MXFFT
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
|
||||
|
||||
class FFTFrontExtractor(FrontExtractorOp):
|
||||
op = 'fft'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
MXFFT.update_node_stat(node, {'is_inverse': False})
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class IFFTFrontExtractor(FrontExtractorOp):
|
||||
op = 'ifft'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
MXFFT.update_node_stat(node, {'is_inverse': True})
|
||||
return cls.enabled
|
||||
@@ -0,0 +1,36 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from extensions.ops.elementwise import Pow
|
||||
from extensions.ops.ReduceOps import ReduceSum
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.common.replacement import FrontReplacementSubgraph
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.graph.graph import Graph, rename_nodes
|
||||
from mo.middle.passes.convert_data_type import data_type_str_to_np
|
||||
|
||||
|
||||
class ComplexAbs(FrontReplacementSubgraph):
|
||||
enabled = True
|
||||
|
||||
def run_after(self):
|
||||
from extensions.front.tf.ComplexAbsAfterComplex import ComplexAbsAfterComplex
|
||||
return [ComplexAbsAfterComplex]
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for complex_abs in graph.get_op_nodes(op='ComplexAbs'):
|
||||
complex_abs_name = complex_abs.soft_get('name', complex_abs.id)
|
||||
power_type = data_type_str_to_np(graph.graph['cmd_params'].data_type)
|
||||
|
||||
squared = create_op_with_const_inputs(graph, Pow, {1: power_type(2.0)},
|
||||
{'name': complex_abs_name + '/squared_parts'})
|
||||
complex_abs.in_port(0).get_connection().set_destination(squared.in_port(0))
|
||||
sum = create_op_with_const_inputs(graph, ReduceSum, {1: int64_array(-1)},
|
||||
{'name': complex_abs_name + '/squared_abs'},
|
||||
squared)
|
||||
sqrt = create_op_with_const_inputs(graph, Pow, {1: power_type(0.5)}, {}, sum)
|
||||
|
||||
complex_abs.out_port(0).get_connection().set_source(sqrt.out_port(0))
|
||||
|
||||
rename_nodes([(complex_abs, complex_abs_name + '/to_be_removed'), (sqrt, complex_abs_name)])
|
||||
@@ -0,0 +1,69 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from extensions.ops.elementwise import Add, Pow
|
||||
from mo.front.common.replacement import FrontReplacementSubgraph
|
||||
from mo.front.subgraph_matcher import SubgraphMatch
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.graph.graph import Graph, rename_nodes
|
||||
from mo.middle.passes.convert_data_type import data_type_str_to_np
|
||||
|
||||
|
||||
class ComplexAbsAfterComplex(FrontReplacementSubgraph):
|
||||
"""
|
||||
This transformation converts a sub-graph
|
||||
|
||||
SomeOp1 SomeOp2
|
||||
| |
|
||||
------------
|
||||
|
|
||||
Complex
|
||||
|
|
||||
ComplexAbs
|
||||
|
||||
into the sub-graph
|
||||
|
||||
SomeOp1 SomeOp2
|
||||
| |
|
||||
Constant[2]--Pow Pow--Constant[2]
|
||||
| |
|
||||
-------------
|
||||
Add
|
||||
|
|
||||
Pow--Constant[0.5]
|
||||
"""
|
||||
enabled = True
|
||||
|
||||
def pattern(self):
|
||||
return dict(
|
||||
nodes=[
|
||||
('complex', dict(op='Complex')),
|
||||
('abs', dict(op='ComplexAbs')),
|
||||
],
|
||||
edges=[
|
||||
('complex', 'abs', {'in': 0}),
|
||||
])
|
||||
|
||||
def replace_sub_graph(self, graph: Graph, match: [dict, SubgraphMatch]):
|
||||
cmp = match['complex']
|
||||
complex_abs = match['abs']
|
||||
complex_abs_name = complex_abs.soft_get('name', complex_abs.id)
|
||||
|
||||
power_type = data_type_str_to_np(graph.graph['cmd_params'].data_type)
|
||||
|
||||
pow0 = create_op_with_const_inputs(graph, Pow, {1: power_type(2.0)},
|
||||
{'name': complex_abs_name + '/real_part_squared'})
|
||||
pow1 = create_op_with_const_inputs(graph, Pow, {1: power_type(2.0)},
|
||||
{'name': complex_abs_name + '/imag_part_squared'})
|
||||
|
||||
cmp.in_port(0).get_connection().set_destination(pow0.in_port(0))
|
||||
cmp.in_port(1).get_connection().set_destination(pow1.in_port(0))
|
||||
|
||||
add = Add(graph, {'name': complex_abs_name + '/squared_abs'}).create_node([pow0, pow1])
|
||||
sqrt = create_op_with_const_inputs(graph, Pow, {1: power_type(0.5)}, {})
|
||||
add.out_port(0).connect(sqrt.in_port(0))
|
||||
|
||||
complex_abs.out_port(0).get_connection().set_source(sqrt.out_port(0))
|
||||
|
||||
rename_nodes([(complex_abs, complex_abs_name + '/to_be_removed'), (sqrt, complex_abs_name)])
|
||||
@@ -0,0 +1,27 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.common.replacement import FrontReplacementSubgraph
|
||||
from mo.front.tf.graph_utils import add_constant_to_negative_values
|
||||
from mo.graph.graph import Graph
|
||||
|
||||
|
||||
class CorrectRollAxes(FrontReplacementSubgraph):
|
||||
"""
|
||||
The transformation SSliceComplex removes 2 StridedSlice and Complex operation. If the Roll node is a consumer
|
||||
of Complex node in the original TF model, then we have a real input tensor for Roll instead of a complex.
|
||||
Negative axes values for the Roll operation should be updated to reflect the fact that the rank of input tensor was
|
||||
increased by one (a new trailing dimension of size 2 containing real and imaginary part of complex number is added).
|
||||
"""
|
||||
enabled = True
|
||||
|
||||
def run_after(self):
|
||||
from extensions.front.tf.SSliceComplex import SSliceComplex
|
||||
return [SSliceComplex]
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for roll in graph.get_op_nodes(op='Roll', input_rank_changed=True):
|
||||
add_constant_to_negative_values(roll, 2, int64_array(-1))
|
||||
del roll['input_rank_changed']
|
||||
@@ -765,6 +765,7 @@ class ObjectDetectionAPIPreprocessor2Replacement(FrontReplacementFromConfigFileG
|
||||
else: # case 1
|
||||
# change output of the end_node to be produced with the last preprocessing op
|
||||
end_node.out_port(0).get_connection().set_source(pre_processing_ops[-1][0].out_port(0))
|
||||
start_node.in_port(0).disconnect()
|
||||
else: # simply remove the nodes in between start_node and end_node (including them). Case 3 and 6
|
||||
end_node.out_port(0).get_connection().set_source(start_node.in_port(0).get_source())
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.common.replacement import FrontReplacementSubgraph
|
||||
from mo.front.subgraph_matcher import SubgraphMatch
|
||||
from mo.front.tf.graph_utils import add_constant_to_negative_values
|
||||
from mo.graph.graph import Graph
|
||||
|
||||
|
||||
class RollRealImagPack(FrontReplacementSubgraph):
|
||||
"""
|
||||
Some TF models contain Roll for complex data, as a part of the sub-graph
|
||||
|
||||
input shift axes
|
||||
| | |
|
||||
-------------------
|
||||
Roll
|
||||
|
|
||||
-------------------
|
||||
| |
|
||||
Real Imag
|
||||
| |
|
||||
------- -------
|
||||
| |
|
||||
Pack
|
||||
|
|
||||
SomeOp
|
||||
|
||||
This sub-graph can be replaced with the sub-graph
|
||||
|
||||
input shift axes
|
||||
| | |
|
||||
-------------------
|
||||
Roll
|
||||
|
|
||||
SomeOp
|
||||
|
||||
But after such replacement, we should correct axes of Roll, because input data are real now. Namely, if
|
||||
there are negative axes for Roll, we need subtract 1 from such axes indices.
|
||||
"""
|
||||
enabled = True
|
||||
|
||||
def run_after(self):
|
||||
from extensions.front.tf.SSliceComplex import SSliceComplex
|
||||
return [SSliceComplex]
|
||||
|
||||
def run_before(self):
|
||||
from extensions.front.Pack import Pack
|
||||
return [Pack]
|
||||
|
||||
def pattern(self):
|
||||
return dict(
|
||||
nodes=[
|
||||
('unroll', dict(op='Roll')),
|
||||
('real', dict(op='Real')),
|
||||
('imag', dict(op='Imag')),
|
||||
('pack', dict(op='Pack')),
|
||||
],
|
||||
edges=[
|
||||
('unroll', 'real', {'in': 0}),
|
||||
('unroll', 'imag', {'in': 0}),
|
||||
('real', 'pack', {'in': 0}),
|
||||
('imag', 'pack', {'in': 1}),
|
||||
])
|
||||
|
||||
def replace_sub_graph(self, graph: Graph, match: [dict, SubgraphMatch]):
|
||||
unroll = match['unroll']
|
||||
add_constant_to_negative_values(unroll, 2, int64_array(-1))
|
||||
pack = match['pack']
|
||||
pack.out_port(0).get_connection().set_source(unroll.out_port(0))
|
||||
graph.remove_nodes_from([match['real'].id, match['imag'].id])
|
||||
@@ -0,0 +1,70 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import logging as log
|
||||
|
||||
from mo.front.common.replacement import FrontReplacementSubgraph
|
||||
from mo.front.subgraph_matcher import SubgraphMatch
|
||||
from mo.graph.graph import Graph
|
||||
|
||||
|
||||
class SSliceComplex(FrontReplacementSubgraph):
|
||||
"""
|
||||
Some TF models contain the sub-graph
|
||||
SomeOp
|
||||
|
|
||||
--------------------------
|
||||
| |
|
||||
StridedSlice StridedSlice
|
||||
| |
|
||||
------------------------
|
||||
Complex
|
||||
|
|
||||
| other inputs
|
||||
| | ... |
|
||||
-------------------
|
||||
SomeOp1
|
||||
|
||||
Here SomeOp is some node with real output and with the shape [N_0, ..., N_{r - 1}, 2], and StridedSlice nodes
|
||||
have output shapes [N_0, ..., N_{r - 1}].
|
||||
|
||||
But MO and Inference Engine do not support complex tensors. Hence, we need to replace this sub-graph with
|
||||
|
||||
SomeOp other inputs
|
||||
| | ... |
|
||||
-------------------
|
||||
SomeOp1
|
||||
|
||||
After this transformation we need to mark SomeOp1 operation that its input rank has changed because
|
||||
its inputs/attributes should probably be updated. Currently we have such a case for a Roll operation.
|
||||
"""
|
||||
enabled = True
|
||||
|
||||
def pattern(self):
|
||||
return dict(
|
||||
nodes=[
|
||||
('strided_slice_real', dict(op='StridedSlice')),
|
||||
('strided_slice_imag', dict(op='StridedSlice')),
|
||||
('complex', dict(op='Complex')),
|
||||
],
|
||||
edges=[
|
||||
('strided_slice_real', 'complex', {'in': 0}),
|
||||
('strided_slice_imag', 'complex', {'in': 1}),
|
||||
])
|
||||
|
||||
def replace_sub_graph(self, graph: Graph, match: [dict, SubgraphMatch]):
|
||||
strided_slice_real = match['strided_slice_real']
|
||||
strided_slice_imag = match['strided_slice_imag']
|
||||
|
||||
real_input = strided_slice_real.in_port(0).get_source().node
|
||||
imag_input = strided_slice_imag.in_port(0).get_source().node
|
||||
if real_input.id != imag_input.id:
|
||||
log.debug('The pattern does not correspond to operation for complex tensor. Different inputs.')
|
||||
return
|
||||
|
||||
complex_node = match['complex']
|
||||
for dst in complex_node.out_port(0).get_connection().get_destinations():
|
||||
after_complex_node = dst.node
|
||||
after_complex_node['input_rank_changed'] = True
|
||||
complex_node.out_port(0).get_connection().set_source(strided_slice_real.in_port(0).get_source())
|
||||
@@ -0,0 +1,38 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from extensions.ops.dft import DFT, IDFT
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.common.replacement import FrontReplacementSubgraph
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.graph.graph import Graph, rename_nodes
|
||||
|
||||
|
||||
class TFFFTToDFT(FrontReplacementSubgraph):
|
||||
"""
|
||||
This transformation converts the operation TFFFT into OpenVINO DFT (if the attribute 'is_inverse' is False),
|
||||
or into OpenVINO IDFT (otherwise).
|
||||
"""
|
||||
enabled = True
|
||||
|
||||
def run_after(self):
|
||||
from extensions.front.tf.RollRealImagPack import RollRealImagPack
|
||||
return [RollRealImagPack]
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for tf_fft in graph.get_op_nodes(op='TFFFT'):
|
||||
tf_fft_name = tf_fft.soft_get('name', tf_fft.id)
|
||||
|
||||
num_of_dims = tf_fft.soft_get('num_of_dimensions', 1)
|
||||
axes = int64_array(range(-num_of_dims, 0))
|
||||
op = IDFT if tf_fft.soft_get('is_inverse', False) else DFT
|
||||
dft_node = create_op_with_const_inputs(graph, op, {1: axes}, {'in_ports_count': 2},
|
||||
tf_fft.in_port(0).get_source().node)
|
||||
|
||||
tf_fft.out_port(0).get_connection().set_source(dft_node.out_port(0))
|
||||
|
||||
rename_nodes([(tf_fft, tf_fft_name + '/to_be_removed'), (dft_node, tf_fft_name)])
|
||||
|
||||
if graph.graph['layout'] == 'NHWC':
|
||||
dft_node['need_insert_transposes_for_dft'] = True
|
||||
@@ -0,0 +1,71 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from extensions.ops.TFFFT import TFFFT
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
|
||||
|
||||
class FFT1DOpFrontExtractor(FrontExtractorOp):
|
||||
op = 'FFT'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
attrs = {'num_of_dimensions': 1, 'is_inverse': False}
|
||||
TFFFT.update_node_stat(node, attrs)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class FFT2DOpFrontExtractor(FrontExtractorOp):
|
||||
op = 'FFT2D'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
attrs = {'num_of_dimensions': 2, 'is_inverse': False}
|
||||
TFFFT.update_node_stat(node, attrs)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class FFT3DOpFrontExtractor(FrontExtractorOp):
|
||||
op = 'FFT3D'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
attrs = {'num_of_dimensions': 3, 'is_inverse': False}
|
||||
TFFFT.update_node_stat(node, attrs)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class IFFT1DOpFrontExtractor(FrontExtractorOp):
|
||||
op = 'IFFT'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
attrs = {'num_of_dimensions': 1, 'is_inverse': True}
|
||||
TFFFT.update_node_stat(node, attrs)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class IFFT2DOpFrontExtractor(FrontExtractorOp):
|
||||
op = 'IFFT2D'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
attrs = {'num_of_dimensions': 2, 'is_inverse': True}
|
||||
TFFFT.update_node_stat(node, attrs)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class IFFT3DOpFrontExtractor(FrontExtractorOp):
|
||||
op = 'IFFT3D'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
attrs = {'num_of_dimensions': 3, 'is_inverse': True}
|
||||
TFFFT.update_node_stat(node, attrs)
|
||||
return cls.enabled
|
||||
@@ -1,10 +1,12 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.middle.pass_separator import PostMiddleStart
|
||||
from extensions.ops.transpose import Transpose
|
||||
|
||||
from mo.graph.graph import Graph, Node
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.graph.graph import Graph, Node, Port
|
||||
from mo.middle.replacement import MiddleReplacementPattern
|
||||
from mo.ops.op import PermuteAttrs
|
||||
|
||||
@@ -159,3 +161,28 @@ def mark_as_correct_data_layout(node: Node):
|
||||
|
||||
for ind, port in node.out_ports().items():
|
||||
mark_output_as_in_correct_layout(node, ind)
|
||||
|
||||
|
||||
def insert_transpose(graph: Graph, input_port: Port, before_input=True):
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
|
||||
input_rank = len(input_port.data.get_shape())
|
||||
if input_rank > 3:
|
||||
if before_input:
|
||||
axis_order = np.concatenate((int64_array([0]),
|
||||
int64_array(list(range(2, input_rank))),
|
||||
int64_array([1])))
|
||||
source_node = input_port.get_source().node
|
||||
transpose_name = source_node.soft_get('name', source_node.id) + '/TransposeToNHWC'
|
||||
else:
|
||||
axis_order = np.concatenate(
|
||||
(int64_array([0]),
|
||||
int64_array([input_rank - 1]),
|
||||
int64_array(list(range(1, input_rank - 1)))))
|
||||
transpose_name = input_port.node.soft_get('name', input_port.node.id) + '/TransposeToNCHW'
|
||||
input_port.node['need_shape_inference'] = True
|
||||
input_port.node['override_output_shape'] = True
|
||||
transpose = create_op_with_const_inputs(graph, Transpose, {1: axis_order}, {'name': transpose_name})
|
||||
input_port.get_connection().insert_node(transpose)
|
||||
transpose['need_shape_inference'] = True
|
||||
transpose['override_output_shape'] = True
|
||||
@@ -0,0 +1,31 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from mo.graph.graph import Graph
|
||||
from mo.ops.op import Op
|
||||
|
||||
|
||||
class TFFFT(Op):
|
||||
"""
|
||||
This operation is intended to read TF operations FFT, FFT2D, FFT3D, IFFT, IFFT2D, IFFT3D.
|
||||
The operation TFFFT has two attributes: an integer attribute num_of_dimensions and a boolean attribute is_inverse.
|
||||
|
||||
If an operation to read is FFT, FFT2D, or FFT3D, then the attribute 'is_inverse' is False, and True otherwise.
|
||||
The attribute 'num_of_dimensions' is equal to number of transformed axes, i.e. 1 for FFT and IFFT, 2 for FFT2D and
|
||||
IFFT2D, 3 for FFT3D and IFFT3D.
|
||||
|
||||
The transformation TFFFTToDFT converts the operation TFFFT into MO DFT (if the attribute 'is_inverse' is False),
|
||||
or into MO IDFT (otherwise).
|
||||
"""
|
||||
op = 'TFFFT'
|
||||
enabled = False
|
||||
|
||||
def __init__(self, graph: Graph, attrs: dict):
|
||||
mandatory_props = {
|
||||
'op': self.op,
|
||||
'out_ports_count': 1,
|
||||
'in_ports_count': 1,
|
||||
}
|
||||
assert 'is_inverse' in attrs, 'Attribute is_inverse is not given for the operation TFFFT.'
|
||||
assert 'num_of_dimensions' in attrs, 'Attribute num_of_dimensions is not given for the operation TFFFT.'
|
||||
super().__init__(graph, mandatory_props, attrs)
|
||||
@@ -0,0 +1,127 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.graph.graph import Node, Graph
|
||||
from mo.ops.op import Op
|
||||
|
||||
|
||||
class FFTBase(Op):
|
||||
enabled = False
|
||||
op = None
|
||||
version = 'opset7'
|
||||
|
||||
def __init__(self, graph: Graph, attrs: dict):
|
||||
mandatory_props = {
|
||||
'out_ports_count': 1,
|
||||
'in_ports_count': 3,
|
||||
'version': self.version,
|
||||
'infer': self.infer
|
||||
}
|
||||
super().__init__(graph, mandatory_props, attrs)
|
||||
|
||||
def infer(self, node: Node):
|
||||
node_name = node.soft_get(node.name, node.id)
|
||||
assert len([p for p in node.in_ports().values() if not p.disconnected()]) in [2, 3], \
|
||||
'(I)DFT node {} must have 2 or 3 inputs'.format(node_name)
|
||||
|
||||
src_shape = node.in_port(0).data.get_shape()
|
||||
assert src_shape is not None, 'The input data shape of (I)DFT node {} must not be None'.format(node_name)
|
||||
assert src_shape[-1] == 2, \
|
||||
'The last dimension of input shape of (I)DFT node {} should be equal to 2'.format(node_name)
|
||||
|
||||
input_rank = len(src_shape)
|
||||
assert input_rank >= 2, 'The input rank of (I)DFT node {} should be greater or equal to 2'.format(node_name)
|
||||
|
||||
axes = FFTBase.get_axes(node)
|
||||
assert input_rank >= len(axes) + 1, \
|
||||
'The input rank must be greater than number of (I)DFT node {} axes'.format(node_name)
|
||||
axes = FFTBase.canonicalize_axes(axes, input_rank)
|
||||
assert (input_rank - 1) not in axes, '(I)DFT node {} axes cannot contain the last axis'.format(node_name)
|
||||
assert len(set(axes)) == len(axes), '(I)DFT node {} axes must be unique.'.format(node_name)
|
||||
|
||||
output_shape = int64_array(src_shape)
|
||||
if node.is_in_port_connected(2):
|
||||
signal_size = FFTBase.get_signal_size(node)
|
||||
signal_size = FFTBase.canonicalize_signal_size(signal_size, axes, src_shape)
|
||||
output_shape[axes] = signal_size
|
||||
|
||||
node.out_port(0).data.set_shape(output_shape)
|
||||
|
||||
@staticmethod
|
||||
def canonicalize_axes(axes, input_rank):
|
||||
"""
|
||||
FFT operation supports for negative axes to transform. More precisely, according to the FFT operation
|
||||
specification, axes should be integers from -(r - 1) to (r - 2) inclusively, where r = rank(data).
|
||||
A negative axis 'a' is interpreted as an axis 'r - 1 + a'. The reason is the following: real input
|
||||
tensor of the shape [n_0, ..., n_{r - 1}, 2] is interpreted as a complex tensor with the shape
|
||||
[n_0, ..., n_{r - 1}]. Hence, we need to 'canonicalize' axes using the formula 'r - 1 + a'.
|
||||
|
||||
:param axes: axes to canonicalize
|
||||
:param input_rank: input tensor rank
|
||||
:return: canonicalized axes
|
||||
"""
|
||||
result = axes.copy()
|
||||
for i, axis in enumerate(axes):
|
||||
if axis < 0:
|
||||
result[i] = axis + input_rank - 1
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def canonicalize_signal_size(signal_size, axes, input_shape):
|
||||
result = signal_size.copy()
|
||||
for i, axis in enumerate(axes):
|
||||
size = signal_size[i]
|
||||
if size == -1:
|
||||
result[i] = input_shape[axis]
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_axes(node: Node):
|
||||
axes = node.in_port(1).get_source().data.get_value()
|
||||
node_name = node.soft_get('name', node.id)
|
||||
assert axes is not None, 'The input with axes is not constant for node {}'.format(node_name)
|
||||
return int64_array(axes)
|
||||
|
||||
@staticmethod
|
||||
def get_signal_size(node: Node):
|
||||
src_shape = node.in_port(0).data.get_shape()
|
||||
assert src_shape is not None
|
||||
input_rank = len(src_shape)
|
||||
if node.is_in_port_connected(2):
|
||||
signal_size = node.in_port(2).get_source().data.get_value()
|
||||
else:
|
||||
axes = FFTBase.get_axes(node)
|
||||
signal_size = [src_shape[: input_rank - 1][a] for a in axes]
|
||||
|
||||
node_name = node.soft_get('name', node.id)
|
||||
assert signal_size is not None, 'The input with signal_size is not constant for node {}'.format(node_name)
|
||||
|
||||
return int64_array(signal_size)
|
||||
|
||||
|
||||
class DFT(FFTBase):
|
||||
op = 'DFT'
|
||||
enabled = False
|
||||
|
||||
def __init__(self, graph: Graph, attrs: dict):
|
||||
mandatory_props = {
|
||||
'type': self.op,
|
||||
'op': self.op,
|
||||
}
|
||||
mandatory_props.update(attrs)
|
||||
super().__init__(graph, mandatory_props)
|
||||
|
||||
|
||||
class IDFT(FFTBase):
|
||||
op = 'IDFT'
|
||||
enabled = False
|
||||
|
||||
def __init__(self, graph: Graph, attrs: dict):
|
||||
mandatory_props = {
|
||||
'type': self.op,
|
||||
'op': self.op,
|
||||
}
|
||||
mandatory_props.update(attrs)
|
||||
super().__init__(graph, mandatory_props)
|
||||
@@ -0,0 +1,42 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.graph.graph import Graph, Node
|
||||
from mo.ops.op import Op
|
||||
|
||||
|
||||
class MXFFT(Op):
|
||||
"""
|
||||
This operation is intended to read MxNet operations FFT and IFFT.
|
||||
The operation MXFFT has one attribute: a boolean attribute is_inverse.
|
||||
|
||||
If an operation to read is FFT, then the attribute 'is_inverse' is False, and True otherwise.
|
||||
|
||||
The transformation MXFFTToDFT converts the operation MXFFT into MO DFT (if the attribute 'is_inverse'
|
||||
is False), or into MO IDFT (otherwise).
|
||||
"""
|
||||
op = 'MXFFT'
|
||||
enabled = False
|
||||
|
||||
def __init__(self, graph: Graph, attrs: dict):
|
||||
mandatory_props = {
|
||||
'op': self.op,
|
||||
'out_ports_count': 1,
|
||||
'in_ports_count': 1,
|
||||
'infer': self.infer
|
||||
}
|
||||
assert 'is_inverse' in attrs, 'Attribute is_inverse is not given for the operation MXFFT.'
|
||||
super().__init__(graph, mandatory_props, attrs)
|
||||
|
||||
def infer(self, node: Node):
|
||||
node_name = node.soft_get('name', node.id)
|
||||
input_shape = node.in_port(0).data.get_shape()
|
||||
assert input_shape is not None, 'Input shape of MXFFT node {} must not be None'.format(node_name)
|
||||
is_inverse = node.soft_get('is_inverse', False)
|
||||
output_shape = input_shape.copy()
|
||||
if is_inverse:
|
||||
output_shape[-1] = output_shape[-1] // 2
|
||||
else:
|
||||
output_shape[-1] = output_shape[-1] * 2
|
||||
node.out_port(0).data.set_shape(int64_array(output_shape))
|
||||
@@ -8,7 +8,8 @@ from mo.ops.op import Op
|
||||
|
||||
|
||||
class Roll(Op):
|
||||
""" Roll operation that shifts elements of a tensor along specified axes.
|
||||
"""
|
||||
Roll operation that shifts elements of a tensor along specified axes.
|
||||
"""
|
||||
op = 'Roll'
|
||||
enabled = False
|
||||
@@ -26,7 +27,6 @@ class Roll(Op):
|
||||
|
||||
class AttributedRoll(Op):
|
||||
""" Roll operation that shifts elements of a tensor along specified axes.
|
||||
|
||||
This operation uses the same semantics as Roll but with shift and axes specified as attributes.
|
||||
Shift and axes are specified as attributes in MxNet.
|
||||
"""
|
||||
|
||||
@@ -10,6 +10,7 @@ import numpy as np
|
||||
from extensions.middle.InsertLayoutPropagationTransposes import mark_input_as_in_correct_layout, \
|
||||
mark_output_as_in_correct_layout
|
||||
from extensions.ops.activation_ops import Sigmoid
|
||||
from extensions.ops.elementwise import Add, Less, Mul
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.graph.graph import Node, Graph
|
||||
from mo.ops.concat import Concat
|
||||
@@ -185,3 +186,31 @@ def add_activation_function_after_node(graph: Graph, node: Node, activation_func
|
||||
else:
|
||||
raise Error('Unknown post-processing activation function "{}".'.format(activation_function))
|
||||
return activation_node
|
||||
|
||||
|
||||
def add_constant_to_negative_values(node: Node, port_idx: int, added_value: np.array):
|
||||
"""
|
||||
This function adds the given values to negative elements of value from the given input port.
|
||||
:param node: node with corrected values in the input port port_idx
|
||||
:param port_idx: input port index for negative values
|
||||
:param added_value: the value to add
|
||||
:return: None
|
||||
"""
|
||||
negative_values_source = node.in_port(port_idx).get_source()
|
||||
negative_values_node = node.in_port(port_idx).get_source().node
|
||||
negative_values_node_name = negative_values_node.soft_get('name', negative_values_node.id)
|
||||
|
||||
graph = node.graph
|
||||
|
||||
less_node = create_op_with_const_inputs(graph, Less,
|
||||
{1: np.array(0, dtype=added_value.dtype)},
|
||||
{'name': negative_values_node_name + '/Less'})
|
||||
mul_node = create_op_with_const_inputs(graph, Mul, {1: added_value}, {'name': negative_values_node_name + '/Mul'})
|
||||
|
||||
node.in_port(port_idx).get_connection().set_destination(less_node.in_port(0))
|
||||
less_node.out_port(0).connect(mul_node.in_port(0))
|
||||
|
||||
add_node = Add(graph, {}).create_node()
|
||||
mul_node.out_port(0).connect(add_node.in_port(1))
|
||||
negative_values_source.connect(add_node.in_port(0))
|
||||
add_node.out_port(0).connect(node.in_port(port_idx))
|
||||
@@ -133,12 +133,18 @@ def compare_graphs(graph: Graph, graph_ref: Graph, last_node: str, last_node_ref
|
||||
if in_node.id not in checked_nodes_ref and in_node.id not in q_ref:
|
||||
q_ref.append(in_node.id)
|
||||
|
||||
out_nodes = node.out_nodes().values() if node.kind == 'op' else sorted_by_name(node.out_nodes())
|
||||
if node.kind == 'op':
|
||||
out_nodes = sorted_by_name([Node(graph, v) for v, _ in node.get_outputs()])
|
||||
else:
|
||||
out_nodes = sorted_by_name(node.out_nodes())
|
||||
for out_node in out_nodes:
|
||||
if out_node.id not in checked_nodes and out_node.id not in q:
|
||||
q.append(out_node.id)
|
||||
|
||||
out_nodes = node_ref.out_nodes().values() if node_ref.kind == 'op' else sorted_by_name(node_ref.out_nodes())
|
||||
if node_ref.kind == 'op':
|
||||
out_nodes = sorted_by_name([Node(graph_ref, v) for v, _ in node_ref.get_outputs()])
|
||||
else:
|
||||
out_nodes = sorted_by_name(node_ref.out_nodes())
|
||||
for out_node in out_nodes:
|
||||
if out_node.id not in checked_nodes_ref and out_node.id not in q_ref:
|
||||
q_ref.append(out_node.id)
|
||||
|
||||
@@ -11,6 +11,7 @@ from extensions.middle.FakeSplitOutputs import AddFakeOutputsToSplit
|
||||
from extensions.ops.Cast import Cast
|
||||
from extensions.ops.ReduceOps import ReduceOp
|
||||
from extensions.ops.activation_ops import Activation
|
||||
from extensions.ops.dft import FFTBase
|
||||
from extensions.ops.elementwise import Elementwise, UnaryElementwise, LogicalElementwise, BiasAdd, Div, Mul, Pow, Sub
|
||||
from extensions.ops.embedding_bag import EmbeddingBagBase
|
||||
from extensions.ops.loop import Loop
|
||||
@@ -60,7 +61,7 @@ def collect_ops(path: str):
|
||||
import_by_path(os.path.join(path, 'mo', 'ops'), ['mo', 'ops'])
|
||||
import_by_path(os.path.join(path, 'extensions', 'ops'), ['extensions', 'ops'])
|
||||
update_registration(classes=[Op, Activation, Elementwise, UnaryElementwise, LogicalElementwise,
|
||||
EmbeddingBagBase, ReduceOp, Scatter, ScatterNDBase],
|
||||
EmbeddingBagBase, ReduceOp, Scatter, ScatterNDBase, FFTBase],
|
||||
enabled_transforms=[], disabled_transforms=[])
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import unittest
|
||||
|
||||
from extensions.back.TransposeDFT import TransposeDFT
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph, result, regular_op_with_shaped_data, valued_const_with_data, connect, \
|
||||
regular_op_with_empty_data
|
||||
|
||||
dft_graph_node_attrs = {
|
||||
**regular_op_with_shaped_data('placeholder', [8, 2, 40, 56], {'type': 'Parameter', 'op': 'Parameter'}),
|
||||
**valued_const_with_data('axes', int64_array([-2, -1])),
|
||||
**regular_op_with_shaped_data('dft', [8, 2, 40, 56], {'op': 'DFT', 'need_insert_transposes_for_dft': True}),
|
||||
**regular_op_with_shaped_data('abs', [8, 2, 40, 56], {'type': 'Abs', 'op': 'Abs'}),
|
||||
**result(),
|
||||
}
|
||||
|
||||
dft_graph_edges = [
|
||||
*connect('placeholder', '0:dft'),
|
||||
*connect('axes', '1:dft'),
|
||||
*connect('dft', 'abs'),
|
||||
*connect('abs', 'output'),
|
||||
]
|
||||
|
||||
|
||||
transposed_dft_graph_node_attrs = {
|
||||
**regular_op_with_shaped_data('placeholder', [8, 2, 40, 56], {'type': 'Parameter', 'op': 'Parameter'}),
|
||||
**regular_op_with_empty_data('transpose_before',
|
||||
{'type': 'Transpose', 'op': 'Transpose', 'need_shape_inference': True}),
|
||||
**valued_const_with_data('transpose_before_axis_const', int64_array([0, 2, 3, 1])),
|
||||
**regular_op_with_empty_data('transpose_after',
|
||||
{'type': 'Transpose', 'op': 'Transpose', 'need_shape_inference': True}),
|
||||
**valued_const_with_data('transpose_after_axis_const', int64_array([0, 3, 1, 2])),
|
||||
**valued_const_with_data('dft_axes', int64_array([-2, -1])),
|
||||
**regular_op_with_shaped_data('dft', [8, 2, 40, 56], {'op': 'DFT', 'need_insert_transposes_for_dft': True}),
|
||||
**regular_op_with_shaped_data('abs', [8, 2, 40, 56], {'type': 'Abs', 'op': 'Abs'}),
|
||||
**result(),
|
||||
}
|
||||
|
||||
transposed_dft_graph_edges = [
|
||||
*connect('placeholder', '0:transpose_before'),
|
||||
*connect('transpose_before_axis_const', '1:transpose_before'),
|
||||
*connect('transpose_before', '0:dft'),
|
||||
*connect('dft_axes', '1:dft'),
|
||||
*connect('dft', '0:transpose_after'),
|
||||
*connect('transpose_after_axis_const', '1:transpose_after'),
|
||||
*connect('transpose_after', 'abs'),
|
||||
*connect('abs', 'output'),
|
||||
]
|
||||
|
||||
|
||||
nontransposed_dft_graph_node_attrs = {
|
||||
**regular_op_with_shaped_data('placeholder', [8, 2, 40, 56], {'type': 'Parameter', 'op': 'Parameter'}),
|
||||
**valued_const_with_data('axes', int64_array([-2, -1])),
|
||||
**regular_op_with_shaped_data('dft', [8, 2, 40, 56], {'op': 'DFT'}),
|
||||
**regular_op_with_shaped_data('abs', [8, 2, 40, 56], {'type': 'Abs', 'op': 'Abs'}),
|
||||
**result(),
|
||||
}
|
||||
|
||||
nontransposed_dft_graph_edges = [
|
||||
*connect('placeholder', '0:dft'),
|
||||
*connect('axes', '1:dft'),
|
||||
*connect('dft', 'abs'),
|
||||
*connect('abs', 'output'),
|
||||
]
|
||||
|
||||
|
||||
class TransposeDFTTest(unittest.TestCase):
|
||||
def test_dft_transpose(self):
|
||||
graph = build_graph(nodes_attrs=dft_graph_node_attrs, edges=dft_graph_edges)
|
||||
ref_graph = build_graph(nodes_attrs=transposed_dft_graph_node_attrs, edges=transposed_dft_graph_edges)
|
||||
graph.graph['fw'] = 'tf'
|
||||
TransposeDFT().find_and_replace_pattern(graph)
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output')
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_dft_nontranspose(self):
|
||||
graph = build_graph(nodes_attrs=nontransposed_dft_graph_node_attrs, edges=nontransposed_dft_graph_edges)
|
||||
ref_graph = build_graph(nodes_attrs=nontransposed_dft_graph_node_attrs, edges=nontransposed_dft_graph_edges)
|
||||
TransposeDFT().find_and_replace_pattern(graph)
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output')
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,191 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
from generator import generator, generate
|
||||
|
||||
from extensions.front.mxnet.MXFFTToDFT import MXFFTToDFT
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
|
||||
fft_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'fft': {'kind': 'op', 'op': 'MXFFT', 'is_inverse': False},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
fft_graph_edges = [
|
||||
('placeholder', 'fft', {'in': 0}),
|
||||
('fft', 'abs'),
|
||||
('abs', 'output'),
|
||||
]
|
||||
|
||||
|
||||
ref_converted_fft_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'rank': {'kind': 'op', 'op': 'Rank'},
|
||||
'unsqueeze': {'type': 'Unsqueeze', 'kind': 'op', 'op': 'Unsqueeze'},
|
||||
'unsqueeze_axis': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([1]), 'value': int64_array([-1])
|
||||
},
|
||||
'one': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(1)
|
||||
},
|
||||
'add': {'type': 'Add', 'kind': 'op', 'op': 'Add'},
|
||||
'zero1': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(0)
|
||||
},
|
||||
'broadcast1': {'type': 'Broadcast', 'kind': 'op', 'op': 'Broadcast'},
|
||||
'one2': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(1)
|
||||
},
|
||||
'zero2': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(0)
|
||||
},
|
||||
'scatter': {'type': 'ScatterUpdate', 'kind': 'op', 'op': 'ScatterUpdate'},
|
||||
'pad': {'type': 'Pad', 'kind': 'op', 'op': 'Pad', 'mode': 'constant'},
|
||||
'fft_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([1]), 'value': int64_array([-1])
|
||||
},
|
||||
'fft': {'kind': 'op', 'op': 'DFT', 'type': 'DFT'},
|
||||
'one3': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(1)
|
||||
},
|
||||
'sub': {'type': 'Subtract', 'kind': 'op', 'op': 'Sub'},
|
||||
'zero3': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(0)
|
||||
},
|
||||
'broadcast2': {'type': 'Broadcast', 'kind': 'op', 'op': 'Broadcast'},
|
||||
'm1_2': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([-1, 2])
|
||||
},
|
||||
'concat': {'type': 'Concat', 'kind': 'op', 'op': 'Concat', 'axis': 0},
|
||||
'reshape': {'kind': 'op', 'op': 'Reshape', 'type': 'Reshape'},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
ref_converted_fft_graph_edges = [
|
||||
('placeholder', 'rank', {'in': 0, 'out': 0}),
|
||||
('placeholder', 'unsqueeze', {'in': 0, 'out': 0}),
|
||||
('unsqueeze_axis', 'unsqueeze', {'in': 1, 'out': 0}),
|
||||
('rank', 'add', {'in': 0, 'out': 0}),
|
||||
('one', 'add', {'in': 1, 'out': 0}),
|
||||
('zero1', 'broadcast1', {'in': 0, 'out': 0}),
|
||||
('add', 'broadcast1', {'in': 1, 'out': 0}),
|
||||
('broadcast1', 'scatter', {'in': 0, 'out': 0}),
|
||||
('rank', 'scatter', {'in': 1, 'out': 0}),
|
||||
('one2', 'scatter', {'in': 2, 'out': 0}),
|
||||
('zero2', 'scatter', {'in': 3, 'out': 0}),
|
||||
('unsqueeze', 'pad', {'in': 0, 'out': 0}),
|
||||
('broadcast1', 'pad', {'in': 1, 'out': 0}),
|
||||
('scatter', 'pad', {'in': 2, 'out': 0}),
|
||||
('pad', 'fft', {'in': 0, 'out': 0}),
|
||||
('fft_axes', 'fft', {'in': 1, 'out': 0}),
|
||||
('rank', 'sub', {'in': 0, 'out': 0}),
|
||||
('one3', 'sub', {'in': 1, 'out': 0}),
|
||||
('zero3', 'broadcast2', {'in': 0, 'out': 0}),
|
||||
('sub', 'broadcast2', {'in': 1, 'out': 0}),
|
||||
('broadcast2', 'concat', {'in': 0, 'out': 0}),
|
||||
('m1_2', 'concat', {'in': 1, 'out': 0}),
|
||||
('fft', 'reshape', {'in': 0, 'out': 0}),
|
||||
('concat', 'reshape', {'in': 1, 'out': 0}),
|
||||
('reshape', 'abs'),
|
||||
('abs', 'output'),
|
||||
]
|
||||
|
||||
|
||||
ref_converted_ifft_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'rank': {'kind': 'op', 'op': 'Rank'},
|
||||
'subtracted_one': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(1)
|
||||
},
|
||||
'sub': {'type': 'Subtract', 'kind': 'op', 'op': 'Sub'},
|
||||
'broadcast': {'type': 'Broadcast', 'kind': 'op', 'op': 'Broadcast'},
|
||||
'broadcasted_value': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(0)
|
||||
},
|
||||
'new_shape': {'type': 'Concat', 'kind': 'op', 'op': 'Concat', 'axis': 0},
|
||||
'new_shape_const': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([-1, 2])
|
||||
},
|
||||
'reshape': {'kind': 'op', 'op': 'Reshape', 'type': 'Reshape'},
|
||||
'fft': {'kind': 'op', 'op': 'IDFT', 'type': 'IDFT'},
|
||||
'fft_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([1]), 'value': int64_array([-1])
|
||||
},
|
||||
'split': {'kind': 'op', 'op': 'Split', 'type': 'Split', 'num_splits': 2},
|
||||
'split_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(-1)
|
||||
},
|
||||
'squeeze': {'kind': 'op', 'op': 'Squeeze', 'type': 'Squeeze'},
|
||||
'squeeze_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([1]), 'value': int64_array([-1])
|
||||
},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
ref_converted_ifft_graph_edges = [
|
||||
('placeholder', 'rank', {'out': 0}),
|
||||
('placeholder', 'reshape', {'out': 0}),
|
||||
('rank', 'sub'),
|
||||
('subtracted_one', 'sub'),
|
||||
('broadcasted_value', 'broadcast'),
|
||||
('sub', 'broadcast'),
|
||||
('broadcast', 'new_shape'),
|
||||
('new_shape_const', 'new_shape'),
|
||||
('new_shape', 'reshape'),
|
||||
('reshape', 'fft'),
|
||||
('fft_axes', 'fft'),
|
||||
('fft', 'split'),
|
||||
('split_axes', 'split'),
|
||||
('split', 'squeeze', {'out': 0}),
|
||||
('squeeze_axes', 'squeeze'),
|
||||
('squeeze', 'abs'),
|
||||
('abs', 'output'),
|
||||
]
|
||||
|
||||
|
||||
@generator
|
||||
class MXFFTToDFTTest(unittest.TestCase):
|
||||
@generate(*[int64_array([3, 100, 100, 8]), int64_array([5, 60])])
|
||||
def test_fft_replacement(self, input_shape):
|
||||
graph = build_graph(nodes_attrs=fft_graph_node_attrs,
|
||||
edges=fft_graph_edges,
|
||||
update_attributes={
|
||||
'placeholder': {'shape': input_shape}
|
||||
})
|
||||
graph.stage = 'front'
|
||||
MXFFTToDFT().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=ref_converted_fft_graph_node_attrs,
|
||||
edges=ref_converted_fft_graph_edges,
|
||||
update_attributes={
|
||||
'placeholder': {'shape': input_shape}
|
||||
})
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output')
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
@generate(*[int64_array([3, 100, 100, 8]), int64_array([5, 60])])
|
||||
def test_ifft_replacement(self, input_shape):
|
||||
graph = build_graph(nodes_attrs=fft_graph_node_attrs,
|
||||
edges=fft_graph_edges,
|
||||
update_attributes={
|
||||
'placeholder': {'shape': input_shape},
|
||||
'fft': {'is_inverse': True}
|
||||
})
|
||||
graph.stage = 'front'
|
||||
MXFFTToDFT().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=ref_converted_ifft_graph_node_attrs,
|
||||
edges=ref_converted_ifft_graph_edges,
|
||||
update_attributes={
|
||||
'placeholder': {'shape': input_shape}
|
||||
})
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output')
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,74 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.front.tf.ComplexAbsAfterComplex import ComplexAbsAfterComplex
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
|
||||
graph_node_attrs = {
|
||||
'placeholder_0': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'placeholder_1': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'complex': {'kind': 'op', 'op': 'Complex'},
|
||||
'complex_abs': {'kind': 'op', 'op': 'ComplexAbs'},
|
||||
'relu': {'type': 'ReLU', 'kind': 'op', 'op': 'ReLU'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
graph_edges = [
|
||||
('placeholder_0', 'complex', {'in': 0}),
|
||||
('placeholder_1', 'complex', {'in': 1}),
|
||||
('complex', 'complex_abs', {'in': 0}),
|
||||
('complex_abs', 'relu'),
|
||||
('relu', 'output'),
|
||||
]
|
||||
|
||||
|
||||
ref_graph_node_attrs = {
|
||||
'placeholder_0': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'placeholder_1': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'pow0_const': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': np.float32(2.0)
|
||||
},
|
||||
'pow1_const': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': np.float32(2.0)
|
||||
},
|
||||
'pow0': {'type': 'Power', 'kind': 'op', 'op': 'Pow'},
|
||||
'pow1': {'type': 'Power', 'kind': 'op', 'op': 'Pow'},
|
||||
'add': {'type': 'Add', 'kind': 'op', 'op': 'Add'},
|
||||
'sqrt_const': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': np.float32(0.5)
|
||||
},
|
||||
'sqrt': {'type': 'Power', 'kind': 'op', 'op': 'Pow'},
|
||||
'relu': {'type': 'ReLU', 'kind': 'op', 'op': 'ReLU'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
ref_graph_edges = [
|
||||
('placeholder_0', 'pow0', {'in': 0}),
|
||||
('placeholder_1', 'pow1', {'in': 0}),
|
||||
('pow0_const', 'pow0', {'in': 1}),
|
||||
('pow1_const', 'pow1', {'in': 1}),
|
||||
('pow0', 'add', {'in': 0}),
|
||||
('pow1', 'add', {'in': 1}),
|
||||
('add', 'sqrt', {'in': 0}),
|
||||
('sqrt_const', 'sqrt', {'in': 1}),
|
||||
('sqrt', 'relu'),
|
||||
('relu', 'output'),
|
||||
]
|
||||
|
||||
|
||||
class ComplexAbsAfterComplexTest(unittest.TestCase):
|
||||
def test_replacement(self):
|
||||
graph = build_graph(nodes_attrs=graph_node_attrs, edges=graph_edges)
|
||||
graph.stage = 'front'
|
||||
ComplexAbsAfterComplex().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=ref_graph_node_attrs, edges=ref_graph_edges)
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,66 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.front.tf.ComplexAbs import ComplexAbs
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
|
||||
graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'complex_abs': {'kind': 'op', 'op': 'ComplexAbs'},
|
||||
'relu': {'type': 'ReLU', 'kind': 'op', 'op': 'ReLU'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
graph_edges = [
|
||||
('placeholder', 'complex_abs'),
|
||||
('complex_abs', 'relu'),
|
||||
('relu', 'output'),
|
||||
]
|
||||
|
||||
|
||||
ref_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'pow2_const': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': np.float32(2.0)
|
||||
},
|
||||
'pow2': {'type': 'Power', 'kind': 'op', 'op': 'Pow'},
|
||||
'sum_axis': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': int64_array(-1)
|
||||
},
|
||||
'sum': {'type': 'ReduceSum', 'kind': 'op', 'op': 'ReduceSum'},
|
||||
'sqrt_const': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'value': np.float32(0.5)
|
||||
},
|
||||
'sqrt': {'type': 'Power', 'kind': 'op', 'op': 'Pow'},
|
||||
'relu': {'type': 'ReLU', 'kind': 'op', 'op': 'ReLU'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
ref_graph_edges = [
|
||||
('placeholder', 'pow2', {'in': 0}),
|
||||
('pow2_const', 'pow2', {'in': 1}),
|
||||
('sum_axis', 'sum', {'in': 1}),
|
||||
('pow2', 'sum', {'in': 0}),
|
||||
('sum', 'sqrt', {'in': 0}),
|
||||
('sqrt_const', 'sqrt', {'in': 1}),
|
||||
('sqrt', 'relu'),
|
||||
('relu', 'output'),
|
||||
]
|
||||
|
||||
|
||||
class ComplexAbsTest(unittest.TestCase):
|
||||
def test_replacement(self):
|
||||
graph = build_graph(nodes_attrs=graph_node_attrs, edges=graph_edges)
|
||||
graph.stage = 'front'
|
||||
ComplexAbs().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=ref_graph_node_attrs, edges=ref_graph_edges)
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,89 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
from extensions.front.tf.CorrectRollAxes import CorrectRollAxes
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
|
||||
graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'roll': {'kind': 'op', 'op': 'Roll', 'type': 'Roll', 'input_rank_changed': True},
|
||||
'roll_shift': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([50, 50])
|
||||
},
|
||||
'roll_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([-2, -1])
|
||||
},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
graph_edges = [
|
||||
('placeholder', 'roll', {'in': 0}),
|
||||
('roll', 'abs'),
|
||||
('abs', 'output'),
|
||||
('roll_shift', 'roll', {'in': 1}),
|
||||
('roll_axes', 'roll', {'in': 2}),
|
||||
]
|
||||
|
||||
|
||||
ref_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'roll': {'kind': 'op', 'op': 'Roll', 'type': 'Roll'},
|
||||
'roll_shift': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([50, 50])
|
||||
},
|
||||
'roll_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([-2, -1])
|
||||
},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
'add': {'type': 'Add', 'kind': 'op', 'op': 'Add'},
|
||||
'mul': {'type': 'Multiply', 'kind': 'op', 'op': 'Mul'},
|
||||
'less': {'type': 'Less', 'kind': 'op', 'op': 'Less'},
|
||||
'zero': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(0)
|
||||
},
|
||||
'minus_one': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(-1)
|
||||
},
|
||||
}
|
||||
|
||||
ref_graph_edges = [
|
||||
('placeholder', 'roll', {'out': 0, 'in': 0}),
|
||||
('roll', 'abs'),
|
||||
('abs', 'output'),
|
||||
('roll_shift', 'roll', {'in': 1}),
|
||||
('mul', 'add', {'in': 1}),
|
||||
('add', 'roll', {'in': 2}),
|
||||
('zero', 'less', {'in': 1}),
|
||||
('minus_one', 'mul', {'in': 1}),
|
||||
('less', 'mul', {'in': 0}),
|
||||
('roll_axes', 'less', {'out': 0, 'in': 0}),
|
||||
('roll_axes', 'add', {'out': 0, 'in': 0}),
|
||||
]
|
||||
|
||||
|
||||
class CorrectRollAxesTest(unittest.TestCase):
|
||||
def test_replacement(self):
|
||||
graph = build_graph(nodes_attrs=graph_node_attrs, edges=graph_edges)
|
||||
graph.stage = 'front'
|
||||
CorrectRollAxes().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=ref_graph_node_attrs, edges=ref_graph_edges)
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_nonreplacement(self):
|
||||
graph = build_graph(nodes_attrs=graph_node_attrs, edges=graph_edges,
|
||||
update_attributes={'roll': {'input_rank_changed': False}})
|
||||
graph.stage = 'front'
|
||||
CorrectRollAxes().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=graph_node_attrs, edges=graph_edges,
|
||||
update_attributes={'roll': {'input_rank_changed': False}})
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,88 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
from extensions.front.tf.RollRealImagPack import RollRealImagPack
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
|
||||
graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'unroll': {'kind': 'op', 'op': 'Roll', 'type': 'Roll'},
|
||||
'real': {'kind': 'op', 'op': 'Real'},
|
||||
'imag': {'kind': 'op', 'op': 'Imag'},
|
||||
'pack': {'kind': 'op', 'op': 'Pack'},
|
||||
'unroll_shift': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([50, 50])
|
||||
},
|
||||
'unroll_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([-2, -1])
|
||||
},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
graph_edges = [
|
||||
('placeholder', 'unroll', {'in': 0}),
|
||||
('unroll', 'real', {'out': 0, 'in': 0}),
|
||||
('unroll', 'imag', {'out': 0, 'in': 0}),
|
||||
('real', 'pack', {'in': 0}),
|
||||
('imag', 'pack', {'in': 1}),
|
||||
('pack', 'abs'),
|
||||
('abs', 'output'),
|
||||
('unroll_shift', 'unroll', {'in': 1}),
|
||||
('unroll_axes', 'unroll', {'in': 2}),
|
||||
]
|
||||
|
||||
|
||||
ref_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'unroll': {'kind': 'op', 'op': 'Roll', 'type': 'Roll'},
|
||||
'unroll_shift': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([50, 50])
|
||||
},
|
||||
'unroll_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([-2, -1])
|
||||
},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
'add': {'type': 'Add', 'kind': 'op', 'op': 'Add'},
|
||||
'mul': {'type': 'Multiply', 'kind': 'op', 'op': 'Mul'},
|
||||
'less': {'type': 'Less', 'kind': 'op', 'op': 'Less'},
|
||||
'zero': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(0)
|
||||
},
|
||||
'minus_one': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([]), 'value': int64_array(-1)
|
||||
},
|
||||
}
|
||||
|
||||
ref_graph_edges = [
|
||||
('placeholder', 'unroll', {'out': 0, 'in': 0}),
|
||||
('unroll', 'abs'),
|
||||
('abs', 'output'),
|
||||
('unroll_shift', 'unroll', {'in': 1}),
|
||||
('unroll_axes', 'unroll', {'in': 2}),
|
||||
|
||||
('mul', 'add', {'in': 1}),
|
||||
('add', 'unroll', {'in': 2}),
|
||||
('zero', 'less', {'in': 1}),
|
||||
('minus_one', 'mul', {'in': 1}),
|
||||
('less', 'mul', {'in': 0}),
|
||||
('unroll_axes', 'less', {'out': 0, 'in': 0}),
|
||||
('unroll_axes', 'add', {'out': 0, 'in': 0}),
|
||||
]
|
||||
|
||||
|
||||
class RollRealImagPackTest(unittest.TestCase):
|
||||
def test_replacement(self):
|
||||
graph = build_graph(nodes_attrs=graph_node_attrs, edges=graph_edges)
|
||||
graph.stage = 'front'
|
||||
RollRealImagPack().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=ref_graph_node_attrs, edges=ref_graph_edges)
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,143 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
from extensions.front.tf.SSliceComplex import SSliceComplex
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
|
||||
graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'strided_slice_real': {
|
||||
'type': 'StridedSlice', 'kind': 'op', 'op': 'StridedSlice', 'begin_mask': int64_array([1]),
|
||||
'end_mask': int64_array([1]), 'ellipsis_mask': int64_array([1]), 'new_axis_mask': int64_array([0]),
|
||||
'shrink_axis_mask': int64_array([0, 1]),
|
||||
},
|
||||
'strided_slice_imag': {
|
||||
'type': 'StridedSlice', 'kind': 'op', 'op': 'StridedSlice', 'begin_mask': int64_array([1]),
|
||||
'end_mask': int64_array([1]), 'ellipsis_mask': int64_array([1]), 'new_axis_mask': int64_array([0]),
|
||||
'shrink_axis_mask': int64_array([0, 1]),
|
||||
},
|
||||
'complex': {'kind': 'op', 'op': 'Complex'},
|
||||
'real_begin': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([0, 0])
|
||||
},
|
||||
'imag_begin': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([0, 1])
|
||||
},
|
||||
'real_end': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([0, 1])
|
||||
},
|
||||
'imag_end': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([0, 2])
|
||||
},
|
||||
'real_strides': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([1, 1])
|
||||
},
|
||||
'imag_strides': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([1, 1])
|
||||
},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
graph_edges = [
|
||||
('placeholder', 'strided_slice_real', {'out': 0, 'in': 0}),
|
||||
('placeholder', 'strided_slice_imag', {'out': 0, 'in': 0}),
|
||||
('strided_slice_real', 'complex', {'in': 0}),
|
||||
('strided_slice_imag', 'complex', {'in': 1}),
|
||||
('complex', 'abs'),
|
||||
('abs', 'output'),
|
||||
('real_begin', 'strided_slice_real', {'in': 1}),
|
||||
('imag_begin', 'strided_slice_imag', {'in': 1}),
|
||||
('real_end', 'strided_slice_real', {'in': 2}),
|
||||
('imag_end', 'strided_slice_imag', {'in': 2}),
|
||||
('real_strides', 'strided_slice_real', {'in': 3}),
|
||||
('imag_strides', 'strided_slice_imag', {'in': 3}),
|
||||
]
|
||||
|
||||
|
||||
ref_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
ref_graph_edges = [
|
||||
('placeholder', 'abs'),
|
||||
('abs', 'output'),
|
||||
]
|
||||
|
||||
|
||||
non_transformed_graph_node_attrs = {
|
||||
'placeholder_0': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'placeholder_1': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'strided_slice_real': {
|
||||
'type': 'StridedSlice', 'kind': 'op', 'op': 'StridedSlice', 'begin_mask': int64_array([1]),
|
||||
'end_mask': int64_array([1]), 'ellipsis_mask': int64_array([1]), 'new_axis_mask': int64_array([0]),
|
||||
'shrink_axis_mask': int64_array([0, 1]),
|
||||
},
|
||||
'strided_slice_imag': {
|
||||
'type': 'StridedSlice', 'kind': 'op', 'op': 'StridedSlice', 'begin_mask': int64_array([1]),
|
||||
'end_mask': int64_array([1]), 'ellipsis_mask': int64_array([1]), 'new_axis_mask': int64_array([0]),
|
||||
'shrink_axis_mask': int64_array([0, 1]),
|
||||
},
|
||||
'complex': {'kind': 'op', 'op': 'Complex'},
|
||||
'real_begin': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([0, 0])
|
||||
},
|
||||
'imag_begin': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([0, 1])
|
||||
},
|
||||
'real_end': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([0, 1])
|
||||
},
|
||||
'imag_end': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([0, 2])
|
||||
},
|
||||
'real_strides': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([1, 1])
|
||||
},
|
||||
'imag_strides': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([1, 1])
|
||||
},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
non_transformed_graph_edges = [
|
||||
('placeholder_0', 'strided_slice_real', {'out': 0, 'in': 0}),
|
||||
('placeholder_1', 'strided_slice_imag', {'out': 0, 'in': 0}),
|
||||
('strided_slice_real', 'complex', {'in': 0}),
|
||||
('strided_slice_imag', 'complex', {'in': 1}),
|
||||
('complex', 'abs'),
|
||||
('abs', 'output'),
|
||||
('real_begin', 'strided_slice_real', {'in': 1}),
|
||||
('imag_begin', 'strided_slice_imag', {'in': 1}),
|
||||
('real_end', 'strided_slice_real', {'in': 2}),
|
||||
('imag_end', 'strided_slice_imag', {'in': 2}),
|
||||
('real_strides', 'strided_slice_real', {'in': 3}),
|
||||
('imag_strides', 'strided_slice_imag', {'in': 3}),
|
||||
]
|
||||
|
||||
|
||||
class SSliceComplexTest(unittest.TestCase):
|
||||
def test_replacement(self):
|
||||
graph = build_graph(nodes_attrs=graph_node_attrs, edges=graph_edges)
|
||||
graph.stage = 'front'
|
||||
SSliceComplex().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=ref_graph_node_attrs, edges=ref_graph_edges)
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_nonreplacement(self):
|
||||
graph = build_graph(nodes_attrs=non_transformed_graph_node_attrs, edges=non_transformed_graph_edges)
|
||||
ref_graph = build_graph(nodes_attrs=non_transformed_graph_node_attrs, edges=non_transformed_graph_edges)
|
||||
graph.stage = 'front'
|
||||
SSliceComplex().find_and_replace_pattern(graph)
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,72 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
from generator import generator, generate
|
||||
|
||||
from extensions.front.tf.TFFFTToDFT import TFFFTToDFT
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
|
||||
dft_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'fft': {'kind': 'op', 'op': 'TFFFT', 'num_of_dimensions': 2, 'is_inverse': False},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
dft_graph_edges = [
|
||||
('placeholder', 'fft', {'in': 0}),
|
||||
('fft', 'abs'),
|
||||
('abs', 'output'),
|
||||
]
|
||||
|
||||
|
||||
ref_dft_graph_node_attrs = {
|
||||
'placeholder': {'shape': int64_array([3, 100, 100, 2]), 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'fft': {'kind': 'op', 'op': 'DFT'},
|
||||
'abs': {'type': 'Abs', 'kind': 'op', 'op': 'Abs'},
|
||||
'output': {'type': None, 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
'fft_axes': {
|
||||
'type': 'Const', 'kind': 'op', 'op': 'Const', 'shape': int64_array([2]), 'value': int64_array([-2, -1])
|
||||
},
|
||||
}
|
||||
|
||||
ref_dft_graph_edges = [
|
||||
('placeholder', 'fft', {'in': 0}),
|
||||
('fft', 'abs'),
|
||||
('abs', 'output'),
|
||||
('fft_axes', 'fft', {'in': 1}),
|
||||
]
|
||||
|
||||
|
||||
@generator
|
||||
class TFFFTToDFTTest(unittest.TestCase):
|
||||
@generate(*[(2, False, 'DFT', int64_array([-2, -1])),
|
||||
(2, True, 'IDFT', int64_array([-2, -1])),
|
||||
(1, False, 'DFT', int64_array([-1])),
|
||||
(1, True, 'IDFT', int64_array([-1])),
|
||||
(3, False, 'DFT', int64_array([-3, -2, -1])),
|
||||
(3, True, 'IDFT', int64_array([-3, -2, -1]))])
|
||||
def test_replacement(self, num_of_dimensions, is_inverse, dft_type, fft_axes):
|
||||
graph = build_graph(nodes_attrs=dft_graph_node_attrs,
|
||||
edges=dft_graph_edges,
|
||||
update_attributes={
|
||||
'fft': {'num_of_dimensions': num_of_dimensions, 'is_inverse': is_inverse},
|
||||
})
|
||||
graph.stage = 'front'
|
||||
setattr(graph.graph['cmd_params'], 'disable_nhwc_to_nchw', False)
|
||||
graph.graph['layout'] = 'NHWC'
|
||||
TFFFTToDFT().find_and_replace_pattern(graph)
|
||||
ref_graph = build_graph(nodes_attrs=ref_dft_graph_node_attrs,
|
||||
edges=ref_dft_graph_edges,
|
||||
update_attributes={
|
||||
'fft': {'kind': 'op', 'op': dft_type},
|
||||
'fft_axes': {'value': fft_axes, 'shape': int64_array(fft_axes.shape)},
|
||||
})
|
||||
(flag, resp) = compare_graphs(graph, ref_graph, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -29,44 +29,6 @@ nodes = {
|
||||
|
||||
|
||||
class SliceReplacerTest(unittest.TestCase):
|
||||
# test case when input goes besides from TFSlice to other nodes
|
||||
def test_slice_replacer_begin_with_2_inputs(self):
|
||||
graph = build_graph(nodes_attrs=nodes, edges=[
|
||||
('input', 'tfslice'),
|
||||
*connect_front('begin:0', '1:tfslice'),
|
||||
*connect_front('begin:0', '0:john_doe'),
|
||||
*connect_front('size:0', '2:tfslice'),
|
||||
*connect_front('tfslice:0', 'output'),
|
||||
], nodes_with_edges_only=True)
|
||||
graph.stage = 'front'
|
||||
|
||||
TFSliceToSliceReplacer().find_and_replace_pattern(graph)
|
||||
|
||||
graph_ref = build_graph(nodes_attrs=nodes, edges=[
|
||||
*connect_front('input:0', 'slice'),
|
||||
*connect_front('input:0', 'shapeof'),
|
||||
*connect_front('begin:0', 'slice:1'),
|
||||
*connect_front('begin:0', 'john_doe:1'),
|
||||
|
||||
*connect_front('begin:0', 'end_const:0'),
|
||||
*connect_front('size:0', 'end_const:1'),
|
||||
*connect_front('size:0', 'equal:0'),
|
||||
|
||||
*connect_front('shapeof:0', 'select:1'),
|
||||
*connect_front('minus_one:0', 'equal:1'),
|
||||
|
||||
*connect_front('equal:0', 'select:0'),
|
||||
|
||||
*connect_front('end_const:0', 'cast:0'),
|
||||
*connect_front('cast:0', 'select:2'),
|
||||
*connect_front('select:0', 'slice:2'),
|
||||
|
||||
*connect_front('slice:0', 'output'),
|
||||
], nodes_with_edges_only=True)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_slice_replacer(self):
|
||||
graph = build_graph(nodes_attrs=nodes, edges=[
|
||||
*connect_front('input:0', '0:tfslice'),
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from generator import generator, generate
|
||||
|
||||
from extensions.ops.dft import FFTBase
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
|
||||
|
||||
@generator
|
||||
class DFTSignalSizeCanonicalizationTest(unittest.TestCase):
|
||||
@generate(*[
|
||||
(int64_array([-1, 77]), int64_array([1, 2]), int64_array([2, 180, 180, 2]), int64_array([180, 77])),
|
||||
(int64_array([390, 87]), int64_array([2, 0]), int64_array([2, 180, 180, 2]), int64_array([390, 87])),
|
||||
(int64_array([600, -1, 40]),
|
||||
int64_array([3, 0, 1]),
|
||||
int64_array([7, 50, 130, 400, 2]),
|
||||
int64_array([600, 7, 40])),
|
||||
(int64_array([-1, 16, -1]),
|
||||
int64_array([3, 0, 2]),
|
||||
int64_array([7, 50, 130, 400, 2]),
|
||||
int64_array([400, 16, 130])),
|
||||
(int64_array([16, -1, -1]),
|
||||
int64_array([3, 0, 2]),
|
||||
int64_array([7, 50, 130, 400, 2]),
|
||||
int64_array([16, 7, 130])),
|
||||
(int64_array([-1, -1, 16]),
|
||||
int64_array([3, 0, 2]),
|
||||
int64_array([7, 50, 130, 400, 2]),
|
||||
int64_array([400, 7, 16])),
|
||||
(int64_array([-1, -1, -1]),
|
||||
int64_array([3, 0, 2]),
|
||||
int64_array([7, 50, 130, 400, 2]),
|
||||
int64_array([400, 7, 130])),
|
||||
])
|
||||
def test_canonicalization(self, signal_size, axes, input_shape, expected_result):
|
||||
canonicalized_signal_size = FFTBase.canonicalize_signal_size(signal_size, axes, input_shape)
|
||||
self.assertTrue(np.array_equal(canonicalized_signal_size, expected_result))
|
||||
Reference in new issue
Block a user