Files
openvino/model-optimizer/extensions/front/tf/TFSliceToSlice.py
T
Yegor Kruglov ce1ec9eab0 Reshape-able SliceConverter (#3198)
* initial commit

* add cast

* data type fix

* added tests

* added test without axes and steps

* remove redundant imports

* discussions resolving

* Add cast to TFSliceToSlice

* layer tests fix

* update unittest

* rework transformation

* added clamp

* move broadcast

* update unittests

* failed e2e fix

* added comment

* little fixes

* comments update
2020-12-01 12:42:40 +03:00

82 lines
3.6 KiB
Python

"""
Copyright (C) 2018-2020 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import numpy as np
from extensions.ops.Cast import Cast
from extensions.ops.elementwise import Add, Equal
from extensions.ops.select import Select
from mo.front.common.replacement import FrontReplacementOp
from mo.graph.graph import Graph, rename_nodes
from mo.ops.const import Const
from mo.ops.slice import Slice
class TFSliceToSliceReplacer(FrontReplacementOp):
"""
This transformation converts TFSlice to internal Slice operation.
In TFSlice size[i] == -1 means take all elements on axis i up to the end including(!) the last
In internal MO Slice (which is borrowed from ONNX) -1 means take all excluding(!) the last (shape[i] - 1).
Also TFSlice has 'sizes' on the second input while Slice has 'ends'.
This transformation was added to avoid multiple if statements in future transformations.
"""
op = 'TFSlice'
enabled = True
def replace_sub_graph(self, graph: Graph, match: dict):
node = match['op']
slice_name = node.soft_get('name', node.id)
slice_node = Slice(graph).create_node()
rename_nodes([(node, slice_name + '/to_be_removed'), (slice_node, slice_name)])
eq_node = Equal(graph, {'name': slice_name + '/equal'}).create_node()
minus_one_node = Const(graph, {'name': slice_name + '/minus_one', 'value': np.array(-1)}).create_node()
int32_max_node = Const(graph, {'name': slice_name + '/int32_max', 'value': np.iinfo(np.int32).max}).create_node()
select_node = Select(graph, {'name': slice_name + '/select'}).create_node()
# node to convert sizes to ends
sum_node = Add(graph, {'name': slice_name + '/end_const'}).create_node()
# reconnect input from tfslice to slice
node.in_port(0).get_source().connect(slice_node.in_port(0))
node.in_port(0).disconnect()
# reconnect begin of tfslice to start of slice
node.in_port(1).get_source().connect(slice_node.in_port(1))
node.in_port(1).disconnect()
# (size -> ends) reconnect begins and sizes to sum to evaluate ends for Slice
# connects begins to slice
slice_node.in_port(1).get_source().connect(sum_node.in_port(0))
node.in_port(2).get_source().connect(sum_node.in_port(1))
node.in_port(2).disconnect()
# if size[i] == -1 when take int32_max as end[i]
sum_node.in_port(1).get_source().connect(eq_node.in_port(0))
minus_one_node.out_port(0).connect(eq_node.in_port(1))
# from equal to 0 port of select
eq_node.out_port(0).connect(select_node.in_port(0))
# from int32_max to 1 of select
int32_max_node.out_port(0).connect(select_node.in_port(1))
# from sum to 2nd of select
sum_node.out_port(0).connect(select_node.in_port(2))
# out of select to end (2nd of slice)
select_node.out_port(0).connect(slice_node.in_port(2))
cast = Cast(graph, dict(name=sum_node.name + '/CastToI64', dst_type=np.int64)).create_node()
select_node.in_port(2).get_connection().insert_node(cast)
node.out_port(0).get_connection().set_source(slice_node.out_port(0))