[TF FE][TF Hub] Support DivNoNan and EnsureShape operations (#19007)
Signed-off-by: Kazantsev, Roman <roman.kazantsev@intel.com>
This commit is contained in:
@@ -140,12 +140,14 @@ const std::map<std::string, CreatorFunction> get_supported_ops() {
|
||||
{"CTCGreedyDecoder", CreatorFunction(translate_ctc_greedy_decoder_op)},
|
||||
{"CTCLoss", CreatorFunction(translate_ctc_loss_op)},
|
||||
{"Cumsum", CreatorFunction(translate_cumsum_op)},
|
||||
{"DivNoNan", CreatorFunction(translate_div_no_nan_op)},
|
||||
{"DepthToSpace", CreatorFunction(translate_depth_to_space_op)},
|
||||
{"DepthwiseConv2dNative", CreatorFunction(translate_depthwise_conv_2d_native_op)},
|
||||
{"DynamicPartition", CreatorFunction(translate_dynamic_partition_op)},
|
||||
{"Einsum", CreatorFunction(translate_einsum_op)},
|
||||
{"Elu", CreatorFunction(translate_elu_op)},
|
||||
{"EmptyTensorList", CreatorFunction(translate_tensor_list_reserve_op)},
|
||||
{"EnsureShape", CreatorFunction(translate_identity_op)},
|
||||
{"ExpandDims", CreatorFunction(translate_expand_dims_op)},
|
||||
{"ExtractImagePatches", CreatorFunction(translate_extract_image_patches_op)},
|
||||
{"FakeQuantWithMinMaxVars", CreatorFunction(translate_fake_quant_op)},
|
||||
|
||||
@@ -55,6 +55,7 @@ OP_CONVERTER(translate_cumsum_op);
|
||||
OP_CONVERTER(translate_crop_and_resize_op);
|
||||
OP_CONVERTER(translate_depth_to_space_op);
|
||||
OP_CONVERTER(translate_depthwise_conv_2d_native_op);
|
||||
OP_CONVERTER(translate_div_no_nan_op);
|
||||
OP_CONVERTER(translate_dynamic_partition_op);
|
||||
OP_CONVERTER(translate_einsum_op);
|
||||
OP_CONVERTER(translate_elu_op);
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2018-2023 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/convert_like.hpp"
|
||||
#include "openvino/op/divide.hpp"
|
||||
#include "openvino/op/equal.hpp"
|
||||
#include "openvino/op/select.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov::op;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
namespace tensorflow {
|
||||
namespace op {
|
||||
OutputVector translate_div_no_nan_op(const NodeContext& node) {
|
||||
default_op_checks(node, 2, {"DivNoNan"});
|
||||
auto numer = node.get_input(0);
|
||||
auto denom = node.get_input(1);
|
||||
|
||||
// prepare auxiliary zero and one constants of the same type as the inputs
|
||||
auto zero = make_shared<v0::Constant>(element::f32, Shape{}, 0.0f)->output(0);
|
||||
auto one = make_shared<v0::Constant>(element::f32, Shape{}, 1.0f)->output(0);
|
||||
zero = make_shared<v1::ConvertLike>(zero, denom);
|
||||
one = make_shared<v1::ConvertLike>(one, denom);
|
||||
|
||||
// compute a mask to get positions of Nan values of division result
|
||||
auto is_zero = make_shared<v1::Equal>(denom, zero);
|
||||
|
||||
// fix zeros in the denomimator to avoid undefined behaviour
|
||||
auto fixed_denom = make_shared<v1::Select>(is_zero, one, denom);
|
||||
|
||||
// compute Division and do not afraid division by zero
|
||||
// since all of them fixed
|
||||
auto div = make_shared<v1::Divide>(numer, fixed_denom);
|
||||
|
||||
// set zero to the result where initially the denomimator is zero
|
||||
auto div_no_nan = make_shared<v1::Select>(is_zero, zero, div);
|
||||
set_node_name(node.get_name(), div_no_nan);
|
||||
return div_no_nan->outputs();
|
||||
}
|
||||
} // namespace op
|
||||
} // namespace tensorflow
|
||||
} // namespace frontend
|
||||
} // namespace ov
|
||||
@@ -3,10 +3,8 @@
|
||||
//
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov::opset8;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
@@ -14,7 +12,8 @@ namespace tensorflow {
|
||||
namespace op {
|
||||
|
||||
OutputVector translate_identity_op(const NodeContext& node) {
|
||||
vector<string> supported_ops = {"Identity",
|
||||
vector<string> supported_ops = {"EnsureShape",
|
||||
"Identity",
|
||||
"PreventGradient",
|
||||
"Snapshot",
|
||||
"StopGradient",
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import tensorflow as tf
|
||||
from common.tf_layer_test_class import CommonTFLayerTest
|
||||
|
||||
|
||||
class TestDivNoNan(CommonTFLayerTest):
|
||||
def _prepare_input(self, inputs_info):
|
||||
assert 'x' in inputs_info
|
||||
assert 'y' in inputs_info
|
||||
x_shape = inputs_info['x']
|
||||
y_shape = inputs_info['y']
|
||||
inputs_data = {}
|
||||
inputs_data['x'] = np.random.randint(-10, 10, x_shape).astype(self.input_type)
|
||||
# generate y in way to have zeros
|
||||
inputs_data['y'] = np.random.randint(-10, 10, y_shape).astype(self.input_type) * \
|
||||
np.random.randint(0, 2, y_shape).astype(self.input_type)
|
||||
return inputs_data
|
||||
|
||||
def create_div_no_nan_net(self, input_shape, input_type):
|
||||
self.input_type = input_type
|
||||
tf.compat.v1.reset_default_graph()
|
||||
# Create the graph and model
|
||||
with tf.compat.v1.Session() as sess:
|
||||
x = tf.compat.v1.placeholder(input_type, input_shape, 'x')
|
||||
y = tf.compat.v1.placeholder(input_type, input_shape, 'y')
|
||||
tf.raw_ops.DivNoNan(x=x, y=y)
|
||||
tf.compat.v1.global_variables_initializer()
|
||||
tf_net = sess.graph_def
|
||||
|
||||
return tf_net, None
|
||||
|
||||
test_data_basic = [
|
||||
dict(input_shape=[10, 20], input_type=np.float32),
|
||||
dict(input_shape=[2, 3, 4], input_type=np.float32),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("params", test_data_basic)
|
||||
@pytest.mark.precommit_tf_fe
|
||||
@pytest.mark.nightly
|
||||
def test_div_no_nan_basic(self, params, ie_device, precision, ir_version, temp_dir,
|
||||
use_new_frontend, use_old_api):
|
||||
self._test(*self.create_div_no_nan_net(**params),
|
||||
ie_device, precision, ir_version, temp_dir=temp_dir,
|
||||
use_new_frontend=use_new_frontend, use_old_api=use_old_api)
|
||||
@@ -0,0 +1,44 @@
|
||||
# Copyright (C) 2018-2023 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
import tensorflow as tf
|
||||
from common.tf_layer_test_class import CommonTFLayerTest
|
||||
|
||||
|
||||
class TestEnsureShape(CommonTFLayerTest):
|
||||
def _prepare_input(self, inputs_info):
|
||||
assert 'tensor' in inputs_info
|
||||
tensor_shape = inputs_info['tensor']
|
||||
inputs_data = {}
|
||||
inputs_data['tensor'] = np.random.randint(-10, 10, tensor_shape).astype(self.input_type)
|
||||
return inputs_data
|
||||
|
||||
def create_ensure_shape_net(self, input_shape, input_type, target_shape):
|
||||
self.input_type = input_type
|
||||
tf.compat.v1.reset_default_graph()
|
||||
# Create the graph and model
|
||||
with tf.compat.v1.Session() as sess:
|
||||
tensor = tf.compat.v1.placeholder(input_type, input_shape, 'tensor')
|
||||
shape = tf.constant(target_shape, dtype=tf.int32)
|
||||
reshape = tf.raw_ops.Reshape(tensor=tensor, shape=shape)
|
||||
tf.raw_ops.EnsureShape(input=reshape, shape=target_shape)
|
||||
tf.compat.v1.global_variables_initializer()
|
||||
tf_net = sess.graph_def
|
||||
|
||||
return tf_net, None
|
||||
|
||||
test_data_basic = [
|
||||
dict(input_shape=[2, 6], input_type=np.float32, target_shape=[2, 3, 2]),
|
||||
dict(input_shape=[1], input_type=np.float32, target_shape=[]),
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize("params", test_data_basic)
|
||||
@pytest.mark.precommit_tf_fe
|
||||
@pytest.mark.nightly
|
||||
def test_ensure_shape_basic(self, params, ie_device, precision, ir_version, temp_dir,
|
||||
use_new_frontend, use_old_api):
|
||||
self._test(*self.create_ensure_shape_net(**params),
|
||||
ie_device, precision, ir_version, temp_dir=temp_dir,
|
||||
use_new_frontend=use_new_frontend, use_old_api=use_old_api)
|
||||
Reference in New Issue
Block a user