From c95b3e51388b9a2c533b77a5a44d3d58877ed63c Mon Sep 17 00:00:00 2001 From: Anastasiia Pnevskaia Date: Wed, 19 Oct 2022 15:46:28 +0200 Subject: [PATCH] Moved MVN reference to ov::core. (#13327) * Moved MVN reference to ov::core. * Code style. * Applied comments. * Code style. * Returned evaluate in evaluates_map() * Added constant folding test. * Use new API. * Use new API. * Use new API. Co-authored-by: Evgenya Stepyreva --- src/core/include/openvino/op/mvn.hpp | 4 ++ .../include/ngraph/runtime/reference/mvn.hpp | 19 ++++++ src/core/src/op/mvn.cpp | 62 +++++++++++++++++++ .../transformations/const_folding_for_mvn.cpp | 47 ++++++++++++++ 4 files changed, 132 insertions(+) create mode 100644 src/tests/functional/inference_engine/transformations/const_folding_for_mvn.cpp diff --git a/src/core/include/openvino/op/mvn.hpp b/src/core/include/openvino/op/mvn.hpp index b87178bffe4..8c8a932a610 100644 --- a/src/core/include/openvino/op/mvn.hpp +++ b/src/core/include/openvino/op/mvn.hpp @@ -125,6 +125,10 @@ public: std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; + bool evaluate(ov::TensorVector& output_values, const ov::TensorVector& input_values) const override; + + bool has_evaluate() const override; + float get_eps() const { return m_eps; } diff --git a/src/core/reference/include/ngraph/runtime/reference/mvn.hpp b/src/core/reference/include/ngraph/runtime/reference/mvn.hpp index 7f4e96118a1..f4d09943823 100644 --- a/src/core/reference/include/ngraph/runtime/reference/mvn.hpp +++ b/src/core/reference/include/ngraph/runtime/reference/mvn.hpp @@ -86,6 +86,25 @@ void mvn_6(const T* arg, divide(out, tmp_buffer.data(), out, in_shape, reduced_shape, op::AutoBroadcastType::NUMPY, true); } } + +template +AxisSet mvn_6_reduction_axes(const ov::Tensor& axes_input, size_t rank) { + T* a = axes_input.data(); + auto v = std::vector(a, a + axes_input.get_shape()[0]); + std::vector axes(v.size(), 0); + for (size_t i = 0; i < v.size(); i++) { + if (v[i] < 0) { + if (rank + v[i] < 0) { + throw ov::Exception("Unexpected axis"); + } + axes[i] = (size_t)(rank + v[i]); + } else { + axes[i] = (size_t)(v[i]); + } + } + return AxisSet(axes); +} + } // namespace reference } // namespace runtime } // namespace ngraph diff --git a/src/core/src/op/mvn.cpp b/src/core/src/op/mvn.cpp index a4fd2be58fd..8562ba60b15 100644 --- a/src/core/src/op/mvn.cpp +++ b/src/core/src/op/mvn.cpp @@ -7,6 +7,7 @@ #include #include "itt.hpp" +#include "ngraph/runtime/reference/mvn.hpp" using namespace std; using namespace ngraph; @@ -135,3 +136,64 @@ bool op::v6::MVN::visit_attributes(AttributeVisitor& visitor) { visitor.on_attribute("eps_mode", m_eps_mode); return true; } + +namespace mvn { +namespace { +template +bool evaluate(ov::TensorVector& outputs, + const ov::TensorVector& inputs, + bool normalize_variance, + float eps, + ov::op::MVNEpsMode eps_mode) { + using T = typename element_type_traits::value_type; + AxisSet reduction_axes; + auto rank = inputs[0].get_shape().size(); + if (inputs[1].get_element_type() == element::i64) { + reduction_axes = runtime::reference::mvn_6_reduction_axes(inputs[1], rank); + } else if (inputs[1].get_element_type() == element::i32) { + reduction_axes = runtime::reference::mvn_6_reduction_axes(inputs[1], rank); + } else { + throw ov::Exception("Unexpected indices type"); + } + runtime::reference::mvn_6(inputs[0].data(), + outputs[0].data(), + inputs[0].get_shape(), + reduction_axes, + normalize_variance, + eps, + eps_mode); + return true; +} + +bool evaluate_mvn(ov::TensorVector& outputs, + const ov::TensorVector& inputs, + bool normalize_variance, + float eps, + ov::op::MVNEpsMode eps_mode) { + bool rc = true; + switch (inputs[0].get_element_type()) { + NGRAPH_TYPE_CASE(evaluate_mvn, f32, outputs, inputs, normalize_variance, eps, eps_mode); + default: + rc = false; + break; + } + return rc; +} +} // namespace +} // namespace mvn + +bool op::v6::MVN::evaluate(ov::TensorVector& outputs, const ov::TensorVector& inputs) const { + OV_OP_SCOPE(v6_MVN_evaluate); + return mvn::evaluate_mvn(outputs, inputs, get_normalize_variance(), get_eps(), get_eps_mode()); +} + +bool op::v6::MVN::has_evaluate() const { + OV_OP_SCOPE(v6_MVN_has_evaluate); + switch (get_input_element_type(0)) { + case ov::element::f32: + return true; + default: + break; + } + return false; +} diff --git a/src/tests/functional/inference_engine/transformations/const_folding_for_mvn.cpp b/src/tests/functional/inference_engine/transformations/const_folding_for_mvn.cpp new file mode 100644 index 00000000000..d22f0c0b707 --- /dev/null +++ b/src/tests/functional/inference_engine/transformations/const_folding_for_mvn.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include + +#include "common_test_utils/test_common.hpp" +#include "common_test_utils/graph_comparator.hpp" + +#include "openvino/opsets/opset10.hpp" +#include "openvino/pass/constant_folding.hpp" +#include "openvino/pass/manager.hpp" +#include "openvino/pass/pattern/op/wrap_type.hpp" +#include "openvino/core/validation_util.hpp" + +using namespace testing; +using namespace std; +using namespace ov; + + +TEST(TransformationTests, ConstFoldingMVN) { + shared_ptr fun(nullptr); + { + const auto in = make_shared(element::f32, Shape{6}); + const auto mvn_in = make_shared(element::f32, Shape{6}, vector(6, 0.0)); + const auto axes = make_shared(element::i32, Shape{1}, vector {0}); + auto mvn = make_shared(mvn_in, axes, false, 1e-9, op::MVNEpsMode::OUTSIDE_SQRT); + auto add = make_shared(in, mvn); + + fun = make_shared(NodeVector {add}, ParameterVector {in}); + + ov::pass::Manager manager; + manager.register_pass(); + manager.run_passes(fun); + } + shared_ptr f_ref(nullptr); + { + const auto in = make_shared(element::f32, Shape{6}); + const auto mvn_const = make_shared(element::f32, Shape{6}, vector(6, 0.0)); + auto add = make_shared(in, mvn_const); + + f_ref = make_shared(NodeVector {add}, ParameterVector {in}); + } + + auto res = compare_functions(fun, f_ref); + ASSERT_TRUE(res.first) << res.second; +}