[TF FE][Opset13] Enable Multinomial operator in TF frontend (#20646)

* Enable Multinomial operator in TF frontend

* Implement requested changes

* Update tests/layer_tests/tensorflow_tests/test_tf_Multinomial.py

Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com>

* Align with CPU implementation

---------

Co-authored-by: Roman Kazantsev <roman.kazantsev@intel.com>
This commit is contained in:
Mateusz Mikolajczyk 2023-12-18 12:00:04 +01:00 committed by GitHub
parent a29843013d
commit a1e296eaa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 178 additions and 0 deletions

View File

@ -233,6 +233,7 @@ const std::map<std::string, CreatorFunction> get_supported_ops() {
{"Merge", CreatorFunction(translate_merge_op)},
{"MirrorPad", CreatorFunction(translate_mirror_pad_op)},
{"MulNoNan", CreatorFunction(translate_mul_no_nan_op)},
{"Multinomial", CreatorFunction(translate_multinomial_op)},
{"MutableHashTable", CreatorFunction(translate_hash_table_op)},
{"MutableHashTableV2", CreatorFunction(translate_hash_table_op)},
{"NonMaxSuppression", CreatorFunction(translate_non_max_suppression_op)},

View File

@ -102,6 +102,7 @@ OP_CONVERTER(translate_max_pool_op);
OP_CONVERTER_NAMED(translate_max_pool_with_argmax);
OP_CONVERTER(translate_mirror_pad_op);
OP_CONVERTER(translate_mul_no_nan_op);
OP_CONVERTER(translate_multinomial_op);
OP_CONVERTER_NAMED(translate_non_max_suppression_op);
OP_CONVERTER(translate_parallel_dynamic_stitch_op);
OP_CONVERTER(translate_placeholder_op);

View File

@ -0,0 +1,31 @@
// Copyright (C) 2018-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include "openvino/op/multinomial.hpp"
#include "common_op_table.hpp"
namespace ov {
namespace frontend {
namespace tensorflow {
namespace op {
OutputVector translate_multinomial_op(const NodeContext& node) {
default_op_checks(node, 2, {"Multinomial"});
auto logits = node.get_input(0);
auto num_samples = node.get_input(1);
auto global_seed = node.get_attribute<int64_t>("seed", 0);
auto op_seed = node.get_attribute<int64_t>("seed2", 0);
auto output_type = node.get_attribute<ov::element::Type>("output_dtype");
auto res =
std::make_shared<ov::op::v13::Multinomial>(logits, num_samples, output_type, true, true, global_seed, op_seed);
set_node_name(node.get_name(), res);
return res->outputs();
}
} // namespace op
} // namespace tensorflow
} // namespace frontend
} // namespace ov

View File

@ -2,6 +2,7 @@
markers =
nightly
precommit
precommit_tf_fe
precommit_ts_backend
precommit_fx_backend
timeout

View File

@ -0,0 +1,144 @@
# 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
import numpy as np
class TestMultinomial(CommonTFLayerTest):
def _prepare_input(self, inputs_dict, kwargs):
inputs_dict["num_samples"] = np.array(kwargs["num_samples"], dtype=np.int32)
inputs_dict["probs"] = kwargs["input"]
return inputs_dict
def create_tf_multinomial_net_shape(
self, global_seed, op_seed, logits_shape, input_type, out_type
):
tf.compat.v1.reset_default_graph()
# Configuration required to make multinomial randomness predictable across devices, results depends on TF parallel execution.
session_conf = tf.compat.v1.ConfigProto(
intra_op_parallelism_threads=1, inter_op_parallelism_threads=1
)
# Create the graph and model
with tf.compat.v1.Session(config=session_conf) as sess:
probs = tf.compat.v1.placeholder(input_type, logits_shape, "probs")
num_samples = tf.compat.v1.placeholder(tf.int32, [], "num_samples")
if global_seed is not None:
tf.random.set_seed(global_seed)
tf.raw_ops.ZerosLike(
x=tf.raw_ops.Multinomial(
logits=tf.math.log(probs),
num_samples=num_samples,
seed=global_seed,
seed2=op_seed,
output_dtype=out_type,
)
)
tf.compat.v1.global_variables_initializer()
tf_net = sess.graph_def
return tf_net, None
def create_tf_multinomial_net_exact(
self, global_seed, op_seed, logits_shape, input_type, out_type
):
tf.compat.v1.reset_default_graph()
# Configuration required to make multinomial randomness predictable across devices, results depends on TF parallel execution.
session_conf = tf.compat.v1.ConfigProto(
intra_op_parallelism_threads=1, inter_op_parallelism_threads=1
)
# Create the graph and model
with tf.compat.v1.Session(config=session_conf) as sess:
probs = tf.compat.v1.placeholder(input_type, logits_shape, "probs")
num_samples = tf.compat.v1.placeholder(tf.int32, [], "num_samples")
if global_seed is not None:
tf.random.set_seed(global_seed)
tf.raw_ops.Multinomial(
logits=tf.math.log(probs),
num_samples=num_samples,
seed=global_seed,
seed2=op_seed,
output_dtype=out_type,
)
tf.compat.v1.global_variables_initializer()
tf_net = sess.graph_def
return tf_net, None
@pytest.mark.parametrize("out_type", [tf.int32, tf.int64])
@pytest.mark.parametrize(
("input", "num_samples", "seed", "test_type"),
[
(
np.array([[0, 1, 0, 0], [0, 0, 0, 1], [1, 0, 0, 0]], dtype=np.float32),
1024,
[32465, 48971],
"exact",
),
(
np.array(
[
[0.001, 0.001, 0.1, 0.9],
[5, 10, 1e-5, 256],
[1, 1e-5, 1e-5, 1e-5],
],
dtype=np.float64,
),
256,
[32465, 48971],
"shape",
),
(np.array([[1, 1, 1, 1]], dtype=np.float16), 1024, [1, 1], "shape"),
(
np.array([[1, 2, 3, 4], [4, 3, 2, 1], [1, 0, 0, 0]], dtype=np.float32),
1,
[78132, None],
"shape",
),
(
np.array([[7, 7, 7, 7], [7, 7, 7, 7], [7, 7, 7, 7]], dtype=np.float32),
1024,
[32465, None],
"shape",
),
],
)
@pytest.mark.nightly
@pytest.mark.precommit_tf_fe
def test_multinomial_basic(
self,
input,
num_samples,
seed,
out_type,
test_type,
ie_device,
precision,
ir_version,
temp_dir,
use_new_frontend,
use_old_api,
):
if ie_device == "GPU":
pytest.skip("Multinomial is not supported on GPU")
net = getattr(self, f"create_tf_multinomial_net_{test_type}")
self._test(
*net(
global_seed=seed[0],
op_seed=seed[1],
logits_shape=input.shape,
input_type=input.dtype,
out_type=out_type,
),
ie_device,
precision,
temp_dir=temp_dir,
ir_version=ir_version,
use_new_frontend=use_new_frontend,
use_old_api=use_old_api,
kwargs_to_prepare_input={"input": input, "num_samples": num_samples},
)