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

[PyAPI] Add Identity Operation #26717

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@
from openvino.runtime.opset15.ops import string_tensor_unpack
from openvino.runtime.opset15.ops import bitwise_left_shift
from openvino.runtime.opset15.ops import bitwise_right_shift
from openvino.runtime.opset15.ops import identity

23 changes: 23 additions & 0 deletions src/bindings/python/src/openvino/runtime/opset15/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,29 @@ def bitwise_left_shift(
)


@nameable_op
def bitwise_right_shift(
data: NodeInput,
copy: bool = False,
name: Optional[str] = None,
) -> Node:
"""Identity operation is used as a placeholder. It either passes down the input,
or creates a copy of the input to forward to the output.

:param data: Tensor with data.
:param copy: Boolean that defines the behavior of Identity. If false, input is passed as output, otherwise, a copy of input is created. Defaults to False.

:return: The new node performing BitwiseRightShift operation.
"""
return _get_node_factory_opset15().create(
"Identity",
as_nodes(data, name=name),
{
"copy": copy,
},
)


@binary_op
def bitwise_right_shift(
arg0: NodeInput,
Expand Down
30 changes: 30 additions & 0 deletions src/bindings/python/tests/test_graph/test_identity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright (C) 2018-2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

import numpy as np
import pytest

import openvino.runtime.opset14 as ops
from openvino import PartialShape, Type


@pytest.mark.parametrize(
("input_shape", "copy", "expected_output_shape"),
[
([4, 4], False, PartialShape([4, 4])),
([10, 8, 8], True, PartialShape([10, 8, 8])),
([-1, -1, -1], True, PartialShape([-1, -1, -1])),
([10, -1, -1], True, PartialShape([10, -1, -1])),
],
)
@pytest.mark.parametrize("op_name", ["identity", "identityOpset15"])
def test_inverse_param_inputs(input_shape, copy, expected_output_shape, op_name):
data = ops.parameter(input_shape, dtype=np.float32)

op = ops.inverse(data, copy=copy, name=op_name)
assert op.get_output_size() == 1
assert op.get_type_name() == "Identity"
assert op.get_friendly_name() == op_name
assert op.get_output_element_type(0) == Type.f32
assert op.get_output_partial_shape(0) == expected_output_shape

39 changes: 39 additions & 0 deletions src/core/include/openvino/op/identity.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include "openvino/op/op.hpp"

namespace ov {
namespace op {
namespace v15 {
/// \brief Identity operation is used as a placeholder op.
///
/// \ingroup ov_ops_cpp_api
class OPENVINO_API Identity : public Op {
public:
OPENVINO_OP("Identity", "opset15");
Identity() = default;
/**
* @brief Identity operation is used as a placeholder. It either passes the tensor down to the next layer,
* or copies the tensor to the output.
*
* @param copy Boolean that determines whether to copy the input to the output, or just return the output.
*/
Identity(const Output<Node>& data, const bool copy = false);

bool visit_attributes(AttributeVisitor& visitor) override;
void validate_and_infer_types() override;
std::shared_ptr<Node> clone_with_new_inputs(const OutputVector& new_args) const override;

bool get_copy() const;
void set_copy(const bool copy);

private:
bool m_copy;
};
} // namespace v15
} // namespace op
} // namespace ov
1 change: 1 addition & 0 deletions src/core/include/openvino/op/ops.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
#include "openvino/op/hswish.hpp"
#include "openvino/op/i420_to_bgr.hpp"
#include "openvino/op/i420_to_rgb.hpp"
#include "openvino/op/identity.hpp"
#include "openvino/op/idft.hpp"
#include "openvino/op/if.hpp"
#include "openvino/op/interpolate.hpp"
Expand Down
2 changes: 2 additions & 0 deletions src/core/include/openvino/opsets/opset15_tbl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ _OPENVINO_OP_REG(ScatterNDUpdate, ov::op::v15)
_OPENVINO_OP_REG(EmbeddingBagPacked, ov::op::v15)
_OPENVINO_OP_REG(EmbeddingBagOffsets, ov::op::v15)
_OPENVINO_OP_REG(Col2Im, ov::op::v15)

_OPENVINO_OP_REG(StringTensorUnpack, ov::op::v15)
_OPENVINO_OP_REG(StringTensorPack, ov::op::v15)
_OPENVINO_OP_REG(BitwiseLeftShift, ov::op::v15)
_OPENVINO_OP_REG(BitwiseRightShift, ov::op::v15)
_OPENVINO_OP_REG(SliceScatter, ov::op::v15)
_OPENVINO_OP_REG(Identity, ov::op::v15)
35 changes: 35 additions & 0 deletions src/core/reference/include/openvino/reference/identity.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#pragma once

#include <cstring>

#include "openvino/core/shape.hpp"

namespace ov {
namespace reference {
namespace identity {

/**
* @brief Identity operation computes the identity of the input tensor.
*
* @param input Input matrix (matrices) pointer.
* @param output Output matrix (matrices) pointer.
* @param copy Boolean that determines whether to return the input as output or
* copy the input to a new memory address.
**/
template <typename T>
void identity(const T** input, T** output, const Shape& shape, const bool copy) {
const auto total_elements = shape_size<Shape>(shape);

if (!copy) {
*output = *input;
} else {
std::memcpy(*output, *input, total_elements * sizeof(T));
}
}
} // namespace identity
} // namespace reference
} // namespace ov
49 changes: 49 additions & 0 deletions src/core/src/op/identity.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <cstring>

#include "itt.hpp"
#include "openvino/core/attribute_visitor.hpp"
#include "openvino/op/identity.hpp"
#include "openvino/op/util/op_types.hpp"
#include "openvino/reference/identity.hpp"

namespace ov {
namespace op {
namespace v15 {

Identity::Identity(const Output<Node>& data, const bool copy) : Op({data}), m_copy(copy) {
constructor_validate_and_infer_types();
}

bool Identity::Identity::visit_attributes(AttributeVisitor& visitor) {
OV_OP_SCOPE(v15_Identity_visit_attributes);
visitor.on_attribute("copy", m_copy);
return true;
}

void Identity::Identity::validate_and_infer_types() {
OV_OP_SCOPE(v15_Identity_validate_and_infer_types);

const auto input_shapes = ov::util::get_node_input_partial_shapes(*this);

set_output_type(0, get_input_element_type(0), input_shapes[0]);
}

std::shared_ptr<Node> Identity::Identity::clone_with_new_inputs(const OutputVector& new_args) const {
OV_OP_SCOPE(v15_Identity_clone_with_new_inputs);
check_new_args_count(this, new_args);

return std::make_shared<Identity>(new_args.at(0), m_copy);
}

bool Identity::get_copy() const {
return m_copy;
}

void Identity::set_copy(const bool copy) {
m_copy = copy;
}
} // namespace ov
2 changes: 1 addition & 1 deletion src/core/tests/opset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ INSTANTIATE_TEST_SUITE_P(opset,
OpsetTestParams{ov::get_opset12, 178},
OpsetTestParams{ov::get_opset13, 186},
OpsetTestParams{ov::get_opset14, 188},
OpsetTestParams{ov::get_opset15, 13}),
OpsetTestParams{ov::get_opset15, 14}),
OpsetTestNameGenerator{});

class MyOpOld : public ov::op::Op {
Expand Down
28 changes: 28 additions & 0 deletions src/core/tests/type_prop/identity.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "openvino/op/Identity.hpp"

#include <gtest/gtest.h>

#include "common_test_utils/test_assertions.hpp"
#include "common_test_utils/type_prop.hpp"
#include "openvino/op/constant.hpp"

using namespace testing;

class TypePropIdentityV15Test : public TypePropOpTest<ov::op::v15::Identity> {};

TEST_F(TypePropIdentityV15Test, default_ctor) {
const auto data = ov::op::v0::Constant::create(ov::element::f64, ov::Shape{2, 2}, {1.0f, 1.0f, 1.0f, 1.0f});
const auto op = make_op();
op->set_arguments(ov::OutputVector{data});
op->validate_and_infer_types();

EXPECT_EQ(op->get_input_size(), 1);
EXPECT_EQ(op->get_output_size(), 1);
EXPECT_EQ(op->get_output_element_type(0), ov::element::f64);
EXPECT_EQ(op->get_output_partial_shape(0), ov::PartialShape({2, 2}));
EXPECT_EQ(op->get_copy(), false);
}
25 changes: 25 additions & 0 deletions src/core/tests/visitors/op/identity.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "openvino/op/Identity.hpp"

#include <gtest/gtest.h>

#include "openvino/op/unique.hpp"
#include "visitors/visitors.hpp"

using ov::test::NodeBuilder;

TEST(attributes, Identity) {
NodeBuilder::opset().insert<ov::op::v15::Identity>();
const auto data = std::make_shared<ov::op::v0::Parameter>(ov::element::f32, ov::Shape{2, 2});

const auto op = std::make_shared<ov::op::v15::Identity>(data, true);
NodeBuilder builder(op, {data});
auto g_identity = ov::as_type_ptr<ov::op::v15::Identity>(builder.create());

constexpr auto expected_attr_count = 1;
EXPECT_EQ(builder.get_value_map_size(), expected_attr_count);
EXPECT_EQ(op->get_copy(), g_identity->get_copy());
}
65 changes: 65 additions & 0 deletions src/plugins/template/backend/ops/identity.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (C) 2018-2024 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include "openvino/reference/Identity.hpp"

#include "Identity_shape_inference.hpp"
#include "evaluate_node.hpp"

template <ov::element::Type_t ET>
inline bool evaluate(const std::shared_ptr<ov::op::v15::Identity>& op,
ov::TensorVector& outputs,
const ov::TensorVector& inputs) {
using T = typename ov::element_type_traits<ET>::value_type;

const std::vector<ov::PartialShape> input_shapes{op->get_input_shape(0)};
outputs[0].set_shape(input_shapes[0]);

ov::reference::Identity<T>(inputs[0].data<const T>(), outputs[0].data<T>(), out_shape, op->get_copy());
return true;
}

template <>
bool evaluate_node<ov::op::v15::Identity>(std::shared_ptr<ov::Node> node,
ov::TensorVector& outputs,
const ov::TensorVector& inputs) {
switch (node->get_input_element_type(0)) {
case ov::element::boolean:
return evaluate<ov::element::boolean>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::bf16:
return evaluate<ov::element::bf16>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::f16:
return evaluate<ov::element::f16>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::f64:
return evaluate<ov::element::f64>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::f32:
return evaluate<ov::element::f32>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::i4:
return evaluate<ov::element::i4>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::i8:
return evaluate<ov::element::i8>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::i16:
return evaluate<ov::element::i16>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::i32:
return evaluate<ov::element::i32>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::i64:
return evaluate<ov::element::i64>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::u1:
return evaluate<ov::element::u1>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::u4:
return evaluate<ov::element::u4>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::u8:
return evaluate<ov::element::u8>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::u16:
return evaluate<ov::element::u16>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::u32:
return evaluate<ov::element::u32>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
case ov::element::u64:
return evaluate<ov::element::u64>(ov::as_type_ptr<ov::op::v15::Identity>(node), outputs, inputs);
default:
OPENVINO_THROW("Unhandled input data type ",
node->get_input_element_type(0).get_type_name(),
" in evaluate_node().");
}
}
4 changes: 4 additions & 0 deletions src/plugins/template/backend/ops/ops_evaluates.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,10 @@ extern template bool evaluate_node<ov::op::v15::EmbeddingBagPacked>(std::shared_
ov::TensorVector& outputs,
const ov::TensorVector& inputs);

extern template bool evaluate_node<ov::op::v15::Identity>(std::shared_ptr<ov::Node> node,
ov::TensorVector& outputs,
const ov::TensorVector& inputs);

extern template bool evaluate_node<ov::op::v15::SliceScatter>(std::shared_ptr<ov::Node> node,
ov::TensorVector& outputs,
const ov::TensorVector& inputs);
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/template/backend/opset_int_tbl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,16 @@ _OPENVINO_OP_REG(AvgPool, ov::op::v14)
_OPENVINO_OP_REG(MaxPool, ov::op::v14)

_OPENVINO_OP_REG(ROIAlignRotated, ov::op::v15)

_OPENVINO_OP_REG(EmbeddingBagOffsets, op::v15)
_OPENVINO_OP_REG(EmbeddingBagPacked, op::v15)
_OPENVINO_OP_REG(Col2Im, ov::op::v15)

_OPENVINO_OP_REG(StringTensorUnpack, ov::op::v15)
_OPENVINO_OP_REG(StringTensorPack, ov::op::v15)
_OPENVINO_OP_REG(BitwiseLeftShift, ov::op::v15)
_OPENVINO_OP_REG(BitwiseRightShift, ov::op::v15)
_OPENVINO_OP_REG(SliceScatter, ov::op::v15)
_OPENVINO_OP_REG(Identity, ov::op::v15)

_OPENVINO_OP_REG(AUGRUCell, ov::op::internal)
_OPENVINO_OP_REG(AUGRUSequence, ov::op::internal)
Expand Down
Loading
Loading