diff --git a/src/core/include/openvino/op/add.hpp b/src/core/include/openvino/op/add.hpp index 054ec3302d8..0a83c97f131 100644 --- a/src/core/include/openvino/op/add.hpp +++ b/src/core/include/openvino/op/add.hpp @@ -38,11 +38,6 @@ public: std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; - bool visit_attributes(AttributeVisitor& visitor) override; - - OPENVINO_SUPPRESS_DEPRECATED_START - bool evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const override; - OPENVINO_SUPPRESS_DEPRECATED_END bool evaluate(TensorVector& outputs, const TensorVector& inputs) const override; bool has_evaluate() const override; }; diff --git a/src/core/reference/include/openvino/reference/add.hpp b/src/core/reference/include/openvino/reference/add.hpp index 85357de726d..4b097ec2bb2 100644 --- a/src/core/reference/include/openvino/reference/add.hpp +++ b/src/core/reference/include/openvino/reference/add.hpp @@ -4,30 +4,37 @@ #pragma once +#include #include -#include "ngraph/shape_util.hpp" #include "openvino/reference/autobroadcast_binop.hpp" namespace ov { namespace reference { -template -void add(const T* arg0, const T* arg1, T* out, size_t count) { - for (size_t i = 0; i < count; i++) { - out[i] = arg0[i] + arg1[i]; - } + +template +void add(const T* arg0, const T* arg1, T* out, const size_t count) { + std::transform(arg0, std::next(arg0, count), arg1, out, std::plus()); } -template +/** + * @brief Reference implementation of binary elementwise Add operator. + * + * @param arg0 Pointer to input 0 data. + * @param arg1 Pointer to input 1 data. + * @param out Pointer to output data. + * @param arg_shape0 Input 0 shape. + * @param arg_shape1 Input 1 shape. + * @param broadcast_spec Broadcast specification mode. + */ +template void add(const T* arg0, const T* arg1, T* out, const Shape& arg0_shape, const Shape& arg1_shape, const op::AutoBroadcastSpec& broadcast_spec) { - autobroadcast_binop(arg0, arg1, out, arg0_shape, arg1_shape, broadcast_spec, [](T x, T y) -> T { - return x + y; - }); + autobroadcast_binop(arg0, arg1, out, arg0_shape, arg1_shape, broadcast_spec, std::plus()); } } // namespace reference } // namespace ov diff --git a/src/core/shape_inference/CMakeLists.txt b/src/core/shape_inference/CMakeLists.txt index 611d118dd31..b04f0cf8573 100644 --- a/src/core/shape_inference/CMakeLists.txt +++ b/src/core/shape_inference/CMakeLists.txt @@ -23,7 +23,8 @@ set_target_properties(${TARGET_NAME} PROPERTIES EXPORT_NAME shape_inference) target_include_directories(${TARGET_NAME} PUBLIC $ - $) + $ + $>) ov_add_clang_format_target(${TARGET_NAME}_clang FOR_TARGETS ${TARGET_NAME}) diff --git a/src/core/shape_inference/include/utils.hpp b/src/core/shape_inference/include/utils.hpp index 9815f5d1bf0..7a1193f3a25 100644 --- a/src/core/shape_inference/include/utils.hpp +++ b/src/core/shape_inference/include/utils.hpp @@ -411,6 +411,17 @@ ov::optional get_input_bounds(const ov::Node* op, size_t port, const IT } return out; } + +/** + * @brief Inference broadcast shape for element wise operator according to broadcast specification stored in operator. + * + * @param op Pointer to operator. + * @param first First input shape. + * @param second Second input shape. + * + * @return Result shape from inputs with applied broadcast specification. + */ +ov::Shape infer_broadcast_shape(const ov::Node* const op, const ov::Shape& first, const ov::Shape& second); } // namespace op /** diff --git a/src/core/shape_inference/src/utils.cpp b/src/core/shape_inference/src/utils.cpp new file mode 100644 index 00000000000..c89221d286a --- /dev/null +++ b/src/core/shape_inference/src/utils.cpp @@ -0,0 +1,16 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "utils.hpp" + +#include "eltwise_shape_inference.hpp" + +namespace ov { +namespace op { + +ov::Shape infer_broadcast_shape(const ov::Node* const op, const ov::Shape& first, const ov::Shape& second) { + return eltwise_shape_infer(op, std::vector{first, second}).front().to_shape(); +} +} // namespace op +} // namespace ov diff --git a/src/core/src/op/add.cpp b/src/core/src/op/add.cpp index 8be44457dc3..316f71b3ebc 100644 --- a/src/core/src/op/add.cpp +++ b/src/core/src/op/add.cpp @@ -2,111 +2,83 @@ // SPDX-License-Identifier: Apache-2.0 // -#include "ngraph/op/add.hpp" +#include "openvino/op/add.hpp" +#include "element_visitor.hpp" #include "itt.hpp" -#include "ngraph/runtime/host_tensor.hpp" #include "openvino/reference/add.hpp" +#include "utils.hpp" -using namespace std; -using namespace ngraph; - -OPENVINO_SUPPRESS_DEPRECATED_START +namespace ov { +namespace op { namespace add { -namespace { -template -bool evaluate(const HostTensorPtr& arg0, - const HostTensorPtr& arg1, - const HostTensorPtr& out, - const op::AutoBroadcastSpec& broadcast_spec) { - ov::reference::add(arg0->get_data_ptr(), - arg1->get_data_ptr(), - out->get_data_ptr(), - arg0->get_shape(), - arg1->get_shape(), - broadcast_spec); - return true; -} +struct Evaluate : element::NoAction { + using ov::element::NoAction::visit; -bool evaluate_add(const HostTensorPtr& arg0, - const HostTensorPtr& arg1, - const HostTensorPtr& out, - const op::AutoBroadcastSpec& broadcast_spec) { - bool rc = true; - out->set_broadcast(broadcast_spec, arg0, arg1); - switch (arg0->get_element_type()) { - NGRAPH_TYPE_CASE(evaluate_add, i8, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, i16, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, i32, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, i64, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, u8, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, u16, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, u32, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, u64, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, bf16, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, f16, arg0, arg1, out, broadcast_spec); - NGRAPH_TYPE_CASE(evaluate_add, f32, arg0, arg1, out, broadcast_spec); - default: - rc = false; - break; + template + static result_type visit(const Tensor& in0, + const Tensor& in1, + Tensor& out, + const AutoBroadcastSpec& broadcast_spec) { + using T = typename element_type_traits::value_type; + reference::add(in0.data(), + in1.data(), + out.data(), + in0.get_shape(), + in1.get_shape(), + broadcast_spec); + return true; } - return rc; -} -} // namespace +}; } // namespace add // ------------------------------- v1 ------------------------------------------ - -op::v1::Add::Add(const Output& arg0, const Output& arg1, const AutoBroadcastSpec& auto_broadcast) +namespace v1 { +Add::Add(const Output& arg0, const Output& arg1, const AutoBroadcastSpec& auto_broadcast) : BinaryElementwiseArithmetic(arg0, arg1, auto_broadcast) { constructor_validate_and_infer_types(); } -bool op::v1::Add::visit_attributes(AttributeVisitor& visitor) { - OV_OP_SCOPE(v1_Add_visit_attributes); - BinaryElementwiseArithmetic::visit_attributes(visitor); - return true; -} - -shared_ptr op::v1::Add::clone_with_new_inputs(const OutputVector& new_args) const { +std::shared_ptr Add::clone_with_new_inputs(const OutputVector& new_args) const { OV_OP_SCOPE(v1_Add_clone_with_new_inputs); check_new_args_count(this, new_args); - return make_shared(new_args.at(0), new_args.at(1), this->get_autob()); + return std::make_shared(new_args.at(0), new_args.at(1), this->get_autob()); } -bool op::v1::Add::evaluate(const HostTensorVector& outputs, const HostTensorVector& inputs) const { +bool Add::evaluate(ov::TensorVector& outputs, const ov::TensorVector& inputs) const { OV_OP_SCOPE(v1_Add_evaluate); - return add::evaluate_add(inputs[0], inputs[1], outputs[0], get_autob()); + OPENVINO_ASSERT(outputs.size() == 1); + OPENVINO_ASSERT(inputs.size() == 2); + + outputs[0].set_shape(infer_broadcast_shape(this, inputs[0].get_shape(), inputs[1].get_shape())); + using namespace ov::element; + return IfTypeOf::apply( + inputs[0].get_element_type(), + inputs[0], + inputs[1], + outputs[0], + get_autob()); } -bool op::v1::Add::evaluate(ov::TensorVector& outputs, const ov::TensorVector& inputs) const { - OV_OP_SCOPE(v1_Add_evaluate); - if (std::none_of(inputs.cbegin(), inputs.cend(), [](const ov::Tensor& t) { - return is_vector(t.get_shape()) && t.get_shape().front() == 0; - })) { - return BinaryElementwiseArithmetic::evaluate(outputs, inputs); - } else { - return true; - } -} - -bool op::v1::Add::has_evaluate() const { +bool Add::has_evaluate() const { OV_OP_SCOPE(v1_Add_has_evaluate); switch (get_input_element_type(0)) { - case ngraph::element::i8: - case ngraph::element::i16: - case ngraph::element::i32: - case ngraph::element::i64: - case ngraph::element::u8: - case ngraph::element::u16: - case ngraph::element::u32: - case ngraph::element::u64: - case ngraph::element::bf16: - case ngraph::element::f16: - case ngraph::element::f32: + case element::i8: + case element::i16: + case element::i32: + case element::i64: + case element::u8: + case element::u16: + case element::u32: + case element::u64: + case element::bf16: + case element::f16: + case element::f32: return true; default: - break; + return false; } - return false; } +} // namespace v1 +} // namespace op +} // namespace ov diff --git a/src/core/src/op/mod.cpp b/src/core/src/op/mod.cpp index 00c24551491..6bb45da0400 100644 --- a/src/core/src/op/mod.cpp +++ b/src/core/src/op/mod.cpp @@ -7,7 +7,7 @@ #include "element_visitor.hpp" #include "itt.hpp" #include "openvino/reference/mod.hpp" -#include "shape_util.hpp" +#include "utils.hpp" namespace ov { namespace op { @@ -49,7 +49,7 @@ bool Mod::evaluate(ov::TensorVector& outputs, const ov::TensorVector& inputs) co OPENVINO_ASSERT(outputs.size() == 1); OPENVINO_ASSERT(inputs.size() == 2); - outputs[0].set_shape(ov::util::get_broadcast_shape(inputs[0].get_shape(), inputs[1].get_shape(), get_autob())); + outputs[0].set_shape(infer_broadcast_shape(this, inputs[0].get_shape(), inputs[1].get_shape())); using namespace ov::element; return IfTypeOf::apply(inputs[0].get_element_type(), inputs[0], diff --git a/src/core/src/op/xor.cpp b/src/core/src/op/xor.cpp index 8a3b9c9e2c4..a571e47618e 100644 --- a/src/core/src/op/xor.cpp +++ b/src/core/src/op/xor.cpp @@ -8,7 +8,7 @@ #include "itt.hpp" #include "openvino/op/logical_xor.hpp" #include "openvino/reference/xor.hpp" -#include "shape_util.hpp" +#include "utils.hpp" namespace ov { namespace op { @@ -37,18 +37,17 @@ bool input_supported_type(const element::Type& et) { return et == element::boolean; } -bool evaluate(TensorVector& outputs, const TensorVector& inputs, const AutoBroadcastSpec& broadcast_spec) { +bool evaluate(const Node* const op, TensorVector& outputs, const TensorVector& inputs) { OPENVINO_ASSERT(outputs.size() == 1); OPENVINO_ASSERT(inputs.size() == 2); - outputs[0].set_shape(ov::util::get_broadcast_shape(inputs[0].get_shape(), inputs[1].get_shape(), broadcast_spec)); - + outputs[0].set_shape(infer_broadcast_shape(op, inputs[0].get_shape(), inputs[1].get_shape())); using namespace ov::element; return IfTypeOf::apply(inputs[0].get_element_type(), inputs[0], inputs[1], outputs[0], - broadcast_spec); + op->get_autob()); } } // namespace } // namespace logxor @@ -68,7 +67,7 @@ std::shared_ptr Xor::clone_with_new_inputs(const OutputVector& new_args) c bool Xor::evaluate(TensorVector& outputs, const TensorVector& inputs) const { OV_OP_SCOPE(v0_Xor_evaluate); - return logxor::evaluate(outputs, inputs, get_autob()); + return logxor::evaluate(this, outputs, inputs); } bool Xor::has_evaluate() const { @@ -92,7 +91,7 @@ std::shared_ptr LogicalXor::clone_with_new_inputs(const OutputVector& new_ bool LogicalXor::evaluate(TensorVector& outputs, const TensorVector& inputs) const { OV_OP_SCOPE(v1_LogicalXor_evaluate); - return logxor::evaluate(outputs, inputs, get_autob()); + return logxor::evaluate(this, outputs, inputs); } bool LogicalXor::has_evaluate() const { diff --git a/src/core/tests/pass/constant_folding.cpp b/src/core/tests/pass/constant_folding.cpp index 672f272d794..005d5c4b8bf 100644 --- a/src/core/tests/pass/constant_folding.cpp +++ b/src/core/tests/pass/constant_folding.cpp @@ -3847,7 +3847,7 @@ public: const ov::op::AutoBroadcastSpec& auto_broadcast = ov::op::AutoBroadcastSpec(ov::op::AutoBroadcastType::NUMPY)) : ov::op::v1::Add(arg0, arg1, auto_broadcast) { ON_CALL(*this, evaluate).WillByDefault([this](ov::TensorVector& outputs, const ov::TensorVector& inputs) { - return ov::Node::evaluate(outputs, inputs); + return ov::op::v1::Add::evaluate(outputs, inputs); }); } MOCK_METHOD(bool,