Skip to content

Commit 560b02d

Browse files
authored
[TF] Support Erfc operation (#29419)
**Details:** Test TF FE and JAX FE against latest versions **Ticket:** TBD --------- Signed-off-by: Kazantsev, Roman <roman.kazantsev@intel.com>
1 parent 5ce3c96 commit 560b02d

File tree

8 files changed

+109
-13
lines changed

8 files changed

+109
-13
lines changed

src/frontends/common_translators/include/common_translators.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ COMMON_OP_CONVERTER(translate_imag);
1818

1919
COMMON_OP_CONVERTER(translate_atan2);
2020
COMMON_OP_CONVERTER(translate_angle);
21+
COMMON_OP_CONVERTER(translate_erfc);
2122

2223
OutputVector translate_atan2_util(const NodeContext& context, const Output<Node>& lhs, const Output<Node>& rhs);
24+
OutputVector translate_erfc_util(const NodeContext& context, const Output<Node>& data);
2325

2426
} // namespace common_translators
2527
} // namespace frontend
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright (C) 2018-2025 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "common_translators.hpp"
6+
#include "openvino/op/erf.hpp"
7+
#include "openvino/op/subtract.hpp"
8+
#include "utils.hpp"
9+
10+
namespace ov {
11+
namespace frontend {
12+
namespace common_translators {
13+
14+
using namespace ov::op;
15+
using namespace std;
16+
17+
OutputVector translate_erfc_util(const NodeContext& context, const Output<Node>& data) {
18+
auto one_const = create_same_type_const_scalar<int32_t>(data, 1);
19+
auto erf = context.mark_node(make_shared<v0::Erf>(data));
20+
auto erfc = context.mark_node(make_shared<v1::Subtract>(one_const, erf));
21+
return {erfc};
22+
}
23+
24+
OutputVector translate_erfc(const NodeContext& context) {
25+
num_inputs_check(context, 1, 1);
26+
auto data = context.get_input(0);
27+
28+
return translate_erfc_util(context, data);
29+
}
30+
31+
} // namespace common_translators
32+
} // namespace frontend
33+
} // namespace ov

src/frontends/pytorch/src/op/erfc.cpp

+2-12
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
// SPDX-License-Identifier: Apache-2.0
33
//
44

5+
#include "common_translators.hpp"
56
#include "openvino/frontend/pytorch/node_context.hpp"
6-
#include "openvino/op/convert.hpp"
7-
#include "openvino/op/erf.hpp"
8-
#include "openvino/op/subtract.hpp"
97
#include "utils.hpp"
108

