From 04c9c28869d574aee1cbc428b4089ee7d7f6e4b2 Mon Sep 17 00:00:00 2001 From: Roman Kazantsev Date: Mon, 16 Jan 2023 21:31:24 +0400 Subject: [PATCH] [TF FE] Fix LRN operation and test it (#15145) It allows to fix inference results mismatch for some models Signed-off-by: Kazantsev, Roman Signed-off-by: Kazantsev, Roman --- src/frontends/tensorflow/src/op/lrn.cpp | 38 +++++++++++-------- .../tensorflow_tests/test_tf_LRN.py | 33 ++++++++++++++++ 2 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 tests/layer_tests/tensorflow_tests/test_tf_LRN.py diff --git a/src/frontends/tensorflow/src/op/lrn.cpp b/src/frontends/tensorflow/src/op/lrn.cpp index 7e950c31b0b..ea7d010baf3 100644 --- a/src/frontends/tensorflow/src/op/lrn.cpp +++ b/src/frontends/tensorflow/src/op/lrn.cpp @@ -4,6 +4,7 @@ #include "op_table.hpp" #include "openvino/opsets/opset8.hpp" +#include "utils.hpp" using namespace std; using namespace ov::opset8; @@ -14,23 +15,30 @@ namespace tensorflow { namespace op { OutputVector translate_lrn_op(const NodeContext& node) { + // The normalization is performed along the last dimension + default_op_checks(node, 1, {"LRN"}); auto input = node.get_input(0); - auto alpha = node.get_attribute("alpha"); - auto beta = node.get_attribute("beta"); - auto bias = node.get_attribute("bias"); - auto depth_radius = node.get_attribute("depth_radius"); - // OV: Each input value is divided by (bias+(alpha/size)*sum(xi^2 for every xi - // in the local region))^beta - // TF: sqr_sum[a, b, c, d] = sum(input[a, b, c, d - depth_radius : d + - // depth_radius + 1] ** 2) - // output = input / (bias + alpha * sqr_sum) ** beta - int64_t size = depth_radius * 2 + 1; - alpha = alpha * size; - // todo: input is in NHWC, need to apply NHWC to NCHW? - auto res = make_shared(input, alpha, beta, bias, static_cast(size)); - set_node_name(node.get_name(), res); - return res->outputs(); + // retrieve attributes + auto depth_radius = node.get_attribute("depth_radius", 5); + auto bias = static_cast(node.get_attribute("bias", 1)); + auto alpha = static_cast(node.get_attribute("alpha", 1)); + auto beta = static_cast(node.get_attribute("beta", 0.5)); + + // adjust attribute values for opset LRN operation + size_t attr_size = static_cast(depth_radius) * 2 + 1; + alpha *= static_cast(attr_size); + + // currently, plugins fallback to the template to execute this operation + // the current implementation supports only the normalization across channel (axes={1}) + // and spatial dimensions (axes={2,3}) + // so we have to transpose inputs and outputs due to this limitation + auto axis = make_shared(element::i32, Shape{1}, 1); + ov::frontend::tensorflow::convert_nhwc_to_nchw(true, input); + auto lrn = make_shared(input, axis, alpha, beta, bias, attr_size)->output(0); + ov::frontend::tensorflow::convert_nchw_to_nhwc(true, lrn); + set_node_name(node.get_name(), lrn.get_node_shared_ptr()); + return {lrn}; } } // namespace op diff --git a/tests/layer_tests/tensorflow_tests/test_tf_LRN.py b/tests/layer_tests/tensorflow_tests/test_tf_LRN.py new file mode 100644 index 00000000000..c60619a1ded --- /dev/null +++ b/tests/layer_tests/tensorflow_tests/test_tf_LRN.py @@ -0,0 +1,33 @@ +# Copyright (C) 2018-2023 Intel Corporation +# SPDX-License-Identifier: Apache-2.0 + +import pytest +import tensorflow as tf +from common.tf_layer_test_class import CommonTFLayerTest + + +class TestLRN(CommonTFLayerTest): + def create_lrn_net(self, input_shape, depth_radius, bias, alpha, beta): + tf.compat.v1.reset_default_graph() + # Create the graph and model + with tf.compat.v1.Session() as sess: + input = tf.compat.v1.placeholder(tf.float32, input_shape, 'input') + tf.raw_ops.LRN(input=input, depth_radius=depth_radius, bias=bias, alpha=alpha, beta=beta) + tf.compat.v1.global_variables_initializer() + + tf_net = sess.graph_def + + return tf_net, None + + test_data_basic = [ + dict(input_shape=[2, 20, 30, 3], depth_radius=3, bias=0.2, alpha=4, beta=0.75), + dict(input_shape=[1, 10, 30, 2], depth_radius=4, bias=1, alpha=3, beta=0.15), + ] + + @pytest.mark.parametrize("params", test_data_basic) + @pytest.mark.precommit_tf_fe + def test_lrn_basic(self, params, ie_device, precision, ir_version, temp_dir, + use_new_frontend, use_old_api): + self._test(*self.create_lrn_net(**params), + ie_device, precision, ir_version, temp_dir=temp_dir, + use_new_frontend=use_new_frontend, use_old_api=use_old_api)