[Python API] add_outputs api (#8626)
* [Python API] add_outputs api * add tests and missed api for tests * fix codestyle * add documentation * fix code style * fix building * add tensorDescriptor tests * add get_any_name and more checks * descriptor tensor name
This commit is contained in:
parent
83991607c3
commit
543584d577
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from openvino.pyopenvino import DescriptorTensor as Tensor
|
@ -0,0 +1,135 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "pyopenvino/graph/descriptors/tensor.hpp"
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
#include <pybind11/stl.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "openvino/core/descriptor/tensor.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
using PyRTMap = std::map<std::string, std::shared_ptr<ov::Variant>>;
|
||||
|
||||
PYBIND11_MAKE_OPAQUE(PyRTMap);
|
||||
|
||||
void regclass_graph_descriptor_Tensor(py::module m) {
|
||||
py::class_<ov::descriptor::Tensor, std::shared_ptr<ov::descriptor::Tensor>> tensor(m, "DescriptorTensor");
|
||||
|
||||
tensor.doc() = "openvino.descriptor.Tensor wraps ov::descriptor::Tensor";
|
||||
|
||||
tensor.def(py::init<const ov::element::Type, const ov::PartialShape, const std::string>(),
|
||||
py::arg("element_type"),
|
||||
py::arg("partial_shape"),
|
||||
py::arg("name"));
|
||||
|
||||
tensor.def("get_shape",
|
||||
&ov::descriptor::Tensor::get_shape,
|
||||
R"(
|
||||
Returns the shape description.
|
||||
|
||||
Returns
|
||||
----------
|
||||
get_shape : Shape
|
||||
The shape description.
|
||||
)");
|
||||
|
||||
tensor.def("get_rt_info",
|
||||
(PyRTMap & (ov::descriptor::Tensor::*)()) & ov::descriptor::Tensor::get_rt_info,
|
||||
py::return_value_policy::reference_internal,
|
||||
R"(
|
||||
Returns PyRTMap which is a dictionary of user defined runtime info.
|
||||
|
||||
Returns
|
||||
----------
|
||||
get_rt_info : PyRTMap
|
||||
A dictionary of user defined data.
|
||||
)");
|
||||
|
||||
tensor.def("size",
|
||||
&ov::descriptor::Tensor::size,
|
||||
R"(
|
||||
Returns the size description
|
||||
|
||||
Returns
|
||||
----------
|
||||
size : size_t
|
||||
The size description.
|
||||
)");
|
||||
|
||||
tensor.def("get_partial_shape",
|
||||
&ov::descriptor::Tensor::get_partial_shape,
|
||||
R"(
|
||||
Returns the partial shape description
|
||||
|
||||
Returns
|
||||
----------
|
||||
get_partial_shape : PartialShape
|
||||
PartialShape description.
|
||||
)");
|
||||
|
||||
tensor.def("get_element_type",
|
||||
&ov::descriptor::Tensor::get_element_type,
|
||||
R"(
|
||||
Returns the element type description
|
||||
|
||||
Returns
|
||||
----------
|
||||
get_element_type : Type
|
||||
Type description
|
||||
)");
|
||||
|
||||
tensor.def("get_names",
|
||||
&ov::descriptor::Tensor::get_names,
|
||||
R"(
|
||||
Returns names
|
||||
|
||||
Returns
|
||||
----------
|
||||
get_names : set
|
||||
Set of names
|
||||
)");
|
||||
|
||||
tensor.def("set_names",
|
||||
&ov::descriptor::Tensor::set_names,
|
||||
py::arg("names"),
|
||||
R"(
|
||||
Set names for tensor
|
||||
|
||||
Parameters
|
||||
----------
|
||||
names : set
|
||||
Set of names
|
||||
)");
|
||||
|
||||
tensor.def("get_any_name",
|
||||
&ov::descriptor::Tensor::get_any_name,
|
||||
R"(
|
||||
Returns any of set name
|
||||
|
||||
Returns
|
||||
----------
|
||||
get_any_name : string
|
||||
Any name
|
||||
)");
|
||||
|
||||
tensor.def_property_readonly("shape", &ov::descriptor::Tensor::get_shape);
|
||||
|
||||
tensor.def_property_readonly("rt_info",
|
||||
(PyRTMap & (ov::descriptor::Tensor::*)()) & ov::descriptor::Tensor::get_rt_info,
|
||||
py::return_value_policy::reference_internal);
|
||||
|
||||
tensor.def_property_readonly("size", &ov::descriptor::Tensor::size);
|
||||
|
||||
tensor.def_property_readonly("partial_shape", &ov::descriptor::Tensor::get_partial_shape);
|
||||
|
||||
tensor.def_property_readonly("element_type", &ov::descriptor::Tensor::get_element_type);
|
||||
|
||||
tensor.def_property_readonly("any_name", &ov::descriptor::Tensor::get_any_name);
|
||||
|
||||
tensor.def_property("names", &ov::descriptor::Tensor::get_names, &ov::descriptor::Tensor::set_names);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
// Copyright (C) 2021 Intel Corporation
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pybind11/pybind11.h>
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
void regclass_graph_descriptor_Tensor(py::module m);
|
@ -14,7 +14,7 @@
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
static const char* CAPSULE_NAME = "ngraph_function";
|
||||
static const char* CAPSULE_NAME = "openvino_function";
|
||||
|
||||
void set_tensor_names(const ov::ParameterVector& parameters) {
|
||||
for (const auto& param : parameters) {
|
||||
@ -352,6 +352,42 @@ void regclass_graph_Function(py::module m) {
|
||||
(ov::Output<const ov::Node>(ov::Function::*)(const std::string&) const) & ov::Function::output,
|
||||
py::arg("tensor_name"));
|
||||
|
||||
function.def(
|
||||
"add_outputs",
|
||||
[](ov::Function& self, py::handle& outputs) {
|
||||
int i = 0;
|
||||
py::list _outputs;
|
||||
if (!py::isinstance<py::list>(outputs)) {
|
||||
if (py::isinstance<py::str>(outputs)) {
|
||||
_outputs.append(outputs.cast<py::str>());
|
||||
} else if (py::isinstance<py::tuple>(outputs)) {
|
||||
_outputs.append(outputs.cast<py::tuple>());
|
||||
} else if (py::isinstance<ov::Output<ov::Node>>(outputs)) {
|
||||
_outputs.append(outputs.cast<ov::Output<ov::Node>>());
|
||||
} else {
|
||||
throw py::type_error("Incorrect type of a value to add as output.");
|
||||
}
|
||||
} else {
|
||||
_outputs = outputs.cast<py::list>();
|
||||
}
|
||||
|
||||
for (py::handle output : _outputs) {
|
||||
if (py::isinstance<py::str>(_outputs[i])) {
|
||||
self.add_output(output.cast<std::string>());
|
||||
} else if (py::isinstance<py::tuple>(output)) {
|
||||
py::tuple output_tuple = output.cast<py::tuple>();
|
||||
self.add_output(output_tuple[0].cast<std::string>(), output_tuple[1].cast<int>());
|
||||
} else if (py::isinstance<ov::Output<ov::Node>>(_outputs[i])) {
|
||||
self.add_output(output.cast<ov::Output<ov::Node>>());
|
||||
} else {
|
||||
throw py::type_error("Incorrect type of a value to add as output at index " + std::to_string(i) +
|
||||
".");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
},
|
||||
py::arg("outputs"));
|
||||
|
||||
function.def("__repr__", [](const ov::Function& self) {
|
||||
std::string class_name = py::cast(self).get_type().attr("__name__").cast<std::string>();
|
||||
std::stringstream shapes_ss;
|
||||
|
@ -149,6 +149,23 @@ void regclass_graph_Node(py::module m) {
|
||||
get_output_partial_shape : PartialShape
|
||||
PartialShape of the output i
|
||||
)");
|
||||
node.def("get_output_tensor",
|
||||
&ov::Node::get_output_tensor,
|
||||
py::arg("i"),
|
||||
py::return_value_policy::reference_internal,
|
||||
R"(
|
||||
Returns the tensor for output i
|
||||
|
||||
Parameters
|
||||
----------
|
||||
i : int
|
||||
Index of the output.
|
||||
|
||||
Returns
|
||||
----------
|
||||
get_output_tensor : descriptor.Tensor
|
||||
Tensor of the output i
|
||||
)");
|
||||
node.def("get_type_name",
|
||||
&ov::Node::get_type_name,
|
||||
R"(
|
||||
|
@ -81,4 +81,14 @@ void regclass_graph_Output(py::module m, std::string typestring)
|
||||
get_target_inputs : Set[Input]
|
||||
Set of Inputs.
|
||||
)");
|
||||
output.def("get_tensor",
|
||||
&ov::Output<VT>::get_tensor,
|
||||
py::return_value_policy::reference_internal,
|
||||
R"(
|
||||
A reference to the tensor descriptor for this output.
|
||||
Returns
|
||||
----------
|
||||
get_tensor : descriptor.Tensor
|
||||
Tensor of the output.
|
||||
)");
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "pyopenvino/core/tensor.hpp"
|
||||
#include "pyopenvino/core/variable_state.hpp"
|
||||
#include "pyopenvino/core/version.hpp"
|
||||
#include "pyopenvino/graph/descriptors/tensor.hpp"
|
||||
#include "pyopenvino/graph/dimension.hpp"
|
||||
#include "pyopenvino/graph/layout.hpp"
|
||||
#include "pyopenvino/graph/layout_helpers.hpp"
|
||||
@ -74,6 +75,7 @@ PYBIND11_MODULE(pyopenvino, m) {
|
||||
regclass_graph_AxisSet(m);
|
||||
regclass_graph_AxisVector(m);
|
||||
regclass_graph_Coordinate(m);
|
||||
regclass_graph_descriptor_Tensor(m);
|
||||
py::module m_op = m.def_submodule("op", "Package ngraph.impl.op that wraps ov::op"); // TODO(!)
|
||||
regclass_graph_op_Constant(m_op);
|
||||
regclass_graph_op_Parameter(m_op);
|
||||
|
@ -0,0 +1,142 @@
|
||||
# Copyright (C) 2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
import openvino.opset8 as ops
|
||||
|
||||
from openvino import Function
|
||||
from openvino.descriptor import Tensor
|
||||
from openvino.impl import PartialShape
|
||||
|
||||
|
||||
def test_function_add_outputs_tensor_name():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
assert "relu_t1" in relu1.get_output_tensor(0).names
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
function = Function(relu2, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
function.add_outputs("relu_t1")
|
||||
assert len(function.get_results()) == 2
|
||||
assert isinstance(function.outputs[1].get_tensor(), Tensor)
|
||||
assert "relu_t1" in function.outputs[1].get_tensor().names
|
||||
|
||||
|
||||
def test_function_add_outputs_op_name():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
function = Function(relu2, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
function.add_outputs(("relu1", 0))
|
||||
assert len(function.get_results()) == 2
|
||||
|
||||
|
||||
def test_function_add_output_port():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
function = Function(relu2, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
function.add_outputs(relu1.output(0))
|
||||
assert len(function.get_results()) == 2
|
||||
|
||||
|
||||
def test_function_add_output_incorrect_tensor_name():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
function = Function(relu2, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
with pytest.raises(RuntimeError) as e:
|
||||
function.add_outputs("relu_t")
|
||||
assert "Tensor name relu_t was not found." in str(e.value)
|
||||
|
||||
|
||||
def test_function_add_output_incorrect_idx():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
function = Function(relu2, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
with pytest.raises(RuntimeError) as e:
|
||||
function.add_outputs(("relu1", 10))
|
||||
assert "Cannot add output to port 10 operation relu1 has only 1 outputs." in str(e.value)
|
||||
|
||||
|
||||
def test_function_add_output_incorrect_name():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
function = Function(relu2, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
with pytest.raises(RuntimeError) as e:
|
||||
function.add_outputs(("relu_1", 0))
|
||||
assert "Port 0 for operation with name relu_1 was not found." in str(e.value)
|
||||
|
||||
|
||||
def test_add_outputs_several_tensors():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
relu2.get_output_tensor(0).set_names({"relu_t2"})
|
||||
relu3 = ops.relu(relu2, name="relu3")
|
||||
function = Function(relu3, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
function.add_outputs(["relu_t1", "relu_t2"])
|
||||
assert len(function.get_results()) == 3
|
||||
|
||||
|
||||
def test_add_outputs_several_ports():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
relu2.get_output_tensor(0).set_names({"relu_t2"})
|
||||
relu3 = ops.relu(relu2, name="relu3")
|
||||
function = Function(relu3, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
function.add_outputs([("relu1", 0), ("relu2", 0)])
|
||||
assert len(function.get_results()) == 3
|
||||
|
||||
|
||||
def test_add_outputs_incorrect_value():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
relu2 = ops.relu(relu1, name="relu2")
|
||||
function = Function(relu2, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
with pytest.raises(TypeError) as e:
|
||||
function.add_outputs(0)
|
||||
assert "Incorrect type of a value to add as output." in str(e.value)
|
||||
|
||||
|
||||
def test_add_outputs_incorrect_outputs_list():
|
||||
input_shape = PartialShape([1])
|
||||
param = ops.parameter(input_shape, dtype=np.float32, name="data")
|
||||
relu1 = ops.relu(param, name="relu1")
|
||||
relu1.get_output_tensor(0).set_names({"relu_t1"})
|
||||
function = Function(relu1, [param], "TestFunction")
|
||||
assert len(function.get_results()) == 1
|
||||
with pytest.raises(TypeError) as e:
|
||||
function.add_outputs([0, 0])
|
||||
assert "Incorrect type of a value to add as output at index 0" in str(e.value)
|
17
runtime/bindings/python/tests/test_ngraph/test_descriptor.py
Normal file
17
runtime/bindings/python/tests/test_ngraph/test_descriptor.py
Normal file
@ -0,0 +1,17 @@
|
||||
# Copyright (C) 2021 Intel Corporation
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from openvino.descriptor import Tensor
|
||||
from openvino.impl import Type, PartialShape
|
||||
|
||||
|
||||
def test_tensor_descriptor_api():
|
||||
td = Tensor(Type.f32, PartialShape([1, 1, 1, 1]), "tensor_name")
|
||||
td.names = {"tensor_name"}
|
||||
assert "tensor_name" in td.names
|
||||
assert isinstance(td, Tensor)
|
||||
assert td.element_type == Type.f32
|
||||
assert td.partial_shape == PartialShape([1, 1, 1, 1])
|
||||
assert repr(td.shape) == "<Shape: {1, 1, 1, 1}>"
|
||||
assert td.size == 4
|
||||
assert td.any_name == "tensor_name"
|
Loading…
Reference in New Issue
Block a user