119
using namespace std;
@@ -22,15 +20,7 @@ OutputVector translate_erfc(const NodeContext& context) {
2220
num_inputs_check(context, 1, 2);
2321
auto x = get_input_with_floating_type(context, 0);
2422

25-
// create 'ones' to use to calculate complementary of Erf output
26-
auto ones = context.mark_node(make_shared<v0::Constant>(element::f32, Shape{}, 1.0f))->output(0);
27-
28-
ones = context.mark_node(std::make_shared<v1::ConvertLike>(ones, x));
29-
30-
// apply Erf to the input tensor 'x'
31-
auto y = context.mark_node(make_shared<v0::Erf>(x));
32-
33-
y = context.mark_node(make_shared<v1::Subtract>(ones, y));
23+
auto y = common_translators::translate_erfc_util(context, x)[0];
3424

3525
if (!context.input_is_none(1)) {
3626
context.mutate_input(1, y);

src/frontends/tensorflow/docs/supported_ops.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ A "supported operation" is one that TensorFlow Frontend can convert to the OpenV
375375
| Enter | YES | |
376376
| Equal | YES | |
377377
| Erf | YES | |
378-
| Erfc | NO | |
378+
| Erfc | YES | |
379379
| Erfinv | NO | |
380380
| EuclideanNorm | YES | |
381381
| Exit | YES | |

src/frontends/tensorflow/src/op_table.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ const std::map<std::string, CreatorFunction> get_supported_ops() {
144144
{"Cos", CreatorFunction(translate_unary_op<v0::Cos>)},
145145
{"Cosh", CreatorFunction(translate_unary_op<v0::Cosh>)},
146146
{"Erf", CreatorFunction(translate_unary_op<v0::Erf>)},
147+
{"Erfc", CreatorFunction(translate_erfc_op)},
147148
{"Exp", CreatorFunction(translate_unary_op<v0::Exp>)},
148149
{"Floor", CreatorFunction(translate_unary_op<v0::Floor>)},
149150
{"Invert", CreatorFunction(translate_unary_op<v13::BitwiseNot>)},

src/frontends/tensorflow_common/include/common_op_table.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ OP_CONVERTER(translate_mul_op);
7474
OP_CONVERTER(translate_dynamic_partition_op);
7575
OP_CONVERTER(translate_einsum_op);
7676
OP_CONVERTER(translate_elu_op);
77+
OP_CONVERTER(translate_erfc_op);
7778
OP_CONVERTER(translate_expm1_op);
7879
OP_CONVERTER(translate_expand_dims_op);
7980
OP_CONVERTER(translate_extract_image_patches_op);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (C) 2018-2025 Intel Corporation
2+
// SPDX-License-Identifier: Apache-2.0
3+
//
4+
5+
#include "common_op_table.hpp"
6+
#include "common_translators.hpp"
7+
8+
using namespace std;
9+
using namespace ov;
10+
using namespace ov::op;
11+
12+
namespace ov {
13+
namespace frontend {
14+
namespace tensorflow {
15+
namespace op {
16+
17+
OutputVector translate_erfc_op(const NodeContext& node) {
18+
default_op_checks(node, 1, {"Erfc"});
19+
auto res = common_translators::translate_erfc(node);
20+
21+
set_node_name(node.get_name(), res[0].get_node_shared_ptr());
22+
return res;
23+
}
24+
} // namespace op
25+
} // namespace tensorflow
26+
} // namespace frontend
27+
} // namespace ov
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Copyright (C) 2018-2025 Intel Corporation
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import numpy as np
5+
import pytest
6+
import tensorflow as tf
7+
from common.tf_layer_test_class import CommonTFLayerTest
8+
9+
rng = np.random.default_rng(3453466)
10+
11+
12+
class TestAddTypes(CommonTFLayerTest):
13+
def _prepare_input(self, inputs_info):
14+
assert 'x:0' in inputs_info, "Test error: inputs_info must contain `x`"
15+
x_shape = inputs_info['x:0']
16+
inputs_data = {}
17+
inputs_data['x:0'] = rng.uniform(-3.0, 3.0, x_shape).astype(self.input_type)
18+
return inputs_data
19+
20+
def create_erfc_net(self, input_shape, input_type):
21+
self.input_type = input_type
22+
tf.compat.v1.reset_default_graph()
23+
# Create the graph and model
24+
with tf.compat.v1.Session() as sess:
25+
x = tf.compat.v1.placeholder(input_type, input_shape, 'x')
26+
tf.raw_ops.Erfc(x=x)
27+
tf.compat.v1.global_variables_initializer()
28+
29+
tf_net = sess.graph_def
30+
31+
return tf_net, None
32+
33+
@pytest.mark.parametrize("input_shape", [[], [2], [3, 4], [3, 2, 1, 4]])
34+
@pytest.mark.parametrize("input_type", [np.float16, np.float32, np.float64])
35+
@pytest.mark.precommit
36+
@pytest.mark.nightly
37+
def test_erfc(self, input_shape, input_type,
38+
ie_device, precision, ir_version, temp_dir,
39+
use_legacy_frontend):
40+
self._test(*self.create_erfc_net(input_shape, input_type),
41+
ie_device, precision, ir_version, temp_dir=temp_dir,
42+
use_legacy_frontend=use_legacy_frontend)

0 commit comments

Comments
 (0)