Extend MO for support of Interpolate-4 (#2026)
* Commit.
* Added opset4 version in the class Interpolate.
* Added class ONNXResize11Op to read ONNX Resize with opset version >= 11.
* Added support for Interpolate-4 into transformations TestInterpolateReshapeWA and InterpolateConcat.
* Added support for Interpolate-4 into transformation InterpolateWithConcat.
* Deleted redundant checks from the transformation UpsampleToResample.
* Reverted last changes.
* Changed ONNX Resize extractor to support for Interpolate-4.
* Added conversion of ONNXResize11Op into Interpolate-4.
* Added support for Interpolate-4 into the transformation InterpolateSequenceToInterpolate.
* Small fix for formatting.
* Written tests for MO version of Interpolate-4 with shape_calculation_mode = sizes.
* Written tests for infer function of Interpolate-4.
* Now transformations InterpolateWithConcat, InterpolateConcat, InterpolateReshapeWA skip Interpolate-4.
* Used create_op_with_const_inputs in the transformation InterpolateSequenceToInterpolate.
* The transformation ONNXResize11ToInterpolate4 was rewritten using find_and_replace_pattern.
* Now the dictionary infers (dictionary of infer functions of Interpolate) is a class static attribute.
* Deleted unused variable.
* Restored original logic of find_and_replace_pattern method of the class InterpolateReshapeWA.
* Used create_op_with_const_inputs() in the transformation InterpolateSequenceToInterpolate for opset1 case.
* Replaced resize_name by resize.soft_get('name', resize.id).
* Small fixes.
* Added two tests for Interpolate-4 infer function.
* Fixed the transformation ONNXResize11ToInterpolateV4 for the case when ONNXResize11 operation has 3 inputs.
* Added conversion of ONNXResize11 with tf_crop_and_resize_mode to ROIPooling + ONNXResize11.
* Fixed bugs in the transformation ONNXResize11ToInterpolateV4 and in the infer function of the operation ONNXResize11.
* Small changes.
* Renamed transformation that converts ONNXResize11 into ROIPooling + ONNXResize11 and fixed BOM-file.
* Fixed tests for the transformation InterpolateSequenceToInterpolate.
* Small change.
* Now the transformation InterpolateSequenceToInterpolate preserves output layer name.
* Deleted the transformation ONNXResize11ToTFCropAndResize.
This commit is contained in:
1 parent
4bd05c5364
commit
dca30b4522
13 files changed
+1641
-109
No files matched your search
@@ -538,6 +538,7 @@ extensions/middle/MulFakeQuantizeFuse.py
|
||||
extensions/middle/MXNetRNNSequenceNormalize.py
|
||||
extensions/middle/MXNetSplitMultiLayers.py
|
||||
extensions/middle/MXTileReplacer.py
|
||||
extensions/middle/ONNXResize11ToInterpolateV4.py
|
||||
extensions/middle/ONNXRNNSequenceNormalize.py
|
||||
extensions/middle/PartialInfer.py
|
||||
extensions/middle/pass_separator.py
|
||||
@@ -640,6 +641,7 @@ extensions/ops/non_zero.py
|
||||
extensions/ops/normalize.py
|
||||
extensions/ops/normalize_l2.py
|
||||
extensions/ops/one_hot.py
|
||||
extensions/ops/ONNXResize11.py
|
||||
extensions/ops/pack.py
|
||||
extensions/ops/parameter.py
|
||||
extensions/ops/pnorm.py
|
||||
|
||||
@@ -17,6 +17,7 @@ import numpy as np
|
||||
|
||||
from extensions.ops.elementwise import Mul
|
||||
from extensions.ops.gather import Gather
|
||||
from extensions.ops.interpolate import Interpolate
|
||||
from mo.back.replacement import BackReplacementPattern
|
||||
from mo.front.caffe.extractors.utils import get_canonical_axis_index
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
@@ -67,7 +68,7 @@ class InterpolateConcat(BackReplacementPattern):
|
||||
|
||||
output_shape = interpolate.out_port(0).data.get_shape()
|
||||
|
||||
interp_axes = [get_canonical_axis_index(output_shape, axis) for axis in interpolate.axes]
|
||||
interp_axes = [get_canonical_axis_index(output_shape, axis) for axis in Interpolate.get_axes(interpolate)]
|
||||
concat_axis = get_canonical_axis_index(output_shape, concat.axis)
|
||||
if concat_axis in interp_axes:
|
||||
return
|
||||
@@ -82,12 +83,13 @@ class InterpolateConcat(BackReplacementPattern):
|
||||
|
||||
shape = Shape(graph, {'name': src.node.soft_get('name', src.node.id) + '/Shape'}).create_node()
|
||||
shape.in_port(0).connect(src)
|
||||
gather = create_op_with_const_inputs(graph, Gather, {1: np.array(interpolate.axes, dtype=np.int32), 2: int64_array(0)},
|
||||
gather = create_op_with_const_inputs(graph, Gather,
|
||||
{1: np.array(interp_axes, dtype=np.int32), 2: int64_array(0)},
|
||||
{'name': shape.name + '/Gathered'}, shape)
|
||||
interpolate.in_port(1).get_connection().set_source(gather.out_port(0))
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for interpolate in graph.get_op_nodes(type='Interpolate'):
|
||||
for interpolate in graph.get_op_nodes(type='Interpolate', version='opset1'):
|
||||
if interpolate.in_port(1).get_source().node.soft_get('type') != 'Const':
|
||||
continue
|
||||
dsts = interpolate.out_port(0).get_destinations()
|
||||
@@ -132,7 +134,7 @@ class InterpolateReshapeWA(BackReplacementPattern):
|
||||
@staticmethod
|
||||
def make_interpolate_reshapeable(interpolate):
|
||||
assert interpolate.soft_get('type') == 'Interpolate'
|
||||
axes = interpolate.axes
|
||||
axes = Interpolate.get_axes(interpolate)
|
||||
input_shape = interpolate.in_port(0).data.get_shape()
|
||||
output_shape = interpolate.out_port(0).data.get_shape()
|
||||
if not np.all(np.remainder(output_shape, input_shape) == 0) and \
|
||||
@@ -149,6 +151,6 @@ class InterpolateReshapeWA(BackReplacementPattern):
|
||||
interpolate.in_port(1).get_connection().set_source(mul.out_port(0))
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for interpolate in graph.get_op_nodes(type='Interpolate'):
|
||||
for interpolate in graph.get_op_nodes(type='Interpolate', version='opset1'):
|
||||
if interpolate.in_port(1).get_source().node.soft_get('type') == 'Const':
|
||||
self.make_interpolate_reshapeable(interpolate)
|
||||
self.make_interpolate_reshapeable(interpolate)
|
||||
@@ -29,7 +29,7 @@ nodes = {
|
||||
**valued_const_with_data('out_shape', np.array([60, 160])),
|
||||
|
||||
**regular_op_with_shaped_data('interpolate', [1, 3, 60, 160], {'type': 'Interpolate', 'axes': [2, 3],
|
||||
'op': 'Interpolate'}),
|
||||
'op': 'Interpolate', 'version': 'opset1'}),
|
||||
|
||||
**regular_op_with_shaped_data('shape', [4], {'type': 'ShapeOf', 'op': 'ShapeOf'}),
|
||||
**valued_const_with_data('indices', np.array([2, 3])),
|
||||
@@ -79,6 +79,7 @@ class TestInterpolateConcat(unittest.TestCase):
|
||||
*connect('placeholder_1', '1:concat'),
|
||||
*connect('concat', 'output'),
|
||||
], nodes_with_edges_only=True)
|
||||
|
||||
InterpolateConcat().find_and_replace_pattern(graph)
|
||||
graph.clean_up()
|
||||
graph_ref = build_graph(nodes, [
|
||||
@@ -93,4 +94,4 @@ class TestInterpolateConcat(unittest.TestCase):
|
||||
*connect('concat', 'output'),
|
||||
], nodes_with_edges_only=True)
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'output', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -16,6 +16,7 @@
|
||||
import numpy as np
|
||||
|
||||
from extensions.ops.gather import Gather
|
||||
from extensions.ops.interpolate import Interpolate
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.common.replacement import FrontReplacementPattern
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
@@ -141,9 +142,7 @@ class InterpolateWithConcat(FrontReplacementPattern):
|
||||
def make_interpolate_reshape_able(self, interpolate: Node, concat: Node):
|
||||
assert interpolate.soft_get('type') == 'Interpolate'
|
||||
assert concat.soft_get('type') == 'Concat'
|
||||
|
||||
interp_axes = interpolate.soft_get('axes', None)
|
||||
interp_axes = interp_axes if interp_axes is None else int64_array(interp_axes)
|
||||
interp_axes = Interpolate.get_axes(interpolate)
|
||||
concat_axis = self.get_concat_axis(concat)
|
||||
|
||||
if concat_axis is None or interp_axes is None \
|
||||
@@ -163,12 +162,12 @@ class InterpolateWithConcat(FrontReplacementPattern):
|
||||
shape = Shape(graph, {'name': src.node.soft_get('name', src.node.id) + '/Shape'}).create_node()
|
||||
shape.in_port(0).connect(src)
|
||||
gather = create_op_with_const_inputs(graph, Gather,
|
||||
{1: np.array(interpolate.axes, dtype=np.int32), 2: int64_array(0)},
|
||||
{1: np.array(interp_axes, dtype=np.int32), 2: int64_array(0)},
|
||||
{'name': shape.name + '/Gathered'}, input_node=shape)
|
||||
interpolate.in_port(1).get_connection().set_source(gather.out_port(0))
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for interpolate in graph.get_op_nodes(type='Interpolate'):
|
||||
for interpolate in graph.get_op_nodes(type='Interpolate', version='opset1'):
|
||||
if interpolate.in_port(1).get_source().node.soft_get('type') != 'Const':
|
||||
continue
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ nodes = {
|
||||
**valued_const_with_data('out_shape', np.array([60, 160])),
|
||||
|
||||
**regular_op_with_shaped_data('interpolate', [1, 3, 60, 160],
|
||||
{'type': 'Interpolate', 'axes': int64_array([2, 3]), 'op': 'Interpolate'}),
|
||||
{'type': 'Interpolate', 'axes': int64_array([2, 3]), 'op': 'Interpolate',
|
||||
'version': 'opset1'}),
|
||||
**regular_op_with_shaped_data('identity_00', [1, 3, 60, 160], {'identity': True, 'op': 'Identity'}),
|
||||
**regular_op_with_shaped_data('identity_01', [1, 3, 60, 160], {'identity': True, 'op': 'Identity'}),
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
"""
|
||||
|
||||
from extensions.ops.upsample import UpsampleOp
|
||||
from extensions.ops.ONNXResize11 import ONNXResize11Op
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.front.onnx.extractors.utils import onnx_attr, get_onnx_opset_version
|
||||
from mo.graph.graph import Node
|
||||
from mo.utils.error import Error
|
||||
|
||||
|
||||
class ResizeExtractor(FrontExtractorOp):
|
||||
@@ -29,7 +29,19 @@ class ResizeExtractor(FrontExtractorOp):
|
||||
def extract(cls, node: Node):
|
||||
onnx_opset_version = get_onnx_opset_version(node)
|
||||
if onnx_opset_version is not None and onnx_opset_version >= 11:
|
||||
raise Error("ONNX Resize operation from opset {} is not supported.".format(onnx_opset_version))
|
||||
mode = onnx_attr(node, 'mode', 's', default=b'nearest').decode()
|
||||
UpsampleOp.update_node_stat(node, {'mode': mode})
|
||||
mode = onnx_attr(node, 'mode', 's', default=b'nearest').decode()
|
||||
transformation_mode = onnx_attr(node,
|
||||
'coordinate_transformation_mode',
|
||||
's',
|
||||
default=b'half_pixel').decode()
|
||||
nearest_mode = onnx_attr(node, 'nearest_mode', 's', default=b'round_prefer_floor').decode()
|
||||
cubic_coeff_a = onnx_attr(node, 'cubic_coeff_a', 'f', default=-0.75)
|
||||
attrs = {
|
||||
'mode': mode, 'coordinate_transformation_mode': transformation_mode,
|
||||
'nearest_mode': nearest_mode, 'cube_coeff': cubic_coeff_a
|
||||
}
|
||||
ONNXResize11Op.update_node_stat(node, attrs)
|
||||
else:
|
||||
mode = onnx_attr(node, 'mode', 's', default=b'nearest').decode()
|
||||
UpsampleOp.update_node_stat(node, {'mode': mode})
|
||||
return cls.enabled
|
||||
@@ -15,13 +15,15 @@
|
||||
"""
|
||||
|
||||
import logging as log
|
||||
import numpy as np
|
||||
from typing import List
|
||||
|
||||
from extensions.ops.interpolate import Interpolate
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.graph.graph import Graph, Node
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.graph.graph import Graph, Node, rename_nodes
|
||||
from mo.middle.replacement import MiddleReplacementPattern
|
||||
from mo.ops.const import Const
|
||||
from mo.utils.error import Error
|
||||
|
||||
|
||||
def node_has_one_consumer(node: Node) -> bool:
|
||||
@@ -50,6 +52,76 @@ class CanBeFused:
|
||||
# We need to accumulate set of axes of compared nodes, because there can be a sequence of a set of axes
|
||||
# {i}{j}{i}
|
||||
self.accumulated_axes = set()
|
||||
self.default_values_for_opset4 = {
|
||||
'mode': None,
|
||||
'shape_calculation_mode': None,
|
||||
'coordinate_transformation_mode': 'half_pixel',
|
||||
'nearest_mode': 'round_prefer_floor',
|
||||
'antialias': 0,
|
||||
'cube_coeff': -0.75
|
||||
}
|
||||
self.default_pads = int64_array([0])
|
||||
|
||||
def _compare_attributes_of_interpolate1(self, first: Node, second: Node) -> bool:
|
||||
"""
|
||||
This function checks whether attributes of Interpolate-1 nodes first and second are identical
|
||||
(except attribute 'axes').
|
||||
:param first: the first of compared nodes
|
||||
:param second: the second of compared nodes
|
||||
:return: True, if attributes of nodes are identical and False otherwise
|
||||
"""
|
||||
# If some of attributes 'mode', 'align_corners', 'antialias', 'pads_begin', 'pads_end' are different,
|
||||
# then attributes of nodes are not identical.
|
||||
op = Interpolate(graph=first.graph, attrs={})
|
||||
for attr in ['mode', 'align_corners', 'antialias', 'pads_begin', 'pads_end']:
|
||||
if first.soft_get(attr, default=op.attrs[attr]) != second.soft_get(attr, default=op.attrs[attr]):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _compare_attributes_of_interpolate4(self, first: Node, second: Node) -> bool:
|
||||
"""
|
||||
This function checks whether attributes of Interpolate-4 nodes first and second are identical.
|
||||
:param first: the first of compared nodes
|
||||
:param second: the second of compared nodes
|
||||
:return: True, if attributes of nodes are identical and False otherwise
|
||||
"""
|
||||
# If some of attributes 'mode', 'coordinate_transformation_mode', 'nearest_mode', 'antialias', 'cube_coeff'
|
||||
# are different, then attributes of first and second are not identical.
|
||||
for attr in self.default_values_for_opset4.keys():
|
||||
default_value = self.default_values_for_opset4[attr]
|
||||
if first.soft_get(attr, default=default_value) != second.soft_get(attr, default=default_value):
|
||||
return False
|
||||
|
||||
# If attributes 'pads_begin' or 'pads_end' of nodes first and second are different, then attributes
|
||||
# of first and second are not identical.
|
||||
for attr in ['pads_begin', 'pads_end']:
|
||||
if not np.array_equal(first.soft_get(attr, default=self.default_pads),
|
||||
second.soft_get(attr, default=self.default_pads)):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _compare_attributes(self, first: Node, second: Node) -> bool:
|
||||
"""
|
||||
This function checks whether attributes of nodes first and second are identical (except attribute 'axes').
|
||||
:param first: the first of compared nodes
|
||||
:param second: the second of compared nodes
|
||||
:return: True, if attributes of nodes are identical and False otherwise
|
||||
"""
|
||||
# If opsets of nodes are different, then nodes have different attributes.
|
||||
fst_opset = first.get_opset()
|
||||
snd_opset = second.get_opset()
|
||||
if fst_opset != snd_opset:
|
||||
return False
|
||||
|
||||
if fst_opset not in ['opset1', 'opset4']:
|
||||
fst_name = first.soft_get('name', first.id)
|
||||
snd_name = second.soft_get('name', second.id)
|
||||
raise Error('Unsupported opset {} for nodes with names {} and {}'.format(fst_opset, fst_name, snd_name))
|
||||
|
||||
if fst_opset == 'opset1':
|
||||
return self._compare_attributes_of_interpolate1(first, second)
|
||||
else:
|
||||
return self._compare_attributes_of_interpolate4(first, second)
|
||||
|
||||
def __call__(self, first: Node, second: Node) -> bool:
|
||||
"""
|
||||
@@ -58,15 +130,11 @@ class CanBeFused:
|
||||
:param second: the second of fused nodes
|
||||
:return: True, if nodes can be fused, and False otherwise
|
||||
"""
|
||||
# If some of attributes 'mode', 'align_corners', 'antialias', 'pads_begin', 'pads_end' are different,
|
||||
# then nodes cannot be fused, because fused result will be incorrect.
|
||||
op = Interpolate(graph=first.graph, attrs={})
|
||||
for attr in ['mode', 'align_corners', 'antialias', 'pads_begin', 'pads_end']:
|
||||
if first.soft_get(attr, default=op.attrs[attr]) != second.soft_get(attr, default=op.attrs[attr]):
|
||||
return False
|
||||
if not self._compare_attributes(first, second):
|
||||
return False
|
||||
|
||||
fst_axes = set([a for a in first.axes])
|
||||
snd_axes = set([a for a in second.axes])
|
||||
fst_axes = set([a for a in Interpolate.get_axes(first)])
|
||||
snd_axes = set([a for a in Interpolate.get_axes(second)])
|
||||
|
||||
self.accumulated_axes = self.accumulated_axes | fst_axes
|
||||
|
||||
@@ -108,6 +176,40 @@ def collect_sequences(xs: List[Node]) -> List[List[Node]]:
|
||||
return result
|
||||
|
||||
|
||||
def get_interpolate_attributes(node: Node) -> dict:
|
||||
opset_to_default_values = {
|
||||
'opset1': {
|
||||
'mode': None,
|
||||
'align_corners': 0,
|
||||
'antialias': 0,
|
||||
'pads_begin': 0,
|
||||
'pads_end': 0,
|
||||
'version': 'opset1'
|
||||
},
|
||||
'opset4': {
|
||||
'mode': None,
|
||||
'shape_calculation_mode': None,
|
||||
'antialias': 0,
|
||||
'pads_begin': int64_array([0]),
|
||||
'pads_end': int64_array([0]),
|
||||
'coordinate_transformation_mode': 'half_pixel',
|
||||
'nearest_mode': 'round_prefer_floor',
|
||||
'cube_coeff': -0.75,
|
||||
'version': 'opset4'
|
||||
},
|
||||
}
|
||||
opset = node.get_opset()
|
||||
result = {}
|
||||
if opset in opset_to_default_values:
|
||||
default_values = opset_to_default_values[opset]
|
||||
for attr in default_values.keys():
|
||||
value = node.soft_get(attr, default=default_values[attr])
|
||||
result[attr] = value
|
||||
return result
|
||||
else:
|
||||
raise Error('Unsupported opset {} for node with name {}.'.format(opset, node.soft_get('name', node.id)))
|
||||
|
||||
|
||||
def replace_sequence(seq: List[Node], graph: Graph):
|
||||
"""
|
||||
This function replaces a sequence of consecutive Interpolate layers with one Interpolate layer,
|
||||
@@ -127,37 +229,55 @@ def replace_sequence(seq: List[Node], graph: Graph):
|
||||
|
||||
dims_and_scales_ = []
|
||||
# Each element of the list dims_and_scales_ is a pair
|
||||
# (axis, output size for this axis)
|
||||
for interp in seq:
|
||||
dims_and_scales_.extend(zip(interp.axes, interp.in_port(1).get_connection().get_source().node.value))
|
||||
# (axis, output size for this axis) (opset1)
|
||||
# or
|
||||
# (axis, output size for this axis, output scales for this axis) (opset4)
|
||||
if seq[0].get_opset() == 'opset1':
|
||||
for interp in seq:
|
||||
dims_and_scales_.extend(zip(Interpolate.get_axes(interp),
|
||||
interp.in_port(1).get_connection().get_source().data.get_value()))
|
||||
|
||||
axis_to_size = sorted(list(dict(dims_and_scales_).items()), key=lambda x: x[0])
|
||||
axes_of_node = int64_array([z[0] for z in axis_to_size])
|
||||
sizes = int64_array([z[1] for z in axis_to_size])
|
||||
axis_to_size = sorted(list(dict(dims_and_scales_).items()), key=lambda x: x[0])
|
||||
axes_of_node = int64_array([z[0] for z in axis_to_size])
|
||||
sizes = int64_array([z[1] for z in axis_to_size])
|
||||
scales = np.ones(len(axis_to_size))
|
||||
else:
|
||||
for interp in seq:
|
||||
dims_and_scales_.extend(zip(Interpolate.get_axes(interp),
|
||||
interp.in_port(1).get_connection().get_source().data.get_value(),
|
||||
interp.in_port(2).get_connection().get_source().data.get_value()))
|
||||
|
||||
axis_to_size = sorted(dims_and_scales_, key=lambda x: x[0])
|
||||
axes_of_node = int64_array([z[0] for z in axis_to_size])
|
||||
sizes = int64_array([z[1] for z in axis_to_size])
|
||||
scales = np.array([z[2] for z in axis_to_size])
|
||||
|
||||
fst_interp_node = seq[0]
|
||||
last_interp_node = seq[-1]
|
||||
fst_interp_node_name = fst_interp_node.name
|
||||
fst_interp_node_mode = fst_interp_node.mode
|
||||
fst_interp_node_align_corners = fst_interp_node.soft_get('align_corners', default=0)
|
||||
fst_interp_node_antialias = fst_interp_node.soft_get('antialias', default=0)
|
||||
fst_interp_node_pads_begin = fst_interp_node.soft_get('pads_begin', default=0)
|
||||
fst_interp_node_pads_end = fst_interp_node.soft_get('pads_end', default=0)
|
||||
interp_node = Interpolate(graph, dict(name=fst_interp_node_name + '/Interpolate_',
|
||||
axes=axes_of_node,
|
||||
mode=fst_interp_node_mode,
|
||||
align_corners=fst_interp_node_align_corners,
|
||||
antialias=fst_interp_node_antialias,
|
||||
pads_begin=fst_interp_node_pads_begin,
|
||||
pads_end=fst_interp_node_pads_end)).create_node()
|
||||
last_interp_node_name = last_interp_node.soft_get('name', last_interp_node.id)
|
||||
attributes = get_interpolate_attributes(fst_interp_node)
|
||||
|
||||
scales_node = Const(graph, dict(name=fst_interp_node_name + '/scales_', value=sizes)).create_node()
|
||||
scales_node.out_port(0).connect(interp_node.in_port(1))
|
||||
opset = fst_interp_node.get_opset()
|
||||
if opset == 'opset1':
|
||||
attributes['axes'] = axes_of_node
|
||||
interp_node = create_op_with_const_inputs(graph, Interpolate, {1: sizes}, attributes)
|
||||
|
||||
fst_interp_connection = fst_interp_node.in_port(0).get_connection()
|
||||
fst_interp_connection.set_destination(interp_node.in_port(0))
|
||||
fst_interp_connection = fst_interp_node.in_port(0).get_connection()
|
||||
fst_interp_connection.set_destination(interp_node.in_port(0))
|
||||
|
||||
last_interp_node.out_port(0).get_connection().set_source(interp_node.out_port(0))
|
||||
last_interp_node.out_port(0).get_connection().set_source(interp_node.out_port(0))
|
||||
else:
|
||||
attributes['in_ports_count'] = 4
|
||||
interp_node = create_op_with_const_inputs(graph, Interpolate,
|
||||
{1: sizes, 2: scales, 3: axes_of_node},
|
||||
attributes)
|
||||
|
||||
fst_interp_connection = fst_interp_node.in_port(0).get_connection()
|
||||
fst_interp_connection.set_destination(interp_node.in_port(0))
|
||||
|
||||
last_interp_node.out_port(0).get_connection().set_source(interp_node.out_port(0))
|
||||
|
||||
rename_nodes([(last_interp_node, last_interp_node_name + '/delete_'), (interp_node, last_interp_node_name)])
|
||||
|
||||
|
||||
class InterpolateSequenceToInterpolate(MiddleReplacementPattern):
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,172 @@
|
||||
"""
|
||||
Copyright (C) 2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import logging as log
|
||||
import numpy as np
|
||||
|
||||
from extensions.ops.activation_ops import Floor
|
||||
from extensions.ops.Cast import Cast
|
||||
from extensions.ops.elementwise import Add, Div, Mul
|
||||
from extensions.ops.interpolate import Interpolate
|
||||
from mo.front.common.layout import get_depth_dim, get_height_dim, get_width_dim
|
||||
from mo.front.common.partial_infer.utils import int64_array, float_array
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.middle.passes.convert_data_type import data_type_str_to_np
|
||||
from mo.middle.replacement import MiddleReplacementPattern
|
||||
from mo.graph.graph import Graph, Node, rename_nodes
|
||||
from mo.ops.const import Const
|
||||
from mo.ops.shape import Shape
|
||||
from mo.ops.strided_slice import StridedSlice
|
||||
|
||||
|
||||
def convert_mode(onnx_mode: str) -> str:
|
||||
return {'nearest': 'nearest', 'linear': 'linear_onnx', 'cubic': 'cubic'}[onnx_mode]
|
||||
|
||||
|
||||
def replace_resize(graph: Graph, resize: Node):
|
||||
log.debug("Converting of ONNX Resize-11 to Interpolate-4 "
|
||||
"is triggered for node {}.".format(resize.soft_get('name', resize.id)))
|
||||
|
||||
input_shape = resize.in_port(0).data.get_shape()
|
||||
input_rank = len(input_shape)
|
||||
resize_name = resize.soft_get('name', resize.id)
|
||||
if input_rank not in {4, 5}:
|
||||
log.warning('The input shape is not 4D or 5D for op with name {}'.format(resize_name))
|
||||
return
|
||||
|
||||
num_of_inputs = len([port for port in resize.in_ports().values() if not port.disconnected()])
|
||||
assert num_of_inputs in {3, 4}, \
|
||||
"Number of inputs of ONNXResize (with name {}) should be equal to 3 or 4".format(resize_name)
|
||||
|
||||
assert resize.soft_get('coordinate_transformation_mode') != 'tf_crop_and_resize', \
|
||||
'Mode tf_crop_and_resize is not supported for op {} with name {}'.format(resize.op, resize_name)
|
||||
|
||||
layout = graph.graph['layout']
|
||||
|
||||
if input_rank == 4:
|
||||
begin_dim = get_height_dim(layout, input_rank)
|
||||
end_dim = get_width_dim(layout, input_rank) + 1
|
||||
else:
|
||||
begin_dim = get_depth_dim(layout, input_rank)
|
||||
end_dim = get_width_dim(layout, input_rank) + 1
|
||||
|
||||
sizes_ss = create_op_with_const_inputs(graph, StridedSlice,
|
||||
{1: int64_array([begin_dim]),
|
||||
2: int64_array([end_dim]),
|
||||
3: int64_array([1])},
|
||||
{'name': resize_name + '/StridedSlice_',
|
||||
'begin_mask': int64_array([1]),
|
||||
'end_mask': int64_array([1]),
|
||||
'new_axis_mask': int64_array([0]),
|
||||
'shrink_axis_mask': int64_array([0]),
|
||||
'ellipsis_mask': int64_array([0])})
|
||||
scales_ss = create_op_with_const_inputs(graph, StridedSlice,
|
||||
{1: int64_array([begin_dim]),
|
||||
2: int64_array([end_dim]),
|
||||
3: int64_array([1])},
|
||||
{'name': resize_name + '/StridedSlice_',
|
||||
'begin_mask': int64_array([1]),
|
||||
'end_mask': int64_array([1]),
|
||||
'new_axis_mask': int64_array([0]),
|
||||
'shrink_axis_mask': int64_array([0]),
|
||||
'ellipsis_mask': int64_array([0])})
|
||||
axes_node = Const(graph,
|
||||
{'name': resize_name + '/axis_',
|
||||
'value': int64_array(np.arange(begin_dim, end_dim))}).create_node()
|
||||
|
||||
shape_calculation_mode = 'scales' if num_of_inputs == 3 else 'sizes'
|
||||
|
||||
interpolate_node = Interpolate(graph, {'version': 'opset4',
|
||||
'mode': convert_mode(resize.mode),
|
||||
'coordinate_transformation_mode': resize.coordinate_transformation_mode,
|
||||
'cube_coeff': resize.cube_coeff,
|
||||
'nearest_mode': resize.nearest_mode,
|
||||
'pads_begin': int64_array([0]),
|
||||
'pads_end': int64_array([0]),
|
||||
'antialias': 0,
|
||||
'shape_calculation_mode': shape_calculation_mode,
|
||||
'in_ports_count': 4}).create_node()
|
||||
|
||||
axes_node.out_port(0).connect(interpolate_node.in_port(3))
|
||||
shape_of = Shape(graph, {'name': resize_name + '/ShapeOf_'}).create_node()
|
||||
|
||||
add_node = create_op_with_const_inputs(graph, Add,
|
||||
{1: float_array([1.0e-5])},
|
||||
{'name': resize_name + '/Add_'})
|
||||
|
||||
input_data_type = data_type_str_to_np(graph.graph['cmd_params'].data_type)
|
||||
|
||||
if num_of_inputs == 3:
|
||||
cast_shape_to_float = Cast(graph, {'dst_type': input_data_type}).create_node()
|
||||
mul_node = Mul(graph, {'name': resize_name + '/Mul_'}).create_node()
|
||||
shape_of.out_port(0).connect(cast_shape_to_float.in_port(0))
|
||||
cast_shape_to_float.out_port(0).connect(mul_node.in_port(0))
|
||||
cast_add_result_to_int = Cast(graph, {'dst_type': np.int64}).create_node()
|
||||
floor_node = Floor(graph, {'name': resize_name + '/Floor_'}).create_node()
|
||||
mul_node.out_port(0).connect(add_node.in_port(0))
|
||||
add_node.out_port(0).connect(floor_node.in_port(0))
|
||||
floor_node.out_port(0).connect(cast_add_result_to_int.in_port(0))
|
||||
cast_add_result_to_int.out_port(0).connect(sizes_ss.in_port(0))
|
||||
sizes_ss.out_port(0).connect(interpolate_node.in_port(1))
|
||||
scales_ss.out_port(0).connect(interpolate_node.in_port(2))
|
||||
|
||||
connection_of_resize_input = resize.in_port(0).get_connection()
|
||||
connection_of_resize_input.set_destination(interpolate_node.in_port(0))
|
||||
|
||||
connection_of_scales = resize.in_port(2).get_connection()
|
||||
connection_of_scales.set_destination(scales_ss.in_port(0))
|
||||
|
||||
connection_of_resize_input.get_source().connect(shape_of.in_port(0))
|
||||
connection_of_scales.get_source().connect(mul_node.in_port(1))
|
||||
else:
|
||||
cast_shape_to_float = Cast(graph, {'dst_type': input_data_type}).create_node()
|
||||
cast_sizes_to_float = Cast(graph, {'dst_type': input_data_type}).create_node()
|
||||
div_node = Div(graph, {'name': resize_name + '/Div_'}).create_node()
|
||||
cast_sizes_to_float.out_port(0).connect(div_node.in_port(0))
|
||||
cast_shape_to_float.out_port(0).connect(div_node.in_port(1))
|
||||
shape_of.out_port(0).connect(cast_shape_to_float.in_port(0))
|
||||
div_node.out_port(0).connect(add_node.in_port(0))
|
||||
add_node.out_port(0).connect(scales_ss.in_port(0))
|
||||
scales_ss.out_port(0).connect(interpolate_node.in_port(2))
|
||||
sizes_ss.out_port(0).connect(interpolate_node.in_port(1))
|
||||
|
||||
connection_of_resize_input = resize.in_port(0).get_connection()
|
||||
connection_of_resize_input.set_destination(interpolate_node.in_port(0))
|
||||
|
||||
connection_of_sizes = resize.in_port(3).get_connection()
|
||||
connection_of_sizes.set_destination(sizes_ss.in_port(0))
|
||||
|
||||
connection_of_resize_input.get_source().connect(shape_of.in_port(0))
|
||||
connection_of_sizes.get_source().connect(cast_sizes_to_float.in_port(0))
|
||||
|
||||
rename_nodes([(resize, resize_name + '/delete'), (interpolate_node, resize_name)])
|
||||
resize.out_port(0).get_connection().set_source(interpolate_node.out_port(0))
|
||||
|
||||
|
||||
class ONNXResize11ToInterpolate4(MiddleReplacementPattern):
|
||||
"""
|
||||
The transformation replaces ONNX Resize 11 with Interpolate-4.
|
||||
"""
|
||||
enabled = True
|
||||
|
||||
def run_before(self):
|
||||
from extensions.middle.InterpolateSequenceToInterpolate import InterpolateSequenceToInterpolate
|
||||
return [InterpolateSequenceToInterpolate]
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
resize11_ops = graph.get_op_nodes(op='ONNXResize11')
|
||||
for resize in resize11_ops:
|
||||
replace_resize(graph, resize)
|
||||
@@ -102,8 +102,6 @@ class UpsampleToResample(MiddleReplacementPattern):
|
||||
begin_value = int64_array([get_depth_dim(layout, input_shape_rank)])
|
||||
factor_value = np.array([depth_scale, height_scale, width_scale])
|
||||
|
||||
|
||||
|
||||
ss = create_op_with_const_inputs(graph, StridedSlice,
|
||||
{1: begin_value,
|
||||
2: int64_array([get_width_dim(layout, input_shape_rank) + 1]),
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
Copyright (C) 2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.graph.graph import Node, Graph
|
||||
from mo.ops.op import Op
|
||||
|
||||
|
||||
class ONNXResize11Op(Op):
|
||||
op = 'ONNXResize11'
|
||||
|
||||
def __init__(self, graph: Graph, attrs: dict):
|
||||
mandatory_props = {
|
||||
'op': self.op,
|
||||
'out_ports_count': 1,
|
||||
'infer': ONNXResize11Op.onnx_resize_infer
|
||||
}
|
||||
super().__init__(graph, mandatory_props, attrs)
|
||||
|
||||
def supported_attrs(self):
|
||||
return [
|
||||
'coordinate_transformation_mode',
|
||||
'cube_coeff',
|
||||
'exclude_outside',
|
||||
'extrapolation_value',
|
||||
'mode',
|
||||
'nearest_mode'
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def onnx_resize_infer(node: Node):
|
||||
input_shape = node.in_port(0).data.get_shape()
|
||||
if input_shape is None:
|
||||
return
|
||||
|
||||
num_of_in_nodes = len(node.in_nodes())
|
||||
assert num_of_in_nodes in {3, 4}, \
|
||||
"Node {} with op {} number of inputs must be equal to 3 or 4.".format(node.name, node.op)
|
||||
|
||||
assert node.coordinate_transformation_mode != 'tf_crop_and_resize', \
|
||||
'Mode tf_crop_and_resize is not supported for op {} with name {}'.format(node.op, node.name)
|
||||
|
||||
if num_of_in_nodes == 3:
|
||||
# i.e. input 'sizes' is not given
|
||||
input2_value = node.in_port(2).data.get_value()
|
||||
assert input2_value is not None, \
|
||||
"Node {} with op {} has no value in input port 2".format(node.soft_get('name', node.id), node.op)
|
||||
scale = np.array(input2_value)
|
||||
output_shape = np.floor(input_shape * scale + 1.0e-6).astype(np.int64)
|
||||
else:
|
||||
# i.e. input 'sizes' is given
|
||||
sizes = node.in_port(3).data.get_value()
|
||||
assert sizes is not None, \
|
||||
"Node {} with op {} has no value in input port 3".format(node.name, node.op)
|
||||
output_shape = int64_array(sizes)
|
||||
|
||||
node.out_port(0).data.set_shape(output_shape.copy())
|
||||
@@ -14,15 +14,118 @@
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.graph.graph import Node, Graph
|
||||
from mo.ops.op import Op, PermuteAttrs
|
||||
|
||||
|
||||
def infer_for_opset4(node: Node):
|
||||
assert len([p for p in node.in_ports().values() if not p.disconnected()]) in [3, 4], \
|
||||
"Interpolate-4 node {} must have 3 or 4 inputs".format(node.soft_get(node.name, node.id))
|
||||
assert node.has_valid('mode')
|
||||
assert node.has_valid('shape_calculation_mode')
|
||||
src_shape = node.in_port(0).data.get_shape()
|
||||
assert src_shape is not None
|
||||
|
||||
input_rank = len(src_shape)
|
||||
|
||||
pads_begin = correct_pad(node.soft_get('pads_begin', [0]), input_rank)
|
||||
pads_end = correct_pad(node.soft_get('pads_end', [0]), input_rank)
|
||||
node['pads_begin'] = pads_begin
|
||||
node['pads_end'] = pads_end
|
||||
|
||||
if len(node.in_ports()) == 3:
|
||||
axes = list(range(0, input_rank))
|
||||
else:
|
||||
axes = node.in_port(3).get_source().data.get_value()
|
||||
assert axes is not None, \
|
||||
"Interpolate-4 node with name {} has None as 'axes' input".format(node.soft_get('name', node.id))
|
||||
|
||||
axes = int64_array(axes)
|
||||
output_shape = src_shape + pads_begin + pads_end
|
||||
if node.shape_calculation_mode == 'sizes':
|
||||
dst_shape = node.in_port(1).data.get_value()
|
||||
assert dst_shape is not None
|
||||
correct_scales_using_dst_shape(node, dst_shape, src_shape, axes)
|
||||
for i, axis in enumerate(axes):
|
||||
output_shape[axis] = dst_shape[i]
|
||||
else:
|
||||
scales = node.in_port(2).data.get_value()
|
||||
assert scales is not None
|
||||
for i, axis in enumerate(axes):
|
||||
output_shape[axis] = math.floor(scales[i] * output_shape[axis] + 1.0e-5)
|
||||
|
||||
node.out_port(0).data.set_shape(output_shape)
|
||||
|
||||
|
||||
def infer_for_opset1(node: Node):
|
||||
assert len([p for p in node.in_ports().values() if not p.disconnected()]) == 2
|
||||
assert node.has_valid('mode')
|
||||
assert node.has_valid('axes')
|
||||
|
||||
src_shape = node.in_port(0).data.get_shape()
|
||||
|
||||
assert src_shape is not None
|
||||
dst_shape = node.in_port(1).data.get_value()
|
||||
assert dst_shape is not None
|
||||
|
||||
output_shape = src_shape.copy()
|
||||
for ind, axis in enumerate(node.axes):
|
||||
output_shape[axis] = dst_shape[ind]
|
||||
|
||||
node.out_port(0).data.set_shape(output_shape)
|
||||
|
||||
PermuteAttrs.create_permute_attrs(node, attrs=[('axes', 'input:0')])
|
||||
|
||||
|
||||
def pad_attribute_to_str(node: Node, attr: str):
|
||||
return ','.join(map(str, node[attr])) if node.has_valid(attr) else None
|
||||
|
||||
|
||||
def correct_pad(pad, rank):
|
||||
pad_len = len(pad)
|
||||
if pad_len < rank:
|
||||
return np.pad(pad, (0, rank - pad_len), 'constant').astype(np.int64)
|
||||
elif pad_len > rank:
|
||||
return np.array(pad[: rank]).astype(np.int64)
|
||||
else:
|
||||
return np.array(pad, dtype=np.int64)
|
||||
|
||||
|
||||
def correct_scales_using_dst_shape(node, dst_shape, src_shape, axes):
|
||||
scales_value = node.in_port(2).data.get_value()
|
||||
if scales_value is None or len(scales_value) != len(dst_shape):
|
||||
corrected_scales = np.zeros(len(dst_shape))
|
||||
for i, axis in enumerate(list(axes)):
|
||||
corrected_scales[i] = math.floor((dst_shape[i] / src_shape[axis]) + 1.0e-5)
|
||||
|
||||
|
||||
class Interpolate(Op):
|
||||
op = 'Interpolate'
|
||||
enabled = False
|
||||
infers = {
|
||||
'opset1': infer_for_opset1,
|
||||
'opset4': infer_for_opset4
|
||||
}
|
||||
|
||||
def __init__(self, graph: Graph, attrs: dict):
|
||||
self.attributes_for_opsets = {
|
||||
'opset1': [
|
||||
('axes', lambda node: ','.join(map(str, node.axes))),
|
||||
'mode', 'align_corners', 'antialias', 'pads_begin', 'pads_end',
|
||||
],
|
||||
'opset4': [
|
||||
'mode', 'antialias', 'nearest_mode', 'cube_coeff', 'coordinate_transformation_mode',
|
||||
'shape_calculation_mode',
|
||||
('pads_begin', lambda node: pad_attribute_to_str(node, 'pads_begin')),
|
||||
('pads_end', lambda node: pad_attribute_to_str(node, 'pads_end')),
|
||||
]
|
||||
}
|
||||
|
||||
mandatory_props = {
|
||||
'op': self.op,
|
||||
'type': self.op,
|
||||
@@ -38,34 +141,34 @@ class Interpolate(Op):
|
||||
'infer': self.infer,
|
||||
|
||||
'force_precision_in_ports': {1: 'int64'},
|
||||
|
||||
'in_ports_count': 2,
|
||||
'out_ports_count': 1,
|
||||
}
|
||||
super().__init__(graph, mandatory_props, attrs)
|
||||
|
||||
def supported_attrs(self):
|
||||
return [
|
||||
('axes', lambda node: ','.join(map(str, node.axes))),
|
||||
'mode', 'align_corners', 'antialias', 'pads_begin', 'pads_end',
|
||||
]
|
||||
opset = self.get_opset()
|
||||
key = opset if opset in self.attributes_for_opsets else 'opset1'
|
||||
return self.attributes_for_opsets[key]
|
||||
|
||||
def infer(self, node: Node):
|
||||
opset = self.get_opset()
|
||||
key = opset if opset in self.infers else 'opset1'
|
||||
self.infers[key](node)
|
||||
|
||||
@staticmethod
|
||||
def infer(node: Node):
|
||||
assert len([p for p in node.in_ports().values() if not p.disconnected()]) == 2
|
||||
assert node.has_valid('mode')
|
||||
assert node.has_valid('axes')
|
||||
def get_axes(node: Node) -> np.ndarray:
|
||||
opset = node.get_opset()
|
||||
if opset == 'opset1':
|
||||
interp_axes = node.soft_get('axes', None)
|
||||
return interp_axes if interp_axes is None else int64_array(interp_axes)
|
||||
|
||||
src_shape = node.in_port(0).data.get_shape()
|
||||
|
||||
assert src_shape is not None
|
||||
dst_shape = node.in_port(1).data.get_value()
|
||||
assert dst_shape is not None
|
||||
input_rank = len(src_shape)
|
||||
|
||||
output_shape = src_shape.copy()
|
||||
for ind, axis in enumerate(node.axes):
|
||||
output_shape[axis] = dst_shape[ind]
|
||||
|
||||
node.out_port(0).data.set_shape(output_shape)
|
||||
|
||||
PermuteAttrs.create_permute_attrs(node, attrs=[('axes', 'input:0')])
|
||||
if len(node.in_ports()) == 3:
|
||||
axes = list(range(0, input_rank))
|
||||
else:
|
||||
axes = node.in_port(3).get_source().data.get_value()
|
||||
return int64_array(axes)
|
||||
@@ -0,0 +1,281 @@
|
||||
"""
|
||||
Copyright (C) 2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from generator import generator, generate
|
||||
|
||||
from extensions.ops.interpolate import Interpolate
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.graph.graph import Node
|
||||
from mo.utils.unittest.graph import build_graph
|
||||
|
||||
|
||||
graph_node_attrs_without_axes = {
|
||||
'input': {'type': 'Parameter', 'kind': 'op'},
|
||||
'input_data': {'kind': 'data', 'shape': None, 'value': None},
|
||||
'sizes': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None},
|
||||
'sizes_data': {'kind': 'data', 'shape': None, 'value': None},
|
||||
'scales': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None},
|
||||
'scales_data': {'kind': 'data', 'shape': None, 'value': None},
|
||||
'interpolate': {
|
||||
'type': 'Interpolate', 'kind': 'op', 'mode': 'nearest', 'shape_calculation_mode': 'sizes',
|
||||
'coordinate_transformation_mode': 'half_pixel', 'version': 'opset4',
|
||||
'nearest_mode': 'round_prefer_floor', 'antialias': 0,
|
||||
},
|
||||
'interpolate_data': {'kind': 'data', 'value': None, 'shape': None},
|
||||
'op_output': {'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
graph_edges_without_axes = [
|
||||
('input', 'input_data'),
|
||||
('sizes', 'sizes_data'),
|
||||
('scales', 'scales_data'),
|
||||
('input_data', 'interpolate', {'in': 0}),
|
||||
('sizes_data', 'interpolate', {'in': 1}),
|
||||
('scales_data', 'interpolate', {'in': 2}),
|
||||
('interpolate', 'interpolate_data'),
|
||||
('interpolate_data', 'op_output'),
|
||||
]
|
||||
|
||||
|
||||
graph_nodes_attrs = {
|
||||
'input': {'type': 'Parameter', 'kind': 'op'},
|
||||
'input_data': {'kind': 'data', 'shape': None, 'value': None},
|
||||
'sizes': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None},
|
||||
'sizes_data': {'kind': 'data', 'shape': None, 'value': None},
|
||||
'scales': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None},
|
||||
'scales_data': {'kind': 'data', 'shape': None, 'value': None},
|
||||
'axes': {'type': 'Const', 'kind': 'op', 'shape': None, 'value': None},
|
||||
'axes_data': {'kind': 'data', 'shape': None, 'value': None},
|
||||
'interpolate': {
|
||||
'type': 'Interpolate', 'kind': 'op', 'mode': 'nearest', 'shape_calculation_mode': 'sizes',
|
||||
'coordinate_transformation_mode': 'half_pixel', 'version': 'opset4',
|
||||
'nearest_mode': 'round_prefer_floor', 'antialias': 0,
|
||||
},
|
||||
'interpolate_data': {'kind': 'data', 'value': None, 'shape': None},
|
||||
'op_output': {'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
graph_edges = [
|
||||
('input', 'input_data'),
|
||||
('sizes', 'sizes_data'),
|
||||
('scales', 'scales_data'),
|
||||
('axes', 'axes_data'),
|
||||
('input_data', 'interpolate', {'in': 0}),
|
||||
('sizes_data', 'interpolate', {'in': 1}),
|
||||
('scales_data', 'interpolate', {'in': 2}),
|
||||
('axes_data', 'interpolate', {'in': 3}),
|
||||
('interpolate', 'interpolate_data'),
|
||||
('interpolate_data', 'op_output'),
|
||||
]
|
||||
|
||||
|
||||
@generator
|
||||
class TestInterpolateOp(unittest.TestCase):
|
||||
@generate(*[([0], [0], [1, 3, 100, 200], [1, 3, 350, 150], [350, 150], [3.5, 150 / 200], [2, 3]),
|
||||
([0, 3, 10, 10], [0], [16, 7, 190, 400], [8, 10, 390, 600],
|
||||
[8, 390, 600], [0.5, 390 / 200, 600 / 410], [0, 2, 3]),
|
||||
([10, 5, 0, 10], [0, 4, 16, 18], [4, 33, 1024, 8000], [56, 42, 520, 8028],
|
||||
[56, 520], [4.0, 0.5], [0, 2]),
|
||||
([0], [0], [1, 16, 85, 470, 690], [20, 16, 40, 470, 1380],
|
||||
[20, 40, 1380], [20.0, 40.0 / 85.0, 1380.0 / 690.0], [0, 2, 4]),
|
||||
([4, 3, 11, 22, 5], [1, 3, 4, 8, 5], [1, 16, 85, 470, 690], [60, 22, 430, 500, 345],
|
||||
[60, 430, 345], [10.0, 4.3, 345.0 / 700.0], [0, 2, 4]),
|
||||
([0], [0], [5, 77, 444, 88, 6050], [100, 308, 4440, 44, 6050],
|
||||
[100, 308, 4440, 44], [20.0, 4.0, 10.0, 0.5], [0, 1, 2, 3]),
|
||||
([0], [0], [1, 100, 200], [1, 350, 150], [350, 150], [3.5, 150 / 200], [1, 2]),
|
||||
([0, 3, 10], [0], [16, 7, 190], [8, 10, 390], [8, 390], [0.5, 390 / 200], [0, 2]),
|
||||
([10, 0, 10], [0, 16, 18], [4, 1024, 8000], [56, 520, 8028], [56, 520], [4.0, 0.5], [0, 1]),
|
||||
([0], [0], [1, 690], [20, 1380], [20, 1380], [20.0, 1380.0 / 690.0], [0, 1]),
|
||||
([4, 3, 11, 22, 5, 0], [1, 3, 4, 8, 5, 0], [1, 16, 85, 470, 690, 349], [60, 22, 430, 500, 345, 349],
|
||||
[60, 430, 345], [10.0, 4.3, 345.0 / 700.0], [0, 2, 4])
|
||||
])
|
||||
def test_interpolate4_using_sizes(self, pads_begin, pads_end, input_shape, output_shape, sizes, scales, axes):
|
||||
graph = build_graph(nodes_attrs=graph_nodes_attrs,
|
||||
edges=graph_edges,
|
||||
update_attributes={
|
||||
'input_data': {'shape': input_shape},
|
||||
'sizes': {'shape': int64_array(sizes).shape, 'value': int64_array(sizes)},
|
||||
'sizes_data': {'shape': int64_array(sizes).shape, 'value': int64_array(sizes)},
|
||||
'scales': {'shape': np.array(scales).shape, 'value': np.array(scales)},
|
||||
'scales_data': {'shape': np.array(scales).shape, 'value': np.array(scales)},
|
||||
'axes': {'shape': int64_array(axes).shape, 'value': int64_array(axes)},
|
||||
'axes_data': {'shape': int64_array(axes).shape, 'value': int64_array(axes)},
|
||||
'interpolate': {'pads_begin': int64_array(pads_begin),
|
||||
'pads_end': int64_array(pads_end)}
|
||||
})
|
||||
|
||||
node = Node(graph, 'interpolate')
|
||||
tested_class = Interpolate(graph=graph, attrs=node.attrs())
|
||||
tested_class.infer(node)
|
||||
|
||||
msg = "Interpolate-4 infer failed for case: sizes={}, scales={}, pads_begin={}, pads_end={}, axes={}," \
|
||||
" expected_shape={}, actual_shape={}"
|
||||
|
||||
self.assertTrue(np.array_equal(graph.node['interpolate_data']['shape'], int64_array(output_shape)),
|
||||
msg.format(sizes, scales, pads_begin, pads_end, axes, output_shape,
|
||||
graph.node['interpolate_data']['shape']))
|
||||
|
||||
@generate(*[([0], [0], [1, 3, 100, 200], [1, 3, 350, 150], [350, 150], [3.5, 150 / 200], [2, 3]),
|
||||
([0, 3, 10, 10], [0], [16, 7, 190, 400], [8, 10, 390, 600],
|
||||
[8, 390, 600], [0.5, 390 / 200, 600 / 410], [0, 2, 3]),
|
||||
([10, 5, 0, 10], [0, 4, 16, 18], [4, 33, 1024, 8000], [56, 42, 520, 8028],
|
||||
[56, 520], [4.0, 0.5], [0, 2]),
|
||||
([0], [0], [1, 16, 85, 470, 690], [20, 16, 40, 470, 1380],
|
||||
[20, 40, 1380], [20.0, 40.0 / 85.0, 1380.0 / 690.0], [0, 2, 4]),
|
||||
([4, 3, 11, 22, 5], [1, 3, 4, 8, 5], [1, 16, 85, 470, 690], [60, 22, 430, 500, 345],
|
||||
[60, 430, 345], [10.0, 4.3, 345.0 / 700.0], [0, 2, 4]),
|
||||
([0], [0], [5, 77, 444, 88, 6050], [100, 308, 4440, 44, 6050],
|
||||
[100, 308, 4440, 44], [20.0, 4.0, 10.0, 0.5], [0, 1, 2, 3]),
|
||||
([0], [0], [1, 100, 200], [1, 350, 150], [350, 150], [3.5, 150 / 200], [1, 2]),
|
||||
([0, 3, 10], [0], [16, 7, 190], [8, 10, 390], [8, 390], [0.5, 390 / 200], [0, 2]),
|
||||
([10, 0, 10], [0, 16, 18], [4, 1024, 8000], [56, 520, 8028], [56, 520], [4.0, 0.5], [0, 1]),
|
||||
([0], [0], [1, 690], [20, 1380], [20, 1380], [20.0, 1380.0 / 690.0], [0, 1]),
|
||||
([4, 3, 11, 22, 5, 0], [1, 3, 4, 8, 5, 0], [1, 16, 85, 470, 690, 349], [60, 22, 430, 500, 345, 349],
|
||||
[60, 430, 345], [10.0, 4.3, 345.0 / 700.0], [0, 2, 4]),
|
||||
([4, 3, 11, 22, 5, 0, 0], [1, 3, 4, 8, 5, 0, 0], [1, 16, 85, 470, 690, 349, 3],
|
||||
[60, 22, 430, 500, 345, 349, 1],
|
||||
[60, 430, 345, 1], [10.0, 4.3, 345.0 / 700.0, 1 / 3], [0, 2, 4, 6]),
|
||||
([4, 3, 11, 22, 5, 0, 0], [1, 3, 4, 8, 5, 0, 0], [1, 16, 85, 470, 690, 349, 3],
|
||||
[60, 22, 430, 500, 345, 349, 1],
|
||||
[60, 430, 345, 1], [10.0, 4.3, 345.0 / 700.0, 0.3333333], [0, 2, 4, 6]),
|
||||
])
|
||||
def test_interpolate4_using_scales(self, pads_begin, pads_end, input_shape, output_shape, sizes, scales, axes):
|
||||
graph = build_graph(nodes_attrs=graph_nodes_attrs,
|
||||
edges=graph_edges,
|
||||
update_attributes={
|
||||
'input_data': {'shape': input_shape},
|
||||
'sizes': {'shape': int64_array(sizes).shape, 'value': int64_array(sizes)},
|
||||
'sizes_data': {'shape': int64_array(sizes).shape, 'value': int64_array(sizes)},
|
||||
'scales': {'shape': np.array(scales).shape, 'value': np.array(scales)},
|
||||
'scales_data': {'shape': np.array(scales).shape, 'value': np.array(scales)},
|
||||
'axes': {'shape': int64_array(axes).shape, 'value': int64_array(axes)},
|
||||
'axes_data': {'shape': int64_array(axes).shape, 'value': int64_array(axes)},
|
||||
'interpolate': {'pads_begin': int64_array(pads_begin),
|
||||
'pads_end': int64_array(pads_end),
|
||||
'shape_calculation_mode': 'scales'}
|
||||
})
|
||||
|
||||
node = Node(graph, 'interpolate')
|
||||
tested_class = Interpolate(graph=graph, attrs=node.attrs())
|
||||
tested_class.infer(node)
|
||||
|
||||
msg = "Interpolate-4 infer failed for case: sizes={}, scales={}, pads_begin={}, pads_end={}, axes={}," \
|
||||
" expected_shape={}, actual_shape={}"
|
||||
|
||||
self.assertTrue(np.array_equal(graph.node['interpolate_data']['shape'], int64_array(output_shape)),
|
||||
msg.format(sizes, scales, pads_begin, pads_end, axes, output_shape,
|
||||
graph.node['interpolate_data']['shape']))
|
||||
|
||||
@generate(*[([0], [0], [1, 3, 100, 200], [1, 3, 350, 150], [1, 3, 350, 150], [1.0, 1.0, 3.5, 150 / 200]),
|
||||
([0, 3, 10, 10], [0], [16, 7, 190, 400], [8, 10, 390, 600],
|
||||
[8, 10, 390, 600], [0.5, 1.0, 390 / 200, 600 / 410]),
|
||||
([10, 5, 0, 10], [0, 4, 16, 18], [4, 33, 1024, 8000], [56, 42, 520, 8028],
|
||||
[56, 42, 520, 8028], [4.0, 1.0, 0.5, 1.0]),
|
||||
([0], [0], [1, 16, 85, 470, 690], [20, 16, 40, 470, 1380],
|
||||
[20, 16, 40, 470, 1380], [20.0, 1.0, 40.0 / 85.0, 1.0, 1380.0 / 690.0]),
|
||||
([4, 3, 11, 22, 5], [1, 3, 4, 8, 5], [1, 16, 85, 470, 690], [60, 22, 430, 500, 345],
|
||||
[60, 22, 430, 500, 345], [10.0, 1.0, 4.3, 1.0, 345.0 / 700.0]),
|
||||
([0], [0], [5, 77, 444, 88, 6050], [100, 308, 4440, 44, 6050],
|
||||
[100, 308, 4440, 44, 6050], [20.0, 4.0, 10.0, 0.5, 1.0]),
|
||||
([0], [0], [1, 100, 200], [1, 350, 150], [1, 350, 150], [1.0, 3.5, 150 / 200]),
|
||||
([0, 3, 10], [0], [16, 7, 190], [8, 10, 390], [8, 10, 390], [0.5, 1.0, 390 / 200]),
|
||||
([10, 0, 10], [0, 16, 18], [4, 1024, 8000], [56, 520, 8028], [56, 520, 8028], [4.0, 0.5, 1.0]),
|
||||
([0], [0], [1, 690], [20, 1380], [20, 1380], [20.0, 1380.0 / 690.0]),
|
||||
([4, 3, 11, 22, 5, 0], [1, 3, 4, 8, 5, 0], [1, 16, 85, 470, 690, 349], [60, 22, 430, 500, 345, 349],
|
||||
[60, 22, 430, 500, 345, 349], [10.0, 1.0, 4.3, 1.0, 345.0 / 700.0, 1.0]),
|
||||
([4, 3, 11, 22, 5, 0, 0], [1, 3, 4, 8, 5, 0, 0], [1, 16, 85, 470, 690, 349, 3],
|
||||
[60, 22, 430, 500, 345, 349, 1],
|
||||
[60, 22, 430, 500, 345, 349, 1], [10.0, 1.0, 4.3, 1.0, 345.0 / 700.0, 1.0, 1 / 3]),
|
||||
])
|
||||
def test_interpolate4_using_sizes_without_axes(self, pads_begin, pads_end, input_shape, output_shape, sizes,
|
||||
scales):
|
||||
graph = build_graph(nodes_attrs=graph_node_attrs_without_axes,
|
||||
edges=graph_edges_without_axes,
|
||||
update_attributes={
|
||||
'input_data': {'shape': input_shape},
|
||||
'sizes': {'shape': int64_array(sizes).shape, 'value': int64_array(sizes)},
|
||||
'sizes_data': {'shape': int64_array(sizes).shape, 'value': int64_array(sizes)},
|
||||
'scales': {'shape': np.array(scales).shape, 'value': np.array(scales)},
|
||||
'scales_data': {'shape': np.array(scales).shape, 'value': np.array(scales)},
|
||||
'interpolate': {'pads_begin': int64_array(pads_begin),
|
||||
'pads_end': int64_array(pads_end),
|
||||
'shape_calculation_mode': 'sizes'}
|
||||
})
|
||||
|
||||
node = Node(graph, 'interpolate')
|
||||
tested_class = Interpolate(graph=graph, attrs=node.attrs())
|
||||
tested_class.infer(node)
|
||||
|
||||
msg = "Interpolate-4 infer failed for case: sizes={}, scales={}, pads_begin={}, pads_end={}," \
|
||||
" expected_shape={}, actual_shape={}"
|
||||
|
||||
self.assertTrue(np.array_equal(graph.node['interpolate_data']['shape'], int64_array(output_shape)),
|
||||
msg.format(sizes, scales, pads_begin, pads_end, output_shape,
|
||||
graph.node['interpolate_data']['shape']))
|
||||
|
||||
@generate(*[([0], [0], [1, 3, 100, 200], [1, 3, 350, 150], [1, 3, 350, 150], [1.0, 1.0, 3.5, 150 / 200]),
|
||||
([0, 3, 10, 10], [0], [16, 7, 190, 400], [8, 10, 390, 600],
|
||||
[8, 10, 390, 600], [0.5, 1.0, 390 / 200, 600 / 410]),
|
||||
([10, 5, 0, 10], [0, 4, 16, 18], [4, 33, 1024, 8000], [56, 42, 520, 8028],
|
||||
[56, 42, 520, 8028], [4.0, 1.0, 0.5, 1.0]),
|
||||
([0], [0], [1, 16, 85, 470, 690], [20, 16, 40, 470, 1380],
|
||||
[20, 16, 40, 470, 1380], [20.0, 1.0, 40.0 / 85.0, 1.0, 1380.0 / 690.0]),
|
||||
([4, 3, 11, 22, 5], [1, 3, 4, 8, 5], [1, 16, 85, 470, 690], [60, 22, 430, 500, 345],
|
||||
[60, 22, 430, 500, 345], [10.0, 1.0, 4.3, 1.0, 345.0 / 700.0]),
|
||||
([0], [0], [5, 77, 444, 88, 6050], [100, 308, 4440, 44, 6050],
|
||||
[100, 308, 4440, 44, 6050], [20.0, 4.0, 10.0, 0.5, 1.0]),
|
||||
([0], [0], [1, 100, 200], [1, 350, 150], [1, 350, 150], [1.0, 3.5, 150 / 200]),
|
||||
([0, 3, 10], [0], [16, 7, 190], [8, 10, 390], [8, 10, 390], [0.5, 1.0, 390 / 200]),
|
||||
([10, 0, 10], [0, 16, 18], [4, 1024, 8000], [56, 520, 8028], [56, 520, 8028], [4.0, 0.5, 1.0]),
|
||||
([0], [0], [1, 690], [20, 1380], [20, 1380], [20.0, 1380.0 / 690.0]),
|
||||
([4, 3, 11, 22, 5, 0], [1, 3, 4, 8, 5, 0], [1, 16, 85, 470, 690, 349], [60, 22, 430, 500, 345, 349],
|
||||
[60, 22, 430, 500, 345, 349], [10.0, 1.0, 4.3, 1.0, 345.0 / 700.0, 1.0]),
|
||||
([4, 3, 11, 22, 5, 0, 0], [1, 3, 4, 8, 5, 0, 0], [1, 16, 85, 470, 690, 349, 3],
|
||||
[60, 22, 430, 500, 345, 349, 1],
|
||||
[60, 22, 430, 500, 345, 349, 1], [10.0, 1.0, 4.3, 1.0, 345.0 / 700.0, 1.0, 1 / 3]),
|
||||
([4, 3, 11, 22, 5, 0, 0], [1, 3, 4, 8, 5, 0, 0], [1, 16, 85, 470, 690, 349, 3],
|
||||
[60, 22, 430, 500, 345, 349, 1],
|
||||
[60, 22, 430, 500, 345, 349, 1], [10.0, 1.0, 4.3, 1.0, 345.0 / 700.0, 1.0, 0.3333333]),
|
||||
])
|
||||
def test_interpolate4_using_scales_without_axes(self, pads_begin, pads_end, input_shape, output_shape, sizes,
|
||||
scales):
|
||||
graph = build_graph(nodes_attrs=graph_node_attrs_without_axes,
|
||||
edges=graph_edges_without_axes,
|
||||
update_attributes={
|
||||
'input_data': {'shape': input_shape},
|
||||
'sizes': {'shape': int64_array(sizes).shape, 'value': int64_array(sizes)},
|
||||
'sizes_data': {'shape': int64_array(sizes).shape, 'value': int64_array(sizes)},
|
||||
'scales': {'shape': np.array(scales).shape, 'value': np.array(scales)},
|
||||
'scales_data': {'shape': np.array(scales).shape, 'value': np.array(scales)},
|
||||
'interpolate': {'pads_begin': int64_array(pads_begin),
|
||||
'pads_end': int64_array(pads_end),
|
||||
'shape_calculation_mode': 'scales'}
|
||||
})
|
||||
|
||||
node = Node(graph, 'interpolate')
|
||||
tested_class = Interpolate(graph=graph, attrs=node.attrs())
|
||||
tested_class.infer(node)
|
||||
|
||||
msg = "Interpolate-4 infer failed for case: sizes={}, scales={}, pads_begin={}, pads_end={}," \
|
||||
" expected_shape={}, actual_shape={}"
|
||||
|
||||
self.assertTrue(np.array_equal(graph.node['interpolate_data']['shape'], int64_array(output_shape)),
|
||||
msg.format(sizes, scales, pads_begin, pads_end, output_shape,
|
||||
graph.node['interpolate_data']['shape']))
|
||||
Reference in new issue
Block a user