Enable ReduceL1 and ReduceL2 operations (#1799)
* Initial version of ReduceL1, ReduceL2 and ReduceLp enabling in the MO * Added operations ReduceL1 and ReduceL2 to nGraph * Removed ReduceLp. Added ReduceL1 and ReduceL2 * Separated specification of ReduceLp into ReduceL1 and ReduceL2 * Updated ReduceL1 and ReduceL2 specification * Fixed ReduceL1 and ReduceL2 type prop tests * Implemented nGraph transformation to decompose ReduceL1 and ReduceL2. Disabled them for CPU and GPU plugins * Updated supported framework layers * Added unit tests for ReduceL1 and ReduceL2 reference implementation * Fixed ReduceXXX operations reference implementation by adding support for a new parameter 'keep_dims' * Fixed constant folding for v0::Any * Added ReduceL1 and ReduceL2 to Python API * Implemented ReduceL1 and ReduceL2 decomposition tests and fixed ReduceL2 decomposition * Added specific creator for ReduceXXX operations instead of NodeBuilders * Fixed conversion ReduceXXX to CNNLayer * Fixed parser for ReduceLogicalXXX operations
This commit is contained in:
@@ -38,7 +38,7 @@ extensions/back/PackBinaryWeights.py
|
||||
extensions/back/pass_separator.py
|
||||
extensions/back/priorbox_mutation.py
|
||||
extensions/back/ProposalMutation.py
|
||||
extensions/back/ReduceToPooling.py
|
||||
extensions/back/ReduceMerge.py
|
||||
extensions/back/ReduceTransposeDimensions.py
|
||||
extensions/back/remove_last_softmax_pattern.py
|
||||
extensions/back/RemoveUselessConvert.py
|
||||
@@ -291,12 +291,7 @@ 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_l2_ext.py
|
||||
extensions/front/onnx/reduce_max_ext.py
|
||||
extensions/front/onnx/reduce_mean_ext.py
|
||||
extensions/front/onnx/reduce_min_ext.py
|
||||
extensions/front/onnx/reduce_prod_ext.py
|
||||
extensions/front/onnx/reduce_sum_ext.py
|
||||
extensions/front/onnx/reduce_ext.py
|
||||
extensions/front/onnx/remove_filtering_boxes_by_size.py
|
||||
extensions/front/onnx/resize_ext.py
|
||||
extensions/front/onnx/resize_to_interpolate.py
|
||||
@@ -327,7 +322,6 @@ extensions/front/PowerToEltwises.py
|
||||
extensions/front/rank_decomposer.py
|
||||
extensions/front/reciprocal.py
|
||||
extensions/front/reduce_axis_normalizer.py
|
||||
extensions/front/ReduceL2Decomposition.py
|
||||
extensions/front/reshape_dim_normalizer.py
|
||||
extensions/front/restore_ports.py
|
||||
extensions/front/scatter_normalizer.py
|
||||
|
||||
@@ -18,7 +18,7 @@ from typing import Dict
|
||||
import numpy as np
|
||||
|
||||
from extensions.back.FuseTransposesSequence import FuseTransposesSequence
|
||||
from extensions.back.ReduceToPooling import ReduceMerge
|
||||
from extensions.back.ReduceMerge import ReduceMerge
|
||||
from extensions.ops.ReduceOps import reduce_map
|
||||
from extensions.ops.gather import Gather
|
||||
from mo.back.replacement import BackReplacementPattern
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
from extensions.front.reduce_axis_normalizer import ReduceAxisNormalizer
|
||||
from extensions.ops.ReduceOps import ReduceSum
|
||||
from extensions.ops.elementwise import Pow, Mul
|
||||
from mo.front.common.partial_infer.utils import int64_array, 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_node
|
||||
|
||||
|
||||
class ReduceL2Decomposition(FrontReplacementOp):
|
||||
op = 'ReduceL2'
|
||||
enabled = True
|
||||
|
||||
def run_before(self):
|
||||
return [ReduceAxisNormalizer]
|
||||
|
||||
def replace_op(self, graph: Graph, node: Node):
|
||||
node_name = node.soft_get('name', node.id)
|
||||
|
||||
rename_node(node, node_name + '/TBR')
|
||||
sqr_node = Mul(graph, {}).create_node()
|
||||
reduce_sum_node = ReduceSum(graph, {'keep_dims': node.soft_get('keep_dims', 0),
|
||||
'axis': node.soft_get('axis', None)}).create_node()
|
||||
sqrt_node = create_op_with_const_inputs(graph, Pow, {1: float_array(0.5)})
|
||||
rename_node(sqrt_node, node_name)
|
||||
|
||||
# Connect nodes
|
||||
node.in_port(0).get_connection().set_destination(sqr_node.in_port(0))
|
||||
sqr_node.in_port(0).get_connection().add_destination(sqr_node.in_port(1))
|
||||
sqr_node.out_port(0).connect(reduce_sum_node.in_port(0))
|
||||
reduce_sum_node.out_port(0).connect(sqrt_node.in_port(0))
|
||||
|
||||
return [sqrt_node.id]
|
||||
@@ -1,63 +0,0 @@
|
||||
"""
|
||||
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 extensions.front.ReduceL2Decomposition import ReduceL2Decomposition
|
||||
from mo.utils.ir_engine.compare_graphs import compare_graphs
|
||||
from mo.utils.unittest.graph import build_graph, const
|
||||
|
||||
nodes_attributes = {
|
||||
'input': {'shape': None, 'type': 'Parameter', 'kind': 'op', 'op': 'Parameter'},
|
||||
'reduce_l2': {'type': None, 'kind': 'op', 'op': 'ReduceL2', 'axis': 0, 'name': 'my_reduce', 'keep_dims': 0},
|
||||
'result': {'type': 'Result', 'value': None, 'kind': 'op', 'op': 'Result'},
|
||||
|
||||
# new layers
|
||||
'mul': {'type': 'Multiply', 'kind': 'op', 'op': 'Mul'},
|
||||
'reduce_sum': {'type': 'ReduceSum', 'kind': 'op', 'op': 'ReduceSum', 'axis': 0, 'keep_dims': 0},
|
||||
'pow': {'type': 'Power', 'kind': 'op', 'op': 'Pow'},
|
||||
**const('half', np.array(0.5, dtype=np.float32)),
|
||||
}
|
||||
|
||||
|
||||
class ReduceL2DecompositionTest(unittest.TestCase):
|
||||
def test(self):
|
||||
graph = build_graph(nodes_attributes,
|
||||
[('input', 'reduce_l2', {'in': 0, 'out': 0}),
|
||||
('reduce_l2', 'result', {'in': 0, 'out': 0}),
|
||||
],
|
||||
{}, nodes_with_edges_only=True)
|
||||
|
||||
graph_ref = build_graph(nodes_attributes,
|
||||
[('input', 'mul', {'in': 0, 'out': 0}),
|
||||
('input', 'mul', {'in': 1, 'out': 0}),
|
||||
('mul', 'reduce_sum', {'in': 0, 'out': 0}),
|
||||
('reduce_sum', 'pow', {'in': 0, 'out': 0}),
|
||||
('half', 'pow', {'in': 1, 'out': 0}),
|
||||
('pow', 'result', {'in': 0, 'out': 0}),
|
||||
],
|
||||
{}, nodes_with_edges_only=True)
|
||||
|
||||
graph.graph['layout'] = 'NCHW'
|
||||
graph.stage = 'front'
|
||||
|
||||
ReduceL2Decomposition().find_and_replace_pattern(graph)
|
||||
|
||||
(flag, resp) = compare_graphs(graph, graph_ref, 'result', check_op_attrs=True)
|
||||
self.assertTrue(flag, resp)
|
||||
self.assertTrue(graph.node[graph.get_nodes_with_attributes(op='Pow')[0]]['name'] == 'my_reduce')
|
||||
97
model-optimizer/extensions/front/onnx/reduce_ext.py
Normal file
97
model-optimizer/extensions/front/onnx/reduce_ext.py
Normal file
@@ -0,0 +1,97 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
from extensions.ops.ReduceOps import ReduceL1, ReduceL2, ReduceMax, ReduceMean, ReduceMin, ReduceProd, ReduceSum
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.front.onnx.extractors.utils import onnx_attr
|
||||
from mo.graph.graph import Node
|
||||
|
||||
|
||||
def update_reduce_node_attrs_with(node: Node, c: callable):
|
||||
axis = onnx_attr(node, 'axes', 'ints', default=None, dst_type=lambda x: int64_array(x))
|
||||
keep_dims = onnx_attr(node, 'keepdims', 'i', default=True)
|
||||
c.update_node_stat(node, {'axis': axis, 'keep_dims': keep_dims})
|
||||
|
||||
|
||||
class ReduceL1Extractor(FrontExtractorOp):
|
||||
op = 'ReduceL1'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
update_reduce_node_attrs_with(node, ReduceL1)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class ReduceL2Extractor(FrontExtractorOp):
|
||||
op = 'ReduceL2'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
update_reduce_node_attrs_with(node, ReduceL2)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class ReduceMaxFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceMax'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
update_reduce_node_attrs_with(node, ReduceMax)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class ReduceMeanFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceMean'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
update_reduce_node_attrs_with(node, ReduceMean)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class ReduceMinFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceMin'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
update_reduce_node_attrs_with(node, ReduceMin)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class ReduceProdFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceProd'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
update_reduce_node_attrs_with(node, ReduceProd)
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class ReduceSumFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceSum'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
update_reduce_node_attrs_with(node, ReduceSum)
|
||||
return cls.enabled
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
from extensions.front.reduce_axis_normalizer import ReduceAxisNormalizer
|
||||
from extensions.ops.ReduceOps import ReduceL2
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.front.onnx.extractors.utils import onnx_attr
|
||||
from mo.graph.graph import Node
|
||||
|
||||
|
||||
class ReduceL2FrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceL2'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
axis = onnx_attr(node, 'axes', 'ints', default=None, dst_type=lambda x: int64_array(x))
|
||||
keep_dims = onnx_attr(node, 'keepdims', 'i', default=True)
|
||||
ReduceL2.update_node_stat(node, {'axis': axis, 'keep_dims': keep_dims})
|
||||
return cls.enabled
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
Copyright (C) 2018-2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from extensions.ops.ReduceOps import ReduceMax
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.front.onnx.extractors.utils import onnx_attr
|
||||
from mo.graph.graph import Node
|
||||
|
||||
|
||||
class ReduceMaxFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceMax'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
axis = onnx_attr(node, 'axes', 'ints', default=None, dst_type=lambda x: int64_array(x))
|
||||
keep_dims = onnx_attr(node, 'keepdims', 'i', default=True)
|
||||
ReduceMax.update_node_stat(node, {'axis': axis, 'keep_dims': keep_dims})
|
||||
return cls.enabled
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
Copyright (C) 2018-2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from extensions.ops.ReduceOps import ReduceMean
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.front.onnx.extractors.utils import onnx_attr
|
||||
from mo.graph.graph import Node
|
||||
|
||||
|
||||
class ReduceMeanFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceMean'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
axis = onnx_attr(node, 'axes', 'ints', default=None, dst_type=lambda x: int64_array(x))
|
||||
keep_dims = onnx_attr(node, 'keepdims', 'i', default=True)
|
||||
ReduceMean.update_node_stat(node, {'axis': axis, 'keep_dims': keep_dims})
|
||||
return cls.enabled
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
Copyright (C) 2018-2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from extensions.ops.ReduceOps import ReduceMin
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.front.onnx.extractors.utils import onnx_attr
|
||||
from mo.graph.graph import Node
|
||||
|
||||
|
||||
class ReduceMinFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceMin'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
axis = onnx_attr(node, 'axes', 'ints', default=None, dst_type=lambda x: int64_array(x))
|
||||
keep_dims = onnx_attr(node, 'keepdims', 'i', default=True)
|
||||
ReduceMin.update_node_stat(node, {'axis': axis, 'keep_dims': keep_dims})
|
||||
return cls.enabled
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
Copyright (C) 2018-2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from extensions.ops.ReduceOps import ReduceProd
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.front.onnx.extractors.utils import onnx_attr
|
||||
from mo.graph.graph import Node
|
||||
|
||||
|
||||
class ReduceProdFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceProd'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
axis = onnx_attr(node, 'axes', 'ints', default=None, dst_type=lambda x: int64_array(x))
|
||||
keep_dims = onnx_attr(node, 'keepdims', 'i', default=True)
|
||||
ReduceProd.update_node_stat(node, {'axis': axis, 'keep_dims': keep_dims})
|
||||
return cls.enabled
|
||||
@@ -1,33 +0,0 @@
|
||||
"""
|
||||
Copyright (C) 2018-2020 Intel Corporation
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
|
||||
from extensions.ops.ReduceOps import ReduceSum
|
||||
from mo.front.common.partial_infer.utils import int64_array
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.front.onnx.extractors.utils import onnx_attr
|
||||
from mo.graph.graph import Node
|
||||
|
||||
|
||||
class ReduceSumFrontExtractor(FrontExtractorOp):
|
||||
op = 'ReduceSum'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
axis = onnx_attr(node, 'axes', 'ints', default=None, dst_type=lambda x: int64_array(x))
|
||||
keep_dims = onnx_attr(node, 'keepdims', 'i', default=True)
|
||||
ReduceSum.update_node_stat(node, {'axis': axis, 'keep_dims': keep_dims})
|
||||
return cls.enabled
|
||||
@@ -46,16 +46,17 @@ class ReduceAxisNormalizer(FrontReplacementSubgraph):
|
||||
node = match['reduce']
|
||||
connected_in_ports = [port for port in node.in_ports().values() if not port.disconnected()]
|
||||
if len(connected_in_ports) == 1:
|
||||
node_name = node.soft_get('name', node.id)
|
||||
|
||||
# if the 'axis' is None then we still add a second input to the layer with a 1D array with 1 element equal
|
||||
# to None. The infer function handles this case because the input shape is known at this stage only
|
||||
if node.has('axis'):
|
||||
const = Const(graph, {'value': node.axis}).create_node()
|
||||
const = Const(graph, {'name': node_name + '/axis', 'value': node.axis}).create_node()
|
||||
node.add_input_port(1, skip_if_exist=True)
|
||||
const.out_port(0).connect(node.in_port(1))
|
||||
del graph.node[node.id]['axis']
|
||||
else:
|
||||
# The default (if there is no 'axis') is to reduce over all the dimensions of the input tensor.
|
||||
node_name = node.name
|
||||
|
||||
begin_of_range = Const(graph, dict(name=node_name + '/range_begin_', value=0)).create_node()
|
||||
step = Const(graph, dict(name=node_name + '/range_step_', value=1)).create_node()
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
"""
|
||||
from extensions.ops.ReduceOps import ReduceProd, ReduceAnd, ReduceMax, ReduceMean, ReduceSum
|
||||
from extensions.ops.ReduceOps import ReduceProd, ReduceAnd, ReduceMax, ReduceMean, ReduceSum, ReduceL2
|
||||
from mo.front.extractor import FrontExtractorOp
|
||||
from mo.graph.graph import Node
|
||||
|
||||
@@ -67,3 +67,13 @@ class SumFrontExtractor(FrontExtractorOp):
|
||||
def extract(cls, node: Node):
|
||||
ReduceSum.update_node_stat(node, {'keep_dims': node.pb.attr["keep_dims"].b})
|
||||
return cls.enabled
|
||||
|
||||
|
||||
class EuclideanNormFrontExtractor(FrontExtractorOp):
|
||||
op = 'EuclideanNorm'
|
||||
enabled = True
|
||||
|
||||
@classmethod
|
||||
def extract(cls, node: Node):
|
||||
ReduceL2.update_node_stat(node, {'keep_dims': node.pb.attr["keep_dims"].b})
|
||||
return cls.enabled
|
||||
|
||||
@@ -24,6 +24,7 @@ from mo.ops.op import Op
|
||||
reduce_map = {
|
||||
'ReduceSum': np.sum,
|
||||
'ReduceProd': np.prod,
|
||||
'ReduceL1': lambda x, axis, keepdims: np.sum(a=np.absolute(x), axis=axis, keepdims=keepdims),
|
||||
'ReduceL2': lambda x, axis, keepdims: np.sqrt(np.sum(a=np.square(x), axis=axis, keepdims=keepdims)),
|
||||
'ReduceMax': np.max,
|
||||
'ReduceMin': np.min,
|
||||
@@ -86,12 +87,13 @@ class ReduceOp(Op):
|
||||
enabled = False
|
||||
op = None
|
||||
op_type = None
|
||||
version = 'opset1'
|
||||
|
||||
def __init__(self, graph: Graph, attrs: dict):
|
||||
super().__init__(graph, {
|
||||
'op': self.op,
|
||||
'type': self.op_type,
|
||||
'version': 'opset1',
|
||||
'version': self.version,
|
||||
'infer': reduce_infer,
|
||||
'keep_dims': 0,
|
||||
'in_ports_count': 2,
|
||||
@@ -138,10 +140,15 @@ class ReduceMean(ReduceOp):
|
||||
enabled = True
|
||||
|
||||
|
||||
class ReduceL1(ReduceOp):
|
||||
op = 'ReduceL1'
|
||||
op_type = 'ReduceL1'
|
||||
version = 'opset4'
|
||||
|
||||
class ReduceL2(ReduceOp):
|
||||
op = 'ReduceL2'
|
||||
op_type = None
|
||||
enabled = True
|
||||
op_type = 'ReduceL2'
|
||||
version = 'opset4'
|
||||
|
||||
|
||||
class ReduceAnd(ReduceOp):
|
||||
|
||||
@@ -28,38 +28,42 @@ nodes_attributes = {
|
||||
**regular_op_with_shaped_data('data', [1, 3, 224, 224], {'type': 'Parameter', 'value': None,
|
||||
'_out_port_data_type': {0: np.float32}}),
|
||||
**valued_const_with_data('axis', int64_array(0)),
|
||||
**regular_op_with_shaped_data('reduce_l2', None, {'op': 'ReduceL2', 'type': None, 'name': 'my_reduce_l2'}),
|
||||
**regular_op_with_shaped_data('reduce_lp', None, {'op': 'ReduceLp', 'type': None, 'name': 'my_reduce_lp'}),
|
||||
**regular_op_with_shaped_data('identity', None, {'op': 'Identity', 'name': 'identity'}),
|
||||
**result('output'),
|
||||
}
|
||||
|
||||
|
||||
@generator
|
||||
class TestCumSum(unittest.TestCase):
|
||||
class ReduceLpTest(unittest.TestCase):
|
||||
@generate(*[
|
||||
([3, 2, 2], [0], True),
|
||||
([3, 2, 2], [1], True),
|
||||
([3, 2, 2], [2], True),
|
||||
([3, 2, 2], [0], False),
|
||||
([3, 2, 2], [1], False),
|
||||
([3, 2, 2], [2], False),
|
||||
([3, 2, 2], [0], True, 1),
|
||||
([3, 2, 2], [0], True, 2),
|
||||
([3, 2, 2], [1], True, 2),
|
||||
([3, 2, 2], [2], True, 2),
|
||||
([3, 2, 2], [0], False, 1),
|
||||
([3, 2, 2], [0], False, 2),
|
||||
([3, 2, 2], [1], False, 2),
|
||||
([3, 2, 2], [2], False, 2),
|
||||
])
|
||||
def test_reduce_l2(self, shape, axes, keepdims):
|
||||
def test_reduce_lp(self, shape, axes, keepdims, p):
|
||||
data = np.reshape(np.arange(1, np.prod(shape) + 1, dtype=np.float32), shape)
|
||||
reduced = np.sqrt(np.sum(a=np.square(data), axis=tuple(axes), keepdims=keepdims))
|
||||
reduced = np.power(np.sum(a=np.abs(np.power(data, p)), axis=tuple(axes), keepdims=keepdims), 1 / p)
|
||||
axis = int64_array(axes)
|
||||
p = int64_array(p)
|
||||
graph = build_graph(nodes_attributes,
|
||||
[*connect('data', '0:reduce_l2'),
|
||||
*connect('axis', '1:reduce_l2'),
|
||||
*connect('reduce_l2', '0:identity'),
|
||||
[*connect('data', '0:reduce_lp'),
|
||||
*connect('axis', '1:reduce_lp'),
|
||||
*connect('reduce_lp', '0:identity'),
|
||||
('identity', 'identity_d', {'out': 0}),
|
||||
('identity_d', 'output')
|
||||
],
|
||||
{'data_d': {'value': data, 'shape': data.shape},
|
||||
'axis_d': {'value': axis, 'shape': axis.shape},
|
||||
'reduce_l2': {'keep_dims': keepdims}},
|
||||
'reduce_lp': {'keep_dims': keepdims}},
|
||||
nodes_with_edges_only=True)
|
||||
|
||||
reduce_node = Node(graph, 'reduce_l2')
|
||||
reduce_node = Node(graph, 'reduce_lp')
|
||||
reduce_node.op = reduce_node.type = 'ReduceL' + str(p)
|
||||
reduce_infer(reduce_node)
|
||||
self.assertTrue(np.array_equal(reduce_node.out_port(0).data.get_value(), reduced))
|
||||
|
||||
Reference in New Issue
Block a user