From 23b54736e43c1f717bfe451db897f49d14a9d545 Mon Sep 17 00:00:00 2001 From: Mateusz Mikolajczyk Date: Tue, 21 May 2024 11:07:14 +0200 Subject: [PATCH] [Opset15] Implementation for EmbeddingBagPacked and EmbeddingBagOffsets ops (#24541) ### Details: - *Create PoC implementation for EmbeddingBag Offsets and Packed that introduce mode 'mean'* - *Add Core, Reference and CPU implementation for both ops* Specification will be added in separate PR ### Tickets: - *138229* --------- Co-authored-by: Michal Lukaszewski --- ...vert_embedding_bag_offsets15_downgrade.hpp | 23 ++ ...nvert_embedding_bag_packed15_downgrade.hpp | 23 ++ .../common_optimizations.cpp | 4 + ...vert_embedding_bag_offsets15_downgrade.cpp | 55 +++ ...nvert_embedding_bag_packed15_downgrade.cpp | 45 +++ ...embedding_bag_offsets15_downgrade_test.cpp | 146 +++++++ ..._embedding_bag_packed15_downgrade_test.cpp | 108 +++++ .../openvino/op/embeddingbag_offsets.hpp | 61 +++ .../openvino/op/embeddingbag_offsets_sum.hpp | 4 +- .../openvino/op/embeddingbag_packed.hpp | 48 +++ .../openvino/op/embeddingbag_packedsum.hpp | 2 + src/core/include/openvino/op/ops.hpp | 2 + .../op/util/embeddingbag_offsets_base.hpp | 43 +- .../op/util/embeddingbag_packed_base.hpp | 30 +- .../include/openvino/opsets/opset15_tbl.hpp | 2 + ...sets_sum.hpp => embedding_bag_offsets.hpp} | 26 +- ...acked_sum.hpp => embedding_bag_packed.hpp} | 20 +- src/core/src/op/embeddingbag_offsets.cpp | 57 +++ src/core/src/op/embeddingbag_offsets_sum.cpp | 4 + src/core/src/op/embeddingbag_packed.cpp | 36 ++ src/core/src/op/embeddingbag_packedsum.cpp | 4 + .../src/op/util/embeddingbag_offsets_base.cpp | 57 ++- .../src/op/util/embeddingbag_packed_base.cpp | 46 ++- src/core/tests/opset.cpp | 2 +- .../tests/type_prop/embeddingbag_offsets.cpp | 380 ++++++++++++++++++ .../tests/type_prop/embeddingbag_packed.cpp | 229 +++++++++++ .../visitors/op/embeddingbag_offsets.cpp | 68 ++++ .../tests/visitors/op/embeddingbag_packed.cpp | 42 ++ .../pytorch/src/op/embedding_bag.cpp | 31 +- src/plugins/intel_cpu/src/cpu_types.cpp | 8 +- src/plugins/intel_cpu/src/cpu_types.h | 2 + ...mbedding_bag_sum.cpp => embedding_bag.cpp} | 112 +++--- .../{embedding_bag_sum.h => embedding_bag.h} | 8 +- ...fset_sum.cpp => embedding_bag_offsets.cpp} | 56 ++- ...g_offset_sum.h => embedding_bag_offsets.h} | 6 +- ...acked_sum.cpp => embedding_bag_packed.cpp} | 55 ++- ...ag_packed_sum.h => embedding_bag_packed.h} | 6 +- .../src/nodes/embedding_segments_sum.cpp | 10 +- .../src/nodes/embedding_segments_sum.h | 4 +- src/plugins/intel_cpu/src/nodes_factory.cpp | 10 +- .../src/shape_inference/shape_inference.cpp | 2 + .../embedding_bag_offsets.cpp | 166 ++++++++ .../embedding_bag_packed.cpp | 153 +++++++ .../backend/ops/embedding_bag_offsets.cpp | 89 ++++ .../backend/ops/embedding_bag_offsets_sum.cpp | 20 +- .../backend/ops/embedding_bag_packed.cpp | 88 ++++ .../backend/ops/embedding_bag_packed_sum.cpp | 16 +- .../template/backend/ops/ops_evaluates.hpp | 7 + .../template/backend/opset_int_tbl.hpp | 3 + .../op_reference/embeddingbag_offsets.cpp | 275 +++++++++++++ .../op_reference/embeddingbag_packed.cpp | 232 +++++++++++ .../src/op_impl_check/single_op_graph.cpp | 18 +- .../src/base/utils/compare_results.cpp | 1 + .../src/base/utils/generate_inputs.cpp | 2 + .../node_builders/embedding_bag_offsets.hpp | 25 ++ .../node_builders/embedding_bag_packed.hpp | 22 + .../node_builders/embedding_bag_offsets.cpp | 56 +++ .../node_builders/embedding_bag_packed.cpp | 41 ++ .../pytorch_tests/test_embedding_bag.py | 201 +++++++-- 59 files changed, 3089 insertions(+), 203 deletions(-) create mode 100644 src/common/transformations/include/transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.hpp create mode 100644 src/common/transformations/include/transformations/op_conversions/convert_embedding_bag_packed15_downgrade.hpp create mode 100644 src/common/transformations/src/transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.cpp create mode 100644 src/common/transformations/src/transformations/op_conversions/convert_embedding_bag_packed15_downgrade.cpp create mode 100644 src/common/transformations/tests/op_conversions/convert_embedding_bag_offsets15_downgrade_test.cpp create mode 100644 src/common/transformations/tests/op_conversions/convert_embedding_bag_packed15_downgrade_test.cpp create mode 100644 src/core/include/openvino/op/embeddingbag_offsets.hpp create mode 100644 src/core/include/openvino/op/embeddingbag_packed.hpp rename src/core/reference/include/openvino/reference/{embedding_bag_offsets_sum.hpp => embedding_bag_offsets.hpp} (79%) rename src/core/reference/include/openvino/reference/{embedding_bag_packed_sum.hpp => embedding_bag_packed.hpp} (65%) create mode 100644 src/core/src/op/embeddingbag_offsets.cpp create mode 100644 src/core/src/op/embeddingbag_packed.cpp create mode 100644 src/core/tests/type_prop/embeddingbag_offsets.cpp create mode 100644 src/core/tests/type_prop/embeddingbag_packed.cpp create mode 100644 src/core/tests/visitors/op/embeddingbag_offsets.cpp create mode 100644 src/core/tests/visitors/op/embeddingbag_packed.cpp rename src/plugins/intel_cpu/src/nodes/{embedding_bag_sum.cpp => embedding_bag.cpp} (53%) rename src/plugins/intel_cpu/src/nodes/{embedding_bag_sum.h => embedding_bag.h} (89%) rename src/plugins/intel_cpu/src/nodes/{embedding_bag_offset_sum.cpp => embedding_bag_offsets.cpp} (67%) rename src/plugins/intel_cpu/src/nodes/{embedding_bag_offset_sum.h => embedding_bag_offsets.h} (84%) rename src/plugins/intel_cpu/src/nodes/{embedding_bag_packed_sum.cpp => embedding_bag_packed.cpp} (60%) rename src/plugins/intel_cpu/src/nodes/{embedding_bag_packed_sum.h => embedding_bag_packed.h} (82%) create mode 100644 src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/embedding_bag_offsets.cpp create mode 100644 src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/embedding_bag_packed.cpp create mode 100644 src/plugins/template/backend/ops/embedding_bag_offsets.cpp create mode 100644 src/plugins/template/backend/ops/embedding_bag_packed.cpp create mode 100644 src/plugins/template/tests/functional/op_reference/embeddingbag_offsets.cpp create mode 100644 src/plugins/template/tests/functional/op_reference/embeddingbag_packed.cpp create mode 100644 src/tests/test_utils/common_test_utils/include/common_test_utils/node_builders/embedding_bag_offsets.hpp create mode 100644 src/tests/test_utils/common_test_utils/include/common_test_utils/node_builders/embedding_bag_packed.hpp create mode 100644 src/tests/test_utils/common_test_utils/src/node_builders/embedding_bag_offsets.cpp create mode 100644 src/tests/test_utils/common_test_utils/src/node_builders/embedding_bag_packed.cpp diff --git a/src/common/transformations/include/transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.hpp b/src/common/transformations/include/transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.hpp new file mode 100644 index 00000000000..18b1339366e --- /dev/null +++ b/src/common/transformations/include/transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "openvino/pass/graph_rewrite.hpp" +#include "transformations_visibility.hpp" + +namespace ov { +namespace pass { +/** + * @ingroup ov_transformation_common_api + * @brief Converts EmbeddingBagOffsets v15 to EmbeddingBagOffsets v3. + */ +class TRANSFORMATIONS_API ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3 : public MatcherPass { +public: + OPENVINO_RTTI("ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3", "0"); + ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3(); +}; + +} // namespace pass +} // namespace ov diff --git a/src/common/transformations/include/transformations/op_conversions/convert_embedding_bag_packed15_downgrade.hpp b/src/common/transformations/include/transformations/op_conversions/convert_embedding_bag_packed15_downgrade.hpp new file mode 100644 index 00000000000..bac6e636ac9 --- /dev/null +++ b/src/common/transformations/include/transformations/op_conversions/convert_embedding_bag_packed15_downgrade.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "openvino/pass/graph_rewrite.hpp" +#include "transformations_visibility.hpp" + +namespace ov { +namespace pass { +/** + * @ingroup ov_transformation_common_api + * @brief Converts EmbeddingBagPacked v15 to EmbeddingBagPacked v3. + */ +class TRANSFORMATIONS_API ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3 : public MatcherPass { +public: + OPENVINO_RTTI("ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3", "0"); + ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3(); +}; + +} // namespace pass +} // namespace ov diff --git a/src/common/transformations/src/transformations/common_optimizations/common_optimizations.cpp b/src/common/transformations/src/transformations/common_optimizations/common_optimizations.cpp index 433c46a2e77..8e3ccc160d6 100644 --- a/src/common/transformations/src/transformations/common_optimizations/common_optimizations.cpp +++ b/src/common/transformations/src/transformations/common_optimizations/common_optimizations.cpp @@ -73,6 +73,8 @@ #include "transformations/op_conversions/convert_deformable_conv_v8_to_v1.hpp" #include "transformations/op_conversions/convert_depth_to_space.hpp" #include "transformations/op_conversions/convert_divide.hpp" +#include "transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.hpp" +#include "transformations/op_conversions/convert_embedding_bag_packed15_downgrade.hpp" #include "transformations/op_conversions/convert_gather_downgrade.hpp" #include "transformations/op_conversions/convert_gather_upgrade.hpp" #include "transformations/op_conversions/convert_gelu.hpp" @@ -224,6 +226,8 @@ bool ov::pass::CommonOptimizations::run_on_model(const std::shared_ptr(); ADD_MATCHER(fq_fusions, FakeQuantizeMulFusion) diff --git a/src/common/transformations/src/transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.cpp b/src/common/transformations/src/transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.cpp new file mode 100644 index 00000000000..ce3401da861 --- /dev/null +++ b/src/common/transformations/src/transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.hpp" + +#include "itt.hpp" +#include "openvino/core/rt_info.hpp" +#include "openvino/op/embeddingbag_offsets.hpp" +#include "openvino/op/embeddingbag_offsets_sum.hpp" +#include "openvino/pass/pattern/op/wrap_type.hpp" +#include "transformations/utils/utils.hpp" + +ov::pass::ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3:: + ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3() { + MATCHER_SCOPE(ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3); + + const auto emb_v15_pattern = pattern::wrap_type(); + + const matcher_pass_callback callback = [OV_CAPTURE_CPY_AND_THIS](pattern::Matcher& m) { + const auto emb_v15 = std::dynamic_pointer_cast(m.get_match_root()); + if (!emb_v15 || transformation_callback(emb_v15) || + emb_v15->get_reduction() != ov::op::v15::EmbeddingBagOffsets::Reduction::SUM) { + return false; + } + std::shared_ptr emb_v3; + if (emb_v15->get_input_size() == 3) { + emb_v3 = std::make_shared(emb_v15->input_value(0), + emb_v15->input_value(1), + emb_v15->input_value(2)); + } else if (emb_v15->get_input_size() == 4) { + emb_v3 = std::make_shared(emb_v15->input_value(0), + emb_v15->input_value(1), + emb_v15->input_value(2), + emb_v15->input_value(3)); + } else if (emb_v15->get_input_size() == 5) { + emb_v3 = std::make_shared(emb_v15->input_value(0), + emb_v15->input_value(1), + emb_v15->input_value(2), + emb_v15->input_value(3), + emb_v15->input_value(4)); + } else { + return false; + } + + emb_v3->set_friendly_name(emb_v15->get_friendly_name()); + copy_runtime_info(emb_v15, emb_v3); + replace_node(emb_v15, emb_v3); + + return true; + }; + + auto m = std::make_shared(emb_v15_pattern, matcher_name); + register_matcher(m, callback); +} diff --git a/src/common/transformations/src/transformations/op_conversions/convert_embedding_bag_packed15_downgrade.cpp b/src/common/transformations/src/transformations/op_conversions/convert_embedding_bag_packed15_downgrade.cpp new file mode 100644 index 00000000000..9269517da9a --- /dev/null +++ b/src/common/transformations/src/transformations/op_conversions/convert_embedding_bag_packed15_downgrade.cpp @@ -0,0 +1,45 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/op_conversions/convert_embedding_bag_packed15_downgrade.hpp" + +#include "itt.hpp" +#include "openvino/core/rt_info.hpp" +#include "openvino/op/embeddingbag_packed.hpp" +#include "openvino/op/embeddingbag_packedsum.hpp" +#include "openvino/pass/pattern/op/wrap_type.hpp" +#include "transformations/utils/utils.hpp" + +ov::pass::ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3::ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3() { + MATCHER_SCOPE(ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3); + + const auto emb_v15_pattern = pattern::wrap_type(); + + const matcher_pass_callback callback = [OV_CAPTURE_CPY_AND_THIS](pattern::Matcher& m) { + const auto emb_v15 = std::dynamic_pointer_cast(m.get_match_root()); + if (!emb_v15 || transformation_callback(emb_v15) || + emb_v15->get_reduction() != ov::op::v15::EmbeddingBagPacked::Reduction::SUM) { + return false; + } + std::shared_ptr emb_v3; + if (emb_v15->get_input_size() == 2) { + emb_v3 = std::make_shared(emb_v15->input_value(0), emb_v15->input_value(1)); + } else if (emb_v15->get_input_size() == 3) { + emb_v3 = std::make_shared(emb_v15->input_value(0), + emb_v15->input_value(1), + emb_v15->input_value(2)); + } else { + return false; + } + + emb_v3->set_friendly_name(emb_v15->get_friendly_name()); + copy_runtime_info(emb_v15, emb_v3); + replace_node(emb_v15, emb_v3); + + return true; + }; + + auto m = std::make_shared(emb_v15_pattern, matcher_name); + register_matcher(m, callback); +} diff --git a/src/common/transformations/tests/op_conversions/convert_embedding_bag_offsets15_downgrade_test.cpp b/src/common/transformations/tests/op_conversions/convert_embedding_bag_offsets15_downgrade_test.cpp new file mode 100644 index 00000000000..431b7e3d7b3 --- /dev/null +++ b/src/common/transformations/tests/op_conversions/convert_embedding_bag_offsets15_downgrade_test.cpp @@ -0,0 +1,146 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/op_conversions/convert_embedding_bag_offsets15_downgrade.hpp" + +#include + +#include + +#include "common_test_utils/ov_test_utils.hpp" +#include "openvino/opsets/opset15.hpp" +#include "openvino/opsets/opset3.hpp" +#include "openvino/pass/manager.hpp" +#include "transformations/utils/utils.hpp" +using namespace ov; +using namespace testing; + +namespace { + +std::shared_ptr create_v15_model(const op::v15::EmbeddingBagOffsets::Reduction reduction_type, + const size_t num_inputs) { + const auto emb_table = std::make_shared(ov::element::f32, ov::Shape{5, 2}); + const auto indices = std::make_shared(ov::element::i32, ov::Shape{4}); + const auto offsets = std::make_shared(ov::element::i32, ov::Shape{3}); + const auto default_index = std::make_shared(ov::element::i32, ov::Shape{}); + const auto per_sample_weights = std::make_shared(ov::element::f32, ov::Shape{4}); + std::shared_ptr emb; + ov::ParameterVector params; + switch (num_inputs) { + case 0: + emb = std::make_shared(); + params = {}; + break; + case 3: + emb = std::make_shared(emb_table, indices, offsets, reduction_type); + params = {emb_table, indices, offsets}; + break; + case 4: + emb = std::make_shared(emb_table, + indices, + offsets, + default_index, + reduction_type); + params = {emb_table, indices, offsets, default_index}; + break; + case 5: + emb = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights, + reduction_type); + params = {emb_table, indices, offsets, default_index, per_sample_weights}; + break; + } + + emb->set_friendly_name("emb15"); + + return std::make_shared(emb->outputs(), params); +} + +std::shared_ptr create_v3_model(const size_t num_inputs) { + const auto emb_table = std::make_shared(ov::element::f32, ov::Shape{5, 2}); + const auto indices = std::make_shared(ov::element::i32, ov::Shape{4}); + const auto offsets = std::make_shared(ov::element::i32, ov::Shape{3}); + const auto default_index = std::make_shared(ov::element::i32, ov::Shape{}); + const auto per_sample_weights = std::make_shared(ov::element::f32, ov::Shape{4}); + std::shared_ptr emb; + ov::ParameterVector params; + switch (num_inputs) { + case 0: + emb = std::make_shared(); + params = {}; + break; + case 3: + emb = std::make_shared(emb_table, indices, offsets); + params = {emb_table, indices, offsets}; + break; + case 4: + emb = std::make_shared(emb_table, indices, offsets, default_index); + params = {emb_table, indices, offsets, default_index}; + break; + case 5: + emb = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights); + params = {emb_table, indices, offsets, default_index, per_sample_weights}; + break; + } + + emb->set_friendly_name("emb3"); + + return std::make_shared(emb->outputs(), params); +} + +} // namespace + +TEST_F(TransformationTestsF, ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3_sum_0) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagOffsets::Reduction::SUM, 0); + model_ref = create_v3_model(0); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3_sum_3) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagOffsets::Reduction::SUM, 3); + model_ref = create_v3_model(3); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3_sum_4) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagOffsets::Reduction::SUM, 4); + model_ref = create_v3_model(4); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3_sum_5) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagOffsets::Reduction::SUM, 5); + model_ref = create_v3_model(5); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3_mean_0) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagOffsets::Reduction::MEAN, 0); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3_mean_3) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagOffsets::Reduction::MEAN, 3); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagOffsets15ToEmbeddingBagOffsetsSum3_mean_4) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagOffsets::Reduction::MEAN, 4); +} diff --git a/src/common/transformations/tests/op_conversions/convert_embedding_bag_packed15_downgrade_test.cpp b/src/common/transformations/tests/op_conversions/convert_embedding_bag_packed15_downgrade_test.cpp new file mode 100644 index 00000000000..020e9a1f1cb --- /dev/null +++ b/src/common/transformations/tests/op_conversions/convert_embedding_bag_packed15_downgrade_test.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "transformations/op_conversions/convert_embedding_bag_packed15_downgrade.hpp" + +#include + +#include + +#include "common_test_utils/ov_test_utils.hpp" +#include "openvino/opsets/opset15.hpp" +#include "openvino/opsets/opset3.hpp" +#include "openvino/pass/manager.hpp" +#include "transformations/utils/utils.hpp" +using namespace ov; +using namespace testing; + +namespace { + +std::shared_ptr create_v15_model(const op::v15::EmbeddingBagPacked::Reduction reduction_type, + const size_t num_inputs) { + const auto emb_table = std::make_shared(ov::element::f32, ov::Shape{5, 2}); + const auto indices = std::make_shared(ov::element::i32, ov::Shape{3, 2}); + const auto per_sample_weights = std::make_shared(ov::element::f32, ov::Shape{3, 2}); + std::shared_ptr emb; + ov::ParameterVector params; + switch (num_inputs) { + case 0: + emb = std::make_shared(); + params = {}; + break; + case 2: + emb = std::make_shared(emb_table, indices, reduction_type); + params = {emb_table, indices}; + break; + case 3: + emb = std::make_shared(emb_table, indices, per_sample_weights, reduction_type); + params = {emb_table, indices, per_sample_weights}; + break; + } + + emb->set_friendly_name("emb15"); + + return std::make_shared(emb->outputs(), params); +} + +std::shared_ptr create_v3_model(const size_t num_inputs) { + const auto emb_table = std::make_shared(ov::element::f32, ov::Shape{5, 2}); + const auto indices = std::make_shared(ov::element::i32, ov::Shape{3, 2}); + const auto per_sample_weights = std::make_shared(ov::element::f32, ov::Shape{3, 2}); + std::shared_ptr emb; + ov::ParameterVector params; + switch (num_inputs) { + case 0: + emb = std::make_shared(); + params = {}; + break; + case 2: + emb = std::make_shared(emb_table, indices); + params = {emb_table, indices}; + break; + case 3: + emb = std::make_shared(emb_table, indices, per_sample_weights); + params = {emb_table, indices, per_sample_weights}; + break; + } + + emb->set_friendly_name("emb3"); + + return std::make_shared(emb->outputs(), params); +} + +} // namespace + +TEST_F(TransformationTestsF, ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3_sum_0) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagPacked::Reduction::SUM, 0); + model_ref = create_v3_model(0); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3_sum_2) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagPacked::Reduction::SUM, 2); + model_ref = create_v3_model(2); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3_sum_3) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagPacked::Reduction::SUM, 3); + model_ref = create_v3_model(3); + comparator.enable(FunctionsComparator::CmpValues::CONST_VALUES); + comparator.enable(FunctionsComparator::CmpValues::ATTRIBUTES); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3_mean_0) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagPacked::Reduction::MEAN, 0); +} + +TEST_F(TransformationTestsF, ConvertEmbeddingBagPacked15ToEmbeddingBagPackedSum3_mean_2) { + manager.register_pass(); + model = create_v15_model(op::v15::EmbeddingBagPacked::Reduction::MEAN, 2); +} diff --git a/src/core/include/openvino/op/embeddingbag_offsets.hpp b/src/core/include/openvino/op/embeddingbag_offsets.hpp new file mode 100644 index 00000000000..82bc074c859 --- /dev/null +++ b/src/core/include/openvino/op/embeddingbag_offsets.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "openvino/core/axis_set.hpp" +#include "openvino/op/util/embeddingbag_offsets_base.hpp" +#include "openvino/op/util/index_reduction.hpp" + +namespace ov { +namespace op { +namespace v15 { +/// \brief Returns embeddings for given indices +/// \ingroup ov_ops_cpp_api +class OPENVINO_API EmbeddingBagOffsets : public util::EmbeddingBagOffsetsBase { +public: + OPENVINO_OP("EmbeddingBagOffsets", "opset15", util::EmbeddingBagOffsetsBase); + /// \brief Constructs a EmbeddingBagOffsets operation. + EmbeddingBagOffsets() = default; + /// \brief Constructs a EmbeddingBagOffsets operation. + /// + /// EmbeddingBagOffsets constructs an output tensor by replacing every index in a + /// given + /// input tensor with a row (from the weights matrix) at that index + /// + /// \param emb_table tensor containing the embedding lookup table of the module of + /// shape [num_emb, emb_dim1, emb_dim2, ...] and of type T + /// \param indices tensor of shape [num_indices] and of type T_IND. Required + /// \param offsets tensor of shape [batch] and of type T_IND containing the starting + /// index positions of each "bag" in indices. Required. + /// \param default_index scalar of type T_IND containing default index in embedding + /// table to fill empty "bags". If not provided empty "bags" + /// are filled with zeros. Optional. + /// \param per_sample_weigths tensor of the same shape as indices and of type T. + /// Each value in this tensor are multiplied with each + /// value pooled from embedding table for each index. Optional. + + EmbeddingBagOffsets(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Output& default_index, + const Output& per_sample_weights, + const Reduction& reduction = Reduction::SUM); + + EmbeddingBagOffsets(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Output& default_index, + const Reduction& reduction = Reduction::SUM); + + EmbeddingBagOffsets(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Reduction& reduction = Reduction::SUM); + + std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; +}; +} // namespace v15 +} // namespace op +} // namespace ov diff --git a/src/core/include/openvino/op/embeddingbag_offsets_sum.hpp b/src/core/include/openvino/op/embeddingbag_offsets_sum.hpp index 8bc8fa8d281..e916fa4a638 100644 --- a/src/core/include/openvino/op/embeddingbag_offsets_sum.hpp +++ b/src/core/include/openvino/op/embeddingbag_offsets_sum.hpp @@ -32,7 +32,7 @@ public: /// \param default_index scalar of type T_IND containing default index in embedding /// table to fill empty "bags". If not provided empty "bags" /// are filled with zeros. Optional. - /// \param per_sample_weigths tensor of the same shape as indices and of type T. + /// \param per_sample_weights tensor of the same shape as indices and of type T. /// Each value in this tensor are multiplied with each /// value pooled from embedding table for each index. Optional. @@ -50,6 +50,8 @@ public: EmbeddingBagOffsetsSum(const Output& emb_table, const Output& indices, const Output& offsets); std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; + + bool visit_attributes(AttributeVisitor& visitor) override; }; } // namespace v3 } // namespace op diff --git a/src/core/include/openvino/op/embeddingbag_packed.hpp b/src/core/include/openvino/op/embeddingbag_packed.hpp new file mode 100644 index 00000000000..13288e0e462 --- /dev/null +++ b/src/core/include/openvino/op/embeddingbag_packed.hpp @@ -0,0 +1,48 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "openvino/core/axis_set.hpp" +#include "openvino/op/util/embeddingbag_packed_base.hpp" +#include "openvino/op/util/index_reduction.hpp" + +namespace ov { +namespace op { +namespace v15 { +/// \brief Returns embeddings for given indices +/// \ingroup ov_ops_cpp_api +class OPENVINO_API EmbeddingBagPacked : public util::EmbeddingBagPackedBase { +public: + OPENVINO_OP("EmbeddingBagPacked", "opset15", util::EmbeddingBagPackedBase); + /// \brief Constructs a EmbeddingBagPacked operation. + EmbeddingBagPacked() = default; + /// \brief Constructs a EmbeddingBagPacked operation. + /// + /// EmbeddingBagPacked constructs an output tensor by replacing every index in a + /// given + /// input tensor with a row (from the weights matrix) at that index + /// + /// \param emb_table Tensor containing the embedding lookup table of the module of + /// shape [num_emb, emb_dim1, emb_dim2, ...] and of type T + /// \param indices Tensor of shape `[batch, indices_per_bag]` and of type *T_IND*. + /// Required. + /// \param per_sample_weigths tensor of the same shape as indices and of type T. + /// Each value in this tensor are multiplied with each + /// value pooled from embedding table for each index. Optional. + + EmbeddingBagPacked(const Output& emb_table, + const Output& indices, + const Output& per_sample_weights, + const Reduction& reduction = Reduction::SUM); + + EmbeddingBagPacked(const Output& emb_table, + const Output& indices, + const Reduction& reduction = Reduction::SUM); + + std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; +}; +} // namespace v15 +} // namespace op +} // namespace ov diff --git a/src/core/include/openvino/op/embeddingbag_packedsum.hpp b/src/core/include/openvino/op/embeddingbag_packedsum.hpp index 7abec388926..de0507d7708 100644 --- a/src/core/include/openvino/op/embeddingbag_packedsum.hpp +++ b/src/core/include/openvino/op/embeddingbag_packedsum.hpp @@ -39,6 +39,8 @@ public: EmbeddingBagPackedSum(const Output& emb_table, const Output& indices); std::shared_ptr clone_with_new_inputs(const OutputVector& new_args) const override; + + bool visit_attributes(AttributeVisitor& visitor) override; }; } // namespace v3 } // namespace op diff --git a/src/core/include/openvino/op/ops.hpp b/src/core/include/openvino/op/ops.hpp index b1e3c23c325..4e2cde0882d 100644 --- a/src/core/include/openvino/op/ops.hpp +++ b/src/core/include/openvino/op/ops.hpp @@ -51,7 +51,9 @@ #include "openvino/op/einsum.hpp" #include "openvino/op/elu.hpp" #include "openvino/op/embedding_segments_sum.hpp" +#include "openvino/op/embeddingbag_offsets.hpp" #include "openvino/op/embeddingbag_offsets_sum.hpp" +#include "openvino/op/embeddingbag_packed.hpp" #include "openvino/op/embeddingbag_packedsum.hpp" #include "openvino/op/equal.hpp" #include "openvino/op/erf.hpp" diff --git a/src/core/include/openvino/op/util/embeddingbag_offsets_base.hpp b/src/core/include/openvino/op/util/embeddingbag_offsets_base.hpp index 030a3f12671..bf2b7ab1c34 100644 --- a/src/core/include/openvino/op/util/embeddingbag_offsets_base.hpp +++ b/src/core/include/openvino/op/util/embeddingbag_offsets_base.hpp @@ -14,6 +14,9 @@ namespace util { class OPENVINO_API EmbeddingBagOffsetsBase : public Op { public: OPENVINO_OP("EmbeddingBagOffsetsBase", "util"); + + enum class Reduction { SUM, MEAN }; + /// \brief Constructs a EmbeddingBagOffsetsBase operation. EmbeddingBagOffsetsBase() = default; /// \brief Constructs a EmbeddingBagOffsetsBase operation. @@ -28,13 +31,12 @@ public: /// \param indices tensor of shape [num_indices] and of type T_IND. Required /// \param offsets tensor of shape [batch] and of type T_IND containing the starting /// index positions of each "bag" in indices. Required. - /// \param per_sample_weigths tensor of the same shape as indices and of type T. + /// \param per_sample_weights tensor of the same shape as indices and of type T. /// Each value in this tensor are multiplied with each /// value pooled from embedding table for each index. Optional. /// \param default_index scalar of type T_IND containing default index in embedding /// table to fill empty "bags". If not provided empty "bags" /// are filled with zeros. Optional. - EmbeddingBagOffsetsBase(const Output& emb_table, const Output& indices, const Output& offsets, @@ -48,16 +50,53 @@ public: EmbeddingBagOffsetsBase(const Output& emb_table, const Output& indices, const Output& offsets); + EmbeddingBagOffsetsBase(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Output& default_index, + const Output& per_sample_weights, + const Reduction& reduction); + + EmbeddingBagOffsetsBase(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Output& default_index, + const Reduction& reduction); + + EmbeddingBagOffsetsBase(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Reduction& reduction); + void validate_and_infer_types() override; bool visit_attributes(AttributeVisitor& visitor) override; + const Reduction& get_reduction() { + return m_reduction; + } + private: static constexpr int EMB_TABLE = 0; static constexpr int INDICES = 1; static constexpr int OFFSETS = 2; static constexpr int DEFAULT_INDEX = 3; static constexpr int PER_SAMPLE_WEIGHTS = 4; + +protected: + Reduction m_reduction = Reduction::SUM; }; } // namespace util } // namespace op +template <> +class OPENVINO_API AttributeAdapter + : public EnumAttributeAdapterBase { +public: + AttributeAdapter(op::util::EmbeddingBagOffsetsBase::Reduction& value) + : EnumAttributeAdapterBase(value) {} + + OPENVINO_RTTI("AttributeAdapter"); +}; + +OPENVINO_API +std::ostream& operator<<(std::ostream& s, const op::util::EmbeddingBagOffsetsBase::Reduction& reduction); } // namespace ov diff --git a/src/core/include/openvino/op/util/embeddingbag_packed_base.hpp b/src/core/include/openvino/op/util/embeddingbag_packed_base.hpp index e79721787c9..b5ab30e2fde 100644 --- a/src/core/include/openvino/op/util/embeddingbag_packed_base.hpp +++ b/src/core/include/openvino/op/util/embeddingbag_packed_base.hpp @@ -13,6 +13,7 @@ namespace util { /// \brief Returns embeddings for given indices class OPENVINO_API EmbeddingBagPackedBase : public Op { public: + enum class Reduction { SUM, MEAN }; OPENVINO_OP("EmbeddingBagPackedBase", "util"); /// \brief Constructs a EmbeddingBagPackedBase operation. EmbeddingBagPackedBase() = default; @@ -26,24 +27,49 @@ public: /// shape [num_emb, emb_dim1, emb_dim2, ...] and of type T /// \param indices Tensor of shape `[batch, indices_per_bag]` and of type *T_IND*. /// Required. - /// \param per_sample_weigths tensor of the same shape as indices and of type T. + /// \param per_sample_weights tensor of the same shape as indices and of type T. /// Each value in this tensor are multiplied with each /// value pooled from embedding table for each index. Optional. - EmbeddingBagPackedBase(const Output& emb_table, const Output& indices, const Output& per_sample_weights); EmbeddingBagPackedBase(const Output& emb_table, const Output& indices); + EmbeddingBagPackedBase(const Output& emb_table, + const Output& indices, + const Output& per_sample_weights, + const Reduction& reduction); + + EmbeddingBagPackedBase(const Output& emb_table, const Output& indices, const Reduction& reduction); + void validate_and_infer_types() override; bool visit_attributes(AttributeVisitor& visitor) override; + const Reduction& get_reduction() { + return m_reduction; + } + private: static constexpr int EMB_TABLE = 0; static constexpr int INDICES = 1; static constexpr int PER_SAMPLE_WEIGHTS = 2; + +protected: + Reduction m_reduction = Reduction::SUM; }; } // namespace util } // namespace op +template <> +class OPENVINO_API AttributeAdapter + : public EnumAttributeAdapterBase { +public: + AttributeAdapter(op::util::EmbeddingBagPackedBase::Reduction& value) + : EnumAttributeAdapterBase(value) {} + + OPENVINO_RTTI("AttributeAdapter"); +}; + +OPENVINO_API +std::ostream& operator<<(std::ostream& s, const op::util::EmbeddingBagPackedBase::Reduction& reduction); } // namespace ov diff --git a/src/core/include/openvino/opsets/opset15_tbl.hpp b/src/core/include/openvino/opsets/opset15_tbl.hpp index 452b90cbd90..eac496c13ab 100644 --- a/src/core/include/openvino/opsets/opset15_tbl.hpp +++ b/src/core/include/openvino/opsets/opset15_tbl.hpp @@ -14,3 +14,5 @@ _OPENVINO_OP_REG(ShapeOf, ov::op::v3) // New operations added in opset15 _OPENVINO_OP_REG(ScatterNDUpdate, ov::op::v15) +_OPENVINO_OP_REG(EmbeddingBagPacked, ov::op::v15) +_OPENVINO_OP_REG(EmbeddingBagOffsets, ov::op::v15) diff --git a/src/core/reference/include/openvino/reference/embedding_bag_offsets_sum.hpp b/src/core/reference/include/openvino/reference/embedding_bag_offsets.hpp similarity index 79% rename from src/core/reference/include/openvino/reference/embedding_bag_offsets_sum.hpp rename to src/core/reference/include/openvino/reference/embedding_bag_offsets.hpp index 48633f008a1..0a424641029 100644 --- a/src/core/reference/include/openvino/reference/embedding_bag_offsets_sum.hpp +++ b/src/core/reference/include/openvino/reference/embedding_bag_offsets.hpp @@ -5,18 +5,22 @@ #pragma once #include "openvino/core/shape.hpp" +#include "openvino/op/util/embeddingbag_offsets_base.hpp" +#include "openvino/reference/divide.hpp" namespace ov { namespace reference { template -void embeddingBagOffsetsSum(const T* emb_table, - const U* indices, - const U* offsets, - const U* default_index, - const T* weights, - T* out, - const size_t indices_count, - const Shape& outShape) { +void embeddingBagOffsets(const T* emb_table, + const U* indices, + const U* offsets, + const U* default_index, + const T* weights, + T* out, + const size_t indices_count, + const Shape& outShape, + ov::op::util::EmbeddingBagOffsetsBase::Reduction reduction) { + using Reduction = ov::op::util::EmbeddingBagOffsetsBase::Reduction; const size_t offsets_size = outShape[0]; std::vector default_indices; if (default_index) @@ -27,7 +31,6 @@ void embeddingBagOffsetsSum(const T* emb_table, embDepth *= outShape[i]; } std::fill(out, out + shape_size(outShape), T{0}); - auto get_indices = [&](size_t emb_index, const U*& indices_ref, size_t& indices_num, size_t& weights_idx, bool& with_weights) { if (emb_index >= offsets_size) @@ -86,6 +89,11 @@ void embeddingBagOffsetsSum(const T* emb_table, } } } + if (reduction == Reduction::MEAN) { + for (size_t i = 0lu; i < embDepth; i++) { + out[dst_index + i] /= (T)indices_size; + } + } } } diff --git a/src/core/reference/include/openvino/reference/embedding_bag_packed_sum.hpp b/src/core/reference/include/openvino/reference/embedding_bag_packed.hpp similarity index 65% rename from src/core/reference/include/openvino/reference/embedding_bag_packed_sum.hpp rename to src/core/reference/include/openvino/reference/embedding_bag_packed.hpp index bfddc0729f0..4616f3b2974 100644 --- a/src/core/reference/include/openvino/reference/embedding_bag_packed_sum.hpp +++ b/src/core/reference/include/openvino/reference/embedding_bag_packed.hpp @@ -5,16 +5,19 @@ #pragma once #include "openvino/core/shape.hpp" +#include "openvino/op/util/embeddingbag_packed_base.hpp" namespace ov { namespace reference { template -void embeddingBagPackedSum(const T* emb_table, - const U* indices, - const T* weights, - T* out, - const Shape& indicesShape, - const Shape& outShape) { +void embeddingBagPacked(const T* emb_table, + const U* indices, + const T* weights, + T* out, + const Shape& indicesShape, + const Shape& outShape, + const ov::op::util::EmbeddingBagPackedBase::Reduction reduction) { + using Reduction = ov::op::util::EmbeddingBagPackedBase::Reduction; const size_t indices_per_bag = indicesShape[1]; size_t embDepth = 1lu; @@ -42,6 +45,11 @@ void embeddingBagPackedSum(const T* emb_table, } } } + if (reduction == Reduction::MEAN) { + for (size_t i = 0lu; i < shape_size(outShape); i++) { + out[i] /= (T)indices_per_bag; + } + } } // embeddingBagPackedSum diff --git a/src/core/src/op/embeddingbag_offsets.cpp b/src/core/src/op/embeddingbag_offsets.cpp new file mode 100644 index 00000000000..9fdb233c7af --- /dev/null +++ b/src/core/src/op/embeddingbag_offsets.cpp @@ -0,0 +1,57 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/embeddingbag_offsets.hpp" + +#include "itt.hpp" + +namespace ov { + +op::v15::EmbeddingBagOffsets::EmbeddingBagOffsets(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Output& default_index, + const Output& per_sample_weights, + const Reduction& reduction) + : util::EmbeddingBagOffsetsBase(emb_table, indices, offsets, default_index, per_sample_weights, reduction) {} + +op::v15::EmbeddingBagOffsets::EmbeddingBagOffsets(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Output& default_index, + const Reduction& reduction) + : util::EmbeddingBagOffsetsBase(emb_table, indices, offsets, default_index, reduction) {} + +op::v15::EmbeddingBagOffsets::EmbeddingBagOffsets(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Reduction& reduction) + : util::EmbeddingBagOffsetsBase(emb_table, indices, offsets, reduction) {} + +std::shared_ptr op::v15::EmbeddingBagOffsets::clone_with_new_inputs(const OutputVector& new_args) const { + OV_OP_SCOPE(v15_EmbeddingBagOffsets_clone_with_new_inputs); + check_new_args_count(this, new_args); + if (new_args.size() == 3) { + return std::make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + m_reduction); + } else if (new_args.size() == 4) { + return std::make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + new_args.at(3), + m_reduction); + } else if (new_args.size() == 5) { + return std::make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + new_args.at(3), + new_args.at(4), + m_reduction); + } else { + OPENVINO_THROW("Incorrect number of arguments"); + } +} +} // namespace ov diff --git a/src/core/src/op/embeddingbag_offsets_sum.cpp b/src/core/src/op/embeddingbag_offsets_sum.cpp index f075fc0434a..96aa3053c3c 100644 --- a/src/core/src/op/embeddingbag_offsets_sum.cpp +++ b/src/core/src/op/embeddingbag_offsets_sum.cpp @@ -46,4 +46,8 @@ std::shared_ptr op::v3::EmbeddingBagOffsetsSum::clone_with_new_inputs(cons OPENVINO_THROW("Incorrect number of arguments"); } } +bool op::v3::EmbeddingBagOffsetsSum::visit_attributes(AttributeVisitor& visitor) { + OV_OP_SCOPE(v3_EmbeddingBagOffsetsSum_visit_attributes); + return true; +} } // namespace ov diff --git a/src/core/src/op/embeddingbag_packed.cpp b/src/core/src/op/embeddingbag_packed.cpp new file mode 100644 index 00000000000..6c7e6b15bcf --- /dev/null +++ b/src/core/src/op/embeddingbag_packed.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/embeddingbag_packed.hpp" + +#include "itt.hpp" + +namespace ov { + +op::v15::EmbeddingBagPacked::EmbeddingBagPacked(const Output& emb_table, + const Output& indices, + const Output& per_sample_weights, + const Reduction& reduction) + : util::EmbeddingBagPackedBase(emb_table, indices, per_sample_weights, reduction) {} + +op::v15::EmbeddingBagPacked::EmbeddingBagPacked(const Output& emb_table, + const Output& indices, + const Reduction& reduction) + : util::EmbeddingBagPackedBase(emb_table, indices, reduction) {} + +std::shared_ptr op::v15::EmbeddingBagPacked::clone_with_new_inputs(const OutputVector& new_args) const { + OV_OP_SCOPE(v15_EmbeddingBagPacked_clone_with_new_inputs); + check_new_args_count(this, new_args); + if (new_args.size() == 2) { + return std::make_shared(new_args.at(0), new_args.at(1), m_reduction); + } else if (new_args.size() == 3) { + return std::make_shared(new_args.at(0), + new_args.at(1), + new_args.at(2), + m_reduction); + } else { + OPENVINO_THROW("Incorrect number of arguments"); + } +} +} // namespace ov diff --git a/src/core/src/op/embeddingbag_packedsum.cpp b/src/core/src/op/embeddingbag_packedsum.cpp index bbf7bc97497..4189b495b8e 100644 --- a/src/core/src/op/embeddingbag_packedsum.cpp +++ b/src/core/src/op/embeddingbag_packedsum.cpp @@ -27,4 +27,8 @@ std::shared_ptr op::v3::EmbeddingBagPackedSum::clone_with_new_inputs(const OPENVINO_THROW("Incorrect number of arguments"); } } +bool op::v3::EmbeddingBagPackedSum::visit_attributes(AttributeVisitor& visitor) { + OV_OP_SCOPE(v3_EmbeddingBagPackedSum_visit_attributes); + return true; +} } // namespace ov diff --git a/src/core/src/op/util/embeddingbag_offsets_base.cpp b/src/core/src/op/util/embeddingbag_offsets_base.cpp index f032c09658d..cf115521cf6 100644 --- a/src/core/src/op/util/embeddingbag_offsets_base.cpp +++ b/src/core/src/op/util/embeddingbag_offsets_base.cpp @@ -12,7 +12,8 @@ ov::op::util::EmbeddingBagOffsetsBase::EmbeddingBagOffsetsBase(const Output& offsets, const Output& default_index, const Output& per_sample_weights) - : Op({emb_table, indices, offsets, default_index, per_sample_weights}) { + : Op({emb_table, indices, offsets, default_index, per_sample_weights}), + m_reduction{Reduction::SUM} { constructor_validate_and_infer_types(); } @@ -20,14 +21,46 @@ ov::op::util::EmbeddingBagOffsetsBase::EmbeddingBagOffsetsBase(const Output& indices, const Output& offsets, const Output& default_index) - : Op({emb_table, indices, offsets, default_index}) { + : Op({emb_table, indices, offsets, default_index}), + m_reduction{Reduction::SUM} { constructor_validate_and_infer_types(); } ov::op::util::EmbeddingBagOffsetsBase::EmbeddingBagOffsetsBase(const Output& emb_table, const Output& indices, const Output& offsets) - : Op({emb_table, indices, offsets}) { + : Op({emb_table, indices, offsets}), + m_reduction{Reduction::SUM} { + constructor_validate_and_infer_types(); +} + +ov::op::util::EmbeddingBagOffsetsBase::EmbeddingBagOffsetsBase(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Output& default_index, + const Output& per_sample_weights, + const Reduction& reduction) + : Op({emb_table, indices, offsets, default_index, per_sample_weights}), + m_reduction{reduction} { + constructor_validate_and_infer_types(); +} + +ov::op::util::EmbeddingBagOffsetsBase::EmbeddingBagOffsetsBase(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Output& default_index, + const Reduction& reduction) + : Op({emb_table, indices, offsets, default_index}), + m_reduction{reduction} { + constructor_validate_and_infer_types(); +} + +ov::op::util::EmbeddingBagOffsetsBase::EmbeddingBagOffsetsBase(const Output& emb_table, + const Output& indices, + const Output& offsets, + const Reduction& reduction) + : Op({emb_table, indices, offsets}), + m_reduction{reduction} { constructor_validate_and_infer_types(); } @@ -67,6 +100,9 @@ void ov::op::util::EmbeddingBagOffsetsBase::validate_and_infer_types() { } if (get_input_size() == 5) { + NODE_VALIDATION_CHECK(this, + m_reduction == Reduction::SUM, + "Per sample weights can only be used in Reduction::SUM mode."); NODE_VALIDATION_CHECK(this, get_input_element_type(EMB_TABLE).compatible(get_input_element_type(PER_SAMPLE_WEIGHTS)), "Per sample weight element type (", @@ -83,5 +119,20 @@ void ov::op::util::EmbeddingBagOffsetsBase::validate_and_infer_types() { bool ov::op::util::EmbeddingBagOffsetsBase::visit_attributes(AttributeVisitor& visitor) { OV_OP_SCOPE(util_EmbeddingBagOffsetsBase_visit_attributes); + visitor.on_attribute("reduction", m_reduction); return true; } +namespace ov { +template <> +OPENVINO_API EnumNames& +EnumNames::get() { + static auto enum_names = EnumNames( + "op::util::EmbeddingBagOffsetsBase::Reduction", + {{"sum", op::util::EmbeddingBagOffsetsBase::Reduction::SUM}, + {"mean", op::util::EmbeddingBagOffsetsBase::Reduction::MEAN}}); + return enum_names; +} +std::ostream& operator<<(std::ostream& s, const op::util::EmbeddingBagOffsetsBase::Reduction& reduction) { + return s << as_string(reduction); +} +} // namespace ov diff --git a/src/core/src/op/util/embeddingbag_packed_base.cpp b/src/core/src/op/util/embeddingbag_packed_base.cpp index cfebf16d68c..1fec7e5bfd2 100644 --- a/src/core/src/op/util/embeddingbag_packed_base.cpp +++ b/src/core/src/op/util/embeddingbag_packed_base.cpp @@ -7,17 +7,35 @@ #include "embeddingbag_packed_shape_inference.hpp" #include "itt.hpp" -using namespace std; - ov::op::util::EmbeddingBagPackedBase::EmbeddingBagPackedBase(const Output& emb_table, const Output& indices, const Output& per_sample_weights) - : Op({emb_table, indices, per_sample_weights}) { + : Op({emb_table, indices, per_sample_weights}), + m_reduction{Reduction::SUM} { constructor_validate_and_infer_types(); } ov::op::util::EmbeddingBagPackedBase::EmbeddingBagPackedBase(const Output& emb_table, const Output& indices) - : Op({emb_table, indices}) { + : Op({emb_table, indices}), + m_reduction{Reduction::SUM} { + constructor_validate_and_infer_types(); +} +ov::op::util::EmbeddingBagPackedBase::EmbeddingBagPackedBase( + const Output& emb_table, + const Output& indices, + const Output& per_sample_weights, + const ov::op::util::EmbeddingBagPackedBase::Reduction& reduction) + : Op({emb_table, indices, per_sample_weights}), + m_reduction{reduction} { + constructor_validate_and_infer_types(); +} + +ov::op::util::EmbeddingBagPackedBase::EmbeddingBagPackedBase( + const Output& emb_table, + const Output& indices, + const ov::op::util::EmbeddingBagPackedBase::Reduction& reduction) + : Op({emb_table, indices}), + m_reduction{reduction} { constructor_validate_and_infer_types(); } @@ -29,6 +47,9 @@ void ov::op::util::EmbeddingBagPackedBase::validate_and_infer_types() { "INDICES type must be i32 or i64"); if (get_input_size() == 3) { + NODE_VALIDATION_CHECK(this, + m_reduction == Reduction::SUM, + "Per sample weights can only be used in Reduction::SUM mode."); NODE_VALIDATION_CHECK(this, get_input_element_type(EMB_TABLE).compatible(get_input_element_type(PER_SAMPLE_WEIGHTS)), "Per sample weight element type (", @@ -45,5 +66,22 @@ void ov::op::util::EmbeddingBagPackedBase::validate_and_infer_types() { bool ov::op::util::EmbeddingBagPackedBase::visit_attributes(AttributeVisitor& visitor) { OV_OP_SCOPE(util_EmbeddingBagPackedBase_visit_attributes); + visitor.on_attribute("reduction", m_reduction); return true; } + +namespace ov { +std::ostream& operator<<(std::ostream& s, const op::util::EmbeddingBagPackedBase::Reduction& reduction) { + return s << as_string(reduction); +} +template <> +OPENVINO_API EnumNames& +EnumNames::get() { + static auto enum_names = EnumNames( + "op::util::EmbeddingBagPackedBase::Reduction", + {{"sum", op::util::EmbeddingBagPackedBase::Reduction::SUM}, + {"mean", op::util::EmbeddingBagPackedBase::Reduction::MEAN}}); + return enum_names; +} + +} // namespace ov diff --git a/src/core/tests/opset.cpp b/src/core/tests/opset.cpp index 346d1b84093..ecd533f0aa8 100644 --- a/src/core/tests/opset.cpp +++ b/src/core/tests/opset.cpp @@ -75,7 +75,7 @@ INSTANTIATE_TEST_SUITE_P(opset, OpsetTestParams{ov::get_opset12, 178}, OpsetTestParams{ov::get_opset13, 186}, OpsetTestParams{ov::get_opset14, 189}, - OpsetTestParams{ov::get_opset15, 4}), + OpsetTestParams{ov::get_opset15, 6}), OpsetTestNameGenerator{}); class MyOpOld : public ov::op::Op { diff --git a/src/core/tests/type_prop/embeddingbag_offsets.cpp b/src/core/tests/type_prop/embeddingbag_offsets.cpp new file mode 100644 index 00000000000..b4a76b9a56e --- /dev/null +++ b/src/core/tests/type_prop/embeddingbag_offsets.cpp @@ -0,0 +1,380 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/embeddingbag_offsets.hpp" + +#include + +#include "common_test_utils/test_assertions.hpp" +#include "common_test_utils/type_prop.hpp" + +using namespace ov; +using namespace testing; + +TEST(type_prop, embedding_bag_offsets_default_ctor) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2, 6}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + auto op = std::make_shared(); + op->set_arguments(OutputVector{emb_table, indices, offsets, default_index, per_sample_weights}); + op->validate_and_infer_types(); + + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{3, 2, 6})); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_reduction_mean) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto reduction = op::v15::EmbeddingBagOffsets::Reduction::MEAN; + + auto embedding_bag_offsets = std::make_shared(emb_table, indices, offsets, reduction); + EXPECT_TRUE(embedding_bag_offsets->get_output_partial_shape(0).same_scheme(PartialShape{3, 2})); + EXPECT_EQ(embedding_bag_offsets->get_output_element_type(0), element::f32); + EXPECT_EQ(indices->get_partial_shape().rank().get_length(), 1); + EXPECT_EQ(offsets->get_partial_shape().rank().get_length(), 1); + EXPECT_EQ(embedding_bag_offsets->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::MEAN); +} + +TEST(type_prop, embedding_bag_reduction_mean_index) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto default_index = std::make_shared(element::i64, Shape{}); + auto reduction = op::v15::EmbeddingBagOffsets::Reduction::MEAN; + + auto embedding_bag_offsets = + std::make_shared(emb_table, indices, offsets, default_index, reduction); + EXPECT_TRUE(embedding_bag_offsets->get_output_partial_shape(0).same_scheme(PartialShape{3, 2})); + EXPECT_EQ(embedding_bag_offsets->get_output_element_type(0), element::f32); + EXPECT_EQ(indices->get_partial_shape().rank().get_length(), 1); + EXPECT_EQ(offsets->get_partial_shape().rank().get_length(), 1); + EXPECT_EQ(embedding_bag_offsets->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::MEAN); +} + +TEST(type_prop, embedding_bag_offsets_labeled_interval_dims) { + auto emb_shape = PartialShape{{5, 10}, {2, 4}, {1, 3}}; + auto emb_symbols = set_shape_symbols(emb_shape); + auto off_shape = PartialShape{{6, 8}}; + auto off_symbols = set_shape_symbols(off_shape); + + auto emb_table = std::make_shared(element::f32, emb_shape); + auto indices = std::make_shared(element::i64, PartialShape{{3, 4}}); + auto offsets = std::make_shared(element::i64, off_shape); + auto per_sample_weights = std::make_shared(element::f32, PartialShape{{3, 4}}); + auto default_index = std::make_shared(element::i64, Shape{}); + + auto op = + std::make_shared(emb_table, indices, offsets, default_index, per_sample_weights); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{{6, 8}, {2, 4}, {1, 3}})); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), + ElementsAre(off_symbols[0], emb_symbols[1], emb_symbols[2])); + EXPECT_EQ(op->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_offsets) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + auto embedding_bag_offsets = + std::make_shared(emb_table, indices, offsets, default_index, per_sample_weights); + EXPECT_TRUE(embedding_bag_offsets->get_output_partial_shape(0).same_scheme(PartialShape{3, 2})); + EXPECT_TRUE(indices->get_partial_shape().same_scheme(per_sample_weights->get_partial_shape())); + EXPECT_EQ(embedding_bag_offsets->get_output_element_type(0), element::f32); + EXPECT_EQ(indices->get_partial_shape().rank().get_length(), 1); + EXPECT_EQ(offsets->get_partial_shape().rank().get_length(), 1); + EXPECT_EQ(embedding_bag_offsets->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_offsets_dynamic_emb_table) { + auto emb_table = std::make_shared(element::f32, PartialShape{5, Dimension::dynamic()}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + auto embedding_bag_offsets = + std::make_shared(emb_table, indices, offsets, default_index, per_sample_weights); + + EXPECT_TRUE(embedding_bag_offsets->get_output_partial_shape(0).same_scheme(PartialShape{3, Dimension::dynamic()})); + EXPECT_EQ(embedding_bag_offsets->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_offsets_dynamic_offsets) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, PartialShape{Dimension::dynamic()}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + auto embedding_bag_offsets = + std::make_shared(emb_table, indices, offsets, default_index, per_sample_weights); + + EXPECT_TRUE(embedding_bag_offsets->get_output_partial_shape(0).same_scheme(PartialShape{Dimension::dynamic(), 2})); + EXPECT_EQ(embedding_bag_offsets->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_offsets_dynamic_emb_table_offsets) { + auto emb_table = std::make_shared(element::f32, PartialShape{5, Dimension::dynamic()}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, PartialShape{Dimension::dynamic()}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + auto reduction = op::v15::EmbeddingBagOffsets::Reduction::SUM; + + auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights, + reduction); + + EXPECT_TRUE(embedding_bag_offsets->get_output_partial_shape(0).same_scheme( + PartialShape{Dimension::dynamic(), Dimension::dynamic()})); + EXPECT_EQ(embedding_bag_offsets->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_offsets_fail_indices_element_type) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::f32, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("INDICES type must be i32 or i64")); +} + +TEST(type_prop, embedding_bag_offsets_fail_offsets_element_type) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::f32, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("OFFSETS type must be i32 or i64")); +} + +TEST(type_prop, embedding_bag_offsets_fail_default_index_element_type) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::f32, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("DEFAULT_INDEX type must be i32 or i64")); +} + +TEST(type_prop, embedding_bag_offsets_fail_mismatch_element_type) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i32, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("Offsets element type (i64) must match indices element type (i32)")); +} + +TEST(type_prop, embedding_bag_offsets_fail_mismatch_element_type_1) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i32, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("Default_index element type (i32) must match indices element type (i64)")); +} + +TEST(type_prop, embedding_bag_offsets_fail_mismatch_element_type_2) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::i64, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("Per sample weight element type (i64) must " + "match embedding table element type (f32)")); +} + +TEST(type_prop, embedding_bag_offsets_fail_mismatch_shape) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{3}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("INDICES and PER_SAMPLE_WEIGHTS shape must be same")); +} + +TEST(type_prop, embedding_bag_offsets_fail_default_index_scalar) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{2}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("DEFAULT_INDEX must be a scalar")); +} + +TEST(type_prop, embedding_bag_offsets_fail_indices_1d) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4, 2}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("INDICES must be 1D")); +} + +TEST(type_prop, embedding_bag_offsets_fail_emb_table_0d) { + auto emb_table = std::make_shared(element::f32, Shape{}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto op = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("EMB_TABLE can't be a scalar")); +} + +TEST(type_prop, embedding_bag_offsets_fail_offsets_1d) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3, 2}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("OFFSETS must be 1D")); +} + +TEST(type_prop, embedding_bag_offsets_fail_per_sample_weights_1d) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4, 2}); + auto default_index = std::make_shared(element::i64, Shape{}); + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights), + NodeValidationFailure, + HasSubstr("PER_SAMPLE_WEIGHTS must be 1D")); +} + +TEST(type_prop, embedding_bag_offsets_fail_per_sample_weights_reduction_mean) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4, 2}); + auto default_index = std::make_shared(element::i64, Shape{}); + auto reduction = op::v15::EmbeddingBagOffsets::Reduction::MEAN; + + OV_EXPECT_THROW(auto embedding_bag_offsets = std::make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights, + reduction), + NodeValidationFailure, + HasSubstr("Per sample weights can only be used in Reduction::SUM mode")); +} + +TEST(type_prop, embedding_bag_offsets_3_args_api) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + + auto embedding_bag_offsets = std::make_shared(emb_table, indices, offsets); + EXPECT_TRUE(embedding_bag_offsets->get_output_partial_shape(0).same_scheme(PartialShape{3, 2})); + EXPECT_EQ(embedding_bag_offsets->get_output_element_type(0), element::f32); + EXPECT_EQ(indices->get_partial_shape().rank().get_length(), 1); + EXPECT_EQ(offsets->get_partial_shape().rank().get_length(), 1); + EXPECT_EQ(embedding_bag_offsets->get_reduction(), op::v15::EmbeddingBagOffsets::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_offsets_fail_indices_element_type_3_args_api) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::f32, Shape{4}); + auto offsets = std::make_shared(element::i64, Shape{3}); + + OV_EXPECT_THROW( + auto embedding_bag_offsets = std::make_shared(emb_table, indices, offsets), + NodeValidationFailure, + HasSubstr("INDICES type must be i32 or i64")); +} diff --git a/src/core/tests/type_prop/embeddingbag_packed.cpp b/src/core/tests/type_prop/embeddingbag_packed.cpp new file mode 100644 index 00000000000..f0bfd131a6c --- /dev/null +++ b/src/core/tests/type_prop/embeddingbag_packed.cpp @@ -0,0 +1,229 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/embeddingbag_packed.hpp" + +#include + +#include "common_test_utils/test_assertions.hpp" +#include "common_test_utils/type_prop.hpp" + +using namespace ov; +using namespace testing; + +TEST(type_prop, embedding_bag_packed_default_ctor) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2, 6}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{3, 4}); + + auto op = std::make_shared(); + op->set_arguments(OutputVector{emb_table, indices, per_sample_weights}); + op->validate_and_infer_types(); + + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{3, 2, 6})); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_reduction(), op::v15::EmbeddingBagPacked::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_packed_labeled_interval_dims_2in) { + auto emb_shape = PartialShape{{5, 10}, {2, 4}, {1, 3}}; + auto emb_symbols = set_shape_symbols(emb_shape); + auto ind_shape = PartialShape{{6, 8}, 4}; + auto ind_symbols = set_shape_symbols(ind_shape); + + auto emb_table = std::make_shared(element::f32, emb_shape); + auto indices = std::make_shared(element::i64, ind_shape); + + auto op = std::make_shared(emb_table, indices); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{{6, 8}, {2, 4}, {1, 3}})); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), + ElementsAre(ind_symbols[0], emb_symbols[1], emb_symbols[2])); + EXPECT_EQ(op->get_reduction(), op::v15::EmbeddingBagPacked::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_packed_labeled_interval_dims_2in_reduction) { + auto emb_shape = PartialShape{{5, 10}, {2, 4}, {1, 3}}; + auto emb_symbols = set_shape_symbols(emb_shape); + auto ind_shape = PartialShape{{6, 8}, 4}; + auto ind_symbols = set_shape_symbols(ind_shape); + auto emb_table = std::make_shared(element::f32, emb_shape); + auto indices = std::make_shared(element::i64, ind_shape); + auto reduction = op::v15::EmbeddingBagPacked::Reduction::MEAN; + + auto op = std::make_shared(emb_table, indices, reduction); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{{6, 8}, {2, 4}, {1, 3}})); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), + ElementsAre(ind_symbols[0], emb_symbols[1], emb_symbols[2])); + EXPECT_EQ(op->get_reduction(), op::v15::EmbeddingBagPacked::Reduction::MEAN); +} + +TEST(type_prop, embedding_bag_packed_labeled_interval_dims_3in) { + auto emb_shape = PartialShape{{5, 10}, {2, 4}, {1, 3}}; + auto emb_symbols = set_shape_symbols(emb_shape); + auto ind_shape = PartialShape{{2, 6}, 4}; + auto ind_symbols = set_shape_symbols(ind_shape); + auto sample_shape = PartialShape{{4, 8}, 4}; + auto sample_symbols = set_shape_symbols(sample_shape); + + auto emb_table = std::make_shared(element::f32, emb_shape); + auto indices = std::make_shared(element::i64, ind_shape); + auto per_sample_weights = std::make_shared(element::f32, sample_shape); + + auto op = std::make_shared(emb_table, indices, per_sample_weights); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{{4, 6}, {2, 4}, {1, 3}})); + EXPECT_THAT(get_shape_symbols(op->get_output_partial_shape(0)), + ElementsAre(ind_symbols[0], emb_symbols[1], emb_symbols[2])); + EXPECT_EQ(op->get_reduction(), op::v15::EmbeddingBagPacked::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_packed) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{3, 4}); + + auto embedding_bag_packed = std::make_shared(emb_table, indices, per_sample_weights); + EXPECT_TRUE(embedding_bag_packed->get_output_partial_shape(0).same_scheme(PartialShape{3, 2})); + EXPECT_TRUE(indices->get_partial_shape().same_scheme(per_sample_weights->get_partial_shape())); + EXPECT_EQ(embedding_bag_packed->get_output_element_type(0), element::f32); + EXPECT_EQ(indices->get_partial_shape().rank().get_length(), 2); + EXPECT_EQ(embedding_bag_packed->get_reduction(), op::v15::EmbeddingBagPacked::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_packed_dynamic_emb_table) { + auto emb_table = std::make_shared(element::f32, PartialShape{5, Dimension::dynamic()}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{3, 4}); + auto default_index = std::make_shared(element::i64, Shape{}); + + auto embedding_bag_packed = std::make_shared(emb_table, indices, per_sample_weights); + + EXPECT_TRUE(embedding_bag_packed->get_output_partial_shape(0).same_scheme(PartialShape{3, Dimension::dynamic()})); + EXPECT_EQ(embedding_bag_packed->get_reduction(), op::v15::EmbeddingBagPacked::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_packed_dynamic_indices) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, PartialShape{Dimension::dynamic(), 4}); + auto per_sample_weights = + std::make_shared(element::f32, PartialShape{Dimension::dynamic(), 4}); + + auto embedding_bag_packed = std::make_shared(emb_table, indices, per_sample_weights); + + EXPECT_TRUE(embedding_bag_packed->get_output_partial_shape(0).same_scheme(PartialShape{Dimension::dynamic(), 2})); + EXPECT_EQ(embedding_bag_packed->get_reduction(), op::v15::EmbeddingBagPacked::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_packed_dynamic_emb_table_indices) { + auto emb_table = std::make_shared(element::f32, PartialShape{5, Dimension::dynamic()}); + auto indices = std::make_shared(element::i64, PartialShape{Dimension::dynamic(), 4}); + auto per_sample_weights = + std::make_shared(element::f32, PartialShape{Dimension::dynamic(), 4}); + auto reduction = op::v15::EmbeddingBagPacked::Reduction::SUM; + auto embedding_bag_packed = + std::make_shared(emb_table, indices, per_sample_weights, reduction); + + EXPECT_TRUE(embedding_bag_packed->get_output_partial_shape(0).same_scheme( + PartialShape{Dimension::dynamic(), Dimension::dynamic()})); + EXPECT_EQ(embedding_bag_packed->get_reduction(), op::v15::EmbeddingBagPacked::Reduction::SUM); +} + +TEST(type_prop, embedding_bag_packed_fail_indices_element_type) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::f32, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{3, 4}); + + OV_EXPECT_THROW(auto embedding_bag_packed = + std::make_shared(emb_table, indices, per_sample_weights), + NodeValidationFailure, + HasSubstr("INDICES type must be i32 or i64")); +} + +TEST(type_prop, embedding_bag_packed_fail_mismatch_element_type) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::i64, Shape{3, 4}); + + OV_EXPECT_THROW(auto embedding_bag_packed = + std::make_shared(emb_table, indices, per_sample_weights), + NodeValidationFailure, + HasSubstr("Per sample weight element type (i64) must " + "match embedding table element type (f32)")); +} + +TEST(type_prop, embedding_bag_packed_fail_mismatch_shape) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4, 3}); + + OV_EXPECT_THROW(auto embedding_bag_packed = + std::make_shared(emb_table, indices, per_sample_weights), + NodeValidationFailure, + HasSubstr("INDICES and PER_SAMPLE_WEIGHTS shape must be same")); +} + +TEST(type_prop, embedding_bag_packed_fail_indices_1d) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{3, 4}); + + OV_EXPECT_THROW(auto embedding_bag_packed = + std::make_shared(emb_table, indices, per_sample_weights), + NodeValidationFailure, + HasSubstr("INDICES must be 2D")); +} + +TEST(type_prop, embedding_bag_packed_fail_emb_table_0d) { + auto emb_table = std::make_shared(element::f32, Shape{}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{3, 4}); + + OV_EXPECT_THROW(auto op = std::make_shared(emb_table, indices, per_sample_weights), + NodeValidationFailure, + HasSubstr("EMB_TABLE can't be a scalar")); +} + +TEST(type_prop, embedding_bag_packed_fail_per_sample_weights_1d) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + + OV_EXPECT_THROW(auto embedding_bag_packed = + std::make_shared(emb_table, indices, per_sample_weights), + NodeValidationFailure, + HasSubstr("PER_SAMPLE_WEIGHTS must be 2D")); +} + +TEST(type_prop, embedding_bag_packed_fail_per_sample_weights_reduction_mean) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = std::make_shared(element::f32, Shape{4}); + auto reduction = op::v15::EmbeddingBagPacked::Reduction::MEAN; + OV_EXPECT_THROW( + auto embedding_bag_packed = + std::make_shared(emb_table, indices, per_sample_weights, reduction), + NodeValidationFailure, + HasSubstr("Per sample weights can only be used in Reduction::SUM mode.")); +} + +TEST(type_prop, embedding_bag_packed_2_args_api) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::i64, Shape{3, 4}); + + auto embedding_bag_packed = std::make_shared(emb_table, indices); + EXPECT_TRUE(embedding_bag_packed->get_output_partial_shape(0).same_scheme(PartialShape{3, 2})); + EXPECT_EQ(embedding_bag_packed->get_output_element_type(0), element::f32); + EXPECT_EQ(indices->get_partial_shape().rank().get_length(), 2); +} + +TEST(type_prop, embedding_bag_packed_fail_indices_element_type_2_args_api) { + auto emb_table = std::make_shared(element::f32, Shape{5, 2}); + auto indices = std::make_shared(element::f32, Shape{3, 4}); + + OV_EXPECT_THROW(auto embedding_bag_packed = std::make_shared(emb_table, indices), + NodeValidationFailure, + HasSubstr("INDICES type must be i32 or i64")); +} diff --git a/src/core/tests/visitors/op/embeddingbag_offsets.cpp b/src/core/tests/visitors/op/embeddingbag_offsets.cpp new file mode 100644 index 00000000000..561b09b1368 --- /dev/null +++ b/src/core/tests/visitors/op/embeddingbag_offsets.cpp @@ -0,0 +1,68 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/embeddingbag_offsets.hpp" + +#include + +#include "visitors/visitors.hpp" + +using namespace std; +using namespace ov; +using ov::test::NodeBuilder; + +TEST(visitor_without_attribute, embedding_bag_offsets_op) { + NodeBuilder::opset().insert(); + auto emb_table = make_shared(element::f32, Shape{5, 2, 3}); + + auto indices = make_shared(element::i64, Shape{4}); + auto offsets = make_shared(element::i64, Shape{4}); + auto default_index = make_shared(element::i64, Shape{}); + auto per_sample_weights = make_shared(element::f32, Shape{4}); + auto reduction = ov::op::v15::EmbeddingBagOffsets::Reduction::SUM; + + auto ebos = make_shared(emb_table, + indices, + offsets, + default_index, + per_sample_weights, + reduction); + NodeBuilder builder(ebos, {emb_table, indices, offsets, default_index, per_sample_weights}); + EXPECT_NO_THROW(auto g_ebos = ov::as_type_ptr(builder.create())); + + const auto expected_attr_count = 1; + EXPECT_EQ(builder.get_value_map_size(), expected_attr_count); +} + +TEST(visitor_without_attribute, embedding_bag_offsets_op2) { + NodeBuilder::opset().insert(); + auto emb_table = make_shared(element::f32, Shape{5, 2, 3}); + + auto indices = make_shared(element::i64, Shape{4}); + auto offsets = make_shared(element::i64, Shape{4}); + auto default_index = make_shared(element::i64, Shape{}); + auto reduction = ov::op::v15::EmbeddingBagOffsets::Reduction::MEAN; + + auto ebos = make_shared(emb_table, indices, offsets, default_index, reduction); + NodeBuilder builder(ebos, {emb_table, indices, offsets, default_index}); + EXPECT_NO_THROW(auto g_ebos = ov::as_type_ptr(builder.create())); + + const auto expected_attr_count = 1; + EXPECT_EQ(builder.get_value_map_size(), expected_attr_count); +} + +TEST(visitor_without_attribute, embedding_bag_offsets_op3) { + NodeBuilder::opset().insert(); + auto emb_table = make_shared(element::f32, Shape{5, 2, 3}); + + auto indices = make_shared(element::i64, Shape{4}); + auto offsets = make_shared(element::i64, Shape{4}); + + auto ebos = make_shared(emb_table, indices, offsets); + NodeBuilder builder(ebos, {emb_table, indices, offsets}); + EXPECT_NO_THROW(auto g_ebos = ov::as_type_ptr(builder.create())); + + const auto expected_attr_count = 1; + EXPECT_EQ(builder.get_value_map_size(), expected_attr_count); +} diff --git a/src/core/tests/visitors/op/embeddingbag_packed.cpp b/src/core/tests/visitors/op/embeddingbag_packed.cpp new file mode 100644 index 00000000000..02de623ea4f --- /dev/null +++ b/src/core/tests/visitors/op/embeddingbag_packed.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/embeddingbag_packed.hpp" + +#include + +#include "visitors/visitors.hpp" + +using namespace std; +using namespace ov; +using ov::test::NodeBuilder; + +TEST(visitor_without_attribute, embedding_bag_packed_op) { + NodeBuilder::opset().insert(); + auto emb_table = make_shared(element::f32, Shape{5, 2}); + auto indices = make_shared(element::i64, Shape{3, 4}); + auto per_sample_weights = make_shared(element::f32, Shape{3, 4}); + auto reduction = ov::op::v15::EmbeddingBagPacked::Reduction::SUM; + + auto ebps = make_shared(emb_table, indices, per_sample_weights, reduction); + NodeBuilder builder(ebps, {emb_table, indices, per_sample_weights}); + EXPECT_NO_THROW(auto g_ebps = ov::as_type_ptr(builder.create())); + + const auto expected_attr_count = 1; + EXPECT_EQ(builder.get_value_map_size(), expected_attr_count); +} + +TEST(visitor_without_attribute, embedding_bag_packed_op2) { + NodeBuilder::opset().insert(); + auto emb_table = make_shared(element::f32, Shape{5, 2}); + auto indices = make_shared(element::i64, Shape{3, 4}); + auto reduction = ov::op::v15::EmbeddingBagPacked::Reduction::MEAN; + + auto ebps = make_shared(emb_table, indices, reduction); + NodeBuilder builder(ebps, {emb_table, indices}); + EXPECT_NO_THROW(auto g_ebps = ov::as_type_ptr(builder.create())); + + const auto expected_attr_count = 1; + EXPECT_EQ(builder.get_value_map_size(), expected_attr_count); +} diff --git a/src/frontends/pytorch/src/op/embedding_bag.cpp b/src/frontends/pytorch/src/op/embedding_bag.cpp index 633eac2a100..b4d424d4e2c 100644 --- a/src/frontends/pytorch/src/op/embedding_bag.cpp +++ b/src/frontends/pytorch/src/op/embedding_bag.cpp @@ -6,8 +6,8 @@ #include "openvino/op/constant.hpp" #include "openvino/op/convert.hpp" #include "openvino/op/convert_like.hpp" -#include "openvino/op/embeddingbag_offsets_sum.hpp" -#include "openvino/op/embeddingbag_packedsum.hpp" +#include "openvino/op/embeddingbag_offsets.hpp" +#include "openvino/op/embeddingbag_packed.hpp" #include "utils.hpp" namespace ov { @@ -18,9 +18,10 @@ namespace op { OutputVector translate_embedding_bag_common(const NodeContext& context) { // aten::embedding_bag(weight, input, offsets=None, scale_grad_by_freq=False, mode_enum=1, sparse=False, // per_sample_weights=None, include_last_offset=False, padding_idx=None) - // we have only EmbeddingBagSum case support, check it before translation + // we have only EmbeddingBag case support, check it before translation + auto mode = context.const_input(4); - PYTORCH_OP_CONVERSION_CHECK(mode == 0, "Only sum mode supported for aten::embedding_bag translation"); + PYTORCH_OP_CONVERSION_CHECK(mode <= 1, "Only sum and mean mode supported for aten::embedding_bag translation"); auto weight = context.get_input(0); auto indices = context.get_input(1); indices = context.mark_node(std::make_shared(indices, element::i32)); @@ -29,17 +30,21 @@ OutputVector translate_embedding_bag_common(const NodeContext& context) { // parameters scale_grad_by_freq, sparse, padding_idx have relation to gradient calculation for training, skip them // no offsets case if (context.input_is_none(2)) { + using Reduction = ov::op::v15::EmbeddingBagPacked::Reduction; + Reduction reduction = Reduction(mode); // no per_sample_weights if (context.input_is_none(6)) { - result = context.mark_node(std::make_shared(weight, indices)); + result = context.mark_node(std::make_shared(weight, indices, reduction)); } else { auto per_sample_weight = context.get_input(6); per_sample_weight = context.mark_node(std::make_shared(per_sample_weight, weight)); result = context.mark_node( - std::make_shared(weight, indices, per_sample_weight)); + std::make_shared(weight, indices, per_sample_weight, reduction)); } } else { // with offsets case + using Reduction = ov::op::v15::EmbeddingBagOffsets::Reduction; + Reduction reduction = Reduction(mode); auto offsets = context.get_input(2); offsets = context.mark_node(std::make_shared(offsets, element::i32)); bool include_last_offset = false; @@ -48,15 +53,17 @@ OutputVector translate_embedding_bag_common(const NodeContext& context) { PYTORCH_OP_CONVERSION_CHECK(!include_last_offset, "Inclusion last offset is not supported"); // no per_sample_wights if (context.input_is_none(6)) { - result = context.mark_node(std::make_shared(weight, indices, offsets)); + result = context.mark_node( + std::make_shared(weight, indices, offsets, reduction)); } else { auto per_sample_weight = context.get_input(6); per_sample_weight = context.mark_node(std::make_shared(per_sample_weight, weight)); - result = context.mark_node(std::make_shared(weight, - indices, - offsets, - zero, - per_sample_weight)); + result = context.mark_node(std::make_shared(weight, + indices, + offsets, + zero, + per_sample_weight, + reduction)); } // aten::embedding_bag returns a tuple of 4 elements: output, offset2bag, bag_size, max_indices. // But the last three outputs are not used in torch.nn.EmbeddingBag or torch.nn.functional.embedding_bag. diff --git a/src/plugins/intel_cpu/src/cpu_types.cpp b/src/plugins/intel_cpu/src/cpu_types.cpp index a10b7cd6812..e3a4c21142b 100644 --- a/src/plugins/intel_cpu/src/cpu_types.cpp +++ b/src/plugins/intel_cpu/src/cpu_types.cpp @@ -163,8 +163,8 @@ static const TypeToNameMap& get_type_to_name_tbl() { {"ReduceSumSquare", Type::Reduce}, {"Broadcast", Type::Broadcast}, {"EmbeddingSegmentsSum", Type::EmbeddingSegmentsSum}, - {"EmbeddingBagPackedSum", Type::EmbeddingBagPackedSum}, - {"EmbeddingBagOffsetsSum", Type::EmbeddingBagOffsetsSum}, + {"EmbeddingBagPackedSum", Type::EmbeddingBagPacked}, + {"EmbeddingBagOffsetsSum", Type::EmbeddingBagOffsets}, {"Gather", Type::Gather}, {"GatherElements", Type::GatherElements}, {"GatherND", Type::GatherND}, @@ -242,6 +242,8 @@ static const TypeToNameMap& get_type_to_name_tbl() { {"RoPE", Type::RoPE}, {"GatherCompressed", Type::Gather}, {"CausalMaskPreprocess", Type::CausalMaskPreprocess}, + {"EmbeddingBagPacked", Type::EmbeddingBagPacked}, + {"EmbeddingBagOffsets", Type::EmbeddingBagOffsets}, }; return type_to_name_tbl; } @@ -311,6 +313,8 @@ std::string NameFromType(const Type type) { CASE(Reduce); CASE(Broadcast); CASE(EmbeddingSegmentsSum); + CASE(EmbeddingBagPacked); + CASE(EmbeddingBagOffsets); CASE(EmbeddingBagPackedSum); CASE(EmbeddingBagOffsetsSum); CASE(Gather); diff --git a/src/plugins/intel_cpu/src/cpu_types.h b/src/plugins/intel_cpu/src/cpu_types.h index 212c0c8c192..5593e6728bb 100644 --- a/src/plugins/intel_cpu/src/cpu_types.h +++ b/src/plugins/intel_cpu/src/cpu_types.h @@ -69,6 +69,8 @@ enum class Type { Interpolate, Reduce, Broadcast, + EmbeddingBagPacked, + EmbeddingBagOffsets, EmbeddingSegmentsSum, EmbeddingBagPackedSum, EmbeddingBagOffsetsSum, diff --git a/src/plugins/intel_cpu/src/nodes/embedding_bag_sum.cpp b/src/plugins/intel_cpu/src/nodes/embedding_bag.cpp similarity index 53% rename from src/plugins/intel_cpu/src/nodes/embedding_bag_sum.cpp rename to src/plugins/intel_cpu/src/nodes/embedding_bag.cpp index e3dbd9e353a..8b144e90c86 100644 --- a/src/plugins/intel_cpu/src/nodes/embedding_bag_sum.cpp +++ b/src/plugins/intel_cpu/src/nodes/embedding_bag.cpp @@ -2,57 +2,60 @@ // SPDX-License-Identifier: Apache-2.0 // +#include "embedding_bag.h" + #include -#include #include +#include + +#include "common/cpu_memcpy.h" #include "dnnl_types.h" #include "openvino/core/parallel.hpp" -#include "embedding_bag_sum.h" #include "openvino/opsets/opset1.hpp" -#include "common/cpu_memcpy.h" namespace ov { namespace intel_cpu { namespace node { -EmbeddingBagSum::EmbeddingBagSum( - const std::shared_ptr& op, - size_t requiredInputNum, - size_t indicesIdx, - size_t perSampleWeightsIdx, - size_t defaultIndexIdx) : - INDICES_IDX(indicesIdx), - PER_SAMPLE_WEIGHTS_IDX(perSampleWeightsIdx), - DEFAULT_INDEX_IDX(defaultIndexIdx) { +EmbeddingBag::EmbeddingBag(const std::shared_ptr& op, + size_t requiredInputNum, + size_t indicesIdx, + size_t perSampleWeightsIdx, + size_t defaultIndexIdx) + : INDICES_IDX(indicesIdx), + PER_SAMPLE_WEIGHTS_IDX(perSampleWeightsIdx), + DEFAULT_INDEX_IDX(defaultIndexIdx) { _layerName = op->get_friendly_name(); - std::string logPrefix = std::string("Layer EmbeddingBagSum with name '") + _layerName + "' "; + std::string logPrefix = std::string("Layer EmbeddingBag with name '") + _layerName + "' "; if (op->get_input_size() < requiredInputNum || op->get_output_size() != 1) OPENVINO_THROW(logPrefix, "has incorrect number of input or output edges!"); - - if (op->get_input_size() > PER_SAMPLE_WEIGHTS_IDX) + if ((op->get_input_size() > PER_SAMPLE_WEIGHTS_IDX)) { _withWeights = true; + } if (_withWeights) { if (op->get_input_shape(PER_SAMPLE_WEIGHTS_IDX) != op->get_input_shape(INDICES_IDX)) OPENVINO_THROW(logPrefix, "must have equal shapes for indices and per_sample_weights inputs."); } } -void EmbeddingBagSum::prepareParams(const VectorDims& indexStaticShape) { +void EmbeddingBag::prepareParams(const VectorDims& indexStaticShape) { _embDepth = 1lu; for (size_t i = 1lu; i < indexStaticShape.size(); i++) { _embDepth *= indexStaticShape[i]; } } -template -void EmbeddingBagSum::processData(const T* srcData, const T* weightsData, - const VectorDims& inDataDims, const MemoryPtr& outMemory) { - std::string msgPrefix = std::string("Node EmbeddingBagSum with name '") + _layerName + "' "; +template +void EmbeddingBag::processData(const T* srcData, + const T* weightsData, + const VectorDims& inDataDims, + const MemoryPtr& outMemory) { + std::string msgPrefix = std::string("Node EmbeddingBag with name '") + _layerName + "' "; initFromInputs(); const size_t outputBagsNum = outMemory->getShape().getStaticDims()[0]; - auto *dstData = outMemory->getDataAs(); + auto* dstData = outMemory->getDataAs(); auto threadBody = [&](const int ithr, const int nthr) { size_t start(0lu), end(0lu); @@ -91,7 +94,8 @@ void EmbeddingBagSum::processData(const T* srcData, const T* weightsData, for (inIdx = 1lu; inIdx < indicesSize; inIdx++) { if (static_cast(indices[inIdx]) >= inDataDims[0]) { - OPENVINO_THROW(msgPrefix + "' has invalid embedding bag index: " + std::to_string(indices[inIdx])); + OPENVINO_THROW(msgPrefix + + "' has invalid embedding bag index: " + std::to_string(indices[inIdx])); } size_t srcIndex = indices[inIdx] * _embDepth; @@ -106,6 +110,11 @@ void EmbeddingBagSum::processData(const T* srcData, const T* weightsData, } } } + if (_reduction == Reduction::MEAN) { + for (size_t i = 0lu; i < _embDepth; i++) { + dstData[dstIndex + i] /= indicesSize; + } + } } else { for (size_t i = 0lu; i < _embDepth; i++) { dstData[dstIndex + i] = 0; @@ -117,30 +126,43 @@ void EmbeddingBagSum::processData(const T* srcData, const T* weightsData, parallel_nt(0, threadBody); } -void EmbeddingBagSum::execute(const uint8_t* srcData, const uint8_t* weightsData, const ov::element::Type &srcPrc, - const VectorDims& inDims, const MemoryPtr& outMemory) { +void EmbeddingBag::execute(const uint8_t* srcData, + const uint8_t* weightsData, + const ov::element::Type& srcPrc, + const VectorDims& inDims, + const MemoryPtr& outMemory) { switch (srcPrc) { - case ov::element::f32: { - return processData::value_type>(reinterpret_cast(srcData), - reinterpret_cast(weightsData), inDims, outMemory); - } - case ov::element::i8: { - return processData::value_type>(reinterpret_cast(srcData), - reinterpret_cast(weightsData), inDims, outMemory); - } - case ov::element::u8: { - return processData::value_type>(srcData, weightsData, inDims, outMemory); - } - case ov::element::i32: { - return processData::value_type>(reinterpret_cast(srcData), - reinterpret_cast(weightsData), inDims, outMemory); - } - default: { - OPENVINO_THROW("EmbeddingBagSum layer does not support precision '" + std::string(srcPrc.get_type_name()) + "'"); - } + case ov::element::f32: { + return processData::value_type>( + reinterpret_cast(srcData), + reinterpret_cast(weightsData), + inDims, + outMemory); + } + case ov::element::i8: { + return processData::value_type>( + reinterpret_cast(srcData), + reinterpret_cast(weightsData), + inDims, + outMemory); + } + case ov::element::u8: { + return processData::value_type>(srcData, weightsData, inDims, outMemory); + } + case ov::element::i32: { + return processData::value_type>( + reinterpret_cast(srcData), + reinterpret_cast(weightsData), + inDims, + outMemory); + } + default: { + OPENVINO_THROW("EmbeddingBag layer does not support precision '" + std::string(srcPrc.get_type_name()) + + "'"); + } } } -} // namespace node -} // namespace intel_cpu -} // namespace ov +} // namespace node +} // namespace intel_cpu +} // namespace ov diff --git a/src/plugins/intel_cpu/src/nodes/embedding_bag_sum.h b/src/plugins/intel_cpu/src/nodes/embedding_bag.h similarity index 89% rename from src/plugins/intel_cpu/src/nodes/embedding_bag_sum.h rename to src/plugins/intel_cpu/src/nodes/embedding_bag.h index beaeaa96de0..28c8666233f 100644 --- a/src/plugins/intel_cpu/src/nodes/embedding_bag_sum.h +++ b/src/plugins/intel_cpu/src/nodes/embedding_bag.h @@ -10,9 +10,10 @@ namespace ov { namespace intel_cpu { namespace node { -class EmbeddingBagSum { +class EmbeddingBag { public: - EmbeddingBagSum( + enum class Reduction { SUM, MEAN }; + EmbeddingBag( const std::shared_ptr&, size_t requiredInputsNum, size_t indicesIdx, @@ -22,7 +23,7 @@ public: void execute(const uint8_t* srcData, const uint8_t* weightsData, const ov::element::Type &srcPrc, const VectorDims& inDims, const MemoryPtr& outMemory); - ~EmbeddingBagSum() = default; + ~EmbeddingBag() = default; protected: virtual void initFromInputs() = 0; @@ -44,6 +45,7 @@ protected: const size_t PER_SAMPLE_WEIGHTS_IDX; const size_t DEFAULT_INDEX_IDX; + Reduction _reduction = Reduction::SUM; bool _withWeights = false; size_t _embDepth = 0; std::string _layerName; diff --git a/src/plugins/intel_cpu/src/nodes/embedding_bag_offset_sum.cpp b/src/plugins/intel_cpu/src/nodes/embedding_bag_offsets.cpp similarity index 67% rename from src/plugins/intel_cpu/src/nodes/embedding_bag_offset_sum.cpp rename to src/plugins/intel_cpu/src/nodes/embedding_bag_offsets.cpp index 4439f40bd8b..4ab297df11c 100644 --- a/src/plugins/intel_cpu/src/nodes/embedding_bag_offset_sum.cpp +++ b/src/plugins/intel_cpu/src/nodes/embedding_bag_offsets.cpp @@ -5,20 +5,21 @@ #include #include #include -#include "embedding_bag_offset_sum.h" -#include "openvino/opsets/opset3.hpp" - +#include "embedding_bag_offsets.h" +#include "openvino/op/embeddingbag_offsets_sum.hpp" +#include "openvino/op/embeddingbag_offsets.hpp" namespace ov { namespace intel_cpu { namespace node { -bool EmbeddingBagOffsetSum::isSupportedOperation(const std::shared_ptr& op, std::string& errorMessage) noexcept { +bool EmbeddingBagOffset::isSupportedOperation(const std::shared_ptr& op, std::string& errorMessage) noexcept { try { const auto embBagOffsetSumOp = ov::as_type_ptr(op); - if (!embBagOffsetSumOp) { - errorMessage = "Node is not an instance of the EmbeddingBagOffsetsSum operation from opset v3."; + const auto embBagOffsetOp = ov::as_type_ptr(op); + if (!embBagOffsetSumOp && !embBagOffsetOp) { + errorMessage = "Node is not an instance of the v3::EmbeddingBagOffsetsSum or v15::EmbeddingBagOffsets operation."; return false; } } catch (...) { @@ -27,14 +28,27 @@ bool EmbeddingBagOffsetSum::isSupportedOperation(const std::shared_ptr& op, const GraphContext::CPtr context) +EmbeddingBagOffset::EmbeddingBagOffset(const std::shared_ptr& op, const GraphContext::CPtr context) : Node(op, context, NgraphShapeInferFactory(op, EMPTY_PORT_MASK)), - EmbeddingBagSum(op, 3lu, 1lu, 4lu, 3lu) { + EmbeddingBag(op, 3lu, 1lu, 4lu, 3lu) { std::string errorMessage; if (!isSupportedOperation(op, errorMessage)) { OPENVINO_THROW_NOT_IMPLEMENTED(errorMessage); } - + auto offsets_op = ov::as_type_ptr(op); + if (offsets_op) { + using OpReduction = ov::op::util::EmbeddingBagOffsetsBase::Reduction; + switch (offsets_op->get_reduction()) { + case OpReduction::SUM: + _reduction = Reduction::SUM; + break; + case OpReduction::MEAN: + _reduction = Reduction::MEAN; + break; + default: + THROW_CPU_NODE_ERR("EmbeddingBagOffsets does not support reduction mode: ", ov::as_string(offsets_op->get_reduction())); + } + } if (getInputShapeAtPort(INDICES_IDX).getRank() != 1ul) OPENVINO_THROW("'", _layerName, "' layer has indices data with invalid rank."); @@ -42,11 +56,11 @@ EmbeddingBagOffsetSum::EmbeddingBagOffsetSum(const std::shared_ptr& op OPENVINO_THROW("'", _layerName, "' layer's offsets data has invalid rank."); } -void EmbeddingBagOffsetSum::initSupportedPrimitiveDescriptors() { +void EmbeddingBagOffset::initSupportedPrimitiveDescriptors() { if (!supportedPrimitiveDescriptors.empty()) return; - std::string logPrefix = std::string("Layer EmbeddingBagSum with name '") + _layerName + "' "; + std::string logPrefix = std::string("Layer EmbeddingBag with name '") + _layerName + "' "; static const std::set supportedPrecisions = {ov::element::f32, ov::element::i8, ov::element::u8, ov::element::i32}; @@ -74,13 +88,13 @@ void EmbeddingBagOffsetSum::initSupportedPrimitiveDescriptors() { addSupportedPrimDesc(inDataConfigurators, {{LayoutType::ncsp, inDataPrecision}}, impl_desc_type::ref_any); } -void EmbeddingBagOffsetSum::prepareParams() { +void EmbeddingBagOffset::prepareParams() { _indicesLen = getParentEdgeAt(INDICES_IDX)->getMemory().getStaticDims()[0]; _offsetsLen = getParentEdgeAt(OFFSETS_IDX)->getMemory().getStaticDims()[0]; - EmbeddingBagSum::prepareParams(getParentEdgeAt(EMB_TABLE_IDX)->getMemory().getStaticDims()); + EmbeddingBag::prepareParams(getParentEdgeAt(EMB_TABLE_IDX)->getMemory().getStaticDims()); } -void EmbeddingBagOffsetSum::initFromInputs() { +void EmbeddingBagOffset::initFromInputs() { indicesData_ = getSrcDataAtPortAs(INDICES_IDX); offsetsData_ = getSrcDataAtPortAs(OFFSETS_IDX); @@ -89,7 +103,7 @@ void EmbeddingBagOffsetSum::initFromInputs() { } } -void EmbeddingBagOffsetSum::getIndices(size_t embIndex, const int*& indices, size_t& size, int& weightsIdx, bool& withWeight) { +void EmbeddingBagOffset::getIndices(size_t embIndex, const int*& indices, size_t& size, int& weightsIdx, bool& withWeight) { if (static_cast(embIndex) >= _offsetsLen) { OPENVINO_THROW("Invalid embedding bag index."); } @@ -122,27 +136,27 @@ void EmbeddingBagOffsetSum::getIndices(size_t embIndex, const int*& indices, siz weightsIdx = offsetsData_[embIndex]; } -void EmbeddingBagOffsetSum::executeDynamicImpl(dnnl::stream strm) { +void EmbeddingBagOffset::executeDynamicImpl(dnnl::stream strm) { execute(strm); } -bool EmbeddingBagOffsetSum::isExecutable() const { +bool EmbeddingBagOffset::isExecutable() const { return !isInputTensorAtPortEmpty(0); } -void EmbeddingBagOffsetSum::execute(dnnl::stream strm) { +void EmbeddingBagOffset::execute(dnnl::stream strm) { const auto *srcData = getSrcDataAtPortAs(0); const uint8_t* weightsData = nullptr; if (_withWeights) weightsData = getSrcDataAtPortAs(PER_SAMPLE_WEIGHTS_IDX); const auto &inputMem = getParentEdgeAt(0)->getMemory(); - EmbeddingBagSum::execute(srcData, weightsData, inputMem.getDesc().getPrecision(), + EmbeddingBag::execute(srcData, weightsData, inputMem.getDesc().getPrecision(), inputMem.getStaticDims(), getDstMemoryAtPort(0)); } -bool EmbeddingBagOffsetSum::created() const { - return getType() == Type::EmbeddingBagOffsetsSum; +bool EmbeddingBagOffset::created() const { + return getType() == Type::EmbeddingBagOffsets; } } // namespace node diff --git a/src/plugins/intel_cpu/src/nodes/embedding_bag_offset_sum.h b/src/plugins/intel_cpu/src/nodes/embedding_bag_offsets.h similarity index 84% rename from src/plugins/intel_cpu/src/nodes/embedding_bag_offset_sum.h rename to src/plugins/intel_cpu/src/nodes/embedding_bag_offsets.h index 65b47648074..a31b518e789 100644 --- a/src/plugins/intel_cpu/src/nodes/embedding_bag_offset_sum.h +++ b/src/plugins/intel_cpu/src/nodes/embedding_bag_offsets.h @@ -4,16 +4,16 @@ #pragma once -#include "embedding_bag_sum.h" +#include "embedding_bag.h" #include "node.h" namespace ov { namespace intel_cpu { namespace node { -class EmbeddingBagOffsetSum : public Node, public EmbeddingBagSum { +class EmbeddingBagOffset : public Node, public EmbeddingBag { public: - EmbeddingBagOffsetSum(const std::shared_ptr& op, const GraphContext::CPtr context); + EmbeddingBagOffset(const std::shared_ptr& op, const GraphContext::CPtr context); void getSupportedDescriptors() override {}; void initSupportedPrimitiveDescriptors() override; diff --git a/src/plugins/intel_cpu/src/nodes/embedding_bag_packed_sum.cpp b/src/plugins/intel_cpu/src/nodes/embedding_bag_packed.cpp similarity index 60% rename from src/plugins/intel_cpu/src/nodes/embedding_bag_packed_sum.cpp rename to src/plugins/intel_cpu/src/nodes/embedding_bag_packed.cpp index afb74934307..0b490a28a81 100644 --- a/src/plugins/intel_cpu/src/nodes/embedding_bag_packed_sum.cpp +++ b/src/plugins/intel_cpu/src/nodes/embedding_bag_packed.cpp @@ -5,18 +5,20 @@ #include #include #include -#include "embedding_bag_packed_sum.h" -#include "openvino/opsets/opset3.hpp" +#include "embedding_bag_packed.h" +#include "openvino/op/embeddingbag_packedsum.hpp" +#include "openvino/op/embeddingbag_packed.hpp" namespace ov { namespace intel_cpu { namespace node { -bool EmbeddingBagPackedSum::isSupportedOperation(const std::shared_ptr& op, std::string& errorMessage) noexcept { +bool EmbeddingBagPacked::isSupportedOperation(const std::shared_ptr& op, std::string& errorMessage) noexcept { try { const auto embBagPackedSumOp = ov::as_type_ptr(op); - if (!embBagPackedSumOp) { - errorMessage = "Node is not an instance of the EmbeddingBagPackedSum operation from opset v3."; + const auto embBagPackedOp = ov::as_type_ptr(op); + if (!embBagPackedSumOp && !embBagPackedOp) { + errorMessage = "Node is not an instance of the v3::EmbeddingBagPackedSum or v15::EmbeddingBagPacked operations."; return false; } } catch (...) { @@ -25,23 +27,36 @@ bool EmbeddingBagPackedSum::isSupportedOperation(const std::shared_ptr& op, const GraphContext::CPtr context) +EmbeddingBagPacked::EmbeddingBagPacked(const std::shared_ptr& op, const GraphContext::CPtr context) : Node(op, context, NgraphShapeInferFactory(op, EMPTY_PORT_MASK)), - EmbeddingBagSum(op, 2lu, 1lu, 2lu, 3lu) { + EmbeddingBag(op, 2lu, 1lu, 2lu, 3lu) { std::string errorMessage; if (!isSupportedOperation(op, errorMessage)) { OPENVINO_THROW_NOT_IMPLEMENTED(errorMessage); } - + auto packed_op = ov::as_type_ptr(op); + if (packed_op) { + using OpReduction = ov::op::util::EmbeddingBagPackedBase::Reduction; + switch (packed_op->get_reduction()) { + case OpReduction::SUM: + _reduction = Reduction::SUM; + break; + case OpReduction::MEAN: + _reduction = Reduction::MEAN; + break; + default: + THROW_CPU_NODE_ERR("EmbeddingBagPacked does not support reduction mode: ", ov::as_string(packed_op->get_reduction())); + } + } if (getInputShapeAtPort(INDICES_IDX).getRank() != 2ul) OPENVINO_THROW("'", _layerName, "' layer has indices data with invalid rank."); } -void EmbeddingBagPackedSum::initSupportedPrimitiveDescriptors() { +void EmbeddingBagPacked::initSupportedPrimitiveDescriptors() { if (!supportedPrimitiveDescriptors.empty()) return; - std::string logPrefix = std::string("Layer EmbeddingBagSum with name '") + _layerName + "' "; + std::string logPrefix = std::string("Layer EmbeddingBag with name '") + _layerName + "' "; static const std::set supportedPrecisions = {ov::element::f32, ov::element::i8, ov::element::u8, ov::element::i32}; @@ -66,17 +81,17 @@ void EmbeddingBagPackedSum::initSupportedPrimitiveDescriptors() { addSupportedPrimDesc(inDataConfigurators, {{LayoutType::ncsp, inDataPrecision}}, impl_desc_type::ref_any); } -void EmbeddingBagPackedSum::prepareParams() { +void EmbeddingBagPacked::prepareParams() { _batch = getParentEdgeAt(INDICES_IDX)->getMemory().getStaticDims()[0]; _indicesPerBag = getParentEdgeAt(INDICES_IDX)->getMemory().getStaticDims()[1]; - EmbeddingBagSum::prepareParams(getParentEdgeAt(EMB_TABLE_IDX)->getMemory().getStaticDims()); + EmbeddingBag::prepareParams(getParentEdgeAt(EMB_TABLE_IDX)->getMemory().getStaticDims()); } -void EmbeddingBagPackedSum::initFromInputs() { +void EmbeddingBagPacked::initFromInputs() { _indices = getSrcDataAtPortAs(INDICES_IDX); } -void EmbeddingBagPackedSum::getIndices(size_t embIndex, const int*& indices, size_t& size, int& weightsIdx, bool& withWeight) { +void EmbeddingBagPacked::getIndices(size_t embIndex, const int*& indices, size_t& size, int& weightsIdx, bool& withWeight) { if (static_cast(embIndex) >= _batch * _indicesPerBag) OPENVINO_THROW("Invalid embedding bag index."); @@ -88,27 +103,27 @@ void EmbeddingBagPackedSum::getIndices(size_t embIndex, const int*& indices, siz weightsIdx = embIndex * _indicesPerBag; } -void EmbeddingBagPackedSum::executeDynamicImpl(dnnl::stream strm) { +void EmbeddingBagPacked::executeDynamicImpl(dnnl::stream strm) { execute(strm); } -bool EmbeddingBagPackedSum::isExecutable() const { +bool EmbeddingBagPacked::isExecutable() const { return !isInputTensorAtPortEmpty(0); } -void EmbeddingBagPackedSum::execute(dnnl::stream strm) { +void EmbeddingBagPacked::execute(dnnl::stream strm) { const auto *srcData = getSrcDataAtPortAs(0); const uint8_t* weightsData = nullptr; if (_withWeights) weightsData = getSrcDataAtPortAs(PER_SAMPLE_WEIGHTS_IDX); const auto &inputMem = getParentEdgeAt(0)->getMemory(); - EmbeddingBagSum::execute(srcData, weightsData, inputMem.getDesc().getPrecision(), + EmbeddingBag::execute(srcData, weightsData, inputMem.getDesc().getPrecision(), inputMem.getStaticDims(), getDstMemoryAtPort(0)); } -bool EmbeddingBagPackedSum::created() const { - return getType() == Type::EmbeddingBagPackedSum; +bool EmbeddingBagPacked::created() const { + return getType() == Type::EmbeddingBagPacked; } } // namespace node diff --git a/src/plugins/intel_cpu/src/nodes/embedding_bag_packed_sum.h b/src/plugins/intel_cpu/src/nodes/embedding_bag_packed.h similarity index 82% rename from src/plugins/intel_cpu/src/nodes/embedding_bag_packed_sum.h rename to src/plugins/intel_cpu/src/nodes/embedding_bag_packed.h index 31b1395b222..6a9d33fe3af 100644 --- a/src/plugins/intel_cpu/src/nodes/embedding_bag_packed_sum.h +++ b/src/plugins/intel_cpu/src/nodes/embedding_bag_packed.h @@ -4,16 +4,16 @@ #pragma once -#include "embedding_bag_sum.h" +#include "embedding_bag.h" #include "node.h" namespace ov { namespace intel_cpu { namespace node { -class EmbeddingBagPackedSum : public Node, public EmbeddingBagSum { +class EmbeddingBagPacked : public Node, public EmbeddingBag { public: - EmbeddingBagPackedSum(const std::shared_ptr& op, const GraphContext::CPtr context); + EmbeddingBagPacked(const std::shared_ptr& op, const GraphContext::CPtr context); void getSupportedDescriptors() override {}; void initSupportedPrimitiveDescriptors() override; diff --git a/src/plugins/intel_cpu/src/nodes/embedding_segments_sum.cpp b/src/plugins/intel_cpu/src/nodes/embedding_segments_sum.cpp index 1278581fdc5..1b2e28e6039 100644 --- a/src/plugins/intel_cpu/src/nodes/embedding_segments_sum.cpp +++ b/src/plugins/intel_cpu/src/nodes/embedding_segments_sum.cpp @@ -27,12 +27,12 @@ bool EmbeddingSegmentsSum::isSupportedOperation(const std::shared_ptr& op, const GraphContext::CPtr context) : Node(op, context, NgraphShapeInferFactory(op, PortMask(NUM_SEGMENTS_IDX))), - EmbeddingBagSum(op, 4lu, 1lu, 5lu, 4lu) { + EmbeddingBag(op, 4lu, 1lu, 5lu, 4lu) { std::string errorMessage; if (!isSupportedOperation(op, errorMessage)) { OPENVINO_THROW_NOT_IMPLEMENTED(errorMessage); } - + _reduction = Reduction::SUM; std::string errPrefix = std::string("EmbeddingSegmentsSum layer with name '") + _layerName + "' "; if (getInputShapeAtPort(INDICES_IDX).getRank() != 1ul) OPENVINO_THROW(errPrefix, "has indices data with invalid rank: ", getInputShapeAtPort(INDICES_IDX).getRank()); @@ -45,7 +45,7 @@ void EmbeddingSegmentsSum::initSupportedPrimitiveDescriptors() { if (!supportedPrimitiveDescriptors.empty()) return; - std::string logPrefix = std::string("Layer EmbeddingBagSum with name '") + _layerName + "' "; + std::string logPrefix = std::string("Layer EmbeddingBag with name '") + _layerName + "' "; static const std::set supportedPrecisions = {ov::element::f32, ov::element::i8, ov::element::u8, ov::element::i32}; @@ -75,7 +75,7 @@ void EmbeddingSegmentsSum::initSupportedPrimitiveDescriptors() { } void EmbeddingSegmentsSum::prepareParams() { - EmbeddingBagSum::prepareParams(getParentEdgeAt(EMB_TABLE_IDX)->getMemory().getStaticDims()); + EmbeddingBag::prepareParams(getParentEdgeAt(EMB_TABLE_IDX)->getMemory().getStaticDims()); } void EmbeddingSegmentsSum::initFromInputs() { @@ -149,7 +149,7 @@ void EmbeddingSegmentsSum::execute(dnnl::stream strm) { weightsData = getSrcDataAtPortAs(PER_SAMPLE_WEIGHTS_IDX); const auto &inputMem = getParentEdgeAt(0)->getMemory(); - EmbeddingBagSum::execute(srcData, weightsData, inputMem.getDesc().getPrecision(), + EmbeddingBag::execute(srcData, weightsData, inputMem.getDesc().getPrecision(), inputMem.getStaticDims(), getDstMemoryAtPort(0)); } diff --git a/src/plugins/intel_cpu/src/nodes/embedding_segments_sum.h b/src/plugins/intel_cpu/src/nodes/embedding_segments_sum.h index 544d9ac09dc..bb312b4dd47 100644 --- a/src/plugins/intel_cpu/src/nodes/embedding_segments_sum.h +++ b/src/plugins/intel_cpu/src/nodes/embedding_segments_sum.h @@ -4,14 +4,14 @@ #pragma once -#include "embedding_bag_sum.h" +#include "embedding_bag.h" #include "node.h" namespace ov { namespace intel_cpu { namespace node { -class EmbeddingSegmentsSum : public Node, public EmbeddingBagSum { +class EmbeddingSegmentsSum : public Node, public EmbeddingBag { public: EmbeddingSegmentsSum(const std::shared_ptr& op, const GraphContext::CPtr context); diff --git a/src/plugins/intel_cpu/src/nodes_factory.cpp b/src/plugins/intel_cpu/src/nodes_factory.cpp index 4209fa82132..7833c60d071 100644 --- a/src/plugins/intel_cpu/src/nodes_factory.cpp +++ b/src/plugins/intel_cpu/src/nodes_factory.cpp @@ -21,8 +21,8 @@ #include "nodes/detection_output.h" #include "nodes/dft.h" #include "nodes/eltwise.h" -#include "nodes/embedding_bag_offset_sum.h" -#include "nodes/embedding_bag_packed_sum.h" +#include "nodes/embedding_bag_offsets.h" +#include "nodes/embedding_bag_packed.h" #include "nodes/embedding_segments_sum.h" #include "nodes/experimental_detectron_detection_output.h" #include "nodes/experimental_detectron_generate_proposals_single_image.h" @@ -124,7 +124,8 @@ Node::NodesFactory::NodesFactory() : Factory("NodesFactory") { INTEL_CPU_NODE(Pooling, Type::Pooling); INTEL_CPU_NODE(Eltwise, Type::Eltwise); INTEL_CPU_NODE(SoftMax, Type::Softmax); - INTEL_CPU_NODE(EmbeddingBagPackedSum, Type::EmbeddingBagPackedSum); + INTEL_CPU_NODE(EmbeddingBagPacked, Type::EmbeddingBagPackedSum); + INTEL_CPU_NODE(EmbeddingBagPacked, Type::EmbeddingBagPacked); INTEL_CPU_NODE(Input, Type::Input); INTEL_CPU_NODE(Input, Type::Output); INTEL_CPU_NODE(MemoryInput, Type::MemoryInput); @@ -158,7 +159,8 @@ Node::NodesFactory::NodesFactory() : Factory("NodesFactory") { INTEL_CPU_NODE(MultiClassNms, Type::MulticlassNms); INTEL_CPU_NODE(Convert, Type::Convert); INTEL_CPU_NODE(ColorConvert, Type::ColorConvert); - INTEL_CPU_NODE(EmbeddingBagOffsetSum, Type::EmbeddingBagOffsetsSum); + INTEL_CPU_NODE(EmbeddingBagOffset, Type::EmbeddingBagOffsetsSum); + INTEL_CPU_NODE(EmbeddingBagOffset, Type::EmbeddingBagOffsets); INTEL_CPU_NODE(Roll, Type::Roll); INTEL_CPU_NODE(Pad, Type::Pad); INTEL_CPU_NODE(Reshape, Type::Reshape); diff --git a/src/plugins/intel_cpu/src/shape_inference/shape_inference.cpp b/src/plugins/intel_cpu/src/shape_inference/shape_inference.cpp index c7b9219d515..2f0fec74375 100644 --- a/src/plugins/intel_cpu/src/shape_inference/shape_inference.cpp +++ b/src/plugins/intel_cpu/src/shape_inference/shape_inference.cpp @@ -402,6 +402,8 @@ using IStaticShapeInferFactory = template <> const IStaticShapeInferFactory::TRegistry IStaticShapeInferFactory::registry{ // opset15 + _OV_OP_SHAPE_INFER_MASK_REG(opset15::EmbeddingBagOffsets, ShapeInferTA, util::bit::mask()), + _OV_OP_SHAPE_INFER_MASK_REG(opset15::EmbeddingBagPacked, ShapeInferTA, util::bit::mask()), _OV_OP_SHAPE_INFER_MASK_REG(op::v15::Col2Im, ShapeInferTA, util::bit::mask(1, 2)), // opset14 _OV_OP_SHAPE_INFER_MASK_REG(opset14::Inverse, ShapeInferTA, util::bit::mask()), diff --git a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/embedding_bag_offsets.cpp b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/embedding_bag_offsets.cpp new file mode 100644 index 00000000000..6b2d3d6e538 --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/embedding_bag_offsets.cpp @@ -0,0 +1,166 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "common_test_utils/node_builders/embedding_bag_offsets.hpp" + +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "utils/cpu_test_utils.hpp" + +using namespace CPUTestUtils; +namespace ov { +namespace test { + +typedef std::tuple, // indices + std::vector, // offsets + size_t, // default_index + bool, // with_weights + bool, // with_def_index + ov::op::util::EmbeddingBagOffsetsBase::Reduction // reduction + > + embeddingBagOffsetsParams; + +typedef std::tuple + embeddingBagOffsetsLayerTestParamsSet; + +class EmbeddingBagOffsetsLayerCPUTest : public testing::WithParamInterface, + virtual public SubgraphBaseTest, + public CPUTestsBase { +public: + using Reduction = ov::op::util::EmbeddingBagOffsetsBase::Reduction; + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + embeddingBagOffsetsParams params; + ElementType netPrecision, indPrecision; + std::string targetDevice; + std::tie(params, netPrecision, indPrecision, targetDevice) = obj.param; + + InputShape inputShapes; + std::vector indices, offsets; + size_t defaultIndex; + bool withWeights, withDefIndex; + Reduction reduction; + std::tie(inputShapes, indices, offsets, defaultIndex, withWeights, withDefIndex, reduction) = params; + + std::ostringstream result; + result << "IS=" << inputShapes << "_"; + result << "I" << ov::test::utils::vec2str(indices) << "_"; + result << "O" << ov::test::utils::vec2str(offsets) << "_"; + result << "DI" << defaultIndex << "_"; + result << "WW" << withWeights << "_"; + result << "WDI" << withDefIndex << "_"; + result << "R" << ov::as_string(reduction) << "_"; + result << "netPRC=" << netPrecision << "_"; + result << "indPRC=" << indPrecision << "_"; + result << "targetDevice=" << targetDevice; + return result.str(); + } + + void SetUp() override { + embeddingBagOffsetsParams embParams; + ElementType indPrecision; + std::tie(embParams, inType, indPrecision, targetDevice) = this->GetParam(); + + InputShape inputShapes; + std::vector indices, offsets; + bool withWeights, withDefIndex; + Reduction reduction; + size_t defaultIndex; + std::tie(inputShapes, indices, offsets, defaultIndex, withWeights, withDefIndex, reduction) = embParams; + + selectedType = makeSelectedTypeStr("ref", inType); + targetDevice = ov::test::utils::DEVICE_CPU; + + init_input_shapes({inputShapes}); + + auto emb_table_node = std::make_shared(inType, inputShapes.first); + ov::ParameterVector params = {emb_table_node}; + + auto embBag = std::dynamic_pointer_cast( + ov::test::utils::make_embedding_bag_offsets(inType, + indPrecision, + emb_table_node, + indices, + offsets, + defaultIndex, + withWeights, + withDefIndex, + reduction)); + ov::ResultVector results{std::make_shared(embBag)}; + function = std::make_shared(results, params, "embeddingBagOffsets"); + } +}; + +TEST_P(EmbeddingBagOffsetsLayerCPUTest, CompareWithRefs) { + run(); + CheckPluginRelatedResults(compiledModel, "embeddingBagOffsets"); +} + +namespace { + +const std::vector netPrecisions = {ElementType::f32, ElementType::i32, ElementType::u8}; + +const std::vector indPrecisions = {ElementType::i64, ElementType::i32}; + +const std::vector input_shapes = { + // dynamic input shapes + {// input model dynamic shapes + {ov::Dimension::dynamic(), ov::Dimension::dynamic()}, + // input tensor shapes + {{5, 6}, {10, 35}}}, + {// input model dynamic shapes + {ov::Dimension::dynamic(), ov::Dimension::dynamic(), ov::Dimension::dynamic()}, + // input tensor shapes + {{5, 4, 16}, {10, 12, 8}}}, + {// input model dynamic shapes with limits + {{5, 10}, {6, 35}, {4, 8}}, + // input tensor shapes + {{5, 6, 4}, {10, 35, 8}, {5, 6, 4}}}, + // static shapes + {{5, 6}, {{5, 6}}}, + {{10, 35}, {{10, 35}}}, + {{5, 4, 16}, {{5, 4, 16}}}, +}; + +const std::vector> indices = {{0, 1, 2, 2, 3}, {4, 4, 3, 1, 0}, {1, 2, 1, 2, 1, 2, 1, 2, 1, 2}}; +const std::vector> offsets = {{0, 2}, {0, 0, 2, 2}, {2, 4}}; +const std::vector default_index = {0, 4}; +const std::vector with_default_index = {false, true}; +const std::vector reduction = { + ov::op::util::EmbeddingBagOffsetsBase::Reduction::SUM, + ov::op::util::EmbeddingBagOffsetsBase::Reduction::MEAN}; + +const auto embBagOffsetArgSetWthWeights = ::testing::Combine(::testing::ValuesIn(input_shapes), + ::testing::ValuesIn(indices), + ::testing::ValuesIn(offsets), + ::testing::ValuesIn(default_index), + ::testing::Values(true), + ::testing::ValuesIn(with_default_index), + ::testing::Values(ov::op::util::EmbeddingBagOffsetsBase::Reduction::SUM)); +const auto embBagOffsetArgSetNoWeights = ::testing::Combine(::testing::ValuesIn(input_shapes), + ::testing::ValuesIn(indices), + ::testing::ValuesIn(offsets), + ::testing::ValuesIn(default_index), + ::testing::Values(false), + ::testing::ValuesIn(with_default_index), + ::testing::ValuesIn(reduction)); +INSTANTIATE_TEST_SUITE_P(smoke_EmbeddingBagOffsets_With_Weights, + EmbeddingBagOffsetsLayerCPUTest, + ::testing::Combine(embBagOffsetArgSetWthWeights, + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(indPrecisions), + ::testing::Values(ov::test::utils::DEVICE_CPU)), + EmbeddingBagOffsetsLayerCPUTest::getTestCaseName); +INSTANTIATE_TEST_SUITE_P(smoke_EmbeddingBagOffsets_No_Weights, + EmbeddingBagOffsetsLayerCPUTest, + ::testing::Combine(embBagOffsetArgSetNoWeights, + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(indPrecisions), + ::testing::Values(ov::test::utils::DEVICE_CPU)), + EmbeddingBagOffsetsLayerCPUTest::getTestCaseName); +} // namespace +} // namespace test +} // namespace ov diff --git a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/embedding_bag_packed.cpp b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/embedding_bag_packed.cpp new file mode 100644 index 00000000000..8b6cd5e5a30 --- /dev/null +++ b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/embedding_bag_packed.cpp @@ -0,0 +1,153 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "common_test_utils/node_builders/embedding_bag_packed.hpp" +#include "openvino/op/util/embeddingbag_packed_base.hpp" + +#include "shared_test_classes/base/ov_subgraph.hpp" +#include "utils/cpu_test_utils.hpp" + +using namespace CPUTestUtils; +namespace ov { +namespace test { + +typedef std::tuple>, // indices + bool, // with_weights + ov::op::util::EmbeddingBagPackedBase::Reduction // reduction + > + embeddingBagPackedParams; + +typedef std::tuple + embeddingBagPackedLayerTestParamsSet; + +class EmbeddingBagPackedLayerCPUTest : public testing::WithParamInterface, + virtual public SubgraphBaseTest, + public CPUTestsBase { +public: + using Reduction = ov::op::util::EmbeddingBagPackedBase::Reduction; + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + embeddingBagPackedParams params; + ElementType netPrecision, indPrecision; + std::string targetDevice; + std::tie(params, netPrecision, indPrecision, targetDevice) = obj.param; + + InputShape inputShapes; + std::vector> indices; + bool withWeights; + Reduction reduction; + std::tie(inputShapes, indices, withWeights, reduction) = params; + + std::ostringstream result; + result << "IS=" << inputShapes << "_"; + result << "I" << ov::test::utils::vec2str(indices) << "_"; + result << "WW" << withWeights << "_"; + result << "R" << ov::as_string(reduction) << "_"; + result << "netPRC=" << netPrecision << "_"; + result << "indPRC=" << indPrecision << "_"; + result << "targetDevice=" << targetDevice; + return result.str(); + } + +protected: + void SetUp() override { + embeddingBagPackedParams embParams; + ElementType indPrecision; + std::tie(embParams, inType, indPrecision, targetDevice) = this->GetParam(); + + InputShape inputShapes; + std::vector> indices; + bool withWeights; + Reduction reduction; + std::tie(inputShapes, indices, withWeights, reduction) = embParams; + + selectedType = makeSelectedTypeStr("ref", inType); + targetDevice = ov::test::utils::DEVICE_CPU; + + init_input_shapes({inputShapes}); + + auto emb_table_node = std::make_shared(inType, inputShapes.first); + ov::ParameterVector params = {emb_table_node}; + + auto embBag = std::dynamic_pointer_cast( + ov::test::utils::make_embedding_bag_packed(inType, + indPrecision, + emb_table_node, + indices, + withWeights, + reduction)); + ov::ResultVector results{std::make_shared(embBag)}; + function = std::make_shared(results, params, "embeddingBagPacked"); + } +}; + +TEST_P(EmbeddingBagPackedLayerCPUTest, CompareWithRefs) { + run(); + CheckPluginRelatedResults(compiledModel, "embeddingBagPacked"); +} + +namespace { + +const std::vector netPrecisions = {ElementType::f32, ElementType::i32, ElementType::u8}; + +const std::vector indPrecisions = {ElementType::i64, ElementType::i32}; + +const std::vector input_shapes = { + // dynamic input shapes + {// input model dynamic shapes + {ov::Dimension::dynamic(), ov::Dimension::dynamic()}, + // input tensor shapes + {{{5, 6}}, {10, 35}}}, + {// input model dynamic shapes + {ov::Dimension::dynamic(), ov::Dimension::dynamic(), ov::Dimension::dynamic()}, + // input tensor shapes + {{5, 4, 16}, {10, 12, 8}}}, + {// input model dynamic shapes with limits + {{5, 10}, {6, 35}, {4, 8}}, + // input tensor shapes + {{5, 6, 4}, {10, 35, 8}, {5, 6, 4}}}, + // static shapes + {{5, 6}, {{5, 6}}}, + {{10, 35}, {{10, 35}}}, + {{5, 4, 16}, {{5, 4, 16}}}, +}; + +const std::vector>> indices = {{{0, 1}, {2, 2}, {3, 4}}, + {{4, 4, 3}, {1, 0, 2}}, + {{1, 2, 1, 2}, {1, 2, 1, 2}}}; + +const std::vector reduction = { + ov::op::util::EmbeddingBagPackedBase::Reduction::SUM, + ov::op::util::EmbeddingBagPackedBase::Reduction::MEAN}; + +const auto embBagPackedArgSetWthWeights = ::testing::Combine(::testing::ValuesIn(input_shapes), + ::testing::ValuesIn(indices), + ::testing::Values(true), + ::testing::Values(ov::op::util::EmbeddingBagPackedBase::Reduction::SUM)); + +const auto embBagPackedArgSetNoWeights = ::testing::Combine(::testing::ValuesIn(input_shapes), + ::testing::ValuesIn(indices), + ::testing::Values(false), + ::testing::ValuesIn(reduction)); + +INSTANTIATE_TEST_SUITE_P(smoke_EmbeddingBagPacked_With_Weights, + EmbeddingBagPackedLayerCPUTest, + ::testing::Combine(embBagPackedArgSetWthWeights, + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(indPrecisions), + ::testing::Values(ov::test::utils::DEVICE_CPU)), + EmbeddingBagPackedLayerCPUTest::getTestCaseName); +INSTANTIATE_TEST_SUITE_P(smoke_EmbeddingBagPacked_No_Weights, + EmbeddingBagPackedLayerCPUTest, + ::testing::Combine(embBagPackedArgSetNoWeights, + ::testing::ValuesIn(netPrecisions), + ::testing::ValuesIn(indPrecisions), + ::testing::Values(ov::test::utils::DEVICE_CPU)), + EmbeddingBagPackedLayerCPUTest::getTestCaseName); +} // namespace +} // namespace test +} // namespace ov diff --git a/src/plugins/template/backend/ops/embedding_bag_offsets.cpp b/src/plugins/template/backend/ops/embedding_bag_offsets.cpp new file mode 100644 index 00000000000..446896ae304 --- /dev/null +++ b/src/plugins/template/backend/ops/embedding_bag_offsets.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/reference/embedding_bag_offsets.hpp" + +#include "evaluate_node.hpp" + +namespace embedding_bag_offsets_v15 { +template +inline void evaluate(const std::shared_ptr& op, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + using T1 = typename ov::element_type_traits::value_type; + using T2 = typename ov::element_type_traits::value_type; + ov::reference::embeddingBagOffsets(inputs[0].data(), + inputs[1].data(), + inputs[2].data(), + inputs.size() > 3 ? inputs[3].data() : nullptr, + inputs.size() > 4 ? inputs[4].data() : nullptr, + outputs[0].data(), + ov::shape_size(inputs[1].get_shape()), + outputs[0].get_shape(), + op->get_reduction()); +} +} // namespace embedding_bag_offsets_v15 + +template +bool evaluate(const std::shared_ptr& op, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + switch (inputs[1].get_element_type()) { + case ov::element::i32: + embedding_bag_offsets_v15::evaluate(op, outputs, inputs); + break; + case ov::element::i64: + embedding_bag_offsets_v15::evaluate(op, outputs, inputs); + break; + default: + return false; + } + return true; +} + +template <> +bool evaluate_node(std::shared_ptr node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + auto element_type = node->get_output_element_type(0); + if (ov::is_type(node) || ov::is_type(node)) + element_type = node->get_input_element_type(1); + + switch (element_type) { + case ov::element::boolean: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::bf16: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::f16: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::f64: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::f32: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i4: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i8: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i16: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i32: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i64: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u1: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u4: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u8: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u16: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u32: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u64: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + default: + OPENVINO_THROW("Unhandled data type ", node->get_element_type().get_type_name(), " in evaluate_node()"); + } +} diff --git a/src/plugins/template/backend/ops/embedding_bag_offsets_sum.cpp b/src/plugins/template/backend/ops/embedding_bag_offsets_sum.cpp index 95a37ddf0da..5ce8e3dbca5 100644 --- a/src/plugins/template/backend/ops/embedding_bag_offsets_sum.cpp +++ b/src/plugins/template/backend/ops/embedding_bag_offsets_sum.cpp @@ -2,9 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // -#include "openvino/reference/embedding_bag_offsets_sum.hpp" - #include "evaluate_node.hpp" +#include "openvino/reference/embedding_bag_offsets.hpp" namespace embedding_bag_offsets_sum_v3 { template @@ -13,14 +12,15 @@ inline void evaluate(const std::shared_ptr& const ov::TensorVector& inputs) { using T1 = typename ov::element_type_traits::value_type; using T2 = typename ov::element_type_traits::value_type; - ov::reference::embeddingBagOffsetsSum(inputs[0].data(), - inputs[1].data(), - inputs[2].data(), - inputs.size() > 3 ? inputs[3].data() : nullptr, - inputs.size() > 4 ? inputs[4].data() : nullptr, - outputs[0].data(), - ov::shape_size(inputs[1].get_shape()), - outputs[0].get_shape()); + ov::reference::embeddingBagOffsets(inputs[0].data(), + inputs[1].data(), + inputs[2].data(), + inputs.size() > 3 ? inputs[3].data() : nullptr, + inputs.size() > 4 ? inputs[4].data() : nullptr, + outputs[0].data(), + ov::shape_size(inputs[1].get_shape()), + outputs[0].get_shape(), + ov::op::v3::EmbeddingBagOffsetsSum::Reduction::SUM); } } // namespace embedding_bag_offsets_sum_v3 diff --git a/src/plugins/template/backend/ops/embedding_bag_packed.cpp b/src/plugins/template/backend/ops/embedding_bag_packed.cpp new file mode 100644 index 00000000000..85217d1bb66 --- /dev/null +++ b/src/plugins/template/backend/ops/embedding_bag_packed.cpp @@ -0,0 +1,88 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/reference/embedding_bag_packed.hpp" + +#include "evaluate_node.hpp" + +namespace embedding_bag_packed_v15 { +template +inline void evaluate(const std::shared_ptr& op, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + using T1 = typename ov::element_type_traits::value_type; + using T2 = typename ov::element_type_traits::value_type; + ov::reference::embeddingBagPacked(inputs[0].data(), + inputs[1].data(), + inputs.size() > 2 ? inputs[2].data() : nullptr, + outputs[0].data(), + inputs[1].get_shape(), + outputs[0].get_shape(), + op->get_reduction()); +} +} // namespace embedding_bag_packed_v15 + +template +bool evaluate(const std::shared_ptr& op, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + switch (inputs[1].get_element_type()) { + case ov::element::i32: + embedding_bag_packed_v15::evaluate(op, outputs, inputs); + break; + case ov::element::i64: + embedding_bag_packed_v15::evaluate(op, outputs, inputs); + break; + default: + return false; + } + + return true; +} + +template <> +bool evaluate_node(std::shared_ptr node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs) { + auto element_type = node->get_output_element_type(0); + if (ov::is_type(node) || ov::is_type(node)) + element_type = node->get_input_element_type(1); + + switch (element_type) { + case ov::element::boolean: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::bf16: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::f16: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::f64: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::f32: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i4: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i8: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i16: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i32: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::i64: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u1: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u4: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u8: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u16: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u32: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + case ov::element::u64: + return evaluate(ov::as_type_ptr(node), outputs, inputs); + default: + OPENVINO_THROW("Unhandled data type ", node->get_element_type().get_type_name(), " in evaluate_node()"); + } +} diff --git a/src/plugins/template/backend/ops/embedding_bag_packed_sum.cpp b/src/plugins/template/backend/ops/embedding_bag_packed_sum.cpp index 48fa179a0d6..0dd8e96ca9c 100644 --- a/src/plugins/template/backend/ops/embedding_bag_packed_sum.cpp +++ b/src/plugins/template/backend/ops/embedding_bag_packed_sum.cpp @@ -2,9 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // -#include "openvino/reference/embedding_bag_packed_sum.hpp" - #include "evaluate_node.hpp" +#include "openvino/reference/embedding_bag_packed.hpp" namespace embedding_bag_packed_sum_v3 { template @@ -13,12 +12,13 @@ inline void evaluate(const std::shared_ptr& o const ov::TensorVector& inputs) { using T1 = typename ov::element_type_traits::value_type; using T2 = typename ov::element_type_traits::value_type; - ov::reference::embeddingBagPackedSum(inputs[0].data(), - inputs[1].data(), - inputs.size() > 2 ? inputs[2].data() : nullptr, - outputs[0].data(), - inputs[1].get_shape(), - outputs[0].get_shape()); + ov::reference::embeddingBagPacked(inputs[0].data(), + inputs[1].data(), + inputs.size() > 2 ? inputs[2].data() : nullptr, + outputs[0].data(), + inputs[1].get_shape(), + outputs[0].get_shape(), + ov::op::v3::EmbeddingBagPackedSum::Reduction::SUM); } } // namespace embedding_bag_packed_sum_v3 diff --git a/src/plugins/template/backend/ops/ops_evaluates.hpp b/src/plugins/template/backend/ops/ops_evaluates.hpp index 5d33f057a54..86ad28035c4 100644 --- a/src/plugins/template/backend/ops/ops_evaluates.hpp +++ b/src/plugins/template/backend/ops/ops_evaluates.hpp @@ -498,6 +498,13 @@ extern template bool evaluate_node(std::shared_ptr ov::TensorVector& outputs, const ov::TensorVector& inputs); +extern template bool evaluate_node(std::shared_ptr node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs); + +extern template bool evaluate_node(std::shared_ptr node, + ov::TensorVector& outputs, + const ov::TensorVector& inputs); extern template bool evaluate_node(std::shared_ptr node, ov::TensorVector& outputs, const ov::TensorVector& inputs); diff --git a/src/plugins/template/backend/opset_int_tbl.hpp b/src/plugins/template/backend/opset_int_tbl.hpp index 80a71e70f2e..f66d60b55da 100644 --- a/src/plugins/template/backend/opset_int_tbl.hpp +++ b/src/plugins/template/backend/opset_int_tbl.hpp @@ -164,6 +164,9 @@ _OPENVINO_OP_REG(AvgPool, ov::op::v14) _OPENVINO_OP_REG(MaxPool, ov::op::v14) _OPENVINO_OP_REG(ROIAlignRotated, ov::op::v14) +_OPENVINO_OP_REG(EmbeddingBagOffsets, op::v15) +_OPENVINO_OP_REG(EmbeddingBagPacked, op::v15) + _OPENVINO_OP_REG(AUGRUCell, ov::op::internal) _OPENVINO_OP_REG(AUGRUSequence, ov::op::internal) _OPENVINO_OP_REG(RMSNorm, ov::op::internal) diff --git a/src/plugins/template/tests/functional/op_reference/embeddingbag_offsets.cpp b/src/plugins/template/tests/functional/op_reference/embeddingbag_offsets.cpp new file mode 100644 index 00000000000..68e428a2264 --- /dev/null +++ b/src/plugins/template/tests/functional/op_reference/embeddingbag_offsets.cpp @@ -0,0 +1,275 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/embeddingbag_offsets.hpp" + +#include + +#include "base_reference_test.hpp" +#include "openvino/op/constant.hpp" + +using namespace reference_tests; +using namespace ov; + +struct EmbeddingBagOffsetsParams { + template + EmbeddingBagOffsetsParams(const ov::Shape& iShape, + const ov::element::Type& iType, + const std::vector& iValues, + const ov::Shape& oShape, + const ov::element::Type& oType, + const std::vector& oValues, + const std::shared_ptr& indices, + const std::shared_ptr& offsets, + const ov::op::v15::EmbeddingBagOffsets::Reduction reduction, + const std::shared_ptr& default_index = nullptr, + const std::shared_ptr& per_sample_weights = nullptr) + : _iShape(iShape), + _iType(iType), + _iData(CreateTensor(iShape, iType, iValues)), + _refShape(oShape), + _refType(oType), + _refData(CreateTensor(oShape, oType, oValues)) { + _indices = indices; + _offsets = offsets; + _reduction = reduction; + _defaultIndex = default_index; + _perSampleWeights = per_sample_weights; + } + ov::Shape _iShape; + ov::element::Type _iType; + ov::Tensor _iData; + + ov::Shape _refShape; + ov::element::Type _refType; + ov::Tensor _refData; + + std::shared_ptr _indices; + std::shared_ptr _offsets; + ov::op::v15::EmbeddingBagOffsets::Reduction _reduction; + std::shared_ptr _defaultIndex; // Optional, default filled zero. + std::shared_ptr _perSampleWeights; // Optional, default is tensor of ones. +}; + +class ReferenceEmbeddingBagOffsetsLayerTest : public testing::TestWithParam, + public CommonReferenceTest { +public: + void SetUp() override { + auto params = GetParam(); + function = CreateFunction(params._iShape, + params._iType, + params._indices, + params._offsets, + params._reduction, + params._defaultIndex, + params._perSampleWeights); + inputData = {params._iData}; + refOutData = {params._refData}; + } + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + auto param = obj.param; + std::ostringstream result; + result << "_iShape=" << param._iShape << "_"; + result << "_iType=" << param._iType << "_"; + result << "_refShape=" << param._refShape << "_"; + result << "_refType=" << param._refType << "_"; + result << "_reduction=" << param._reduction; + return result.str(); + } + +private: + static std::shared_ptr CreateFunction(const Shape& input_shape, + const element::Type& input_type, + const std::shared_ptr indices, + const std::shared_ptr offsets, + const ov::op::v15::EmbeddingBagOffsets::Reduction reduction, + const std::shared_ptr default_index, + const std::shared_ptr per_sample_weights) { + const auto in = std::make_shared(input_type, input_shape); + + if (default_index) { + if (per_sample_weights) { + const auto ess = std::make_shared(in, + indices, + offsets, + default_index, + per_sample_weights, + reduction); + return std::make_shared(NodeVector{ess}, ParameterVector{in}); + } else { + const auto ess = + std::make_shared(in, indices, offsets, default_index, reduction); + return std::make_shared(NodeVector{ess}, ParameterVector{in}); + } + } else { + const auto ess = std::make_shared(in, indices, offsets, reduction); + return std::make_shared(NodeVector{ess}, ParameterVector{in}); + } + } +}; + +TEST_P(ReferenceEmbeddingBagOffsetsLayerTest, CompareWithRefs) { + Exec(); +} + +INSTANTIATE_TEST_SUITE_P( + smoke_EmbeddingBagOffsets_With_Hardcoded_Refs, + ReferenceEmbeddingBagOffsetsLayerTest, + ::testing::Values( + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::f32, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f32, + {-1.05f, -1.2f, -0.2f, -0.6f, -0.1f, 0.4f}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::SUM, + std::make_shared(element::i32, ov::Shape(), std::vector{0}), + std::make_shared(element::f32, + ov::Shape({4}), + std::vector{0.5, 0.5, 0.5, 0.5})), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::f64, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f64, + std::vector{-2.1, -2.4, -0.2, -0.6, -0.2, 0.8}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::SUM, + std::make_shared(element::i32, ov::Shape(), std::vector{0})), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::i32, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i32, + std::vector{-6, -4, 0, 0, 2, 18}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::SUM), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::u32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::u32, + std::vector{6, 8, 3, 4, 16, 18}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::SUM, + std::make_shared(element::i32, ov::Shape(), std::vector{1})), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::f16, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f16, + std::vector{-2.1, -2.4, 0, 0, -0.2, 0.8}, + std::make_shared(element::i64, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i64, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::SUM), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::i64, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i64, + std::vector{-6, -4, -1, 2, 2, 18}, + std::make_shared(element::i64, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i64, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::SUM, + std::make_shared(element::i64, ov::Shape(), std::vector{0})), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::i8, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i8, + std::vector{-12, -8, -1, 2, 4, 36}, + std::make_shared(element::i64, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i64, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::SUM, + std::make_shared(element::i64, ov::Shape(), std::vector{0}), + std::make_shared(element::i8, ov::Shape({4}), std::vector{2, 2, 2, 2})), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::u8, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::u8, + std::vector{6, 8, 1, 2, 16, 18}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::SUM, + std::make_shared(element::i32, ov::Shape(), std::vector{0})), + // Reduction MEAN + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::f64, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f64, + std::vector{-1.05, -1.2, -0.2, -0.6, -0.1, 0.4}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::MEAN, + std::make_shared(element::i32, ov::Shape(), std::vector{0})), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::i32, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i32, + std::vector{-3, -2, 0, 0, 1, 9}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::MEAN), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::u32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::u32, + std::vector{3, 4, 3, 4, 8, 9}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::MEAN, + std::make_shared(element::i32, ov::Shape(), std::vector{1})), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::f16, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f16, + std::vector{-1.05, -1.2, 0, 0, -0.1, 0.4}, + std::make_shared(element::i64, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i64, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::MEAN), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::i64, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i64, + std::vector{-3, -2, -1, 2, 1, 9}, + std::make_shared(element::i64, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i64, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::MEAN, + std::make_shared(element::i64, ov::Shape(), std::vector{0})), + EmbeddingBagOffsetsParams( + ov::Shape{5, 2}, + ov::element::u8, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::u8, + std::vector{3, 4, 1, 2, 8, 9}, + std::make_shared(element::i32, ov::Shape({4}), std::vector{0, 2, 3, 4}), + std::make_shared(element::i32, ov::Shape({3}), std::vector{0, 2, 2}), + ov::op::v15::EmbeddingBagOffsets::Reduction::MEAN, + std::make_shared(element::i32, ov::Shape(), std::vector{0}))), + ReferenceEmbeddingBagOffsetsLayerTest::getTestCaseName); diff --git a/src/plugins/template/tests/functional/op_reference/embeddingbag_packed.cpp b/src/plugins/template/tests/functional/op_reference/embeddingbag_packed.cpp new file mode 100644 index 00000000000..1bebe0bf188 --- /dev/null +++ b/src/plugins/template/tests/functional/op_reference/embeddingbag_packed.cpp @@ -0,0 +1,232 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/embeddingbag_packed.hpp" + +#include + +#include "base_reference_test.hpp" +#include "openvino/op/constant.hpp" + +using namespace reference_tests; +using namespace ov; + +struct EmbeddingBagPackedParams { + template + EmbeddingBagPackedParams(const ov::Shape& iShape, + const ov::element::Type& iType, + const std::vector& iValues, + const ov::Shape& oShape, + const ov::element::Type& oType, + const std::vector& oValues, + const std::shared_ptr& indices, + const ov::op::v15::EmbeddingBagPacked::Reduction reduction, + const std::shared_ptr& per_sample_weights = nullptr) + : _iShape(iShape), + _iType(iType), + _iData(CreateTensor(iShape, iType, iValues)), + _refShape(oShape), + _refType(oType), + _refData(CreateTensor(oShape, oType, oValues)) { + _indices = indices; + _reduction = reduction; + _perSampleWeights = per_sample_weights; + } + ov::Shape _iShape; + ov::element::Type _iType; + ov::Tensor _iData; + + ov::Shape _refShape; + ov::element::Type _refType; + ov::Tensor _refData; + + std::shared_ptr _indices; + ov::op::v15::EmbeddingBagPacked::Reduction _reduction; + std::shared_ptr _perSampleWeights; // Optional, default is tensor of ones. +}; + +class ReferenceEmbeddingBagPackedLayerTest : public testing::TestWithParam, + public CommonReferenceTest { +public: + void SetUp() override { + auto params = GetParam(); + function = + CreateFunction(params._iShape, params._iType, params._indices, params._reduction, params._perSampleWeights); + inputData = {params._iData}; + refOutData = {params._refData}; + } + static std::string getTestCaseName(const testing::TestParamInfo& obj) { + auto param = obj.param; + std::ostringstream result; + result << "_iShape=" << param._iShape << "_"; + result << "_iType=" << param._iType << "_"; + result << "_refShape=" << param._refShape << "_"; + result << "_refType=" << param._refType << "_"; + result << "_reduction=" << param._reduction; + return result.str(); + } + +private: + static std::shared_ptr CreateFunction(const Shape& input_shape, + const element::Type& input_type, + const std::shared_ptr indices, + const ov::op::v15::EmbeddingBagPacked::Reduction reduction, + const std::shared_ptr per_sample_weights) { + const auto in = std::make_shared(input_type, input_shape); + + if (per_sample_weights) { + const auto ess = std::make_shared(in, indices, per_sample_weights, reduction); + return std::make_shared(NodeVector{ess}, ParameterVector{in}); + } else { + const auto ess = std::make_shared(in, indices, reduction); + return std::make_shared(NodeVector{ess}, ParameterVector{in}); + } + } +}; + +TEST_P(ReferenceEmbeddingBagPackedLayerTest, CompareWithRefs) { + Exec(); +} + +template +inline std::shared_ptr CreateConstant(const std::vector>& val, + const ov::element::Type& element_type) { + if (val.size() > 0) { + ov::Shape i_shape({val.size(), val[0].size()}); + + size_t i_size = ov::shape_size(i_shape); + std::vector i_values(i_size); + + for (size_t i = 0; i < i_shape[0]; i++) { + for (size_t j = 0; j < i_shape[1]; j++) { + i_values[i * i_shape[1] + j] = val[i][j]; + } + } + + return std::make_shared(element_type, i_shape, i_values); + } else { + return std::make_shared(element_type, ov::Shape(), std::vector()); + } +} + +INSTANTIATE_TEST_SUITE_P( + smoke_EmbeddingBagPacked_With_Hardcoded_Refs, + ReferenceEmbeddingBagPackedLayerTest, + ::testing::Values( + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::f32, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f32, + std::vector{-1.05f, -1.2f, -1.f, -1.1f, -0.1f, 0.4f}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i32), + ov::op::v15::EmbeddingBagPacked::Reduction::SUM, + CreateConstant({{0.5, 0.5}, {0.5, 0.5}, {0.5, 0.5}}, element::f32)), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::f64, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f64, + std::vector{-2.1, -2.4, -2.0, -2.2, -0.2, 0.8}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i32), + ov::op::v15::EmbeddingBagPacked::Reduction::SUM), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::i32, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i32, + std::vector{-6, -4, -2, -2, 2, 18}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i32), + ov::op::v15::EmbeddingBagPacked::Reduction::SUM), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::u32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::u32, + std::vector{6, 8, 8, 10, 16, 18}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i32), + ov::op::v15::EmbeddingBagPacked::Reduction::SUM), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::f16, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f16, + std::vector{-2.1, -2.4, -2.0, -2.2, -0.2, 0.8}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i64), + ov::op::v15::EmbeddingBagPacked::Reduction::SUM), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::i64, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i64, + std::vector{-6, -4, -2, -2, 2, 18}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i64), + ov::op::v15::EmbeddingBagPacked::Reduction::SUM), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::i8, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i8, + std::vector{-12, -8, -4, -4, 4, 36}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i64), + ov::op::v15::EmbeddingBagPacked::Reduction::SUM, + CreateConstant({{2, 2}, {2, 2}, {2, 2}}, element::i8)), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::u8, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::u8, + std::vector{6, 8, 8, 10, 16, 18}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i64), + ov::op::v15::EmbeddingBagPacked::Reduction::SUM), + // Reduction MEAN + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::f64, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f64, + std::vector{-1.05, -1.2, -1., -1.1, -0.1, 0.4}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i32), + ov::op::v15::EmbeddingBagPacked::Reduction::MEAN), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::i32, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i32, + std::vector{-3, -2, -1, -1, 1, 9}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i32), + ov::op::v15::EmbeddingBagPacked::Reduction::MEAN), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::u32, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::u32, + std::vector{3, 4, 4, 5, 8, 9}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i32), + ov::op::v15::EmbeddingBagPacked::Reduction::MEAN), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::f16, + std::vector{-0.2, -0.6, -0.1, -0.4, -1.9, -1.8, -1., 1.5, 0.8, -0.7}, + ov::Shape{3, 2}, + ov::element::f16, + std::vector{-1.05, -1.2, -1.0, -1.1, -0.1, 0.4}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i64), + ov::op::v15::EmbeddingBagPacked::Reduction::MEAN), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::i64, + std::vector{-1, 2, 3, 4, -5, -6, -7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::i64, + std::vector{-3, -2, -1, -1, 1, 9}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i64), + ov::op::v15::EmbeddingBagPacked::Reduction::MEAN), + EmbeddingBagPackedParams(ov::Shape{5, 2}, + ov::element::u8, + std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + ov::Shape{3, 2}, + ov::element::u8, + std::vector{3, 4, 4, 5, 8, 9}, + CreateConstant({{0, 2}, {1, 2}, {3, 4}}, element::i64), + ov::op::v15::EmbeddingBagPacked::Reduction::MEAN)), + ReferenceEmbeddingBagPackedLayerTest::getTestCaseName); 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 1996d244d52..75095ea3226 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 @@ -1790,14 +1790,17 @@ std::shared_ptr generateEmbeddingBagOffsetsBase(const std::shared_ptr const auto offsets = std::make_shared(utils::create_and_fill_tensor(ov::element::i32, ov::Shape{3})); const auto default_index = std::make_shared(ov::element::i32, ov::Shape(), std::vector{0}); - std::shared_ptr EmbeddingBagOffsetsSumNode; + std::shared_ptr EmbeddingBagOffsetsNode; if (ov::is_type(node)) { - EmbeddingBagOffsetsSumNode = std::make_shared(params.at(0), indices, offsets, default_index); + EmbeddingBagOffsetsNode = std::make_shared(params.at(0), indices, offsets, default_index); + } else if (ov::is_type(node)) { + const auto reduction = ov::op::v15::EmbeddingBagOffsets::Reduction::MEAN; + EmbeddingBagOffsetsNode = std::make_shared(params.at(0), indices, offsets, default_index, reduction); } else { return nullptr; } - ov::ResultVector results{std::make_shared(EmbeddingBagOffsetsSumNode)}; + ov::ResultVector results{std::make_shared(EmbeddingBagOffsetsNode)}; return std::make_shared(results, params, "EmbeddingBagOffsetsBaseGraph"); } @@ -1805,14 +1808,17 @@ std::shared_ptr generateEmbeddingBagPackedBase(const std::shared_ptr< ov::ParameterVector params{std::make_shared(ov::element::f32, ov::Shape{{5, 2}})}; const auto indices = std::make_shared(utils::create_and_fill_tensor(ov::element::i32, ov::Shape{2, 3})); - std::shared_ptr EmbeddingBagPackedSumNode; + std::shared_ptr EmbeddingBagPackedNode; if (ov::is_type(node)) { - EmbeddingBagPackedSumNode = std::make_shared(params.at(0), indices); + EmbeddingBagPackedNode = std::make_shared(params.at(0), indices); + } else if (ov::is_type(node)) { + const auto reduction = ov::op::v15::EmbeddingBagPacked::Reduction::SUM; + EmbeddingBagPackedNode = std::make_shared(params.at(0), indices, reduction); } else { return nullptr; } - ov::ResultVector results{std::make_shared(EmbeddingBagPackedSumNode)}; + ov::ResultVector results{std::make_shared(EmbeddingBagPackedNode)}; return std::make_shared(results, params, "EmbeddingBagPackedBaseGraph"); } diff --git a/src/tests/functional/shared_test_classes/src/base/utils/compare_results.cpp b/src/tests/functional/shared_test_classes/src/base/utils/compare_results.cpp index 03680f72d57..c9185e9a4fc 100644 --- a/src/tests/functional/shared_test_classes/src/base/utils/compare_results.cpp +++ b/src/tests/functional/shared_test_classes/src/base/utils/compare_results.cpp @@ -204,6 +204,7 @@ CompareMap getCompareMap() { #include "openvino/opsets/opset12_tbl.hpp" #include "openvino/opsets/opset13_tbl.hpp" #include "openvino/opsets/opset14_tbl.hpp" +#include "openvino/opsets/opset15_tbl.hpp" #include "ov_ops/opset_private_tbl.hpp" #undef _OPENVINO_OP_REG diff --git a/src/tests/functional/shared_test_classes/src/base/utils/generate_inputs.cpp b/src/tests/functional/shared_test_classes/src/base/utils/generate_inputs.cpp index 55259b81f8f..39dfc9dcac5 100644 --- a/src/tests/functional/shared_test_classes/src/base/utils/generate_inputs.cpp +++ b/src/tests/functional/shared_test_classes/src/base/utils/generate_inputs.cpp @@ -1124,6 +1124,8 @@ InputsMap getInputMap() { #include "openvino/opsets/opset11_tbl.hpp" #include "openvino/opsets/opset12_tbl.hpp" #include "openvino/opsets/opset13_tbl.hpp" +#include "openvino/opsets/opset14_tbl.hpp" +#include "openvino/opsets/opset15_tbl.hpp" #include "ov_ops/opset_private_tbl.hpp" #undef _OPENVINO_OP_REG diff --git a/src/tests/test_utils/common_test_utils/include/common_test_utils/node_builders/embedding_bag_offsets.hpp b/src/tests/test_utils/common_test_utils/include/common_test_utils/node_builders/embedding_bag_offsets.hpp new file mode 100644 index 00000000000..d53a8fef2ce --- /dev/null +++ b/src/tests/test_utils/common_test_utils/include/common_test_utils/node_builders/embedding_bag_offsets.hpp @@ -0,0 +1,25 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// +#pragma once + +#pragma once + +#include "openvino/core/node.hpp" +#include "openvino/op/util/embeddingbag_offsets_base.hpp" + +namespace ov { +namespace test { +namespace utils { +std::shared_ptr make_embedding_bag_offsets(const element::Type& data_type, + const ov::element::Type& indices_type, + const ov::Output& emb_table_node, + const std::vector& indices, + const std::vector& offsets, + size_t default_index, + bool with_weights, + bool with_default_index, + ov::op::util::EmbeddingBagOffsetsBase::Reduction reduction); +} // namespace utils +} // namespace test +} // namespace ov diff --git a/src/tests/test_utils/common_test_utils/include/common_test_utils/node_builders/embedding_bag_packed.hpp b/src/tests/test_utils/common_test_utils/include/common_test_utils/node_builders/embedding_bag_packed.hpp new file mode 100644 index 00000000000..8740a03df25 --- /dev/null +++ b/src/tests/test_utils/common_test_utils/include/common_test_utils/node_builders/embedding_bag_packed.hpp @@ -0,0 +1,22 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// +#pragma once + +#pragma once + +#include "openvino/core/node.hpp" +#include "openvino/op/util/embeddingbag_packed_base.hpp" + +namespace ov { +namespace test { +namespace utils { +std::shared_ptr make_embedding_bag_packed(const ov::element::Type& data_type, + const ov::element::Type& indices_type, + const ov::Output& emb_table_node, + const std::vector>& indices, + bool with_weights, + ov::op::util::EmbeddingBagPackedBase::Reduction reduction); +} // namespace utils +} // namespace test +} // namespace ov diff --git a/src/tests/test_utils/common_test_utils/src/node_builders/embedding_bag_offsets.cpp b/src/tests/test_utils/common_test_utils/src/node_builders/embedding_bag_offsets.cpp new file mode 100644 index 00000000000..5c4caff07b9 --- /dev/null +++ b/src/tests/test_utils/common_test_utils/src/node_builders/embedding_bag_offsets.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "common_test_utils/node_builders/embedding_bag_offsets.hpp" + +#include "common_test_utils/ov_tensor_utils.hpp" +#include "openvino/op/constant.hpp" +#include "openvino/op/embeddingbag_offsets.hpp" + +namespace ov { +namespace test { +namespace utils { +std::shared_ptr make_embedding_bag_offsets(const element::Type& data_type, + const ov::element::Type& indices_type, + const ov::Output& emb_table_node, + const std::vector& indices, + const std::vector& offsets, + size_t default_index, + bool with_weights, + bool with_default_index, + ov::op::util::EmbeddingBagOffsetsBase::Reduction reduction) { + ov::Shape i_shape = {indices.size()}; + auto indices_node = std::make_shared(indices_type, i_shape, indices); + ov::Shape o_shape = {offsets.size()}; + auto offsetsNode = std::make_shared(indices_type, o_shape, offsets); + + std::shared_ptr embBag; + if (with_default_index) { + auto defIdxNode = std::make_shared(indices_type, ov::Shape{}, default_index); + if (with_weights) { + auto tensor = create_and_fill_tensor(data_type, ov::Shape{indices.size()}); + auto weights_node = std::make_shared(tensor); + + embBag = std::make_shared(emb_table_node, + indices_node, + offsetsNode, + defIdxNode, + weights_node, + reduction); + } else { + embBag = std::make_shared(emb_table_node, + indices_node, + offsetsNode, + defIdxNode, + reduction); + } + } else { + embBag = + std::make_shared(emb_table_node, indices_node, offsetsNode, reduction); + } + return embBag; +} +} // namespace utils +} // namespace test +} // namespace ov diff --git a/src/tests/test_utils/common_test_utils/src/node_builders/embedding_bag_packed.cpp b/src/tests/test_utils/common_test_utils/src/node_builders/embedding_bag_packed.cpp new file mode 100644 index 00000000000..1c43fa8fb28 --- /dev/null +++ b/src/tests/test_utils/common_test_utils/src/node_builders/embedding_bag_packed.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2018-2024 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "common_test_utils/node_builders/embedding_bag_packed.hpp" + +#include "common_test_utils/ov_tensor_utils.hpp" +#include "openvino/op/constant.hpp" +#include "openvino/op/embeddingbag_packed.hpp" + +namespace ov { +namespace test { +namespace utils { +std::shared_ptr make_embedding_bag_packed(const ov::element::Type& data_type, + const ov::element::Type& indices_type, + const ov::Output& emb_table_node, + const std::vector>& indices, + bool with_weights, + ov::op::util::EmbeddingBagPackedBase::Reduction reduction) { + ov::Shape i_shape({indices.size(), indices[0].size()}); + size_t i_size = ov::shape_size(i_shape); + std::vector i_values(i_size); + for (int i = 0; i < indices.size(); i++) + memcpy(i_values.data() + indices[0].size() * i, indices[i].data(), indices[0].size() * sizeof(size_t)); + auto indicesNode = std::make_shared(indices_type, i_shape, i_values); + + std::shared_ptr embBag; + if (with_weights) { + auto tensor = create_and_fill_tensor(data_type, i_shape); + auto weights_node = std::make_shared(tensor); + + embBag = + std::make_shared(emb_table_node, indicesNode, weights_node, reduction); + } else { + embBag = std::make_shared(emb_table_node, indicesNode, reduction); + } + return embBag; +} +} // namespace utils +} // namespace test +} // namespace ov diff --git a/tests/layer_tests/pytorch_tests/test_embedding_bag.py b/tests/layer_tests/pytorch_tests/test_embedding_bag.py index 64723aece88..237fa74cd3b 100644 --- a/tests/layer_tests/pytorch_tests/test_embedding_bag.py +++ b/tests/layer_tests/pytorch_tests/test_embedding_bag.py @@ -11,89 +11,228 @@ from pytorch_layer_test_class import PytorchLayerTest class TestEmbeddingBag1dOffsets(PytorchLayerTest): def _prepare_input(self, indicies_dtype, per_sample_weights=False): import numpy as np + indices = np.array([2, 2, 2, 2, 4, 3, 2, 9]).astype(indicies_dtype) weights = np.random.randn(10, 10).astype(np.float32) offsets = np.array([0, 4]).astype(indicies_dtype) if per_sample_weights: - per_sample_weights = np.random.randn( - *indices.shape).astype(np.float32) + per_sample_weights = np.random.randn(*indices.shape).astype(np.float32) return (indices, weights, offsets, per_sample_weights) return (indices, weights, offsets) - def create_model(self, per_sample_weights): + def create_model(self, mode, per_sample_weights): import torch import torch.nn.functional as F class aten_embedding_bag(torch.nn.Module): - def __init__(self, per_sample_weights=False) -> None: + def __init__(self, mode=None, per_sample_weights=False) -> None: super().__init__() + self.mode = mode if per_sample_weights: self.forward = self.forward_offsets_per_sample_weights def forward(self, indicies, weight, offsets): - return F.embedding_bag(indicies, weight, offsets, mode="sum") + return F.embedding_bag(indicies, weight, offsets, mode=self.mode) - def forward_offsets_per_sample_weights(self, indicies, weight, offsets, per_sample_wights): - return F.embedding_bag(indicies, weight, offsets, mode="sum", per_sample_weights=per_sample_wights) + def forward_offsets_per_sample_weights( + self, indicies, weight, offsets, per_sample_wights + ): + return F.embedding_bag( + indicies, + weight, + offsets, + mode=self.mode, + per_sample_weights=per_sample_wights, + ) ref_net = None - return aten_embedding_bag(per_sample_weights), ref_net, "aten::embedding_bag" + return ( + aten_embedding_bag(mode, per_sample_weights), + ref_net, + "aten::embedding_bag", + ) @pytest.mark.nightly @pytest.mark.precommit @pytest.mark.precommit_fx_backend @pytest.mark.parametrize("indicies_dtype", ["int", "int32"]) - @pytest.mark.parametrize("per_sample_weights", [True, False]) - @pytest.mark.xfail(condition=platform.system() == 'Darwin' and platform.machine() == 'arm64', - reason='Ticket - 122715') - def test_embedding_bag(self, ie_device, precision, ir_version, indicies_dtype, per_sample_weights): - self._test(*self.create_model(per_sample_weights), ie_device, precision, ir_version, - kwargs_to_prepare_input={"indicies_dtype": indicies_dtype, "per_sample_weights": per_sample_weights}, - trace_model=True, dynamic_shapes=not per_sample_weights and ie_device != "GPU") + @pytest.mark.parametrize( + "mode, per_sample_weights", [("mean", False), ("sum", False), ("sum", True)] + ) + @pytest.mark.xfail( + condition=platform.system() == "Darwin" and platform.machine() == "arm64", + reason="Ticket - 122715", + ) + def test_embedding_bag( + self, ie_device, precision, ir_version, indicies_dtype, mode, per_sample_weights + ): + self._test( + *self.create_model(mode, per_sample_weights), + ie_device, + precision, + ir_version, + kwargs_to_prepare_input={ + "indicies_dtype": indicies_dtype, + "per_sample_weights": per_sample_weights, + }, + trace_model=True, + dynamic_shapes=not per_sample_weights and ie_device != "GPU" + ) class TestEmbeddingBag2d(PytorchLayerTest): def _prepare_input(self, indicies_size, indicies_dtype, per_sample_weights): import numpy as np - indices = np.random.randint( - 0, 9, size=indicies_size).astype(indicies_dtype) + + indices = np.random.randint(0, 9, size=indicies_size).astype(indicies_dtype) weights = np.random.randn(10, 10).astype(np.float32) if per_sample_weights: - per_sample_weights = np.random.randn( - *indices.shape).astype(np.float32) + per_sample_weights = np.random.randn(*indices.shape).astype(np.float32) return (indices, weights, per_sample_weights) return (indices, weights) - def create_model(self, per_sample_weights): + def create_model(self, mode, per_sample_weights): import torch import torch.nn.functional as F class aten_embedding_bag(torch.nn.Module): - def __init__(self, per_sample_weights=False) -> None: + def __init__(self, mode=None, per_sample_weights=False) -> None: super().__init__() + self.mode = mode if per_sample_weights: self.forward = self.forward_per_sample_weights def forward(self, indicies, weight): - return F.embedding_bag(indicies, weight, mode="sum") + return F.embedding_bag(indicies, weight, mode=self.mode) def forward_per_sample_weights(self, indicies, weight, per_sample_wights): - return F.embedding_bag(indicies, weight, mode="sum", per_sample_weights=per_sample_wights) + return F.embedding_bag( + indicies, + weight, + mode=self.mode, + per_sample_weights=per_sample_wights, + ) ref_net = None - return aten_embedding_bag(per_sample_weights), ref_net, "aten::embedding_bag" + return ( + aten_embedding_bag(mode, per_sample_weights), + ref_net, + "aten::embedding_bag", + ) @pytest.mark.nightly @pytest.mark.precommit @pytest.mark.precommit_fx_backend @pytest.mark.parametrize("indicies_size", [[1, 1], [2, 5], [3, 10], [4, 7]]) @pytest.mark.parametrize("indicies_dtype", ["int", "int32"]) - @pytest.mark.parametrize("per_sample_weights", [True, False]) - @pytest.mark.xfail(condition=platform.system() == 'Darwin' and platform.machine() == 'arm64', - reason='Ticket - 122715') - def test_embedding_bag(self, ie_device, precision, ir_version, indicies_dtype, indicies_size, per_sample_weights): - self._test(*self.create_model(per_sample_weights), ie_device, precision, ir_version, - kwargs_to_prepare_input={"indicies_size": indicies_size, "indicies_dtype": indicies_dtype, "per_sample_weights": per_sample_weights}, - trace_model=True, dynamic_shapes=not per_sample_weights and ie_device != "GPU") + @pytest.mark.parametrize( + "mode, per_sample_weights", [("mean", False), ("sum", False), ("sum", True)] + ) + @pytest.mark.xfail( + condition=platform.system() == "Darwin" and platform.machine() == "arm64", + reason="Ticket - 122715", + ) + def test_embedding_bag( + self, + ie_device, + precision, + ir_version, + indicies_dtype, + indicies_size, + mode, + per_sample_weights, + ): + self._test( + *self.create_model(mode, per_sample_weights), + ie_device, + precision, + ir_version, + kwargs_to_prepare_input={ + "indicies_size": indicies_size, + "indicies_dtype": indicies_dtype, + "per_sample_weights": per_sample_weights, + }, + trace_model=True, + dynamic_shapes=not per_sample_weights and ie_device != "GPU" + ) + + +class TestEmbeddingBagPretrained(PytorchLayerTest): + def _prepare_input(self, indicies_size, indicies_dtype, per_sample_weights): + import numpy as np + + indices = np.random.randint(0, 9, size=indicies_size).astype(indicies_dtype) + if per_sample_weights: + per_sample_weights = np.random.randn(*indices.shape).astype(np.float32) + return (indices, per_sample_weights) + return (indices,) + + def create_model(self, mode, per_sample_weights): + import torch + import numpy as np + + class aten_embedding_bag(torch.nn.Module): + def __init__(self, mode=None, per_sample_weights=False) -> None: + super().__init__() + self.mode = mode + weights = torch.from_numpy(np.random.randn(10, 10).astype(np.float32)) + + self.embeddings = torch.nn.EmbeddingBag.from_pretrained( + weights, mode=mode + ) + if per_sample_weights: + self.forward = self.forward_per_sample_weights + + def forward(self, indicies): + return self.embeddings(indicies) + + def forward_per_sample_weights(self, indicies, per_sample_wights): + return ( + self.embeddings(indicies, per_sample_weights=per_sample_wights), + ) + + ref_net = None + + return ( + aten_embedding_bag(mode, per_sample_weights), + ref_net, + "aten::embedding_bag", + ) + + @pytest.mark.nightly + @pytest.mark.precommit + @pytest.mark.precommit_fx_backend + @pytest.mark.parametrize("indicies_size", [[1, 1], [2, 5], [3, 10], [4, 7]]) + @pytest.mark.parametrize("indicies_dtype", ["int", "int32"]) + @pytest.mark.parametrize( + "mode, per_sample_weights", [("mean", False), ("sum", False), ("sum", True)] + ) + @pytest.mark.xfail( + condition=platform.system() == "Darwin" and platform.machine() == "arm64", + reason="Ticket - 122715", + ) + def test_embedding_bag( + self, + ie_device, + precision, + ir_version, + indicies_dtype, + indicies_size, + mode, + per_sample_weights, + ): + self._test( + *self.create_model(mode, per_sample_weights), + ie_device, + precision, + ir_version, + kwargs_to_prepare_input={ + "indicies_size": indicies_size, + "indicies_dtype": indicies_dtype, + "per_sample_weights": per_sample_weights, + }, + trace_model=True, + dynamic_shapes=not per_sample_weights and ie_device != "GPU" + )