Add axis support (#5242)
* Add axis support * Update dequant extractor * Update qdeq ops * Refactoring quantize * Update dequantize resolver * Update dequantize op * Refactoring dequantize * Some fixes for quantize and dequantize * Update unit tests * Reafctoring quantize/dequantize axis support * Move quantize/dequantize resolvers to middle * hot fix * Fix unit tests * Fix unit tests * Update quintize resolver comment * Refactoring code according to code review * Fix according to review * Change order for transforms quantize pipline
This commit is contained in:
1 parent
c029b07d34
commit
642a62d0e2
15 files changed
+790
-348
No files matched your search
@@ -276,7 +276,6 @@ extensions/front/onnx/cumsum_ext.py
|
||||
extensions/front/onnx/deformable_conv_ext.py
|
||||
extensions/front/onnx/depth_to_space_ext.py
|
||||
extensions/front/onnx/dequantize_linear_ext.py
|
||||
extensions/front/onnx/dequantize_linear_resolver.py
|
||||
extensions/front/onnx/detection_output.py
|
||||
extensions/front/onnx/detectionoutput_ext.py
|
||||
extensions/front/onnx/dropout_ext.py
|
||||
@@ -328,7 +327,6 @@ extensions/front/onnx/proposal_ext.py
|
||||
extensions/front/onnx/quantize_dequantize_linear.py
|
||||
extensions/front/onnx/quantize_ext.py
|
||||
extensions/front/onnx/quantize_linear_ext.py
|
||||
extensions/front/onnx/quantize_linear_resolver.py
|
||||
extensions/front/onnx/range_ext.py
|
||||
extensions/front/onnx/reduce_ext.py
|
||||
extensions/front/onnx/remove_filtering_boxes_by_size.py
|
||||
@@ -580,6 +578,7 @@ extensions/middle/DecomposeBidirectionalRNNSequence.py
|
||||
extensions/middle/Deconvolution3rdInputNormalization.py
|
||||
extensions/middle/DeleteControlFlowEdges.py
|
||||
extensions/middle/DeleteNotExecutable.py
|
||||
extensions/middle/dequantize_linear_resolver.py
|
||||
extensions/middle/DilatedConvolution.py
|
||||
extensions/middle/EltwiseChecker.py
|
||||
extensions/middle/EltwiseInputReshape.py
|
||||
@@ -614,6 +613,7 @@ extensions/middle/permute_tensor_iterator.py
|
||||
extensions/middle/PoolV2ToAttributedPool.py
|
||||
extensions/middle/preprocessing.py
|
||||
extensions/middle/quantize_fuses.py
|
||||
extensions/middle/quantize_linear_resolver.py
|
||||
extensions/middle/ReluQuantizeFuse.py
|
||||
extensions/middle/RemoveDuplicationMemory.py
|
||||
extensions/middle/RemoveIdentity.py
|
||||
|
||||
@@ -14,8 +14,9 @@ class DequantizeLinearFrontExtractor(FrontExtractorOp):
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node):
|
||||
attrs = {}
|
||||
if get_onnx_opset_version(node) >= 13:
|
||||
log.warning('Ignoring "axis" attribute for DequantizeLinear-{} node, inference might be incorrect.'.format(
|
||||
get_onnx_opset_version(node)))
|
||||
DequantizeLinear.update_node_stat(node)
|
||||
axis = onnx_attr(node, 'axis', 'i', default=None)
|
||||
attrs.update(axis=axis)
|
||||
DequantizeLinear.update_node_stat(node, attrs)
|
||||
return cls.enabled
|
||||
@@ -1,40 +0,0 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from extensions.front.onnx.quantize_dequantize_linear import QuantizeDequantizeLinear
|
||||
from extensions.ops.Cast import Cast
|
||||
from extensions.ops.elementwise import Mul, Sub
|
||||
from mo.front.common.replacement import FrontReplacementOp
|
||||
from mo.graph.graph import Graph, Node, rename_nodes
|
||||
from mo.middle.passes.convert_data_type import data_type_str_to_np
|
||||
|
||||
|
||||
class DequantizeLinearResolver(FrontReplacementOp):
|
||||
"""
|
||||
DequantizeLinear can be replace with the following formula: y = (x - x_zero_point) * x_scale
|
||||
"""
|
||||
op = "DequantizeLinear"
|
||||
enabled = True
|
||||
|
||||
def run_after(self):
|
||||
return [QuantizeDequantizeLinear]
|
||||
|
||||
def replace_op(self, graph: Graph, node: Node):
|
||||
node_name = node.soft_get('name', node.id)
|
||||
model_data_type = data_type_str_to_np(graph.graph['cmd_params'].data_type)
|
||||
cast = Cast(graph, {'dst_type': model_data_type, 'name': node_name + '/Cast'}).create_node()
|
||||
node.in_port(0).get_connection().set_destination(cast.in_port(0))
|
||||
mul = Mul(graph, {}).create_node()
|
||||
|
||||
if node.is_in_port_connected(2):
|
||||
sub = Sub(graph, {'name': node_name + '/Sub'}).create_node()
|
||||
cast.out_port(0).connect(sub.in_port(0))
|
||||
node.in_port(2).get_connection().set_destination(sub.in_port(1))
|
||||
sub.out_port(0).connect(mul.in_port(0))
|
||||
else:
|
||||
cast.out_port(0).connect(mul.in_port(0))
|
||||
|
||||
node.in_port(1).get_connection().set_destination(mul.in_port(1))
|
||||
rename_nodes([(node, node_name + '/TBD'), (mul, node_name)])
|
||||
|
||||
return [mul.id]
|
||||
@@ -14,7 +14,7 @@ class QuantizeLinearFrontExtractor(FrontExtractorOp):
|
||||
def extract(cls, node):
|
||||
attrs = {}
|
||||
if get_onnx_opset_version(node) >= 13:
|
||||
axis = onnx_attr(node, 'axis', 'i', default=1)
|
||||
axis = onnx_attr(node, 'axis', 'i', default=None)
|
||||
attrs.update(axis=axis)
|
||||
QuantizeLinear.update_node_stat(node, attrs)
|
||||
return cls.enabled
|
||||
@@ -1,69 +0,0 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.front.onnx.quantize_dequantize_linear import QuantizeDequantizeLinear
|
||||
from extensions.ops.Cast import Cast
|
||||
from extensions.ops.elementwise import Mul
|
||||
from extensions.ops.fakequantize import FakeQuantize
|
||||
from mo.front.common.partial_infer.utils import float_array
|
||||
from mo.front.common.replacement import FrontReplacementOp
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.graph.graph import Graph, Node, rename_nodes
|
||||
from mo.ops.const import Const
|
||||
from mo.utils.error import Error
|
||||
|
||||
|
||||
class QuantizeLinearResolver(FrontReplacementOp):
|
||||
"""
|
||||
Replaces QuantizeLinear with FakeQuantize
|
||||
"""
|
||||
op = "QuantizeLinear"
|
||||
enabled = True
|
||||
|
||||
def run_after(self):
|
||||
return [QuantizeDequantizeLinear]
|
||||
|
||||
def replace_op(self, graph: Graph, node: Node):
|
||||
node_name = node.soft_get('name', node.id)
|
||||
|
||||
if node.is_in_port_connected(2):
|
||||
zerop = node.in_port(2).get_source().node
|
||||
else:
|
||||
zerop = Const(graph, {'value': np.array(0, dtype=np.uint8), 'name': node_name + '/ZeroPoint'}).create_node()
|
||||
|
||||
assert zerop.soft_get('type') == 'Const', 'only constant for zero_point is supported for QuantizeLinear'
|
||||
zero_point_type = zerop.value.dtype
|
||||
# data type affects range of output values: [-128..127] or [0..255]
|
||||
if zero_point_type == np.int8:
|
||||
output_low_value = -128.0
|
||||
output_high_value = 127.0
|
||||
elif zero_point_type == np.uint8:
|
||||
output_low_value = 0.0
|
||||
output_high_value = 255.0
|
||||
else:
|
||||
raise Error('Not expected type {} for zero point value in node {}'.format(
|
||||
zero_point_type, zerop.soft_get('name')))
|
||||
fake_quantize = create_op_with_const_inputs(graph, FakeQuantize, {3: float_array(output_low_value),
|
||||
4: float_array(output_high_value)},
|
||||
{'levels': 256, 'name': node_name + '/FakeQuantize'})
|
||||
node.in_port(0).get_connection().set_destination(fake_quantize.in_port(0))
|
||||
|
||||
# Calculate input_low value
|
||||
mul_low = create_op_with_const_inputs(graph, Mul, {1: float_array(output_low_value - zerop.value)},
|
||||
{'name': node_name + '/Mul/Low'})
|
||||
node.in_port(1).get_connection().set_destination(mul_low.in_port(0))
|
||||
mul_low.out_port(0).connect(fake_quantize.in_port(1))
|
||||
|
||||
# Calculate input_high value
|
||||
mul_high = create_op_with_const_inputs(graph, Mul, {1: float_array(output_high_value - zerop.value)},
|
||||
{'name': node_name + '/Mul/High'})
|
||||
mul_low.in_port(0).get_connection().add_destination(mul_high.in_port(0))
|
||||
mul_high.out_port(0).connect(fake_quantize.in_port(2))
|
||||
|
||||
cast = Cast(graph, {'dst_type': zero_point_type, 'name': node_name + '/Cast'}).create_node()
|
||||
rename_nodes([(node, node_name + '/TBD'), (cast, node_name)])
|
||||
fake_quantize.out_port(0).connect(cast.in_port(0))
|
||||
|
||||
return [cast.id]
|
||||
@@ -0,0 +1,66 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.ops.Cast import Cast
|
||||
from extensions.ops.elementwise import Mul, Sub
|
||||
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, rename_nodes
|
||||
from mo.middle.passes.convert_data_type import data_type_str_to_np
|
||||
from mo.middle.replacement import MiddleReplacementPattern
|
||||
from mo.ops.reshape import Reshape
|
||||
|
||||
|
||||
class DequantizeLinearResolver(MiddleReplacementPattern):
|
||||
"""
|
||||
Transformation result depends on the axis value.
|
||||
If the axis is not set or x_scale input is scalar or 1D tensor with one element then DequantizeLinear is
|
||||
replaced with the sub-graph which can be expressed with the following formula:
|
||||
y = (x - x_zero_point) * x_scale
|
||||
In other cases DequantizeLinear can be replace to formula with addition reshape x_zero_point and x_scale.
|
||||
Target shape for reshape depend on axis.
|
||||
"""
|
||||
enabled = True
|
||||
graph_condition = [lambda graph: graph.graph['layout'] == 'NCHW']
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for dequantize_node in graph.get_op_nodes(op='DequantizeLinear'):
|
||||
node_name = dequantize_node.soft_get('name', dequantize_node.id)
|
||||
axis = dequantize_node.soft_get('axis', None)
|
||||
scale_y_shape = dequantize_node.in_port(1).data.get_shape()
|
||||
model_data_type = data_type_str_to_np(graph.graph['cmd_params'].data_type)
|
||||
cast = Cast(graph, {'dst_type': model_data_type, 'name': node_name + '/Cast'}).create_node()
|
||||
dequantize_node.in_port(0).get_connection().set_destination(cast.in_port(0))
|
||||
mul = Mul(graph, {}).create_node()
|
||||
|
||||
is_second_port_connected = dequantize_node.is_in_port_connected(2)
|
||||
if is_second_port_connected:
|
||||
sub = Sub(graph, {'name': node_name + '/Sub'}).create_node()
|
||||
cast.out_port(0).connect(sub.in_port(0))
|
||||
dequantize_node.in_port(2).get_connection().set_destination(sub.in_port(1))
|
||||
sub.out_port(0).connect(mul.in_port(0))
|
||||
else:
|
||||
cast.out_port(0).connect(mul.in_port(0))
|
||||
|
||||
dequantize_node.in_port(1).get_connection().set_destination(mul.in_port(1))
|
||||
dequantize_node.out_port(0).get_connection().set_source(mul.out_port(0))
|
||||
rename_nodes([(dequantize_node, node_name + '/TBD'), (mul, node_name)])
|
||||
|
||||
assert scale_y_shape is not None
|
||||
if axis is not None and len(scale_y_shape) > 0 and scale_y_shape[0] > 1:
|
||||
input_shape = cast.in_port(0).data.get_shape()
|
||||
target_shape = np.ones(len(input_shape), np.int64)
|
||||
target_shape[axis] = input_shape[axis]
|
||||
|
||||
mul_reshape = create_op_with_const_inputs(graph, Reshape, {1: int64_array(target_shape)},
|
||||
{'name': node_name + '/Reshape/Mul'})
|
||||
mul.in_port(1).get_connection().set_destination(mul_reshape.in_port(0))
|
||||
mul_reshape.out_port(0).connect(mul.in_port(1))
|
||||
|
||||
if is_second_port_connected:
|
||||
sub_reshape = create_op_with_const_inputs(graph, Reshape, {1: int64_array(target_shape)},
|
||||
{'name': node_name + '/Reshape/Sub'})
|
||||
sub.in_port(1).get_connection().set_destination(sub_reshape.in_port(0))
|
||||
sub_reshape.out_port(0).connect(sub.in_port(1))
|
||||
@@ -6,6 +6,7 @@ import numpy as np
|
||||
from extensions.middle.BinarizeWeightsM1P1 import BinarizeWeightsM1P1
|
||||
from extensions.middle.DeleteControlFlowEdges import DeleteControlFlowEdges
|
||||
from extensions.middle.EltwiseChecker import EltwiseChecker
|
||||
from extensions.middle.quantize_linear_resolver import QuantizeLinearResolver
|
||||
from mo.graph.graph import Graph
|
||||
from mo.middle.passes.fusing.helpers import get_value_in_port
|
||||
from mo.middle.replacement import MiddleReplacementPattern
|
||||
@@ -75,7 +76,7 @@ class FakeQuantizeFuse(MiddleReplacementPattern):
|
||||
graph_condition = [lambda graph: not graph.graph['cmd_params'].disable_fusing]
|
||||
|
||||
def run_after(self):
|
||||
return [MarkNodesToFuseUpToFakeQuantize]
|
||||
return [QuantizeLinearResolver]
|
||||
|
||||
def run_before(self):
|
||||
return [BinarizeWeightsM1P1]
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.ops.Cast import Cast
|
||||
from extensions.ops.elementwise import Mul
|
||||
from extensions.ops.fakequantize import FakeQuantize
|
||||
from mo.front.common.partial_infer.utils import float_array, int64_array
|
||||
from mo.front.tf.graph_utils import create_op_with_const_inputs
|
||||
from mo.graph.graph import Graph, rename_nodes
|
||||
from mo.middle.replacement import MiddleReplacementPattern
|
||||
from mo.ops.const import Const
|
||||
from mo.ops.reshape import Reshape
|
||||
from mo.utils.error import Error
|
||||
|
||||
|
||||
class QuantizeLinearResolver(MiddleReplacementPattern):
|
||||
"""
|
||||
Replaces QuantizeLinear with FakeQuantize
|
||||
Transformation result depends on the axis value.
|
||||
If the axis is not set or x_scale input is scalar or 1D tensor with one element then QuantizeLinear is
|
||||
replaced with the sub-graph which can be expressed with the following formula:
|
||||
QuantizeLinear -> FakeQuantize(input
|
||||
Mul(y_scale, Const(low_value))
|
||||
Mul(y_scale, Const(high_value))
|
||||
Const(low_value)
|
||||
Const(high_value))
|
||||
low_value and high_value depend on from y_zero_point type
|
||||
In other cases y_scale and y_zero_point can be transform with addition reshape.
|
||||
Target shape for y_scale and y_zero_point depend on axis value.
|
||||
"""
|
||||
enabled = True
|
||||
graph_condition = [lambda graph: graph.graph['layout'] == 'NCHW']
|
||||
|
||||
def run_after(self):
|
||||
from extensions.middle.quantize_fuses import MarkNodesToFuseUpToFakeQuantize
|
||||
return [MarkNodesToFuseUpToFakeQuantize]
|
||||
|
||||
def find_and_replace_pattern(self, graph: Graph):
|
||||
for quantize_node in graph.get_op_nodes(op='QuantizeLinear'):
|
||||
node_name = quantize_node.soft_get('name', quantize_node.id)
|
||||
axis = quantize_node.soft_get('axis', None)
|
||||
scale_y_shape = quantize_node.in_port(1).data.get_shape()
|
||||
|
||||
if quantize_node.is_in_port_connected(2):
|
||||
zerop = quantize_node.in_port(2).get_source().node
|
||||
else:
|
||||
zerop = Const(graph,
|
||||
{'value': np.array(0, dtype=np.uint8), 'name': node_name + '/ZeroPoint'}).create_node()
|
||||
|
||||
assert zerop.soft_get('type') == 'Const', 'only constant for zero_point is supported for QuantizeLinear'
|
||||
zero_point_type = zerop.value.dtype
|
||||
# data type affects range of output values: [-128..127] or [0..255]
|
||||
if zero_point_type == np.int8:
|
||||
output_low_value = -128.0
|
||||
output_high_value = 127.0
|
||||
elif zero_point_type == np.uint8:
|
||||
output_low_value = 0.0
|
||||
output_high_value = 255.0
|
||||
else:
|
||||
raise Error('Not expected type {} for zero point value in node {}'.format(
|
||||
zero_point_type, zerop.soft_get('name')))
|
||||
|
||||
fake_quantize = create_op_with_const_inputs(graph, FakeQuantize, {3: float_array(output_low_value),
|
||||
4: float_array(output_high_value)},
|
||||
{'levels': 256, 'name': node_name + '/FakeQuantize'})
|
||||
quantize_node.in_port(0).get_connection().set_destination(fake_quantize.in_port(0))
|
||||
|
||||
# Calculate input_low value
|
||||
mul_low = create_op_with_const_inputs(graph, Mul, {1: float_array(output_low_value - zerop.value)},
|
||||
{'name': node_name + '/Mul/Low'})
|
||||
quantize_node.in_port(1).get_connection().set_destination(mul_low.in_port(0))
|
||||
mul_low.out_port(0).connect(fake_quantize.in_port(1))
|
||||
|
||||
# Calculate input_high value
|
||||
mul_high = create_op_with_const_inputs(graph, Mul, {1: float_array(output_high_value - zerop.value)},
|
||||
{'name': node_name + '/Mul/High'})
|
||||
mul_low.in_port(0).get_connection().add_destination(mul_high.in_port(0))
|
||||
mul_high.out_port(0).connect(fake_quantize.in_port(2))
|
||||
|
||||
cast = Cast(graph, {'dst_type': zero_point_type, 'name': node_name + '/Cast'}).create_node()
|
||||
fake_quantize.out_port(0).connect(cast.in_port(0))
|
||||
quantize_node.out_port(0).get_connection().set_source(cast.out_port(0))
|
||||
rename_nodes([(quantize_node, node_name + '/TBD'), (cast, node_name)])
|
||||
|
||||
assert scale_y_shape is not None
|
||||
if axis is not None and len(scale_y_shape) > 0 and scale_y_shape[0] > 1:
|
||||
input_shape = fake_quantize.in_port(0).data.get_shape()
|
||||
target_shape = np.ones(len(input_shape), np.int)
|
||||
target_shape[axis] = input_shape[axis]
|
||||
mul_low_reshape = create_op_with_const_inputs(graph, Reshape, {1: int64_array(target_shape)},
|
||||
{'name': node_name + '/Reshape/Mul/Low'})
|
||||
mul_high_reshape = create_op_with_const_inputs(graph, Reshape, {1: int64_array(target_shape)},
|
||||
{'name': node_name + '/Reshape/Mul/high'})
|
||||
|
||||
fake_quantize.in_port(1).get_connection().set_destination(mul_low_reshape.in_port(0))
|
||||
fake_quantize.in_port(2).get_connection().set_destination(mul_high_reshape.in_port(0))
|
||||
|
||||
mul_low_reshape.out_port(0).connect(fake_quantize.in_port(1))
|
||||
mul_high_reshape.out_port(0).connect(fake_quantize.in_port(2))
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from mo.front.common.partial_infer.elemental import copy_shape_infer
|
||||
from mo.graph.graph import Graph
|
||||
from mo.ops.op import Op
|
||||
|
||||
@@ -13,8 +14,9 @@ class DequantizeLinear(Op):
|
||||
mandatory_props = {
|
||||
'type': None,
|
||||
'op': self.op,
|
||||
'axis': None,
|
||||
'version': None,
|
||||
'infer': None,
|
||||
'infer': copy_shape_infer,
|
||||
'out_ports_count': 1,
|
||||
'in_ports_count': 3,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from mo.front.common.partial_infer.elemental import copy_shape_infer
|
||||
from mo.graph.graph import Graph
|
||||
from mo.ops.op import Op
|
||||
|
||||
@@ -13,8 +14,9 @@ class QuantizeLinear(Op):
|
||||
mandatory_props = {
|
||||
'type': None,
|
||||
'op': self.op,
|
||||
'axis': None,
|
||||
'version': None,
|
||||
'infer': None,
|
||||
'infer': copy_shape_infer,
|
||||
'out_ports_count': 1,
|
||||
'in_ports_count': 3,
|
||||
}
|
||||
|
||||
@@ -58,8 +58,8 @@ class Broadcast(Op):
|
||||
node.out_port(0).data.set_value(bi_directional_broadcasting(input_value, target_shape))
|
||||
elif node.mode == 'explicit':
|
||||
axes_mapping = node.in_port(2).data.get_value()
|
||||
assert axes_mapping is not None, 'Broadcast(mode="explicit") with dynamic axes_mapping input ' \
|
||||
'is not supported. Node: `{}`'.format(node_name)
|
||||
assert axes_mapping is not None, 'Broadcast(mode="explicit") with dynamic axes_mapping input ' \
|
||||
'is not supported. Node: `{}`'.format(node_name)
|
||||
PermuteInputs().set_input_permutation(node.in_node(2), node, 'output:0', 'axis')
|
||||
axes_mapping = node.in_port(2).data.get_value()
|
||||
node.out_port(0).data.set_value(explicit_broadcasting(input_value, target_shape, axes_mapping))
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.front.onnx.dequantize_linear_resolver import DequantizeLinearResolver
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
nodes1_attributes = {
|
||||
'input': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'dequantize': {'kind': 'op', 'op': 'DequantizeLinear'},
|
||||
'scale_param_dq': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'zerop_param_dq': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'out': {'kind': 'op', 'op': 'AnyOp'},
|
||||
}
|
||||
|
||||
nodes_ref_attributes = {
|
||||
'input': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'cast': {'kind': 'op', 'op': 'Cast', 'type': 'Convert'},
|
||||
'sub': {'kind': 'op', 'op': 'Sub', 'type': 'Subtract'},
|
||||
'mul': {'kind': 'op', 'op': 'Mul', 'type': 'Multiply'},
|
||||
'scale_param_dq': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'zerop_param_dq': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'out': {'kind': 'op', 'op': 'AnyOp'},
|
||||
}
|
||||
|
||||
|
||||
class TestDequantizeLinearResolver(unittest.TestCase):
|
||||
|
||||
def test_dequantize(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'dequantize'),
|
||||
('scale_param_dq', 'dequantize'),
|
||||
('zerop_param_dq', 'dequantize'),
|
||||
('dequantize', 'out'),
|
||||
],
|
||||
{'scale_param_dq': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'zerop_param_dq': {'shape': np.array([]), 'value': np.uint8(0)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'cast'),
|
||||
('cast', 'sub'),
|
||||
('zerop_param_dq', 'sub'),
|
||||
('sub', 'mul'),
|
||||
('scale_param_dq', 'mul'),
|
||||
('mul', 'out'),
|
||||
],
|
||||
{'scale_param_dq': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'zerop_param_dq': {'shape': np.array([]), 'value': np.uint8(0)}
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'front'
|
||||
DequantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_dequantize_no_zerop(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'dequantize'),
|
||||
('scale_param_dq', 'dequantize'),
|
||||
('dequantize', 'out'),
|
||||
],
|
||||
{'scale_param_dq': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'cast'),
|
||||
('cast', 'mul'),
|
||||
('scale_param_dq', 'mul'),
|
||||
('mul', 'out'),
|
||||
],
|
||||
{'scale_param_dq': {'shape': np.array([]), 'value': np.float32(1.0 / 255)}
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'front'
|
||||
DequantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -1,144 +0,0 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.front.onnx.quantize_linear_resolver import QuantizeLinearResolver
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from unit_tests.utils.graph import build_graph
|
||||
|
||||
nodes1_attributes = {
|
||||
'input': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'quantize': {'kind': 'op', 'op': 'QuantizeLinear'},
|
||||
'scale_param_q': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'zerop_param_q': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'out': {'kind': 'op', 'op': 'AnyOp'},
|
||||
}
|
||||
|
||||
nodes_ref_attributes = {
|
||||
'input': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'cast': {'kind': 'op', 'op': 'Cast', 'type': 'Convert'},
|
||||
'f_quantize': {'kind': 'op', 'op': 'FakeQuantize', 'type': 'FakeQuantize'},
|
||||
'mul1': {'kind': 'op', 'op': 'Mul', 'type': 'Multiply'},
|
||||
'mul2': {'kind': 'op', 'op': 'Mul', 'type': 'Multiply'},
|
||||
'scale_param_q': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'in_low': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'in_high': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'out_low': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'out_high': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'out': {'kind': 'op', 'op': 'AnyOp'},
|
||||
}
|
||||
|
||||
|
||||
class TestQuantizeLinearResolver(unittest.TestCase):
|
||||
|
||||
def test_quantize_uint8(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'quantize'),
|
||||
('scale_param_q', 'quantize'),
|
||||
('zerop_param_q', 'quantize'),
|
||||
('quantize', 'out'),
|
||||
],
|
||||
{'scale_param_q': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'zerop_param_q': {'shape': np.array([]), 'value': np.uint8(128)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'f_quantize'),
|
||||
('scale_param_q', 'mul1', {'out': 0}),
|
||||
('in_low', 'mul1'),
|
||||
('mul1', 'f_quantize'),
|
||||
('scale_param_q', 'mul2', {'out': 0}),
|
||||
('in_high', 'mul2'),
|
||||
('mul2', 'f_quantize'),
|
||||
('out_low', 'f_quantize'),
|
||||
('out_high', 'f_quantize'),
|
||||
('f_quantize', 'cast'),
|
||||
('cast', 'out'),
|
||||
],
|
||||
{'in_low': {'shape': np.array([]), 'value': -128},
|
||||
'in_high': {'shape': np.array([]), 'value': 127},
|
||||
'out_low': {'shape': np.array([]), 'value': 0},
|
||||
'out_high': {'shape': np.array([]), 'value': 255},
|
||||
'cast': {'dst_type': np.uint8}
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'front'
|
||||
QuantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_quantize_int8(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'quantize'),
|
||||
('scale_param_q', 'quantize'),
|
||||
('zerop_param_q', 'quantize'),
|
||||
('quantize', 'out'),
|
||||
],
|
||||
{'scale_param_q': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'zerop_param_q': {'shape': np.array([]), 'value': np.int8(0)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'f_quantize'),
|
||||
('scale_param_q', 'mul1', {'out': 0}),
|
||||
('in_low', 'mul1'),
|
||||
('mul1', 'f_quantize'),
|
||||
('scale_param_q', 'mul2', {'out': 0}),
|
||||
('in_high', 'mul2'),
|
||||
('mul2', 'f_quantize'),
|
||||
('out_low', 'f_quantize'),
|
||||
('out_high', 'f_quantize'),
|
||||
('f_quantize', 'cast'),
|
||||
('cast', 'out'),
|
||||
],
|
||||
{'in_low': {'shape': np.array([]), 'value': -128},
|
||||
'in_high': {'shape': np.array([]), 'value': 127},
|
||||
'out_low': {'shape': np.array([]), 'value': -128},
|
||||
'out_high': {'shape': np.array([]), 'value': 127},
|
||||
'cast': {'dst_type': np.int8}
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'front'
|
||||
QuantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_quantize_no_zerop(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'quantize'),
|
||||
('scale_param_q', 'quantize'),
|
||||
('quantize', 'out'),
|
||||
],
|
||||
{'scale_param_q': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'f_quantize'),
|
||||
('scale_param_q', 'mul1', {'out': 0}),
|
||||
('in_low', 'mul1'),
|
||||
('mul1', 'f_quantize'),
|
||||
('scale_param_q', 'mul2', {'out': 0}),
|
||||
('in_high', 'mul2'),
|
||||
('mul2', 'f_quantize'),
|
||||
('out_low', 'f_quantize'),
|
||||
('out_high', 'f_quantize'),
|
||||
('f_quantize', 'cast'),
|
||||
('cast', 'out'),
|
||||
],
|
||||
{'in_low': {'shape': np.array([]), 'value': 0},
|
||||
'in_high': {'shape': np.array([]), 'value': 255},
|
||||
'out_low': {'shape': np.array([]), 'value': 0},
|
||||
'out_high': {'shape': np.array([]), 'value': 255},
|
||||
'cast': {'dst_type': np.uint8}
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'front'
|
||||
QuantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,237 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.middle.dequantize_linear_resolver import DequantizeLinearResolver
|
||||
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
|
||||
from generator import generator, generate
|
||||
|
||||
nodes1_attributes = {
|
||||
'input': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'input_data': {'kind': 'data', 'shape': None},
|
||||
'dequantize': {'kind': 'op', 'op': 'DequantizeLinear', 'axis': 1},
|
||||
'dequantize_data': {'kind': 'data', 'shape': None},
|
||||
'scale_param_dq': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'scale_param_dq_data': {'kind': 'data', 'shape': None},
|
||||
'zerop_param_dq': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'zerop_param_dq_data': {'kind': 'data', 'shape': None},
|
||||
'out': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'out_data': {'kind': 'data', 'shape': None},
|
||||
'result': {'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
nodes_ref_attributes = {
|
||||
'input': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'input_data': {'kind': 'data', 'shape': None},
|
||||
'cast': {'kind': 'op', 'op': 'Cast', 'type': 'Convert'},
|
||||
'cast_data': {'kind': 'data', 'shape': None},
|
||||
'sub': {'kind': 'op', 'op': 'Sub', 'type': 'Subtract'},
|
||||
'sub_data': {'kind': 'data', 'shape': None},
|
||||
'mul': {'kind': 'op', 'op': 'Mul', 'type': 'Multiply'},
|
||||
'mul_data': {'kind': 'data', 'shape': None},
|
||||
'scale_param_dq': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'scale_param_dq_data': {'kind': 'data', 'shape': None},
|
||||
'zerop_param_dq': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'zerop_param_dq_data': {'kind': 'data', 'shape': None},
|
||||
'out': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'out_data': {'kind': 'data', 'shape': None},
|
||||
'result': {'kind': 'op', 'op': 'Result'},
|
||||
|
||||
'sub_reshape_const': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'sub_reshape_const_data': {'kind': 'data', 'shape': None},
|
||||
'sub_reshape': {'kind': 'op', 'type': 'Reshape', 'op': 'Reshape'},
|
||||
'sub_reshape_data': {'kind': 'data', 'shape': None},
|
||||
|
||||
'mul_reshape_const': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'mul_reshape_const_data': {'kind': 'data', 'shape': None},
|
||||
'mul_reshape': {'kind': 'op', 'type': 'Reshape', 'op': 'Reshape'},
|
||||
'mul_reshape_data': {'kind': 'data', 'shape': None},
|
||||
}
|
||||
|
||||
|
||||
class TestDequantizeLinearResolver(unittest.TestCase):
|
||||
|
||||
def test_dequantize(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'dequantize'),
|
||||
('dequantize', 'dequantize_data'),
|
||||
('scale_param_dq', 'scale_param_dq_data'),
|
||||
('zerop_param_dq', 'zerop_param_dq_data'),
|
||||
('scale_param_dq_data', 'dequantize'),
|
||||
('zerop_param_dq_data', 'dequantize'),
|
||||
('dequantize_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'input_data': {'shape': int64_array([1, 3, 224, 224])},
|
||||
'scale_param_dq': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'scale_param_dq_data': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'zerop_param_dq': {'shape': np.array([]), 'value': np.uint8(0)},
|
||||
'zerop_param_dq_data': {'shape': np.array([]), 'value': np.uint8(0)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'cast'),
|
||||
('cast', 'cast_data'),
|
||||
('cast_data', 'sub'),
|
||||
('zerop_param_dq', 'zerop_param_dq_data'),
|
||||
('zerop_param_dq_data', 'sub'),
|
||||
('sub', 'sub_data'),
|
||||
('sub_data', 'mul'),
|
||||
('scale_param_dq', 'scale_param_dq_data'),
|
||||
('scale_param_dq_data', 'mul'),
|
||||
('mul', 'mul_data'),
|
||||
('mul_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'input_data': {'shape': int64_array([1, 3, 224, 224])},
|
||||
'scale_param_dq': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'scale_param_dq_data': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'zerop_param_dq': {'shape': np.array([]), 'value': np.uint8(0)},
|
||||
'zerop_param_dq_data': {'shape': np.array([]), 'value': np.uint8(0)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'middle'
|
||||
DequantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_dequantize_no_zerop(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'dequantize'),
|
||||
('dequantize', 'dequantize_data'),
|
||||
('scale_param_dq', 'scale_param_dq_data'),
|
||||
('scale_param_dq_data', 'dequantize'),
|
||||
('dequantize', 'dequantize_data'),
|
||||
('dequantize_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'input_data': {'shape': int64_array([1, 3, 224, 224])},
|
||||
'scale_param_dq': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'scale_param_dq_data': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'cast'),
|
||||
('cast', 'cast_data'),
|
||||
('cast_data', 'mul'),
|
||||
('scale_param_dq', 'scale_param_dq_data'),
|
||||
('scale_param_dq_data', 'mul'),
|
||||
('mul', 'mul_data'),
|
||||
('mul_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'input_data': {'shape': int64_array([1, 3, 224, 224])},
|
||||
'scale_param_dq': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'scale_param_dq_data': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'middle'
|
||||
DequantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
@generator
|
||||
class TestDequantizeWithAxis(unittest.TestCase):
|
||||
@generate(*[(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([1, 1, 4, 1]), 2),
|
||||
(int64_array([1, 3, 4, 4]), int64_array([2, 3, 4, 5]),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([1, 3, 1, 1]), 1),
|
||||
(int64_array([2, 3, 4, 4]), int64_array([2, 3, 4, 5]),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([2, 1, 1, 1]), 0),
|
||||
(int64_array([1, 3, 4, 4]), int64_array([2, 3, 4, 5]),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([1, 1, 4, 1]), -2),
|
||||
(int64_array([1, 3, 4, 4]), int64_array([2, 3, 4, 5]),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([1, 1, 1, 4]), -1),
|
||||
(int64_array([1, 3, 4, 4]), int64_array([2, 3, 4, 5]),
|
||||
np.array([2, 3, 4, 5], dtype=np.int32), int64_array([1, 1, 4, 1]), 2),
|
||||
(int64_array([1, 3, 4, 4]), int64_array([2, 3, 4, 5]),
|
||||
np.array([2, 3, 4, 5], dtype=np.int32), int64_array([1, 3, 1, 1]), 1),
|
||||
(int64_array([2, 3, 4, 4]), int64_array([2, 3, 4, 5]),
|
||||
np.array([2, 3, 4, 5], dtype=np.int32), int64_array([2, 1, 1, 1]), 0),
|
||||
])
|
||||
def test_dequantize_with_axis(self, input_shape, scale_param_value, zero_param_value, target_shape, axis):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'dequantize'),
|
||||
('dequantize', 'dequantize_data'),
|
||||
('scale_param_dq', 'scale_param_dq_data'),
|
||||
('zerop_param_dq', 'zerop_param_dq_data'),
|
||||
('scale_param_dq_data', 'dequantize'),
|
||||
('zerop_param_dq_data', 'dequantize'),
|
||||
('dequantize_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'input_data': {'shape': input_shape},
|
||||
'dequantize': {'axis': axis},
|
||||
'scale_param_dq': {'shape': scale_param_value.shape,
|
||||
'value': scale_param_value},
|
||||
'scale_param_dq_data': {'shape': scale_param_value.shape,
|
||||
'value': scale_param_value},
|
||||
'zerop_param_dq': {'shape': zero_param_value.shape,
|
||||
'value': zero_param_value},
|
||||
'zerop_param_dq_data': {'shape': zero_param_value.shape,
|
||||
'value': zero_param_value},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'cast'),
|
||||
('cast', 'cast_data'),
|
||||
('cast_data', 'sub'),
|
||||
('zerop_param_dq', 'zerop_param_dq_data'),
|
||||
|
||||
('zerop_param_dq_data', 'sub_reshape'),
|
||||
('sub_reshape_const', 'sub_reshape_const_data'),
|
||||
('sub_reshape_const_data', 'sub_reshape'),
|
||||
('sub_reshape', 'sub_reshape_data'),
|
||||
('sub_reshape_data', 'sub'),
|
||||
|
||||
('sub', 'sub_data'),
|
||||
('sub_data', 'mul'),
|
||||
('scale_param_dq', 'scale_param_dq_data'),
|
||||
|
||||
('scale_param_dq_data', 'mul_reshape'),
|
||||
('mul_reshape_const', 'mul_reshape_const_data'),
|
||||
('mul_reshape_const_data', 'mul_reshape'),
|
||||
('mul_reshape', 'mul_reshape_data'),
|
||||
('mul_reshape_data', 'mul'),
|
||||
|
||||
('mul', 'mul_data'),
|
||||
('mul_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'input_data': {'shape': input_shape},
|
||||
'scale_param_dq': {'shape': scale_param_value.shape,
|
||||
'value': scale_param_value},
|
||||
'scale_param_dq_data': {'shape': scale_param_value.shape,
|
||||
'value': scale_param_value},
|
||||
'zerop_param_dq': {'shape': zero_param_value.shape,
|
||||
'value': zero_param_value},
|
||||
'zerop_param_dq_data': {'shape': zero_param_value.shape,
|
||||
'value': zero_param_value},
|
||||
'sub_reshape_const_data': {'shape': target_shape.shape, 'value': target_shape},
|
||||
'mul_reshape_const_data': {'shape': target_shape.shape, 'value': target_shape},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'middle'
|
||||
DequantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'out', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
@@ -0,0 +1,369 @@
|
||||
# Copyright (C) 2018-2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
from extensions.middle.quantize_linear_resolver import QuantizeLinearResolver
|
||||
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
|
||||
from generator import generator, generate
|
||||
|
||||
nodes1_attributes = {
|
||||
'input': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'input_data': {'kind': 'data', 'shape': None},
|
||||
'quantize': {'kind': 'op', 'op': 'QuantizeLinear', 'axis': 1},
|
||||
'quantize_data': {'kind': 'data', 'shape': None},
|
||||
'scale_param_q': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'scale_param_q_data': {'kind': 'data', 'shape': None},
|
||||
'zerop_param_q': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'zerop_param_q_data': {'kind': 'data', 'shape': None},
|
||||
'out': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'out_data': {'kind': 'data', 'shape': None},
|
||||
'result': {'kind': 'op', 'op': 'Result'},
|
||||
}
|
||||
|
||||
nodes_ref_attributes = {
|
||||
'input': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'input_data': {'kind': 'data', 'shape': None},
|
||||
'cast': {'kind': 'op', 'op': 'Cast', 'type': 'Convert'},
|
||||
'cast_data': {'kind': 'data', 'shape': None},
|
||||
'f_quantize': {'kind': 'op', 'op': 'FakeQuantize', 'type': 'FakeQuantize'},
|
||||
'f_quantize_data': {'kind': 'data', 'shape': None},
|
||||
'mul1': {'kind': 'op', 'op': 'Mul', 'type': 'Multiply'},
|
||||
'mul1_data': {'kind': 'data', 'shape': None},
|
||||
'mul2': {'kind': 'op', 'op': 'Mul', 'type': 'Multiply'},
|
||||
'mul2_data': {'kind': 'data', 'shape': None},
|
||||
'scale_param_q': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'scale_param_q_data': {'kind': 'data', 'shape': None},
|
||||
'in_low': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'in_low_data': {'kind': 'data', 'shape': None},
|
||||
'in_high': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'in_high_data': {'kind': 'data', 'shape': None},
|
||||
'out_low': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'out_low_data': {'kind': 'data', 'shape': None},
|
||||
'out_high': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'out_high_data': {'kind': 'data', 'shape': None},
|
||||
'out': {'kind': 'op', 'op': 'AnyOp'},
|
||||
'out_data': {'kind': 'data', 'shape': None},
|
||||
'result': {'kind': 'op', 'op': 'Result'},
|
||||
|
||||
'high_reshape_const': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'high_reshape_const_data': {'kind': 'data', 'shape': None},
|
||||
'high_reshape': {'kind': 'op', 'type': 'Reshape', 'op': 'Reshape'},
|
||||
'high_reshape_data': {'kind': 'data', 'shape': None},
|
||||
|
||||
'low_reshape_const': {'kind': 'op', 'type': 'Const', 'op': 'Const'},
|
||||
'low_reshape_const_data': {'kind': 'data', 'shape': None},
|
||||
'low_reshape': {'kind': 'op', 'type': 'Reshape', 'op': 'Reshape'},
|
||||
'low_reshape_data': {'kind': 'data', 'shape': None},
|
||||
}
|
||||
|
||||
|
||||
class TestQuantizeLinearResolver(unittest.TestCase):
|
||||
|
||||
def test_quantize_uint8(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'quantize'),
|
||||
('scale_param_q', 'scale_param_q_data'),
|
||||
('scale_param_q_data', 'quantize'),
|
||||
('zerop_param_q', 'zerop_param_q_data'),
|
||||
('zerop_param_q_data', 'quantize'),
|
||||
('quantize', 'quantize_data'),
|
||||
('quantize_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{
|
||||
'quantize': {'axis': 2},
|
||||
'scale_param_q': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'scale_param_q_data': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'zerop_param_q': {'shape': np.array([]), 'value': np.uint8(128)},
|
||||
'zerop_param_q_data': {'shape': np.array([]), 'value': np.uint8(128)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'f_quantize'),
|
||||
('scale_param_q', 'scale_param_q_data'),
|
||||
('scale_param_q_data', 'mul1', {'out': 0}),
|
||||
('in_low', 'in_low_data'),
|
||||
('in_low_data', 'mul1'),
|
||||
('mul1', 'mul1_data'),
|
||||
('mul1_data', 'f_quantize'),
|
||||
('f_quantize', 'f_quantize_data'),
|
||||
('scale_param_q_data', 'mul2', {'out': 0}),
|
||||
('in_high', 'in_high_data'),
|
||||
('in_high_data', 'mul2'),
|
||||
('mul2', 'mul2_data'),
|
||||
('mul2_data', 'f_quantize'),
|
||||
('out_low', 'out_low_data'),
|
||||
('out_low_data', 'f_quantize'),
|
||||
('out_high', 'out_high_data'),
|
||||
('out_high_data', 'f_quantize'),
|
||||
('f_quantize_data', 'cast'),
|
||||
('cast', 'cast_data'),
|
||||
('cast_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'in_low': {'shape': np.array([]), 'value': -128},
|
||||
'in_low_data': {'shape': np.array([]), 'value': -128},
|
||||
'in_high': {'shape': np.array([]), 'value': 127},
|
||||
'in_high_data': {'shape': np.array([]), 'value': 127},
|
||||
'out_low': {'shape': np.array([]), 'value': 0},
|
||||
'out_low_data': {'shape': np.array([]), 'value': 0},
|
||||
'out_high': {'shape': np.array([]), 'value': 255},
|
||||
'out_high_data': {'shape': np.array([]), 'value': 255},
|
||||
'cast': {'dst_type': np.uint8}
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'middle'
|
||||
QuantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'result', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_quantize_int8(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'quantize'),
|
||||
('scale_param_q', 'scale_param_q_data'),
|
||||
('scale_param_q_data', 'quantize'),
|
||||
('zerop_param_q', 'zerop_param_q_data'),
|
||||
('zerop_param_q_data', 'quantize'),
|
||||
('quantize', 'quantize_data'),
|
||||
('quantize_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'scale_param_q': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'scale_param_q_data': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'zerop_param_q': {'shape': np.array([]), 'value': np.int8(0)},
|
||||
'zerop_param_q_data': {'shape': np.array([]), 'value': np.int8(0)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'f_quantize'),
|
||||
('scale_param_q', 'scale_param_q_data'),
|
||||
('scale_param_q_data', 'mul1', {'out': 0}),
|
||||
('in_low', 'in_low_data'),
|
||||
('in_low_data', 'mul1'),
|
||||
('mul1', 'mul1_data'),
|
||||
('mul1_data', 'f_quantize'),
|
||||
('f_quantize', 'f_quantize_data'),
|
||||
('scale_param_q_data', 'mul2', {'out': 0}),
|
||||
('in_high', 'in_high_data'),
|
||||
('in_high_data', 'mul2'),
|
||||
('mul2', 'mul2_data'),
|
||||
('mul2_data', 'f_quantize'),
|
||||
('out_low', 'out_low_data'),
|
||||
('out_low_data', 'f_quantize'),
|
||||
('out_high', 'out_high_data'),
|
||||
('out_high_data', 'f_quantize'),
|
||||
('f_quantize_data', 'cast'),
|
||||
('cast', 'cast_data'),
|
||||
('cast_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'in_low': {'shape': np.array([]), 'value': -128},
|
||||
'in_low_data': {'shape': np.array([]), 'value': -128},
|
||||
'in_high': {'shape': np.array([]), 'value': 127},
|
||||
'in_high_data': {'shape': np.array([]), 'value': 127},
|
||||
'out_low': {'shape': np.array([]), 'value': -128},
|
||||
'out_low_data': {'shape': np.array([]), 'value': -128},
|
||||
'out_high': {'shape': np.array([]), 'value': 127},
|
||||
'out_high_data': {'shape': np.array([]), 'value': 127},
|
||||
'cast': {'dst_type': np.int8}
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'middle'
|
||||
QuantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'result', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
def test_quantize_no_zerop(self):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'quantize'),
|
||||
('quantize', 'quantize_data'),
|
||||
('scale_param_q', 'scale_param_q_data'),
|
||||
('scale_param_q_data', 'quantize'),
|
||||
('quantize', 'quantize_data'),
|
||||
('quantize_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'scale_param_q': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
'scale_param_q_data': {'shape': np.array([]), 'value': np.float32(1.0 / 255)},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'f_quantize'),
|
||||
('scale_param_q', 'scale_param_q_data'),
|
||||
('scale_param_q_data', 'mul1', {'out': 0}),
|
||||
('in_low', 'in_low_data'),
|
||||
('in_low_data', 'mul1'),
|
||||
('mul1', 'mul1_data'),
|
||||
('mul1_data', 'f_quantize'),
|
||||
('f_quantize', 'f_quantize_data'),
|
||||
('scale_param_q_data', 'mul2', {'out': 0}),
|
||||
('in_high', 'in_high_data'),
|
||||
('in_high_data', 'mul2'),
|
||||
('mul2', 'mul2_data'),
|
||||
('mul2_data', 'f_quantize'),
|
||||
('out_low', 'out_low_data'),
|
||||
('out_low_data', 'f_quantize'),
|
||||
('out_high', 'out_high_data'),
|
||||
('out_high_data', 'f_quantize'),
|
||||
('f_quantize_data', 'cast'),
|
||||
('cast', 'cast_data'),
|
||||
('cast_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'in_low': {'shape': np.array([]), 'value': 0},
|
||||
'in_low_data': {'shape': np.array([]), 'value': 0},
|
||||
'in_high': {'shape': np.array([]), 'value': 255},
|
||||
'in_high_data': {'shape': np.array([]), 'value': 255},
|
||||
'out_low': {'shape': np.array([]), 'value': 0},
|
||||
'out_low_data': {'shape': np.array([]), 'value': 0},
|
||||
'out_high': {'shape': np.array([]), 'value': 255},
|
||||
'out_high_data': {'shape': np.array([]), 'value': 255},
|
||||
'cast': {'dst_type': np.uint8}
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'middle'
|
||||
QuantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'result', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
|
||||
|
||||
@generator
|
||||
class TestQuantizeWithAxis(unittest.TestCase):
|
||||
@generate(*[(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([1, 1, 4, 1]),
|
||||
np.array([-2., -3., -4., -5.]), np.array([253., 252., 251., 250.]),
|
||||
0, 255, 2),
|
||||
(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([1, 3, 1, 1]),
|
||||
np.array([-2., -3., -4., -5.]), np.array([253., 252., 251., 250.]),
|
||||
0, 255, 1),
|
||||
(int64_array([2, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([2, 1, 1, 1]),
|
||||
np.array([-2., -3., -4., -5.]), np.array([253., 252., 251., 250.]),
|
||||
0, 255, 0),
|
||||
(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([1, 1, 1, 4]),
|
||||
np.array([-2., -3., -4., -5.]), np.array([253., 252., 251., 250.]),
|
||||
0, 255, -1),
|
||||
(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.uint8), int64_array([1, 1, 4, 1]),
|
||||
np.array([-2., -3., -4., -5.]), np.array([253., 252., 251., 250.]),
|
||||
0, 255, -2),
|
||||
(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.int8), int64_array([1, 1, 4, 1]),
|
||||
np.array([-130., -131., -132., -133.]), np.array([125., 124., 123., 122.]),
|
||||
-128.0, 127.0, 2),
|
||||
(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.int8), int64_array([1, 3, 1, 1]),
|
||||
np.array([-130., -131., -132., -133.]), np.array([125., 124., 123., 122.]),
|
||||
-128.0, 127.0, 1),
|
||||
(int64_array([2, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.int8), int64_array([2, 1, 1, 1]),
|
||||
np.array([-130., -131., -132., -133.]), np.array([125., 124., 123., 122.]),
|
||||
-128.0, 127.0, 0),
|
||||
(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.int8), int64_array([1, 1, 1, 4]),
|
||||
np.array([-130., -131., -132., -133.]), np.array([125., 124., 123., 122.]),
|
||||
-128.0, 127.0, -1),
|
||||
(int64_array([1, 3, 4, 4]), np.array([2, 3, 4, 5], dtype=np.float32),
|
||||
np.array([2, 3, 4, 5], dtype=np.int8), int64_array([1, 1, 4, 1]),
|
||||
np.array([-130., -131., -132., -133.]), np.array([125., 124., 123., 122.]),
|
||||
-128.0, 127.0, -2),
|
||||
])
|
||||
def test_quantize_with_axis(self, input_shape, scale_param_value, zero_param_value,
|
||||
target_shape, in_low, in_high, out_low, out_high, axis):
|
||||
graph = build_graph(nodes1_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'quantize'),
|
||||
('scale_param_q', 'scale_param_q_data'),
|
||||
('scale_param_q_data', 'quantize'),
|
||||
('zerop_param_q', 'zerop_param_q_data'),
|
||||
('zerop_param_q_data', 'quantize'),
|
||||
('quantize', 'quantize_data'),
|
||||
('quantize_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{
|
||||
'quantize': {'axis': axis},
|
||||
'input': {'shape': input_shape},
|
||||
'input_data': {'shape': input_shape},
|
||||
'scale_param_q': {'shape': scale_param_value.shape, 'value': scale_param_value},
|
||||
'scale_param_q_data': {'shape': scale_param_value.shape, 'value': scale_param_value},
|
||||
'zerop_param_q': {'shape': zero_param_value.shape, 'value': zero_param_value},
|
||||
'zerop_param_q_data': {'shape': zero_param_value.shape, 'value': zero_param_value},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_ref_attributes,
|
||||
[('input', 'input_data'),
|
||||
('input_data', 'f_quantize'),
|
||||
('scale_param_q', 'scale_param_q_data'),
|
||||
('scale_param_q_data', 'mul1', {'out': 0}),
|
||||
('in_low', 'in_low_data'),
|
||||
('in_low_data', 'mul1'),
|
||||
('mul1', 'mul1_data'),
|
||||
('mul1_data', 'high_reshape'),
|
||||
('high_reshape_const', 'high_reshape_const_data'),
|
||||
('high_reshape_const_data', 'high_reshape'),
|
||||
('high_reshape', 'high_reshape_data'),
|
||||
('high_reshape_data', 'f_quantize'),
|
||||
|
||||
('f_quantize', 'f_quantize_data'),
|
||||
('scale_param_q_data', 'mul2', {'out': 0}),
|
||||
('in_high', 'in_high_data'),
|
||||
('in_high_data', 'mul2'),
|
||||
('mul2', 'mul2_data'),
|
||||
('mul2_data', 'low_reshape'),
|
||||
('low_reshape', 'low_reshape_data'),
|
||||
('low_reshape_data', 'f_quantize'),
|
||||
('low_reshape_const', 'low_reshape_const_data'),
|
||||
('low_reshape_const_data', 'low_reshape'),
|
||||
('out_low', 'out_low_data'),
|
||||
('out_low_data', 'f_quantize'),
|
||||
|
||||
('out_high', 'out_high_data'),
|
||||
('out_high_data', 'f_quantize'),
|
||||
('f_quantize_data', 'cast'),
|
||||
('cast', 'cast_data'),
|
||||
('cast_data', 'out'),
|
||||
('out', 'out_data'),
|
||||
('out_data', 'result'),
|
||||
],
|
||||
{'in_low': {'shape': in_low.shape, 'value': in_low},
|
||||
'in_low_data': {'shape': in_low.shape, 'value': in_low},
|
||||
'in_high': {'shape': in_high.shape, 'value': in_high},
|
||||
'in_high_data': {'shape': in_high.shape, 'value': in_high},
|
||||
'out_low': {'shape': np.array([]), 'value': out_low},
|
||||
'out_low_data': {'shape': np.array([]), 'value': out_low},
|
||||
'out_high': {'shape': np.array([]), 'value': out_high},
|
||||
'out_high_data': {'shape': np.array([]), 'value': out_high},
|
||||
'cast': {'dst_type': zero_param_value.dtype},
|
||||
'low_reshape_const_data': {'shape': target_shape.shape, 'value': target_shape},
|
||||
'high_reshape_const_data': {'shape': target_shape.shape, 'value': target_shape},
|
||||
}, nodes_with_edges_only=True)
|
||||
|
||||
graph.stage = 'middle'
|
||||
QuantizeLinearResolver().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'result', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
Reference in new issue
Block a user