From e3f1ff7f2a711001eb9c002b5d618c96382b4a21 Mon Sep 17 00:00:00 2001 From: Pawel Raasz Date: Tue, 12 Sep 2023 13:27:51 +0200 Subject: [PATCH] Migrate mod op evaluate (#19687) --- src/core/dev_api/shape_util.hpp | 45 ++++++ .../include/openvino/reference/mod.hpp | 36 ++++- src/core/src/op/mod.cpp | 128 ++++++++---------- src/core/src/shape_util.cpp | 8 ++ src/plugins/template/backend/ops/mod.cpp | 12 +- 5 files changed, 141 insertions(+), 88 deletions(-) diff --git a/src/core/dev_api/shape_util.hpp b/src/core/dev_api/shape_util.hpp index dc86d0ec0b1..fb935ed5127 100644 --- a/src/core/dev_api/shape_util.hpp +++ b/src/core/dev_api/shape_util.hpp @@ -27,10 +27,55 @@ OPENVINO_API Shape make_dynamic_shape(); OPENVINO_DEPRECATED("This function is deprecated and will be removed soon.") OPENVINO_API bool is_dynamic_shape(const Shape& s); +/** + * @brief Creates reduced shape from input by removing dimensions. + * + * @param input Input shape for reduce calculation. + * @param axes Reduction axes. + * @return Reduced shape. + */ OPENVINO_API Shape reduce(const Shape& input, const AxisSet& axes); + +/** + * @brief Creates reduced shape from input removing or replacing dimension. + * + * The reduction type depends on `keep_dims` flags. If it's set to true then reduced dimension will be replaced by `1`, + * otherwise removed. + * + * @param input Input shape for reduce calculation. + * @param axes Reduction axes. + * @param keep_dims Flag to keep reduced dimension. + * @return Reduced shape. + */ OPENVINO_API Shape reduce(const Shape& input, const AxisSet& axes, const bool keep_dims); + +/** + * @brief Creates reduced vector from input by removing elements. + * + * @param input Input vector for reduce calculation. + * @param axes Reduction axes. + * @return Reduced vector + */ OPENVINO_API std::vector reduce(const std::vector& input, const AxisSet& axes); +/** + * @brief Creates reduced shape from input by replacing reduced dimension with `1`. + * + * @param input Input shape for reduce calculation. + * @param axes Reduction axes. + * @return Reduced shape. + */ OPENVINO_API Shape reduce_keep_dims(const Shape& input, const AxisSet& axes); + +/** + * @brief Get the broadcast shape as merge second shape into first according to broadcast specification. + * + * @param first First input shape. + * @param second Second input shape. + * @param broadcast_spec Broadcast specification. + * + * @return Result shape from inputs with applied broadcast specification. + */ +Shape get_broadcast_shape(const Shape& first, const Shape& second, const op::AutoBroadcastSpec& broadcast_spec); } // namespace util } // namespace ov diff --git a/src/core/reference/include/openvino/reference/mod.hpp b/src/core/reference/include/openvino/reference/mod.hpp index 76af9cbe95a..81ae69e32eb 100644 --- a/src/core/reference/include/openvino/reference/mod.hpp +++ b/src/core/reference/include/openvino/reference/mod.hpp @@ -8,19 +8,41 @@ #include #include "openvino/reference/autobroadcast_binop.hpp" +#include "openvino/reference/utils/type_util.hpp" namespace ov { namespace reference { -template -void mod(const T* arg0, - const T* arg1, - T* out, +namespace func { +template ::value>::type* = nullptr> +constexpr T mod(const T x, const T y) { + return x % y; +} + +template ()>::type* = nullptr> +T mod(const T x, const T y) { + return x - (std::trunc(x / y) * y); +} +} // namespace func + +/** + * @brief Reference implementation of binary elementwise Mod operator. + * + * @param arg0 Iterator to input 0 data. + * @param arg1 Iterator to input 1 data. + * @param out Iterator to output data. + * @param arg_shape0 Input 0 shape. + * @param arg_shape1 Input 1 shape. + * @param broadcast_spec Broadcast specification mode. + */ +template +void mod(InputIt arg0, + InputIt arg1, + OutputIt out, const Shape& arg_shape0, const Shape& arg_shape1, const op::AutoBroadcastSpec& broadcast_spec) { - autobroadcast_binop(arg0, arg1, out, arg_shape0, arg_shape1, broadcast_spec, [](T x, T y) -> T { - return static_cast(x - std::truncf(static_cast(x / y)) * y); - }); + using T = typename std::iterator_traits::value_type; + autobroadcast_binop(arg0, arg1, out, arg_shape0, arg_shape1, broadcast_spec, &func::mod); } } // namespace reference } // namespace ov diff --git a/src/core/src/op/mod.cpp b/src/core/src/op/mod.cpp index 8e605815b88..00c24551491 100644 --- a/src/core/src/op/mod.cpp +++ b/src/core/src/op/mod.cpp @@ -2,101 +2,79 @@ // SPDX-License-Identifier: Apache-2.0 // -#include "ngraph/op/mod.hpp" +#include "openvino/op/mod.hpp" +#include "element_visitor.hpp" #include "itt.hpp" #include "openvino/reference/mod.hpp" +#include "shape_util.hpp" -using namespace std; -using namespace ngraph; +namespace ov { +namespace op { +namespace mod { +struct Evaluate : ov::element::NoAction { + using ov::element::NoAction::visit; -// ------------------------------ v1 ------------------------------------------- + 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::mod(in0.data(), + in1.data(), + out.data(), + in0.get_shape(), + in1.get_shape(), + broadcast_spec); + return true; + } +}; +} // namespace mod -op::v1::Mod::Mod(const Output& arg0, const Output& arg1, const AutoBroadcastSpec& auto_broadcast) +namespace v1 { +v1::Mod::Mod(const Output& arg0, const Output& arg1, const AutoBroadcastSpec& auto_broadcast) : BinaryElementwiseArithmetic(arg0, arg1, auto_broadcast) { constructor_validate_and_infer_types(); } -shared_ptr op::v1::Mod::clone_with_new_inputs(const OutputVector& new_args) const { +std::shared_ptr Mod::clone_with_new_inputs(const OutputVector& new_args) const { OV_OP_SCOPE(v1_Mod_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()); } -namespace mod_op { -namespace { -template -bool evaluate(const ov::Tensor& arg0, - const ov::Tensor& arg1, - const ov::Tensor& out, - const op::AutoBroadcastSpec& broadcast_spec) { - ov::reference::mod(arg0.data(), - arg1.data(), - out.data(), - arg0.get_shape(), - arg1.get_shape(), - broadcast_spec); - return true; -} - -bool evaluate_mod(const ov::Tensor& arg0, - const ov::Tensor& arg1, - const ov::Tensor& out, - const op::AutoBroadcastSpec& broadcast_spec) { - bool rc = true; - switch (arg0.get_element_type()) { - case ov::element::Type_t::i8: { - rc = evaluate(arg0, arg1, out, broadcast_spec); - } break; - case ov::element::Type_t::i16: { - rc = evaluate(arg0, arg1, out, broadcast_spec); - } break; - case ov::element::Type_t::i32: { - rc = evaluate(arg0, arg1, out, broadcast_spec); - } break; - case ov::element::Type_t::i64: { - rc = evaluate(arg0, arg1, out, broadcast_spec); - } break; - case ov::element::Type_t::u8: { - rc = evaluate(arg0, arg1, out, broadcast_spec); - } break; - case ov::element::Type_t::u16: { - rc = evaluate(arg0, arg1, out, broadcast_spec); - } break; - case ov::element::Type_t::u32: { - rc = evaluate(arg0, arg1, out, broadcast_spec); - } break; - case ov::element::Type_t::u64: { - rc = evaluate(arg0, arg1, out, broadcast_spec); - } break; - default: - rc = false; - break; - } - return rc; -} -} // namespace -} // namespace mod_op - -bool op::v1::Mod::evaluate(ov::TensorVector& outputs, const ov::TensorVector& inputs) const { +bool Mod::evaluate(ov::TensorVector& outputs, const ov::TensorVector& inputs) const { OV_OP_SCOPE(v1_Mod_evaluate); - return mod_op::evaluate_mod(inputs[0], inputs[1], outputs[0], get_autob()); + 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())); + using namespace ov::element; + return IfTypeOf::apply(inputs[0].get_element_type(), + inputs[0], + inputs[1], + outputs[0], + get_autob()); } -bool op::v1::Mod::has_evaluate() const { +bool Mod::has_evaluate() const { OV_OP_SCOPE(v1_Mod_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 element::i8: + case element::i16: + case element::i32: + case element::i64: + case element::u8: + case element::u16: + case element::u32: + case element::u64: return true; default: - break; + return false; } - return false; } +} // namespace v1 +} // namespace op +} // namespace ov diff --git a/src/core/src/shape_util.cpp b/src/core/src/shape_util.cpp index c0fc6219ec2..411adb7ba5b 100644 --- a/src/core/src/shape_util.cpp +++ b/src/core/src/shape_util.cpp @@ -6,6 +6,7 @@ #include +#include "openvino/core/partial_shape.hpp" #include "shape_util.hpp" using namespace ngraph; @@ -128,5 +129,12 @@ std::vector reduce(const std::vector& input, const AxisSet& axes Shape reduce_keep_dims(const Shape& input, const AxisSet& axes) { return ov::replace_container(input, axes); } + +Shape get_broadcast_shape(const Shape& first, const Shape& second, const op::AutoBroadcastSpec& broadcast_spec) { + auto out_shape = PartialShape(first); + OPENVINO_ASSERT(PartialShape::broadcast_merge_into(out_shape, second, broadcast_spec), + "Argument shapes are inconsistent"); + return out_shape.to_shape(); +} } // namespace util } // namespace ov diff --git a/src/plugins/template/backend/ops/mod.cpp b/src/plugins/template/backend/ops/mod.cpp index e84ef8ffe01..a8e4ac1cbc4 100644 --- a/src/plugins/template/backend/ops/mod.cpp +++ b/src/plugins/template/backend/ops/mod.cpp @@ -11,12 +11,12 @@ bool evaluate(const std::shared_ptr& op, const ngraph::HostTensorVector& outputs, const ngraph::HostTensorVector& inputs) { using T = typename ngraph::element_type_traits::value_type; - ov::reference::mod(inputs[0]->get_data_ptr(), - inputs[1]->get_data_ptr(), - outputs[0]->get_data_ptr(), - inputs[0]->get_shape(), - inputs[1]->get_shape(), - op->get_autob()); + ov::reference::mod(inputs[0]->get_data_ptr(), + inputs[1]->get_data_ptr(), + outputs[0]->get_data_ptr(), + inputs[0]->get_shape(), + inputs[1]->get_shape(), + op->get_autob()); return true; }