Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Util to set (auto) names on model's input, output tensors #28975

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
59 changes: 21 additions & 38 deletions src/bindings/python/src/pyopenvino/graph/model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "openvino/core/except.hpp"
#include "openvino/core/graph_util.hpp"
#include "openvino/core/model.hpp" // ov::Model
#include "openvino/core/model_util.hpp"
#include "openvino/core/partial_shape.hpp"
#include "openvino/op/assign.hpp"
#include "openvino/op/parameter.hpp" // ov::op::v0::Parameter
Expand All @@ -30,15 +31,14 @@ using PyRTMap = ov::RTMap;

PYBIND11_MAKE_OPAQUE(PyRTMap);

static void set_tensor_names(const ov::ParameterVector& parameters) {
for (const auto& param : parameters) {
ov::Output<ov::Node> p = param;
if (p.get_node()->output(0).get_names().empty()) {
std::unordered_set<std::string> p_names({p.get_node()->get_friendly_name()});
p.get_node()->output(0).set_names(p_names);
}
}
namespace {
template <class... Args>
std::shared_ptr<ov::Model> make_model_with_tensor_names(Args&&... args) {
auto model = std::make_shared<ov::Model>(std::forward<Args>(args)...);
ov::util::set_tensors_names(ov::AUTO, *model);
return model;
}
} // namespace

static std::shared_ptr<ov::Node> get_node_ptr(std::shared_ptr<ov::Node> node) {
return node;
Expand Down Expand Up @@ -163,9 +163,8 @@ void regclass_graph_Model(py::module m) {
const std::vector<std::shared_ptr<ov::Node>>& nodes,
const ov::ParameterVector& params,
const std::string& name) {
set_tensor_names(params);
const auto sinks = cast_to_sink_vector(nodes);
auto model = std::make_shared<ov::Model>(res, sinks, params, name);
auto model = make_model_with_tensor_names(res, sinks, params, name);
set_correct_variables_for_assign_ops(model, sinks);
return model;
}),
Expand All @@ -189,8 +188,7 @@ void regclass_graph_Model(py::module m) {
model.def(py::init([](const std::vector<std::shared_ptr<ov::Node>>& results,
const ov::ParameterVector& parameters,
const std::string& name) {
set_tensor_names(parameters);
return std::make_shared<ov::Model>(results, parameters, name);
return make_model_with_tensor_names(results, parameters, name);
}),
py::arg("results"),
py::arg("parameters"),
Expand All @@ -209,8 +207,7 @@ void regclass_graph_Model(py::module m) {
model.def(py::init([](const std::shared_ptr<ov::Node>& result,
const ov::ParameterVector& parameters,
const std::string& name) {
set_tensor_names(parameters);
return std::make_shared<ov::Model>(result, parameters, name);
return make_model_with_tensor_names(result, parameters, name);
}),
py::arg("result"),
py::arg("parameters"),
Expand All @@ -228,8 +225,7 @@ void regclass_graph_Model(py::module m) {

model.def(
py::init([](const ov::OutputVector& results, const ov::ParameterVector& parameters, const std::string& name) {
set_tensor_names(parameters);
return std::make_shared<ov::Model>(results, parameters, name);
return make_model_with_tensor_names(results, parameters, name);
}),
py::arg("results"),
py::arg("parameters"),
Expand All @@ -249,9 +245,8 @@ void regclass_graph_Model(py::module m) {
const std::vector<std::shared_ptr<ov::Node>>& nodes,
const ov::ParameterVector& parameters,
const std::string& name) {
set_tensor_names(parameters);
const auto sinks = cast_to_sink_vector(nodes);
auto model = std::make_shared<ov::Model>(results, sinks, parameters, name);
auto model = make_model_with_tensor_names(results, sinks, parameters, name);
set_correct_variables_for_assign_ops(model, sinks);
return model;
}),
Expand All @@ -276,9 +271,8 @@ void regclass_graph_Model(py::module m) {
const ov::OutputVector& nodes,
const ov::ParameterVector& parameters,
const std::string& name) {
set_tensor_names(parameters);
const auto sinks = cast_to_sink_vector(nodes);
auto model = std::make_shared<ov::Model>(results, sinks, parameters, name);
auto model = make_model_with_tensor_names(results, sinks, parameters, name);
set_correct_variables_for_assign_ops(model, sinks);
return model;
}),
Expand All @@ -304,9 +298,7 @@ void regclass_graph_Model(py::module m) {
const ov::ParameterVector& parameters,
const ov::op::util::VariableVector& variables,
const std::string& name) {
set_tensor_names(parameters);
const auto sinks = cast_to_sink_vector(nodes);
return std::make_shared<ov::Model>(results, sinks, parameters, variables, name);
return make_model_with_tensor_names(results, cast_to_sink_vector(nodes), parameters, variables, name);
}),
py::arg("results"),
py::arg("sinks"),
Expand All @@ -332,9 +324,8 @@ void regclass_graph_Model(py::module m) {
const ov::OutputVector& nodes,
const ov::ParameterVector& parameters,
const std::string& name) {
set_tensor_names(parameters);
const auto sinks = cast_to_sink_vector(nodes);
auto model = std::make_shared<ov::Model>(results, sinks, parameters, name);
auto model = make_model_with_tensor_names(results, sinks, parameters, name);
set_correct_variables_for_assign_ops(model, sinks);
return model;
}),
Expand All @@ -360,9 +351,7 @@ void regclass_graph_Model(py::module m) {
const ov::ParameterVector& parameters,
const ov::op::util::VariableVector& variables,
const std::string& name) {
set_tensor_names(parameters);
const auto sinks = cast_to_sink_vector(nodes);
return std::make_shared<ov::Model>(results, sinks, parameters, variables, name);
return make_model_with_tensor_names(results, cast_to_sink_vector(nodes), parameters, variables, name);
}),
py::arg("results"),
py::arg("sinks"),
Expand All @@ -389,9 +378,7 @@ void regclass_graph_Model(py::module m) {
const ov::ParameterVector& parameters,
const ov::op::util::VariableVector& variables,
const std::string& name) {
set_tensor_names(parameters);
const auto sinks = cast_to_sink_vector(nodes);
return std::make_shared<ov::Model>(results, sinks, parameters, variables, name);
return make_model_with_tensor_names(results, cast_to_sink_vector(nodes), parameters, variables, name);
}),
py::arg("results"),
py::arg("sinks"),
Expand All @@ -418,9 +405,7 @@ void regclass_graph_Model(py::module m) {
const ov::ParameterVector& parameters,
const ov::op::util::VariableVector& variables,
const std::string& name) {
set_tensor_names(parameters);
const auto sinks = cast_to_sink_vector(nodes);
return std::make_shared<ov::Model>(results, sinks, parameters, variables, name);
return make_model_with_tensor_names(results, cast_to_sink_vector(nodes), parameters, variables, name);
}),
py::arg("results"),
py::arg("sinks"),
Expand All @@ -444,8 +429,7 @@ void regclass_graph_Model(py::module m) {
const ov::ParameterVector& parameters,
const ov::op::util::VariableVector& variables,
const std::string& name) {
set_tensor_names(parameters);
return std::make_shared<ov::Model>(results, parameters, variables, name);
return make_model_with_tensor_names(results, parameters, variables, name);
}),
py::arg("results"),
py::arg("parameters"),
Expand All @@ -468,8 +452,7 @@ void regclass_graph_Model(py::module m) {
const ov::ParameterVector& parameters,
const ov::op::util::VariableVector& variables,
const std::string& name) {
set_tensor_names(parameters);
return std::make_shared<ov::Model>(results, parameters, variables, name);
return make_model_with_tensor_names(results, parameters, variables, name);
}),
py::arg("results"),
py::arg("parameters"),
Expand Down
6 changes: 4 additions & 2 deletions src/bindings/python/tests/test_graph/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from openvino import Dimension, Model, PartialShape, Shape

