[Opset13][pyAPI] Python API Multinomial-13 (#20400)

* Init Multinomial op python API

* Add python tests for Multinomial op

* Update num_samples input description
This commit is contained in:
Katarzyna Mitrus 2023-10-13 12:50:02 +02:00 committed by Alexander Nesterov
parent e8d80f9b0d
commit 146b0c0be8
3 changed files with 120 additions and 0 deletions

View File

@ -106,6 +106,7 @@ from openvino.runtime.opset1.ops import minimum
from openvino.runtime.opset4.ops import mish
from openvino.runtime.opset1.ops import mod
from openvino.runtime.opset9.ops import multiclass_nms
from openvino.runtime.opset13.ops import multinomial
from openvino.runtime.opset1.ops import multiply
from openvino.runtime.opset6.ops import mvn
from openvino.runtime.opset1.ops import negative

View File

@ -110,6 +110,47 @@ def bitwise_xor(
)
@nameable_op
def multinomial(
probs: NodeInput,
num_samples: NodeInput,
convert_type: str,
with_replacement: bool,
log_probs: bool,
global_seed: int = 0,
op_seed: int = 0,
) -> Node:
"""Return a node which generates a sequence of class indices sampled from the multinomial distribution.
:param probs: Tensor with probabilities of floating-point type, and shape [class_size] or [batch_size, class_size].
:param num_samples: Tensor (scalar or 1D) a single element of type i32 or i64,
specifying the number of samples to draw from the multinomial distribution.
:param convert_type: Specifies the output tensor type, possible values: 'i64', 'i32'.
:param with_replacement: Flag that specifies whether to sample with replacement.
:param log_probs: Flag that specifies whether *probs* should be treated as unnormalized log probabilities.
:param global_seed: Specifies global seed value. Required to be a positive integer or 0.
:param op_seed: Specifies operational seed value. Required to be a positive integer or 0.
:return: The new node performing Multinomial operation.
"""
inputs = as_nodes(probs, num_samples)
if global_seed < 0:
raise RuntimeError(f"global_seed should be positive or 0. Got: {global_seed}")
if op_seed < 0:
raise RuntimeError(f"op_seed should be positive or 0. Got: {op_seed}")
attributes = {
"convert_type": convert_type,
"with_replacement": with_replacement,
"log_probs": log_probs,
"global_seed": global_seed,
"op_seed": op_seed,
}
return _get_node_factory_opset13().create("Multinomial", inputs, attributes)
@nameable_op
def nms_rotated(
boxes: NodeInput,

View File

@ -0,0 +1,78 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018-2023 Intel Corporation
# SPDX-License-Identifier: Apache-2.0
import numpy as np
import pytest
import openvino.runtime.opset13 as ops
from openvino.runtime import PartialShape, Dimension, Type
@pytest.mark.parametrize(
("probs_shape", "num_samples_shape", "convert_type", "with_replacement", "log_probs", "global_seed", "op_seed", "expected_out_shape"),
[
([4, 16], [], "i32", False, True, 7461, 1546, PartialShape([4, -1])),
([8], [1], "i64", True, False, 0, 0, PartialShape([-1])),
],
)
def test_multinomial_param_inputs(probs_shape, num_samples_shape, convert_type, with_replacement, log_probs, global_seed, op_seed, expected_out_shape):
probs = ops.parameter(probs_shape, dtype=np.float32)
num_samples = ops.parameter(num_samples_shape, dtype=np.int32)
op = ops.multinomial(probs, num_samples,
convert_type=convert_type,
with_replacement=with_replacement,
log_probs=log_probs,
global_seed=global_seed,
op_seed=op_seed)
assert op.get_output_size() == 1
assert op.get_type_name() == "Multinomial"
assert op.get_output_element_type(0) == Type.i32 if convert_type == "i32" else Type.i64
assert op.get_output_partial_shape(0) == expected_out_shape
@pytest.mark.parametrize(
("probs_array", "num_samples_val", "convert_type", "with_replacement", "log_probs", "global_seed", "op_seed", "expected_out_shape"),
[
(np.array([0.7, 0.3, 0.6, 0.5]), 3, "i32", False, True, 111, 222, PartialShape([3])),
(np.array([[0.7, 0.3], [0.6, 0.5]]), 2, "i64", True, False, 111, 222, PartialShape([2, 2])),
],
)
def test_multinomial_const_inputs(probs_array, num_samples_val, convert_type, with_replacement, log_probs, global_seed, op_seed, expected_out_shape):
probs = ops.constant(probs_array, dtype=np.float32)
num_samples = ops.constant(num_samples_val, dtype=np.int32)
op = ops.multinomial(probs, num_samples,
convert_type=convert_type,
with_replacement=with_replacement,
log_probs=log_probs,
global_seed=global_seed,
op_seed=op_seed)
assert op.get_output_size() == 1
assert op.get_type_name() == "Multinomial"
assert op.get_output_element_type(0) == Type.i32 if convert_type == "i32" else Type.i64
assert op.get_output_partial_shape(0) == expected_out_shape
@pytest.mark.parametrize(
("probs_shape", "num_samples_shape", "convert_type", "with_replacement", "log_probs", "expected_out_shape"),
[
([10], [1], "i32", True, True, PartialShape([-1])),
([2, 16], [], "i64", False, False, PartialShape([2, -1])),
],
)
def test_multinomial_default_attrs(probs_shape, num_samples_shape, convert_type, with_replacement, log_probs, expected_out_shape):
probs = ops.parameter(probs_shape, dtype=np.float32)
num_samples = ops.parameter(num_samples_shape, dtype=np.int32)
op = ops.multinomial(probs, num_samples,
convert_type=convert_type,
with_replacement=with_replacement,
log_probs=log_probs)
assert op.get_output_size() == 1
assert op.get_type_name() == "Multinomial"
assert op.get_output_element_type(0) == Type.i32 if convert_type == "i32" else Type.i64
assert op.get_output_partial_shape(0) == expected_out_shape