diff --git a/src/core/include/openvino/op/scatter_nd_update.hpp b/src/core/include/openvino/op/scatter_nd_update.hpp index 653a6857f69d23..b791d9aa04383e 100644 --- a/src/core/include/openvino/op/scatter_nd_update.hpp +++ b/src/core/include/openvino/op/scatter_nd_update.hpp @@ -29,5 +29,55 @@ class OPENVINO_API ScatterNDUpdate : public util::ScatterNDBase { bool has_evaluate() const override; }; } // namespace v3 +namespace v14 { +/// \brief Add updates to slices from inputs addressed by indices +/// \ingroup ov_ops_cpp_api +class OPENVINO_API ScatterNDUpdate : public util::ScatterNDBase { +public: + OPENVINO_OP("ScatterNDUpdate", "opset14", util::ScatterNDBase); + + /// \brief Lists the supported reduction types for this version of the operator. + /// See the specification for the description of how reduction works with ScatterNDUpdate. + enum class Reduction { NONE, SUM, SUB, PROD, MIN, MAX }; + + ScatterNDUpdate() = default; + /// \param inputs Tensor + /// \param indices Index tensor: Data type must be `element::i32` or `element::i64` + /// \param updates Tensor: Must have same type as inputs + /// \param reduction Reduction: Type of operation to perform on inputs + ScatterNDUpdate(const Output& inputs, + const Output& indices, + const Output& updates, + const Reduction reduction = Reduction::NONE); + + std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; + bool visit_attributes(AttributeVisitor& visitor) override; + bool evaluate(TensorVector& outputs, const TensorVector& inputs) const override; + bool evaluate_lower(TensorVector& output_values) const override; + bool evaluate_upper(TensorVector& output_values) const override; + bool evaluate_symbol(TensorSymbolVector& output_symbols) const override; + bool has_evaluate() const override; + + Reduction get_reduction() const; + + void set_reduction(const Reduction reduction); + +private: + Reduction m_reduction = Reduction::NONE; +}; +} // namespace v14 } // namespace op + +OPENVINO_API +std::ostream& operator<<(std::ostream& s, const op::v14::ScatterNDUpdate::Reduction& reduction); + +template <> +class OPENVINO_API AttributeAdapter + : public EnumAttributeAdapterBase { +public: + AttributeAdapter(op::v14::ScatterNDUpdate::Reduction& value) + : EnumAttributeAdapterBase(value) {} + + OPENVINO_RTTI("AttributeAdapter"); +}; } // namespace ov diff --git a/src/core/include/openvino/opsets/opset14_tbl.hpp b/src/core/include/openvino/opsets/opset14_tbl.hpp index 1e1c520e475852..eba086b5c31240 100644 --- a/src/core/include/openvino/opsets/opset14_tbl.hpp +++ b/src/core/include/openvino/opsets/opset14_tbl.hpp @@ -87,7 +87,6 @@ _OPENVINO_OP_REG(Reshape, ov::op::v1) _OPENVINO_OP_REG(Result, ov::op::v0) _OPENVINO_OP_REG(ReverseSequence, ov::op::v0) _OPENVINO_OP_REG(ROIPooling, ov::op::v0) -_OPENVINO_OP_REG(ScatterNDUpdate, ov::op::v3) _OPENVINO_OP_REG(Select, ov::op::v1) _OPENVINO_OP_REG(Selu, ov::op::v0) _OPENVINO_OP_REG(Sign, ov::op::v0) @@ -221,3 +220,4 @@ _OPENVINO_OP_REG(FakeConvert, ov::op::v13) // New operations added in opset14 _OPENVINO_OP_REG(ConvertPromoteTypes, ov::op::v14) _OPENVINO_OP_REG(Inverse, ov::op::v14) +_OPENVINO_OP_REG(ScatterNDUpdate, ov::op::v14) diff --git a/src/core/reference/include/openvino/reference/scatter_nd_update.hpp b/src/core/reference/include/openvino/reference/scatter_nd_update.hpp index 8ce97e90902de4..86ee6f842a97dc 100644 --- a/src/core/reference/include/openvino/reference/scatter_nd_update.hpp +++ b/src/core/reference/include/openvino/reference/scatter_nd_update.hpp @@ -8,10 +8,82 @@ #include #include "openvino/core/shape.hpp" +#include "openvino/op/scatter_nd_update.hpp" +#include "openvino/reference/maximum.hpp" +#include "openvino/reference/minimum.hpp" +#include "openvino/reference/multiply.hpp" +#include "openvino/reference/xor.hpp" #include "utils/span.hpp" namespace ov { namespace reference { +using Reduction = ov::op::v14::ScatterNDUpdate::Reduction; +template +using reduction_function = T (*)(const T, const T); + +namespace func { +// TODO move this functions to other reference implementations to reduce binary size. Binary for +// ScatterElementsUpdate-12 can also be updated. Ticket: CVS-138266 +template +constexpr T add(const T a, const T b) { + return a + b; +} +template +constexpr T subtract(const T a, const T b) { + return a - b; +} + +template +constexpr T logical_and(const T a, const T b) { + return static_cast(a) && static_cast(b); +} + +template +constexpr T logical_or(const T a, const T b) { + return static_cast(a) || static_cast(b); +} + +} // namespace func + +template ::type, char>::value>::type* = nullptr> +reduction_function reduction_functor_for(const Reduction reduction_type) { + using U = typename std::decay::type; + switch (reduction_type) { + case Reduction::MAX: + return func::max; + case Reduction::MIN: + return func::min; + case Reduction::PROD: + return func::multiply; + case Reduction::SUM: + return func::add; + case Reduction::SUB: + return func::subtract; + case Reduction::NONE: + default: + return nullptr; + } +} + +template ::type, char>::value>::type* = nullptr> +reduction_function reduction_functor_for(const Reduction reduction_type) { + using U = typename std::decay::type; + switch (reduction_type) { + case Reduction::MIN: + case Reduction::PROD: + return func::logical_and; + case Reduction::SUM: + case Reduction::MAX: + return func::logical_or; + case Reduction::SUB: + return func::logical_xor; + case Reduction::NONE: + default: + return nullptr; + } +} + template void scatterNdUpdate(const dataType* const inputData, const indicesType* const indices, @@ -19,7 +91,8 @@ void scatterNdUpdate(const dataType* const inputData, dataType* const outBuf, const Shape& dataShape, const Shape& indicesShape, - const Shape& updatesShape) { + const Shape& updatesShape, + const Reduction reduction_type = Reduction::NONE) { const auto update_chunk_shape = span(dataShape).drop_front(indicesShape.back()); const auto update_el_number = shape_size(update_chunk_shape); @@ -32,9 +105,8 @@ void scatterNdUpdate(const dataType* const inputData, }; return padding; }(); - + const auto reduction = reduction_functor_for(reduction_type); std::vector indicesCopy(indices, indices + shape_size(indicesShape)); - const auto num_of_updates = shape_size(span(indicesShape).drop_back(1)); for (size_t i = 0; i != num_of_updates; ++i) { const auto indices_coord = indicesCopy.data() + i * indicesShape.back(); @@ -52,10 +124,17 @@ void scatterNdUpdate(const dataType* const inputData, const auto out_index = std::inner_product(begin(coord), end(coord), begin(input_data_dim_pading), uint64_t(0)); const auto update_data = updates + i * update_el_number; - const auto update_mem_size = update_el_number * sizeof(dataType); OPENVINO_ASSERT(out_index >= 0 && out_index + update_el_number <= shape_size(dataShape), "Index is out of bounds"); - std::memcpy(outBuf + out_index, update_data, update_mem_size); + if (reduction) { + std::transform(outBuf + out_index, + outBuf + out_index + update_el_number, + update_data, + outBuf + out_index, + reduction); + } else { + std::memcpy(outBuf + out_index, update_data, update_el_number * sizeof(dataType)); + } } } } // namespace reference diff --git a/src/core/src/op/scatter_nd_update.cpp b/src/core/src/op/scatter_nd_update.cpp index a1cc302f2af4b9..af97649bb12d36 100644 --- a/src/core/src/op/scatter_nd_update.cpp +++ b/src/core/src/op/scatter_nd_update.cpp @@ -22,7 +22,8 @@ struct Evaluate : public element::NoAction { Tensor& output, const Shape& data_shape, const Shape& indices_shape, - const Shape& updates_shape) { + const Shape& updates_shape, + const v14::ScatterNDUpdate::Reduction reduction) { using namespace ov::element; return IF_TYPE_OF(sctter_nd_eval_idx_type, OV_PP_ET_LIST(i32, i64), @@ -34,7 +35,8 @@ struct Evaluate : public element::NoAction { output.data
(), data_shape, indices_shape, - updates_shape); + updates_shape, + reduction); } private: @@ -48,31 +50,25 @@ struct Evaluate : public element::NoAction { DT* const output, const Shape& data_shape, const Shape& indices_shape, - const Shape& updates_shape) { + const Shape& updates_shape, + const v14::ScatterNDUpdate::Reduction reduction) { reference::scatterNdUpdate(data, indices.data(), updates, output, data_shape, indices_shape, - updates_shape); + updates_shape, + reduction); return true; } }; }; -} // namespace scatter_nd_update - -namespace v3 { -std::shared_ptr ScatterNDUpdate::clone_with_new_inputs(const OutputVector& new_args) const { - OV_OP_SCOPE(v3_ScatterNDUpdate_clone_with_new_inputs); - check_new_args_count(this, new_args); - return std::make_shared(new_args.at(util::ScatterNDBase::INPUTS), - new_args.at(util::ScatterNDBase::INDICES), - new_args.at(util::ScatterNDBase::UPDATES)); -} - -bool ScatterNDUpdate::evaluate(TensorVector& outputs, const TensorVector& inputs) const { - OV_OP_SCOPE(v3_ScatterNDUpdate_evaluate); +namespace { +bool evaluate(const op::util::ScatterNDBase* node, + TensorVector& outputs, + const TensorVector& inputs, + const op::v14::ScatterNDUpdate::Reduction reduction) { OPENVINO_ASSERT(inputs.size() == 3); OPENVINO_ASSERT(outputs.size() == 1); @@ -85,8 +81,8 @@ bool ScatterNDUpdate::evaluate(TensorVector& outputs, const TensorVector& inputs const auto& updates_shape = updates.get_shape(); output.set_shape(data_shape); using namespace ov::element; - return IF_TYPE_OF_CONVERT_TENSORS(v3_ScatterNDUpdate_evaluate, - this, + return IF_TYPE_OF_CONVERT_TENSORS(scatter_evaluate, + node, outputs, inputs, OV_PP_ET_LIST(boolean, f32, i32, i64, u32, u64), @@ -98,13 +94,11 @@ bool ScatterNDUpdate::evaluate(TensorVector& outputs, const TensorVector& inputs output, data_shape, indices_shape, - updates_shape); + updates_shape, + reduction); } - -bool ScatterNDUpdate::has_evaluate() const { - OV_OP_SCOPE(v3_ScatterNDUpdate_has_evaluate); - - switch (get_output_element_type(0)) { +bool has_evaluate(const op::util::ScatterNDBase* node) { + switch (node->get_output_element_type(0)) { case element::boolean: case element::f16: case element::f32: @@ -116,7 +110,7 @@ bool ScatterNDUpdate::has_evaluate() const { default: return false; } - switch (get_input_element_type(1)) { + switch (node->get_input_element_type(1)) { case element::i32: case element::i64: return true; @@ -124,6 +118,27 @@ bool ScatterNDUpdate::has_evaluate() const { return false; } } +} // namespace +} // namespace scatter_nd_update +namespace v3 { +std::shared_ptr ScatterNDUpdate::clone_with_new_inputs(const OutputVector& new_args) const { + OV_OP_SCOPE(v3_ScatterNDUpdate_clone_with_new_inputs); + check_new_args_count(this, new_args); + return std::make_shared(new_args.at(util::ScatterNDBase::INPUTS), + new_args.at(util::ScatterNDBase::INDICES), + new_args.at(util::ScatterNDBase::UPDATES)); +} + +bool ScatterNDUpdate::evaluate(TensorVector& outputs, const TensorVector& inputs) const { + OV_OP_SCOPE(v3_ScatterNDUpdate_evaluate); + constexpr auto reduction = op::v14::ScatterNDUpdate::Reduction::NONE; + return scatter_nd_update::evaluate(this, outputs, inputs, reduction); +} + +bool ScatterNDUpdate::has_evaluate() const { + OV_OP_SCOPE(v3_ScatterNDUpdate_has_evaluate); + return scatter_nd_update::has_evaluate(this); +} bool ScatterNDUpdate::evaluate_lower(TensorVector& output_values) const { OV_OP_SCOPE(v3_ScatterNDUpdate_evaluate_lower); @@ -140,5 +155,75 @@ bool ScatterNDUpdate::evaluate_symbol(TensorSymbolVector& output_symbols) const return default_symbol_evaluator(this, {0, 2}, output_symbols); } } // namespace v3 + +namespace v14 { +ScatterNDUpdate::ScatterNDUpdate(const Output& inputs, + const Output& indices, + const Output& updates, + const ScatterNDUpdate::Reduction reduction) + : op::util::ScatterNDBase(inputs, indices, updates), + m_reduction{reduction} { + constructor_validate_and_infer_types(); +} +std::shared_ptr ScatterNDUpdate::clone_with_new_inputs(const OutputVector& new_args) const { + OV_OP_SCOPE(v14_ScatterNDUpdate_clone_with_new_inputs); + check_new_args_count(this, new_args); + return std::make_shared(new_args.at(0), new_args.at(1), new_args.at(2), m_reduction); +} + +bool ScatterNDUpdate::visit_attributes(AttributeVisitor& visitor) { + OV_OP_SCOPE(v14_ScatterNDUpdate_visit_attributes); + visitor.on_attribute("reduction", m_reduction); + return true; +} + +bool ScatterNDUpdate::evaluate(TensorVector& outputs, const TensorVector& inputs) const { + OV_OP_SCOPE(v14_ScatterNDUpdate_evaluate); + return scatter_nd_update::evaluate(this, outputs, inputs, m_reduction); +} + +bool ScatterNDUpdate::has_evaluate() const { + OV_OP_SCOPE(v14_ScatterNDUpdate_has_evaluate); + return scatter_nd_update::has_evaluate(this); +} + +ScatterNDUpdate::Reduction ScatterNDUpdate::get_reduction() const { + return m_reduction; +} + +void ScatterNDUpdate::set_reduction(const ScatterNDUpdate::Reduction reduction) { + m_reduction = reduction; +} +bool ScatterNDUpdate::evaluate_lower(TensorVector& output_values) const { + OV_OP_SCOPE(v14_ScatterNDUpdate_evaluate_lower); + return get_input_tensor(1).has_and_set_bound() && default_lower_bound_evaluator(this, output_values); +} + +bool ScatterNDUpdate::evaluate_upper(TensorVector& output_values) const { + OV_OP_SCOPE(v14_ScatterNDUpdate_evaluate_upper); + return get_input_tensor(1).has_and_set_bound() && default_upper_bound_evaluator(this, output_values); +} + +bool ScatterNDUpdate::evaluate_symbol(TensorSymbolVector& output_symbols) const { + OV_OP_SCOPE(v14_ScatterNDUpdate_evaluate_symbol); + return default_symbol_evaluator(this, {0, 2}, output_symbols); +} + +} // namespace v14 } // namespace op +std::ostream& operator<<(std::ostream& s, const op::v14::ScatterNDUpdate::Reduction& reduction) { + return s << as_string(reduction); +} +template <> +OPENVINO_API EnumNames& EnumNames::get() { + static auto enum_names = + EnumNames("op::v14::ScatterNDUpdate::Reduction", + {{"none", op::v14::ScatterNDUpdate::Reduction::NONE}, + {"sum", op::v14::ScatterNDUpdate::Reduction::SUM}, + {"sub", op::v14::ScatterNDUpdate::Reduction::SUB}, + {"prod", op::v14::ScatterNDUpdate::Reduction::PROD}, + {"min", op::v14::ScatterNDUpdate::Reduction::MIN}, + {"max", op::v14::ScatterNDUpdate::Reduction::MAX}}); + return enum_names; +} } // namespace ov diff --git a/src/core/tests/type_prop/scatter_nd_update.cpp b/src/core/tests/type_prop/scatter_nd_update.cpp index c632e63ff5ea27..6ed14396ad5c10 100644 --- a/src/core/tests/type_prop/scatter_nd_update.cpp +++ b/src/core/tests/type_prop/scatter_nd_update.cpp @@ -5,21 +5,33 @@ #include "openvino/op/scatter_nd_update.hpp" #include "common_test_utils/type_prop.hpp" +#include "openvino/op/broadcast.hpp" +#include "openvino/op/constant.hpp" #include "openvino/op/shape_of.hpp" -#include "openvino/opsets/opset10.hpp" -using namespace std; using namespace ov; +using namespace testing; -TEST(type_prop, scatter_nd_update_v3_fail_indices_element_type) { +template +class TypePropScatterNDUpdateTest : public TypePropOpTest { +protected: + void SetUp() override { + set_shape_symbols(data_3d_dynamic); + } + PartialShape data_3d_dynamic{{2, 5}, 2, {4, 10}}; +}; + +TYPED_TEST_SUITE_P(TypePropScatterNDUpdateTest); + +TYPED_TEST_P(TypePropScatterNDUpdateTest, scatter_nd_update_v3_fail_indices_element_type) { Shape ref_shape{2, 3, 4}; Shape indices_shape{2, 1}; Shape updates_shape{2, 2, 1, 4}; - auto R = make_shared(element::f32, ref_shape); - auto I = make_shared(element::f16, indices_shape); - auto U = make_shared(element::f32, updates_shape); + auto R = std::make_shared(element::f32, ref_shape); + auto I = std::make_shared(element::f16, indices_shape); + auto U = std::make_shared(element::f32, updates_shape); try { - auto G = make_shared(R, I, U); + auto G = this->make_op(R, I, U); // Should have thrown, so fail if it didn't FAIL() << "Incorrect indices element type"; } catch (const NodeValidationFailure& error) { @@ -29,16 +41,16 @@ TEST(type_prop, scatter_nd_update_v3_fail_indices_element_type) { } } -TEST(type_prop, scatter_nd_update_v3_fail_updates_rank) { +TYPED_TEST_P(TypePropScatterNDUpdateTest, scatter_nd_update_v3_fail_updates_rank) { Shape ref_shape{3, 3, 3}; Shape indices_shape{1}; Shape updates_shape{3, 3, 3}; Shape out_shape{3, 3, 3}; - auto R = make_shared(element::f32, ref_shape); - auto I = make_shared(element::i32, indices_shape); - auto U = make_shared(element::f32, updates_shape); + auto R = std::make_shared(element::f32, ref_shape); + auto I = std::make_shared(element::i32, indices_shape); + auto U = std::make_shared(element::f32, updates_shape); try { - auto G = make_shared(R, I, U); + auto G = this->make_op(R, I, U); // Should have thrown, so fail if it didn't FAIL() << "Incorrect updates rank"; } catch (const NodeValidationFailure& error) { @@ -50,16 +62,16 @@ TEST(type_prop, scatter_nd_update_v3_fail_updates_rank) { } } -TEST(type_prop, scatter_nd_update_fail_updates_element_type) { +TYPED_TEST_P(TypePropScatterNDUpdateTest, scatter_nd_update_fail_updates_element_type) { Shape ref_shape{3, 3, 3}; Shape indices_shape{1}; Shape updates_shape{3, 3}; Shape out_shape{3, 3, 3}; - auto R = make_shared(element::f32, ref_shape); - auto I = make_shared(element::i32, indices_shape); - auto U = make_shared(element::i32, updates_shape); + auto R = std::make_shared(element::f32, ref_shape); + auto I = std::make_shared(element::i32, indices_shape); + auto U = std::make_shared(element::i32, updates_shape); try { - auto G = make_shared(R, I, U); + auto G = this->make_op(R, I, U); // Should have thrown, so fail if it didn't FAIL() << "Created ScatterND op with incorrect updates element type."; } catch (const NodeValidationFailure& error) { @@ -69,16 +81,16 @@ TEST(type_prop, scatter_nd_update_fail_updates_element_type) { } } -TEST(type_prop, scatter_nd_update_fail_updates_shape) { +TYPED_TEST_P(TypePropScatterNDUpdateTest, scatter_nd_update_fail_updates_shape) { Shape ref_shape{3, 3, 3}; Shape indices_shape{1}; Shape updates_shape{2, 3}; Shape out_shape{3, 3, 3}; - auto R = make_shared(element::f32, ref_shape); - auto I = make_shared(element::i32, indices_shape); - auto U = make_shared(element::f32, updates_shape); + auto R = std::make_shared(element::f32, ref_shape); + auto I = std::make_shared(element::i32, indices_shape); + auto U = std::make_shared(element::f32, updates_shape); try { - auto G = make_shared(R, I, U); + auto G = this->make_op(R, I, U); // Should have thrown, so fail if it didn't FAIL() << "Incorrect updates shape"; } catch (const NodeValidationFailure& error) { @@ -90,16 +102,16 @@ TEST(type_prop, scatter_nd_update_fail_updates_shape) { } } -TEST(type_prop, scatter_nd_update_fail_indices_last_dim) { +TYPED_TEST_P(TypePropScatterNDUpdateTest, scatter_nd_update_fail_indices_last_dim) { Shape ref_shape{3, 3, 3}; Shape indices_shape{2, 4}; Shape updates_shape{2, 3, 3}; Shape out_shape{3, 3, 3}; - auto R = make_shared(element::f32, ref_shape); - auto I = make_shared(element::i32, indices_shape); - auto U = make_shared(element::f32, updates_shape); + auto R = std::make_shared(element::f32, ref_shape); + auto I = std::make_shared(element::i32, indices_shape); + auto U = std::make_shared(element::f32, updates_shape); try { - auto G = make_shared(R, I, U); + auto G = this->make_op(R, I, U); // Should have thrown, so fail if it didn't FAIL() << "Incorrect indices innermost dim"; } catch (const NodeValidationFailure& error) { @@ -109,84 +121,73 @@ TEST(type_prop, scatter_nd_update_fail_indices_last_dim) { } } -using namespace ov::opset10; -using namespace testing; - -class TypePropScatterUpdateNDV3Test : public TypePropOpTest { -protected: - void SetUp() override { - set_shape_symbols(data_3d_dynamic); - } - PartialShape data_3d_dynamic{{2, 5}, 2, {4, 10}}; -}; +TYPED_TEST_P(TypePropScatterNDUpdateTest, data_input_partial_shape_and_symbols_propagation) { + const auto d = std::make_shared(element::f32, this->data_3d_dynamic); + const auto i = std::make_shared(element::i32, PartialShape{3, 2}); + const auto u = std::make_shared(element::f32, PartialShape{3, 5}); -TEST_F(TypePropScatterUpdateNDV3Test, data_input_partial_shape_and_symbols_propagation) { - const auto d = std::make_shared(element::f32, data_3d_dynamic); - const auto i = std::make_shared(element::i32, PartialShape{3, 2}); - const auto u = std::make_shared(element::f32, PartialShape{3, 5}); - - const auto op = make_op(d, i, u); + const auto op = this->make_op(d, i, u); EXPECT_EQ(op->get_input_size(), 3); EXPECT_EQ(op->get_output_size(), 1); EXPECT_EQ(op->get_output_element_type(0), element::f32); - EXPECT_EQ(op->get_output_partial_shape(0), data_3d_dynamic); - EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), get_shape_symbols(data_3d_dynamic)); + EXPECT_EQ(op->get_output_partial_shape(0), this->data_3d_dynamic); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), get_shape_symbols(this->data_3d_dynamic)); } -TEST_F(TypePropScatterUpdateNDV3Test, indicies_input_is_dynamic) { - const auto d = std::make_shared(element::f64, data_3d_dynamic); - const auto i = std::make_shared(element::i32, PartialShape::dynamic()); - const auto u = std::make_shared(element::f64, PartialShape{3, 5}); +TYPED_TEST_P(TypePropScatterNDUpdateTest, indicies_input_is_dynamic) { + const auto d = std::make_shared(element::f64, this->data_3d_dynamic); + const auto i = std::make_shared(element::i32, PartialShape::dynamic()); + const auto u = std::make_shared(element::f64, PartialShape{3, 5}); - const auto op = make_op(d, i, u); + const auto op = this->make_op(d, i, u); EXPECT_EQ(op->get_output_element_type(0), element::f64); - EXPECT_EQ(op->get_output_partial_shape(0), data_3d_dynamic); - EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), get_shape_symbols(data_3d_dynamic)); + EXPECT_EQ(op->get_output_partial_shape(0), this->data_3d_dynamic); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), get_shape_symbols(this->data_3d_dynamic)); } -TEST_F(TypePropScatterUpdateNDV3Test, updates_input_is_dynamic) { - const auto d = std::make_shared(element::f64, data_3d_dynamic); - const auto i = std::make_shared(element::i32, PartialShape{3, 2}); - const auto u = std::make_shared(element::f64, PartialShape::dynamic()); +TYPED_TEST_P(TypePropScatterNDUpdateTest, updates_input_is_dynamic) { + const auto d = std::make_shared(element::f64, this->data_3d_dynamic); + const auto i = std::make_shared(element::i32, PartialShape{3, 2}); + const auto u = std::make_shared(element::f64, PartialShape::dynamic()); - const auto op = make_op(d, i, u); + const auto op = this->make_op(d, i, u); EXPECT_EQ(op->get_output_element_type(0), element::f64); - EXPECT_EQ(op->get_output_partial_shape(0), data_3d_dynamic); - EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), get_shape_symbols(data_3d_dynamic)); + EXPECT_EQ(op->get_output_partial_shape(0), this->data_3d_dynamic); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), get_shape_symbols(this->data_3d_dynamic)); } -TEST_F(TypePropScatterUpdateNDV3Test, indicies_input_has_interval_dimensions) { - const auto d = std::make_shared(element::i64, data_3d_dynamic); - const auto i = std::make_shared(element::i32, PartialShape{{0, 3}, 1}); - const auto u = std::make_shared(element::i64, PartialShape{3, 2, {8, 10}}); +TYPED_TEST_P(TypePropScatterNDUpdateTest, indicies_input_has_interval_dimensions) { + const auto d = std::make_shared(element::i64, this->data_3d_dynamic); + const auto i = std::make_shared(element::i32, PartialShape{{0, 3}, 1}); + const auto u = std::make_shared(element::i64, PartialShape{3, 2, {8, 10}}); - const auto op = make_op(d, i, u); + const auto op = this->make_op(d, i, u); EXPECT_EQ(op->get_output_element_type(0), element::i64); - EXPECT_EQ(op->get_output_partial_shape(0), data_3d_dynamic); - EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), get_shape_symbols(data_3d_dynamic)); + EXPECT_EQ(op->get_output_partial_shape(0), this->data_3d_dynamic); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), get_shape_symbols(this->data_3d_dynamic)); } -TEST_F(TypePropScatterUpdateNDV3Test, updates_input_is_scalar) { - const auto d = std::make_shared(element::i8, data_3d_dynamic); - const auto i = std::make_shared(element::i32, PartialShape{3}); - const auto u = std::make_shared(element::i8, PartialShape{}); +TYPED_TEST_P(TypePropScatterNDUpdateTest, updates_input_is_scalar) { + const auto d = std::make_shared(element::i8, this->data_3d_dynamic); + const auto i = std::make_shared(element::i32, PartialShape{3}); + const auto u = std::make_shared(element::i8, PartialShape{}); - const auto op = make_op(d, i, u); + const auto op = this->make_op(d, i, u); EXPECT_EQ(op->get_output_element_type(0), element::i8); - EXPECT_EQ(op->get_output_partial_shape(0), data_3d_dynamic); + EXPECT_EQ(op->get_output_partial_shape(0), this->data_3d_dynamic); } -TEST_F(TypePropScatterUpdateNDV3Test, default_ctor) { - const auto d = std::make_shared(element::i64, PartialShape{2, 3, 5, 1}); - const auto i = std::make_shared(element::i32, PartialShape{1, 3}); - const auto u = std::make_shared(element::i64, PartialShape{1, 1}); +TYPED_TEST_P(TypePropScatterNDUpdateTest, default_ctor) { + const auto d = std::make_shared(element::i64, PartialShape{2, 3, 5, 1}); + const auto i = std::make_shared(element::i32, PartialShape{1, 3}); + const auto u = std::make_shared(element::i64, PartialShape{1, 1}); - const auto op = make_op(); + const auto op = this->make_op(); op->set_arguments(OutputVector{d, i, u}); op->validate_and_infer_types(); @@ -195,16 +196,17 @@ TEST_F(TypePropScatterUpdateNDV3Test, default_ctor) { EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), Each(nullptr)); } -TEST_F(TypePropScatterUpdateNDV3Test, preserve_partial_values_and_symbols_via_evaluates_bounds) { - const auto d = Constant::create(element::i64, Shape{4}, {2, 3, 15, 4}); - const auto i = Constant::create(element::i64, Shape{2, 1}, {2, 0}); +TYPED_TEST_P(TypePropScatterNDUpdateTest, preserve_partial_values_and_symbols_via_evaluates_bounds) { + const auto d = op::v0::Constant::create(element::i64, Shape{4}, {2, 3, 15, 4}); + const auto i = op::v0::Constant::create(element::i64, Shape{2, 1}, {2, 0}); auto u_shape = PartialShape{{10, 20}, {3, 4}}; auto symbols = set_shape_symbols(u_shape); - const auto shape_of_u = std::make_shared(std::make_shared(element::i64, u_shape)); - const auto op = make_op(d, i, shape_of_u); + const auto shape_of_u = + std::make_shared(std::make_shared(element::i64, u_shape)); + const auto op = this->make_op(d, i, shape_of_u); - auto param = std::make_shared(element::f32, PartialShape{1}); + auto param = std::make_shared(element::f32, PartialShape{1}); auto bc = std::make_shared(param, op, op::BroadcastType::BIDIRECTIONAL); EXPECT_EQ(bc->get_output_partial_shape(0), PartialShape({{3, 4}, 3, {10, 20}, 4})); @@ -212,35 +214,98 @@ TEST_F(TypePropScatterUpdateNDV3Test, preserve_partial_values_and_symbols_via_ev ElementsAre(symbols[1], nullptr, symbols[0], nullptr)); } -TEST_F(TypePropScatterUpdateNDV3Test, indices_dynamic_type) { - const auto d = std::make_shared(element::f32, data_3d_dynamic); - const auto i = std::make_shared(element::dynamic, PartialShape{3, 2}); - const auto u = std::make_shared(element::f32, PartialShape{3, 5}); +TYPED_TEST_P(TypePropScatterNDUpdateTest, indices_dynamic_type) { + const auto d = std::make_shared(element::f32, this->data_3d_dynamic); + const auto i = std::make_shared(element::dynamic, PartialShape{3, 2}); + const auto u = std::make_shared(element::f32, PartialShape{3, 5}); - const auto op = make_op(d, i, u); + const auto op = this->make_op(d, i, u); EXPECT_EQ(op->get_output_element_type(0), element::f32); - EXPECT_EQ(op->get_output_partial_shape(0), data_3d_dynamic); + EXPECT_EQ(op->get_output_partial_shape(0), this->data_3d_dynamic); } -TEST_F(TypePropScatterUpdateNDV3Test, updates_dynamic_type) { - const auto d = std::make_shared(element::i64, data_3d_dynamic); - const auto i = std::make_shared(element::i32, PartialShape{3, 2}); - const auto u = std::make_shared(element::dynamic, PartialShape{3, 5}); +TYPED_TEST_P(TypePropScatterNDUpdateTest, updates_dynamic_type) { + const auto d = std::make_shared(element::i64, this->data_3d_dynamic); + const auto i = std::make_shared(element::i32, PartialShape{3, 2}); + const auto u = std::make_shared(element::dynamic, PartialShape{3, 5}); - const auto op = make_op(d, i, u); + const auto op = this->make_op(d, i, u); EXPECT_EQ(op->get_output_element_type(0), element::i64); - EXPECT_EQ(op->get_output_partial_shape(0), data_3d_dynamic); + EXPECT_EQ(op->get_output_partial_shape(0), this->data_3d_dynamic); } -TEST_F(TypePropScatterUpdateNDV3Test, all_dynamic_type) { - const auto d = std::make_shared(element::dynamic, data_3d_dynamic); - const auto i = std::make_shared(element::i64, PartialShape{3, 2}); - const auto u = std::make_shared(element::dynamic, PartialShape{3, 5}); +TYPED_TEST_P(TypePropScatterNDUpdateTest, all_dynamic_type) { + const auto d = std::make_shared(element::dynamic, this->data_3d_dynamic); + const auto i = std::make_shared(element::i64, PartialShape{3, 2}); + const auto u = std::make_shared(element::dynamic, PartialShape{3, 5}); - const auto op = make_op(d, i, u); + const auto op = this->make_op(d, i, u); EXPECT_EQ(op->get_output_element_type(0), element::dynamic); - EXPECT_EQ(op->get_output_partial_shape(0), data_3d_dynamic); + EXPECT_EQ(op->get_output_partial_shape(0), this->data_3d_dynamic); +} + +TEST(type_prop, scatter_nd_update_v14_default_attribute) { + const auto d = std::make_shared(element::i64, PartialShape{2, 3, 5, 1}); + const auto i = std::make_shared(element::i32, PartialShape{1, 3}); + const auto u = std::make_shared(element::i64, PartialShape{1, 1}); + + const auto op = std::make_shared(); + op->set_arguments(OutputVector{d, i, u}); + op->validate_and_infer_types(); + + EXPECT_EQ(op->get_output_element_type(0), element::i64); + EXPECT_EQ(op->get_reduction(), op::v14::ScatterNDUpdate::Reduction::NONE); + EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({2, 3, 5, 1})); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), Each(nullptr)); +} + +TEST(type_prop, scatter_nd_update_v14_attribute_setter_enum) { + const auto d = std::make_shared(element::i64, PartialShape{2, 3, 5, 1}); + const auto i = std::make_shared(element::i32, PartialShape{1, 3}); + const auto u = std::make_shared(element::i64, PartialShape{1, 1}); + + const auto op = std::make_shared(); + op->set_arguments(OutputVector{d, i, u}); + op->set_reduction(op::v14::ScatterNDUpdate::Reduction::PROD); + op->validate_and_infer_types(); + + EXPECT_EQ(op->get_output_element_type(0), element::i64); + EXPECT_EQ(op->get_reduction(), op::v14::ScatterNDUpdate::Reduction::PROD); + EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({2, 3, 5, 1})); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), Each(nullptr)); } + +TEST(type_prop, scatter_nd_update_v14_attribute_constructor) { + const auto d = std::make_shared(element::i64, PartialShape{2, 3, 5, 1}); + const auto i = std::make_shared(element::i32, PartialShape{1, 3}); + const auto u = std::make_shared(element::i64, PartialShape{1, 1}); + + const auto op = std::make_shared(d, i, u, op::v14::ScatterNDUpdate::Reduction::MAX); + + EXPECT_EQ(op->get_output_element_type(0), element::i64); + EXPECT_EQ(op->get_reduction(), op::v14::ScatterNDUpdate::Reduction::MAX); + EXPECT_EQ(op->get_output_partial_shape(0), PartialShape({2, 3, 5, 1})); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), Each(nullptr)); +} + +REGISTER_TYPED_TEST_SUITE_P(TypePropScatterNDUpdateTest, + default_ctor, + indices_dynamic_type, + indicies_input_has_interval_dimensions, + data_input_partial_shape_and_symbols_propagation, + indicies_input_is_dynamic, + preserve_partial_values_and_symbols_via_evaluates_bounds, + scatter_nd_update_fail_indices_last_dim, + scatter_nd_update_fail_updates_element_type, + scatter_nd_update_fail_updates_shape, + scatter_nd_update_v3_fail_indices_element_type, + scatter_nd_update_v3_fail_updates_rank, + updates_dynamic_type, + updates_input_is_dynamic, + updates_input_is_scalar, + all_dynamic_type); +using OpVersions = ::testing::Types; +INSTANTIATE_TYPED_TEST_SUITE_P(type_prop, TypePropScatterNDUpdateTest, OpVersions); diff --git a/src/core/tests/visitors/op/scatter_nd_update.cpp b/src/core/tests/visitors/op/scatter_nd_update.cpp index afff3bdb186273..4869682f9b0cbe 100644 --- a/src/core/tests/visitors/op/scatter_nd_update.cpp +++ b/src/core/tests/visitors/op/scatter_nd_update.cpp @@ -25,3 +25,22 @@ TEST(attributes, scatter_nd_update) { const auto expected_attr_count = 0; EXPECT_EQ(builder.get_value_map_size(), expected_attr_count); } + +TEST(attributes, scatter_nd_update_v14) { + NodeBuilder::opset().insert(); + + auto data = std::make_shared(element::f32, Shape{1000, 256, 10, 15}); + auto indices = std::make_shared(element::i32, Shape{25, 125, 3}); + auto updates = std::make_shared(element::f32, Shape{25, 125, 15}); + + auto scatter = std::make_shared(data, + indices, + updates, + op::v14::ScatterNDUpdate::Reduction::PROD); + NodeBuilder builder(scatter, {data, indices, updates}); + const auto g_scatter = ov::as_type_ptr(builder.create()); + + const auto expected_attr_count = 1; + EXPECT_EQ(builder.get_value_map_size(), expected_attr_count); + EXPECT_EQ(g_scatter->get_reduction(), scatter->get_reduction()); +} diff --git a/src/plugins/template/tests/functional/op_reference/scatter_nd_update.cpp b/src/plugins/template/tests/functional/op_reference/scatter_nd_update.cpp index d2523d9ab84e9b..f154a3c94cec26 100644 --- a/src/plugins/template/tests/functional/op_reference/scatter_nd_update.cpp +++ b/src/plugins/template/tests/functional/op_reference/scatter_nd_update.cpp @@ -11,6 +11,7 @@ using namespace reference_tests; using namespace ov; +using Reduction = ov::op::v14::ScatterNDUpdate::Reduction; namespace { struct ScatterNDUpdateParams { @@ -23,25 +24,41 @@ struct ScatterNDUpdateParams { indexTensor(indexTensor), updateTensor(updateTensor), expectedTensor(expectedTensor), + reduction(Reduction::NONE), + testcaseName(testcaseName) {} + + ScatterNDUpdateParams(const reference_tests::Tensor& dataTensor, + const reference_tests::Tensor& indexTensor, + const reference_tests::Tensor& updateTensor, + const reference_tests::Tensor& expectedTensor, + const Reduction paramReduction, + const std::string& testcaseName) + : dataTensor(dataTensor), + indexTensor(indexTensor), + updateTensor(updateTensor), + expectedTensor(expectedTensor), + reduction{paramReduction}, testcaseName(testcaseName) {} reference_tests::Tensor dataTensor; reference_tests::Tensor indexTensor; reference_tests::Tensor updateTensor; reference_tests::Tensor expectedTensor; + Reduction reduction; std::string testcaseName; }; -class ReferenceScatterNDUpdateLayerTest : public testing::TestWithParam, - public CommonReferenceTest { -public: +class ReferenceScatterNDUpdateV3LayerTest : public testing::TestWithParam, + public CommonReferenceTest { +protected: void SetUp() override { - auto params = GetParam(); + const auto& params = GetParam(); function = CreateFunction(params); inputData = {params.dataTensor.data}; refOutData = {params.expectedTensor.data}; } +public: static std::string getTestCaseName(const testing::TestParamInfo& obj) { auto param = obj.param; std::ostringstream result; @@ -75,7 +92,44 @@ class ReferenceScatterNDUpdateLayerTest : public testing::TestWithParam, + public CommonReferenceTest { +protected: + void SetUp() override { + const auto& params = GetParam(); + function = CreateFunction(params); + inputData = {params.dataTensor.data}; + refOutData = {params.expectedTensor.data}; + } + +public: + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + const auto& param = obj.param; + std::ostringstream result; + result << ReferenceScatterNDUpdateV3LayerTest::getTestCaseName(obj); + result << "_reduction=" << param.reduction; + return result.str(); + } + +private: + static std::shared_ptr CreateFunction(const ScatterNDUpdateParams& params) { + const auto data = std::make_shared(params.dataTensor.type, params.dataTensor.shape); + const auto indices = std::make_shared(params.indexTensor.type, + params.indexTensor.shape, + params.indexTensor.data.data()); + const auto updates = std::make_shared(params.updateTensor.type, + params.updateTensor.shape, + params.updateTensor.data.data()); + const auto scatter = std::make_shared(data, indices, updates, params.reduction); + return std::make_shared(NodeVector{scatter}, ParameterVector{data}); + } +}; + +TEST_P(ReferenceScatterNDUpdateV3LayerTest, CompareWithRefs) { + Exec(); +} + +TEST_P(ReferenceScatterNDUpdateV14LayerTest, CompareWithRefs) { Exec(); } @@ -87,8 +141,8 @@ std::vector generateScatterNDUpdateParams() { // scatter_nd_update_1x1 ScatterNDUpdateParams(reference_tests::Tensor({1}, IN_ET, std::vector{1}), reference_tests::Tensor({1}, IU_ET, std::vector{0}), - reference_tests::Tensor({1}, IN_ET, std::vector{20}), - reference_tests::Tensor({1}, IN_ET, std::vector{20}), + reference_tests::Tensor({1}, IN_ET, std::vector{40}), + reference_tests::Tensor({1}, IN_ET, std::vector{40}), "scatter_nd_update_1x1"), // scatter_nd_update_2x2_by_1 ScatterNDUpdateParams(reference_tests::Tensor({2, 2}, IN_ET, std::vector{1, 2, 3, 4}), @@ -189,7 +243,335 @@ std::vector generateScatterNDUpdateParams() { return scatterParams; } -std::vector generateScatterNDUpdateCombinedParams() { +template +std::vector generateScatterNDUpdateV14Params() { + using T = typename element_type_traits::value_type; + using U = typename element_type_traits::value_type; + std::vector scatterParams{ + // Duplicated indices tests: + ScatterNDUpdateParams(reference_tests::Tensor({1}, IN_ET, std::vector{1}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 0}), + reference_tests::Tensor({2}, IN_ET, std::vector{40, 50}), + reference_tests::Tensor({1}, IN_ET, std::vector{50}), + "scatter_nd_update_1x1_duplicated_indices"), + ScatterNDUpdateParams(reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 1, 1, 1, 1, 1}), + reference_tests::Tensor({2, 2}, IU_ET, std::vector{0, 1, 0, 1}), + reference_tests::Tensor({2}, IN_ET, std::vector{5, 10}), + reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 10, 1, 1, 1, 1}), + "scatter_nd_update_tf_example_duplicated_indices"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{8, 12, 1, 5, 3, 19, 2, 4, 13, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 18, 23, 16, 17, 11, 22, 0, 10, 20}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{2, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{4, 15, 11, 13, 15, 23, 1, 4, 4, 11, 2, 10, 1, 25, 25, 19, 23, 10}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{8, 12, 1, 5, 3, 19, 2, 4, 13, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 11, 2, 10, 1, 25, 25, 19, 23, 10}), + "scatter_nd_update_3x3_by_1_duplicated_indices"), + + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{11, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 39}), + reference_tests::Tensor({3, 3}, IU_ET, std::vector{0, 0, 0, 2, -1, 2, -1, 2, -1}), + reference_tests::Tensor({3}, IN_ET, std::vector{91, 99, 100}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{91, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 100}), + "scatter_nd_update_3x3_by_3_duplicated_indices"), + ScatterNDUpdateParams(reference_tests::Tensor({8}, IN_ET, std::vector{1, 2, 3, 4, 5, 6, 7, 8}), + reference_tests::Tensor({5, 1}, IU_ET, std::vector{4, 3, 1, 7, 1}), + reference_tests::Tensor({5}, IN_ET, std::vector{9, 10, 11, 12, 22}), + reference_tests::Tensor({8}, IN_ET, std::vector{1, 22, 3, 10, 9, 6, 7, 12}), + "scatter_nd_update_1d_from_examples_duplicated_indices"), + ScatterNDUpdateParams( + reference_tests::Tensor({4, 4, 4}, IN_ET, std::vector{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1, + 1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1, + 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8, + 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8}), + reference_tests::Tensor({3, 1}, IU_ET, std::vector{0, 2, -2}), + reference_tests::Tensor({3, 4, 4}, IN_ET, std::vector{5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, + 8, 8, 8, 8, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 10, 10, 10, 10, + 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13}), + reference_tests::Tensor({4, 4, 4}, IN_ET, std::vector{5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, + 8, 8, 8, 1, 2, 3, 4, 5, 6, 7, 8, 8, 7, + 6, 5, 4, 3, 2, 1, 10, 10, 10, 10, 11, 11, 11, + 11, 12, 12, 12, 12, 13, 13, 13, 13, 8, 7, 6, 5, + 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8}), + "scatter_nd_update_4x4_shape_from_examples_duplicated_indices"), + ScatterNDUpdateParams( + reference_tests::Tensor({4, 4, 4}, IN_ET, std::vector{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1, + 1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1, + 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8, + 8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8}), + reference_tests::Tensor({3, 2, 2}, IU_ET, std::vector{0, 0, 2, 2, 1, 1, 3, 3, 0, 0, 2, 2}), + reference_tests::Tensor({3, 2, 4}, IN_ET, std::vector{15, 16, 17, 18, 25, 26, 27, 28, 35, 36, 37, 38, + 45, 46, 47, 48, 55, 56, 57, 58, 65, 66, 67, 68}), + reference_tests::Tensor({4, 4, 4}, IN_ET, std::vector{55, 56, 57, 58, 5, 6, 7, 8, 8, 7, 6, 5, 4, + 3, 2, 1, 1, 2, 3, 4, 35, 36, 37, 38, 8, 7, + 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, + 1, 65, 66, 67, 68, 5, 6, 7, 8, 8, 7, 6, 5, + 4, 3, 2, 1, 1, 2, 3, 4, 45, 46, 47, 48}), + "scatter_nd_update_4x4_v2_duplicated_indices"), + // Reduction tests: + // scatter_nd_update_1x1 + ScatterNDUpdateParams(reference_tests::Tensor({1}, IN_ET, std::vector{1}), + reference_tests::Tensor({1}, IU_ET, std::vector{0}), + reference_tests::Tensor({1}, IN_ET, std::vector{40}), + reference_tests::Tensor({1}, IN_ET, std::vector{41}), + Reduction::SUM, + "scatter_nd_update_1x1_SUM"), + ScatterNDUpdateParams(reference_tests::Tensor({1}, IN_ET, std::vector{40}), + reference_tests::Tensor({1}, IU_ET, std::vector{0}), + reference_tests::Tensor({1}, IN_ET, std::vector{40}), + reference_tests::Tensor({1}, IN_ET, std::vector{0}), + Reduction::SUB, + "scatter_nd_update_1x1_SUB"), + ScatterNDUpdateParams(reference_tests::Tensor({1}, IN_ET, std::vector{2}), + reference_tests::Tensor({1}, IU_ET, std::vector{0}), + reference_tests::Tensor({1}, IN_ET, std::vector{40}), + reference_tests::Tensor({1}, IN_ET, std::vector{80}), + Reduction::PROD, + "scatter_nd_update_1x1_PROD"), + ScatterNDUpdateParams(reference_tests::Tensor({1}, IN_ET, std::vector{2}), + reference_tests::Tensor({1}, IU_ET, std::vector{0}), + reference_tests::Tensor({1}, IN_ET, std::vector{40}), + reference_tests::Tensor({1}, IN_ET, std::vector{40}), + Reduction::MAX, + "scatter_nd_update_1x1_MAX"), + ScatterNDUpdateParams(reference_tests::Tensor({1}, IN_ET, std::vector{2}), + reference_tests::Tensor({1}, IU_ET, std::vector{0}), + reference_tests::Tensor({1}, IN_ET, std::vector{40}), + reference_tests::Tensor({1}, IN_ET, std::vector{2}), + Reduction::MIN, + "scatter_nd_update_1x1_MIN"), + // scatter_nd_update_tf_example + ScatterNDUpdateParams(reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 1, 1, 1, 1, 1}), + reference_tests::Tensor({2, 2}, IU_ET, std::vector{0, 1, 2, 0}), + reference_tests::Tensor({2}, IN_ET, std::vector{5, 10}), + reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 6, 1, 1, 11, 1}), + Reduction::SUM, + "scatter_nd_update_tf_example"), + ScatterNDUpdateParams(reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 6, 1, 1, 11, 1}), + reference_tests::Tensor({2, 2}, IU_ET, std::vector{0, 1, 2, 0}), + reference_tests::Tensor({2}, IN_ET, std::vector{5, 10}), + reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 1, 1, 1, 1, 1}), + Reduction::SUB, + "scatter_nd_update_tf_example"), + ScatterNDUpdateParams(reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 2, 1, 1, 2, 1}), + reference_tests::Tensor({2, 2}, IU_ET, std::vector{0, 1, 2, 0}), + reference_tests::Tensor({2}, IN_ET, std::vector{5, 10}), + reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 10, 1, 1, 20, 1}), + Reduction::PROD, + "scatter_nd_update_tf_example"), + ScatterNDUpdateParams(reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 1, 1, 1, 1, 1}), + reference_tests::Tensor({2, 2}, IU_ET, std::vector{0, 1, 2, 0}), + reference_tests::Tensor({2}, IN_ET, std::vector{5, 10}), + reference_tests::Tensor({3, 2}, IN_ET, std::vector{1, 5, 1, 1, 10, 1}), + Reduction::MAX, + "scatter_nd_update_tf_example"), + ScatterNDUpdateParams(reference_tests::Tensor({3, 2}, IN_ET, std::vector{15, 15, 15, 15, 15, 15}), + reference_tests::Tensor({2, 2}, IU_ET, std::vector{0, 1, 2, 0}), + reference_tests::Tensor({2}, IN_ET, std::vector{5, 10}), + reference_tests::Tensor({3, 2}, IN_ET, std::vector{15, 5, 15, 15, 10, 15}), + Reduction::MIN, + "scatter_nd_update_tf_example"), + // scatter_nd_update_3x3_by_1 + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{8, 12, 1, 5, 3, 19, 2, 4, 13, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 18, 23, 16, 17, 11, 22, 0, 10, 20}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{4, 15, 11, 13, 15, 23, 1, 4, 4, 11, 2, 10, 1, 25, 25, 19, 23, 10}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{12, 27, 12, 18, 18, 42, 3, 8, 17, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 29, 25, 26, 18, 36, 47, 19, 33, 30}), + Reduction::SUM, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{8, 12, 1, 5, 3, 19, 2, 4, 13, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 18, 23, 16, 17, 11, 22, 0, 10, 20}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{4, 15, 11, 13, 15, 23, 1, 4, 4, 11, 2, 10, 1, 25, 25, 19, 23, 10}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{32, 180, 11, 65, 45, 437, 2, 16, 52, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 198, 46, 160, 17, 275, 550, 0, 230, 200}), + Reduction::PROD, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{8, 12, 1, 5, 3, 19, 2, 4, 13, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 18, 23, 16, 17, 11, 22, 0, 10, 20}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{4, 15, 11, 13, 15, 23, 1, 4, 4, 11, 2, 10, 1, 25, 25, 19, 23, 10}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{8, 15, 11, 13, 15, 23, 2, 4, 13, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 18, 23, 16, 17, 25, 25, 19, 23, 20}), + Reduction::MAX, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{8, 12, 1, 5, 3, 19, 2, 4, 13, + 7, 6, 25, 5, 12, 11, 23, 17, 2, + 18, 23, 16, 17, 11, 22, 0, 10, 20}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{4, 15, 11, 13, 15, 23, 1, 4, 4, 11, 2, 10, 1, 25, 25, 19, 23, 10}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{4, 12, 1, 5, 3, 19, 1, 4, 4, 7, 6, 25, 5, 12, + 11, 23, 17, 2, 11, 2, 10, 1, 11, 22, 0, 10, 10}), + Reduction::MIN, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{37, 29, 48, 48, 27, 29, 26, 42, 42, + 48, 49, 25, 39, 36, 47, 34, 49, 42, + 35, 37, 49, 42, 46, 26, 41, 31, 41}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor( + {2, 3, 3}, + IN_ET, + std::vector{18, 13, 13, 19, 13, 1, 25, 24, 15, 6, 12, 17, 12, 10, 8, 18, 16, 19}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{19, 16, 35, 29, 14, 28, 1, 18, 27, + 48, 49, 25, 39, 36, 47, 34, 49, 42, + 29, 25, 32, 30, 36, 18, 23, 15, 22}), + Reduction::SUB, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{11, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 39}), + reference_tests::Tensor({3, 3}, IU_ET, std::vector{0, 0, 0, 2, -1, 2, -1, 2, -1}), + reference_tests::Tensor({3}, IN_ET, std::vector{2, 4, 6}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{13, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 49}), + Reduction::SUM, + "scatter_nd_update_3x3_by_3_duplicated_indices"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{11, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 39}), + reference_tests::Tensor({3, 3}, IU_ET, std::vector{0, 0, 0, 2, -1, 2, -1, 2, -1}), + reference_tests::Tensor({3}, IN_ET, std::vector{2, 4, 6}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{9, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 29}), + Reduction::SUB, + "scatter_nd_update_3x3_by_3_duplicated_indices"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{11, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 39}), + reference_tests::Tensor({3, 3}, IU_ET, std::vector{0, 0, 0, 2, -1, 2, -1, 2, -1}), + reference_tests::Tensor({3}, IN_ET, std::vector{2, 4, 6}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{22, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 936}), + Reduction::PROD, + "scatter_nd_update_3x3_by_3_duplicated_indices"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{11, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 39}), + reference_tests::Tensor({3, 3}, IU_ET, std::vector{0, 0, 0, 2, -1, 2, -1, 2, -1}), + reference_tests::Tensor({3}, IN_ET, std::vector{2, 4, 6}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{11, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 39}), + Reduction::MAX, + "scatter_nd_update_3x3_by_3_duplicated_indices"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{11, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 39}), + reference_tests::Tensor({3, 3}, IU_ET, std::vector{0, 0, 0, 2, -1, 2, -1, 2, -1}), + reference_tests::Tensor({3}, IN_ET, std::vector{2, 4, 6}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{2, 12, 13, 14, 15, 16, 17, 18, 19, + 21, 22, 23, 24, 25, 26, 27, 28, 29, + 31, 32, 33, 34, 35, 36, 37, 38, 4}), + Reduction::MIN, + "scatter_nd_update_3x3_by_3_duplicated_indices"), + }; + return scatterParams; +} + +template +std::vector generateScatterNDUpdateV14ParamsReductionsBoolean() { + const auto IN_ET = element::Type_t::boolean; + using T = typename element_type_traits::value_type; + using U = typename element_type_traits::value_type; + std::vector scatterParams{ + // scatter_nd_update_3x3_by_1 + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0}), + Reduction::SUM, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0}), + Reduction::PROD, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0}), + Reduction::MAX, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0}), + Reduction::MIN, + "scatter_nd_update_3x3_by_1"), + ScatterNDUpdateParams( + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0}), + reference_tests::Tensor({2, 1}, IU_ET, std::vector{0, 2}), + reference_tests::Tensor({2, 3, 3}, + IN_ET, + std::vector{0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0}), + reference_tests::Tensor({3, 3, 3}, IN_ET, std::vector{1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0}), + Reduction::SUB, + "scatter_nd_update_3x3_by_1"), + }; + return scatterParams; +} + +std::vector generateScatterNDUpdateV3CombinedParams() { const std::vector> scatterTypeParams{ generateScatterNDUpdateParams(), generateScatterNDUpdateParams(), @@ -214,12 +596,42 @@ std::vector generateScatterNDUpdateCombinedParams() { return combinedParams; } +std::vector generateScatterNDUpdateV14CombinedParams() { + const std::vector> scatterTypeParams{ + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14Params(), + generateScatterNDUpdateV14ParamsReductionsBoolean(), + generateScatterNDUpdateV14ParamsReductionsBoolean(), + }; + std::vector combinedParams = generateScatterNDUpdateV3CombinedParams(); + + for (const auto& params : scatterTypeParams) { + combinedParams.insert(combinedParams.end(), params.begin(), params.end()); + } + return combinedParams; +} + +INSTANTIATE_TEST_SUITE_P(smoke_ScatterNDUpdate_With_Hardcoded_Refs, + ReferenceScatterNDUpdateV3LayerTest, + testing::ValuesIn(generateScatterNDUpdateV3CombinedParams()), + ReferenceScatterNDUpdateV3LayerTest::getTestCaseName); + INSTANTIATE_TEST_SUITE_P(smoke_ScatterNDUpdate_With_Hardcoded_Refs, - ReferenceScatterNDUpdateLayerTest, - testing::ValuesIn(generateScatterNDUpdateCombinedParams()), - ReferenceScatterNDUpdateLayerTest::getTestCaseName); + ReferenceScatterNDUpdateV14LayerTest, + testing::ValuesIn(generateScatterNDUpdateV14CombinedParams()), + ReferenceScatterNDUpdateV14LayerTest::getTestCaseName); -class ReferenceScatterNDUpdateLayerNegativeTest : public ReferenceScatterNDUpdateLayerTest {}; +class ReferenceScatterNDUpdateLayerNegativeTest : public ReferenceScatterNDUpdateV3LayerTest {}; TEST_P(ReferenceScatterNDUpdateLayerNegativeTest, CompareWithRefsNegative) { LoadNetwork(); diff --git a/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp b/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp index d8920e6309cc05..17efee42a00cf0 100644 --- a/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp +++ b/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp @@ -1426,6 +1426,8 @@ std::shared_ptr generateScatterNDBase(const std::shared_ptr scatterNode; if (ov::is_type(node)) { scatterNode = std::make_shared(data, indices, updates); + } else if (ov::is_type(node)) { + scatterNode = std::make_shared(data, indices, updates, ov::op::v14::ScatterNDUpdate::Reduction::SUM); } else { return nullptr; }