import openvino.opset8 as ov
import openvino.opset13 as ov


def test_dimension():
Expand Down Expand Up @@ -408,14 +408,16 @@ def test_repr_dynamic_shape():
parameter_a = ov.parameter(shape, dtype=np.float32, name="A")
parameter_b = ov.parameter(shape, dtype=np.float32, name="B")
param_sum = parameter_a + parameter_b
# set tensor name to have deterministic output name of model (default use unique node name)
param_sum.output(0).set_names({"sum"})
model = Model(param_sum, [parameter_a, parameter_b], "simple_dyn_shapes_graph")

assert (
repr(model)
== "<Model: 'simple_dyn_shapes_graph'\ninputs["
+ "\n<ConstOutput: names[A] shape[?,2] type: f32>,"
+ "\n<ConstOutput: names[B] shape[?,2] type: f32>\n]"
+ "\noutputs[\n<ConstOutput: names[] shape[?,2] type: f32>\n]>"
+ "\noutputs[\n<ConstOutput: names[sum] shape[?,2] type: f32>\n]>"
)

ops = model.get_ordered_ops()
Expand Down
4 changes: 2 additions & 2 deletions src/bindings/python/tests/test_runtime/test_ovdict.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ def test_ovdict_single_output_noname(device, is_direct):
_ = result["some_name"]
assert "some_name" in str(e0.value)

# Check if returned names are tuple with one empty set
# Check if returned names are tuple with one default name set
assert len(result.names()) == 1
assert result.names()[0] == set()
assert result.names()[0] != set()


