From e2c9f24400aed91cdf81cf2d97666992c4e40bf4 Mon Sep 17 00:00:00 2001 From: sami0i <152037752+sami0i@users.noreply.github.com> Date: Sun, 7 Jan 2024 16:04:12 +0100 Subject: [PATCH] [TF FE] Support Div operation for TensorFlow (#21730) * Support Div operation for TensorFlow * Update test_tf_Div.py * Update div.cpp * Update op_table and common_op_table * update translate_div_op * print inputs * update div.cpp * set m_pythondiv to false * update div.cpp * update div.cpp * Update tests/layer_tests/tensorflow_tests/test_tf_Div.py * Update tests/layer_tests/tensorflow_tests/test_tf_Div.py --------- Co-authored-by: Roman Kazantsev --- src/frontends/tensorflow/src/op_table.cpp | 1 + .../include/common_op_table.hpp | 1 + .../tensorflow_common/src/op/div.cpp | 59 +++++++++++++++++++ .../tensorflow_tests/test_tf_Div.py | 50 ++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 src/frontends/tensorflow_common/src/op/div.cpp create mode 100644 tests/layer_tests/tensorflow_tests/test_tf_Div.py diff --git a/src/frontends/tensorflow/src/op_table.cpp b/src/frontends/tensorflow/src/op_table.cpp index 062d29cf8b06ac..f01d8e5fb2fabf 100644 --- a/src/frontends/tensorflow/src/op_table.cpp +++ b/src/frontends/tensorflow/src/op_table.cpp @@ -106,6 +106,7 @@ const std::map get_supported_ops() { {"BitwiseAnd", CreatorFunction(translate_binary_op)}, {"BitwiseOr", CreatorFunction(translate_binary_op)}, {"BitwiseXor", CreatorFunction(translate_binary_op)}, + {"Div", CreatorFunction(translate_div_op)}, {"Equal", CreatorFunction(translate_binary_op)}, {"FloorMod", CreatorFunction(translate_binary_op)}, {"Greater", CreatorFunction(translate_binary_op)}, diff --git a/src/frontends/tensorflow_common/include/common_op_table.hpp b/src/frontends/tensorflow_common/include/common_op_table.hpp index c2f756b4aecc62..0b83ad0ca5680b 100644 --- a/src/frontends/tensorflow_common/include/common_op_table.hpp +++ b/src/frontends/tensorflow_common/include/common_op_table.hpp @@ -63,6 +63,7 @@ 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_div_op); OP_CONVERTER(translate_mul_op); OP_CONVERTER(translate_dynamic_partition_op); OP_CONVERTER(translate_einsum_op); diff --git a/src/frontends/tensorflow_common/src/op/div.cpp b/src/frontends/tensorflow_common/src/op/div.cpp new file mode 100644 index 00000000000000..2d9ead42d50f6e --- /dev/null +++ b/src/frontends/tensorflow_common/src/op/div.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "common_op_table.hpp" +#include "openvino/op/divide.hpp" + +using namespace std; +using namespace ov::op; + +namespace ov { +namespace frontend { +namespace tensorflow { +namespace op { +OutputVector translate_div_op(const NodeContext& node) { + default_op_checks(node, 2, {"Div"}); + auto x = node.get_input(0); + auto y = node.get_input(1); + // Check if the element type is a signed integer + if (x.get_element_type().is_integral_number() && x.get_element_type().is_signed()) { + // prepare auxiliary zero constants of the same type as the inputs + auto const_zero = create_same_type_const_scalar(x, 0); + + // compute the modulus of x and y + auto mod_result = make_shared(x, y); + // compute a mask to get positions of non-zero values of mod result + auto mod_non_zero = make_shared(mod_result, const_zero); + + // compute the division of x and y + auto divide = make_shared(x, y); + // compute a mask to get positions of negative values of division result + auto div_is_neg = make_shared(divide, const_zero); + + // compute a boolean mask of elements for non-zero values of Mod result and negative values of Divide result + auto mask = make_shared(mod_non_zero, div_is_neg); + + // prepare auxiliary one constants of the same type as the inputs + auto const_one = create_same_type_const_scalar(x, 1); + // add 1 to the divide result + auto add_result = make_shared(divide, const_one); + + // select division results based on the mask + // - perform floor division for non-negative values. + // - round negative values to the nearest zero. + auto div = make_shared(mask, add_result, divide); + set_node_name(node.get_name(), div); + return div->outputs(); + } else { + // for other cases (non-signed-integer types) + // compute regular division of x and y + auto div = make_shared(x, y); + set_node_name(node.get_name(), div); + return div->outputs(); + } +} +} // namespace op +} // namespace tensorflow +} // namespace frontend +} // namespace ov diff --git a/tests/layer_tests/tensorflow_tests/test_tf_Div.py b/tests/layer_tests/tensorflow_tests/test_tf_Div.py new file mode 100644 index 00000000000000..2d71f16a85c66c --- /dev/null +++ b/tests/layer_tests/tensorflow_tests/test_tf_Div.py @@ -0,0 +1,50 @@ +# 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 TestDiv(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 = {} + # generate x and y + inputs_data['x'] = np.random.randint(-10, 10, x_shape).astype(self.input_type) + inputs_data['y'] = np.random.randint(1, 10, y_shape)*np.random.choice([-1,1], y_shape) + return inputs_data + + def create_div_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.Div(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.param(dict(input_shape=[8, 5], input_type=np.int32), + marks=pytest.mark.xfail(reason='Ticket TBD - Divide inconsistent behavior on different systems')), + dict(input_shape=[], input_type=np.float32), + ] + + @pytest.mark.parametrize("params", test_data_basic) + @pytest.mark.precommit_tf_fe + @pytest.mark.nightly + def test_div_basic(self, params, ie_device, precision, ir_version, temp_dir, + use_new_frontend, use_old_api): + self._test(*self.create_div_net(**params), + ie_device, precision, ir_version, temp_dir=temp_dir, + use_new_frontend=use_new_frontend, use_old_api=use_old_api) \ No newline at end of file