@pytest.mark.parametrize("is_direct", [True, False])
Expand Down
3 changes: 3 additions & 0 deletions src/core/dev_api/openvino/core/descriptor_tensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
namespace ov {
namespace descriptor {

/// @brief Defines tensor name port separator.
inline constexpr auto port_separator = ':';

class Tensor;
class Input;
class Output;
Expand Down
95 changes: 95 additions & 0 deletions src/core/dev_api/openvino/core/model_util.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (C) 2018-2025 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include <unordered_map>

#include "openvino/core/core_visibility.hpp"
#include "openvino/core/descriptor/tensor.hpp"
#include "openvino/core/model.hpp"

namespace ov {

/** @brief Generic atg suggests automated functionality.
*
* Can be use for template specialization or function overloading
*/
struct AutoTag {};
inline constexpr AutoTag AUTO{};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe to wrap it into one more namespace (ov::util::AUTO or ov::name::AUTO or smth else)?
ov::AUTO looks unobvious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is generic purpose Tag it will be easier use it from main ov namespace.


/** @brief Alias to map of port number and tensor names */
using TensorNamesMap = std::unordered_map<size_t, TensorNames>;
} // namespace ov

namespace ov::util {

/** @brief Set input tensors names for the model
*
* Sets only tensors defined in the input map.
* The tensors defined in map but not existing in the model will be ignored.
*
* @param model Model to set its input tensors names.
* @param inputs_names Map of input tensor names.
*/
OPENVINO_API void set_input_tensors_names(Model& model, const TensorNamesMap& inputs_names);

/** @brief Set input tensors names for the model
*
* Sets tensors defined in the input map others on others set to default names if there is no name.
* The tensors defined in map but not existing in the model will be ignored.
*
* @param model Model to set its input tensors names.
* @param inputs_names Map of input tensor names. Default empty.
*/
OPENVINO_API void set_input_tensors_names(const AutoTag&, Model& model, const TensorNamesMap& inputs_names = {});

/** @brief Set output tensors names for the model
*
* Sets only tensors defined in the output map.
* The tensors defined in map but not existing in the model will be ignored.
*
* @param model Model to set its output tensors names.
* @param outputs_names Map of output tensor names.AnyMap
*/
OPENVINO_API void set_output_tensor_names(Model& model, const TensorNamesMap& outputs_names);

/** @brief Set output tensors names for the model.
*
* Sets tensors defined in the output map others on others set to default names if there is no name.
* The tensors defined in map but not existing in the model will be ignored.
*
* @param model Model to set its output tensors names.
* @param outputs_names Map of output tensor names. Default empty.
*/
OPENVINO_API void set_output_tensor_names(const AutoTag&, Model& model, const TensorNamesMap& outputs_names = {});

/** @brief Set input and output tensors names for the model
*
* Sets only tensors defined in the input and output maps.
* The tensors defined in maps but not existing in the model will be ignored.
*
* @param model Model to set its input and output tensors names.
* @param inputs_names Map of input tensor names.
* @param outputs_names Map of output tensor names.
*/
OPENVINO_API void set_tensors_names(Model& model,
const TensorNamesMap& inputs_names,
const TensorNamesMap& outputs_names);

/** @brief Set input and output tensors names for the model.
*
* Sets tensors defined in the input and output maps others on others set to default names if there is no name.
* The tensors defined in map but not existing in the model will be ignored.
*
* @param model Model to set its input and output tensors names.
* @param inputs_names Map of input tensor names. Default empty.
* @param outputs_names Map of output tensor names. Default empty.
*/
OPENVINO_API void set_tensors_names(const AutoTag&,
Model& model,
const TensorNamesMap& inputs_names = {},
const TensorNamesMap& outputs_names = {});

} // namespace ov::util
17 changes: 14 additions & 3 deletions src/core/dev_api/openvino/op/util/node_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,29 @@

#pragma once

#include <string>

#include "openvino/core/node.hpp"

namespace ov {
namespace op {
namespace util {
/**
* @brief Creates default tensor name for given Node's output.
* The name format is "node_name:output_port".
*
* @param output - Node's output to create name for tensor.
* @return Default tensor name.
*/
OPENVINO_API std::string make_default_tensor_name(const Output<const Node>& output);
} // namespace util

namespace op::util {
/**
* @brief Set name for both node and output tensor. Any other names will be overriden by a given single name
* @param node - node to rename
* @param name - new name
* @param output_port - output port to rename
*/
void OPENVINO_API set_name(ov::Node& node, const std::string& name, size_t output_port = 0);
} // namespace util
} // namespace op
} // namespace op::util
} // namespace ov
2 changes: 2 additions & 0 deletions src/core/include/openvino/core/descriptor/tensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ using TensorSymbol = std::vector<std::shared_ptr<Symbol>>;
/// \brief Alias for vector of symbol tensors.
using TensorSymbolVector = std::vector<TensorSymbol>;

/// \brief Alias for set of tensor names.
using TensorNames = std::unordered_set<std::string>;
namespace descriptor {
class ITensorDescriptor;

Expand Down
Loading
Loading