diff --git a/src/common/transformations/include/transformations/op_conversions/convert_reduce_to_pooling.hpp b/src/common/transformations/include/transformations/op_conversions/convert_reduce_to_pooling.hpp index b74a0ff538e011..662660b926aa52 100644 --- a/src/common/transformations/include/transformations/op_conversions/convert_reduce_to_pooling.hpp +++ b/src/common/transformations/include/transformations/op_conversions/convert_reduce_to_pooling.hpp @@ -72,7 +72,7 @@ ov::matcher_pass_callback ConvertReduceBase::convert_reduce_to_pooling() { return [&](ov::pass::pattern::Matcher& m) { auto reduce = std::dynamic_pointer_cast(m.get_match_root()); - if (!reduce || transformation_callback(reduce)) { + if (!reduce || transformation_callback(reduce) || ov::shape_size(reduce->input_value(0).get_shape()) == 0) { return false; } diff --git a/src/core/reference/include/openvino/reference/reduce_mean.hpp b/src/core/reference/include/openvino/reference/reduce_mean.hpp index 4c46d4ca786d09..f046f4f96197bb 100644 --- a/src/core/reference/include/openvino/reference/reduce_mean.hpp +++ b/src/core/reference/include/openvino/reference/reduce_mean.hpp @@ -26,6 +26,10 @@ void reduce_mean(const T* in, T* out, const Shape& in_shape, const AxisSet& redu reduce_sum(in, out, in_shape, reduction_axes); const auto out_shape = util::reduce(in_shape, reduction_axes); + if (shape_size(in_shape) == 0) { + return; + } + const auto out_size = shape_size(out_shape); const auto count = static_cast(shape_size(in_shape) / out_size); std::transform(out, std::next(out, out_size), out, [count](const T value) { diff --git a/src/plugins/intel_cpu/src/nodes/reduce.cpp b/src/plugins/intel_cpu/src/nodes/reduce.cpp index 6cfc94a02b9f3b..6882327bbf0275 100644 --- a/src/plugins/intel_cpu/src/nodes/reduce.cpp +++ b/src/plugins/intel_cpu/src/nodes/reduce.cpp @@ -2089,7 +2089,7 @@ void Reduce::initSupportedPrimitiveDescriptors() { } bool Reduce::isExecutable() const { - return !isInputTensorAtPortEmpty(REDUCE_DATA); + return !isOutputTensorAtPortEmpty(0); } void Reduce::prepareParams() { @@ -2274,6 +2274,18 @@ void Reduce::execute(dnnl::stream strm) { const uint8_t *src_data = srcMemPtr->getDataAs(); uint8_t *dst_data = dstMemPtr->getDataAs(); + const auto& src_shape = srcMemPtr->getStaticDims(); + if ((shape_size(src_shape) == 0 || srcMemPtr->getSize() == 0)) { + if (dstMemPtr->getSize() > 0) { + init_dst_data(dst_data, dstMemPtr->getSize()); + const bool skip_post_process = getAlgorithm() == Algorithm::ReduceMean || attr.get()->post_ops_.len() == 0; + if (!skip_post_process) { + reduce_kernel_post_process(dst_data); + } + } + return; + } + if (jit_mode) { if (is_hybrid_layout) { dst_data = reinterpret_cast(prc_mem.get_data_handle()); diff --git a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/arm/reduce.cpp b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/arm/reduce.cpp index 6d1aa855c31865..313465eeb20a3e 100644 --- a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/arm/reduce.cpp +++ b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/arm/reduce.cpp @@ -18,6 +18,8 @@ namespace { std::vector> inputShapes_5D = { {{{}, {{2, 19, 2, 2, 9}}}}, + {{{}, {{0, 19, 2, 2, 9}}}}, + {{{}, {{1, 0, 0, 2, 9}}}}, }; const std::vector> axes5D = { diff --git a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/common/reduce.cpp b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/common/reduce.cpp index f962c20e1566f5..daada1ce839f91 100644 --- a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/common/reduce.cpp +++ b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/common/reduce.cpp @@ -145,6 +145,7 @@ INSTANTIATE_TEST_SUITE_P( ReduceCPULayerTest::getTestCaseName ); + INSTANTIATE_TEST_SUITE_P( smoke_Reduce_Int32_CPU, ReduceCPULayerTest, diff --git a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/x64/reduce.cpp b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/x64/reduce.cpp index 302e47fd45aa84..c5381a871954be 100644 --- a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/x64/reduce.cpp +++ b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/instances/x64/reduce.cpp @@ -53,6 +53,12 @@ std::vector> inputShapes_SingleBatch_dyn = { {{{{1, 5}, 19, {1, 5}, {1, 10}}, {{1, 19, 2, 2}, {1, 19, 2, 9}}}}, }; +std::vector> inputShapes_Dynmic_ZeroDim = { + {{{-1, -1, -1, -1}, {{2, 0, 3, 9}}}}, + {{{2, 0, -1, -1}, {{2, 0, 3, 9}}}}, + {{{2, 0, -1, -1}, {{2, 0, 3, 0}}}} +}; + std::vector cpuParams_3D = { CPUSpecificParams({ncw}, {ncw}, {}, {}), }; @@ -699,7 +705,51 @@ INSTANTIATE_TEST_SUITE_P( ReduceCPULayerTest::getTestCaseName ); + +/* ================================ 2.3 Empty dims ================================ */ +const auto params_MultiAxis_4D_dynamic_with_zero = testing::Combine( + testing::Combine( + testing::ValuesIn(axesND()), + testing::Values(ov::test::utils::OpType::VECTOR), + testing::ValuesIn(keepDims()), + testing::ValuesIn(reductionTypes()), + testing::ValuesIn(inpOutPrc()), + testing::Values(ElementType::undefined), + testing::Values(ElementType::undefined), + testing::ValuesIn(inputShapes_Dynmic_ZeroDim)), + testing::Values(emptyCPUSpec), + testing::Values(emptyFusingSpec), + testing::ValuesIn(additionalConfig())); + +const auto params_MultiAxis_4D_dynamic_with_zero_fusing = testing::Combine( + testing::Combine( + testing::ValuesIn(axesNDFusing), + testing::Values(ov::test::utils::OpType::VECTOR), + testing::ValuesIn(keepDims()), + testing::ValuesIn(reductionTypes()), + testing::ValuesIn(inpOutPrc()), + testing::Values(ElementType::undefined), + testing::Values(ElementType::undefined), + testing::ValuesIn(inputShapes_Dynmic_ZeroDim)), + testing::Values(emptyCPUSpec), + testing::Values(fusingSwish), + testing::ValuesIn(additionalConfig())); + +INSTANTIATE_TEST_SUITE_P( + smoke_Reduce_MultiAxis_4D_dynamic_with_zero_CPU, + ReduceCPULayerTest, + params_MultiAxis_4D_dynamic_with_zero, + ReduceCPULayerTest::getTestCaseName +); + +INSTANTIATE_TEST_SUITE_P( + smoke_Reduce_MultiAxis_4D_dynamic_with_zero_fusing_CPU, + ReduceCPULayerTest, + params_MultiAxis_4D_dynamic_with_zero_fusing, + ReduceCPULayerTest::getTestCaseName +); + } // namespace } // namespace Reduce } // namespace test -} // namespace ov \ No newline at end of file +} // namespace ov diff --git a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/reduce_ops.cpp b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/reduce_ops.cpp index 297d973a796dd0..9b7ae687e9c81d 100644 --- a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/reduce_ops.cpp +++ b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/reduce_ops.cpp @@ -29,6 +29,12 @@ const std::vector> input_shapes = { std::vector{3, 5, 7, 9}, }; +const std::vector> input_shapes_0_dim = { + std::vector{2, 0, 4, 1}, + std::vector{8, 0, 4, 0}, + std::vector{0, 0, 0, 0}, +}; + const std::vector> input_shapes_one_axis = { std::vector{10, 20, 30, 40}, std::vector{3, 5, 7, 9}, @@ -167,6 +173,16 @@ const auto params_reduction_types = testing::Combine( testing::Values(ov::test::utils::DEVICE_CPU) ); +const auto params_empty_input = testing::Combine( + testing::ValuesIn(axes), + testing::Values(op_types[1]), + testing::ValuesIn(keep_dims), + testing::ValuesIn(reduction_types), + testing::Values(model_types[0]), + testing::ValuesIn(input_shapes_0_dim), + testing::Values(ov::test::utils::DEVICE_CPU) +); + const auto params_reduction_types_logical = testing::Combine( testing::Values(std::vector{0, 1, 3}), testing::Values(op_types[1]), @@ -250,6 +266,13 @@ INSTANTIATE_TEST_SUITE_P( ReduceOpsLayerTest::getTestCaseName ); +INSTANTIATE_TEST_SUITE_P( + smoke_Reduce_ReductionTypes_EmptyTensor, + ReduceOpsLayerTest, + params_empty_input, + ReduceOpsLayerTest::getTestCaseName +); + INSTANTIATE_TEST_SUITE_P( smoke_ReduceLogical_ReductionTypes, ReduceOpsLayerTest, diff --git a/src/plugins/template/tests/functional/op_reference/reduce_l1.cpp b/src/plugins/template/tests/functional/op_reference/reduce_l1.cpp index 6e0c2fe2aa24e0..e47295f247b35f 100644 --- a/src/plugins/template/tests/functional/op_reference/reduce_l1.cpp +++ b/src/plugins/template/tests/functional/op_reference/reduce_l1.cpp @@ -25,6 +25,28 @@ std::vector generateReductionParams(const bool keep_dims) { reference_tests::Tensor(reduce(Shape{3, 2, 2}, AxisSet{2}, keep_dims), element::Type(IN_ET), std::vector{3, 7, 11, 15, 19, 23}))}; + auto out_shape_from_empty = Shape{2, 1, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2}; + } + params.push_back( + ReductionParams(ReductionType::L1, + keep_dims, + std::vector{1, 2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{0, 0}))); + + out_shape_from_empty = Shape{2, 0, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2, 0}; + } + params.push_back( + ReductionParams(ReductionType::L1, + keep_dims, + std::vector{2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{0, 0}))); + return params; } diff --git a/src/plugins/template/tests/functional/op_reference/reduce_l2.cpp b/src/plugins/template/tests/functional/op_reference/reduce_l2.cpp index 565f89d58f7238..b5820f6970ae5b 100644 --- a/src/plugins/template/tests/functional/op_reference/reduce_l2.cpp +++ b/src/plugins/template/tests/functional/op_reference/reduce_l2.cpp @@ -29,6 +29,27 @@ std::vector generateReductionParams(const bool keep_dims) { reference_tests::Tensor(reduce(Shape{3, 2, 2}, AxisSet{2}, keep_dims), element::Type(IN_ET), std::vector{2.23606798, 5.0, 7.81024968, 10.63014581, 13.45362405, 16.2788206}))}; + auto out_shape_from_empty = Shape{2, 1, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2}; + } + params.push_back( + ReductionParams(ReductionType::L2, + keep_dims, + std::vector{1, 2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{0, 0}))); + + out_shape_from_empty = Shape{2, 0, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2, 0}; + } + params.push_back( + ReductionParams(ReductionType::L2, + keep_dims, + std::vector{2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{}))); return params; } @@ -45,6 +66,7 @@ std::vector generateReductionParams(const bool keep_dims) { reference_tests::Tensor(reduce(Shape{3, 2, 2}, AxisSet{2}, keep_dims), element::Type(IN_ET), std::vector{2, 5, 8, 11, 13, 16}))}; + return params; } diff --git a/src/plugins/template/tests/functional/op_reference/reduce_max.cpp b/src/plugins/template/tests/functional/op_reference/reduce_max.cpp index 0674595de4ec43..7ab89fc16d1900 100644 --- a/src/plugins/template/tests/functional/op_reference/reduce_max.cpp +++ b/src/plugins/template/tests/functional/op_reference/reduce_max.cpp @@ -79,6 +79,29 @@ std::vector generateReductionParams(const bool keep_dims) { reference_tests::Tensor(reduce(Shape{3, 3, 3}, AxisSet{0, 1, 2}, keep_dims), element::Type(IN_ET), std::vector{27}))}; + auto out_shape_from_empty = Shape{2, 1, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2}; + } + const auto default_val = std::numeric_limits::lowest(); + params.push_back(ReductionParams( + ReductionType::Max, + keep_dims, + std::vector{1, 2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{default_val, default_val}))); + + out_shape_from_empty = Shape{2, 0, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2, 0}; + } + params.push_back( + ReductionParams(ReductionType::Max, + keep_dims, + std::vector{2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{}))); + return params; } diff --git a/src/plugins/template/tests/functional/op_reference/reduce_mean.cpp b/src/plugins/template/tests/functional/op_reference/reduce_mean.cpp index def9d837b46df6..07159de9704a30 100644 --- a/src/plugins/template/tests/functional/op_reference/reduce_mean.cpp +++ b/src/plugins/template/tests/functional/op_reference/reduce_mean.cpp @@ -41,6 +41,28 @@ std::vector generateReductionParams(const bool keep_dims) { reference_tests::Tensor(reduce(Shape{3, 2}, AxisSet{1}, keep_dims), element::Type(IN_ET), std::vector{1.5, 3.5, 5.5}))}; + auto out_shape_from_empty = Shape{2, 1, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2}; + } + params.push_back( + ReductionParams(ReductionType::Mean, + keep_dims, + std::vector{1, 2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{0, 0}))); + + out_shape_from_empty = Shape{2, 0, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2, 0}; + } + params.push_back( + ReductionParams(ReductionType::Mean, + keep_dims, + std::vector{2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{}))); + return params; } diff --git a/src/plugins/template/tests/functional/op_reference/reduce_min.cpp b/src/plugins/template/tests/functional/op_reference/reduce_min.cpp index abc9dca157684b..f982af07ab12a5 100644 --- a/src/plugins/template/tests/functional/op_reference/reduce_min.cpp +++ b/src/plugins/template/tests/functional/op_reference/reduce_min.cpp @@ -79,6 +79,29 @@ std::vector generateReductionParams(const bool keep_dims) { reference_tests::Tensor(reduce(Shape{3, 3, 3}, AxisSet{0, 1, 2}, keep_dims), element::Type(IN_ET), std::vector{1}))}; + auto out_shape_from_empty = Shape{2, 1, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2}; + } + constexpr auto max_value = + std::numeric_limits::has_infinity ? std::numeric_limits::infinity() : std::numeric_limits::max(); + params.push_back(ReductionParams( + ReductionType::Min, + keep_dims, + std::vector{1, 2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{max_value, max_value}))); + + out_shape_from_empty = Shape{2, 0, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2, 0}; + } + params.push_back( + ReductionParams(ReductionType::Min, + keep_dims, + std::vector{2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{}))); return params; } diff --git a/src/plugins/template/tests/functional/op_reference/reduce_prod.cpp b/src/plugins/template/tests/functional/op_reference/reduce_prod.cpp index d030633932fd73..54e39dad68826f 100644 --- a/src/plugins/template/tests/functional/op_reference/reduce_prod.cpp +++ b/src/plugins/template/tests/functional/op_reference/reduce_prod.cpp @@ -74,6 +74,28 @@ std::vector generateReductionParams(const bool keep_dims) { 19 * 20 * 21, 22 * 23 * 24, 25 * 26 * 27}))}; + auto out_shape_from_empty = Shape{2, 1, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2}; + } + const T default_val = T{1}; + params.push_back(ReductionParams( + ReductionType::Prod, + keep_dims, + std::vector{1, 2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{default_val, default_val}))); + + out_shape_from_empty = Shape{2, 0, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2, 0}; + } + params.push_back( + ReductionParams(ReductionType::Prod, + keep_dims, + std::vector{2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{}))); return params; } diff --git a/src/plugins/template/tests/functional/op_reference/reduce_sum.cpp b/src/plugins/template/tests/functional/op_reference/reduce_sum.cpp index ab77acc3cf696a..dd8dcd38635c79 100644 --- a/src/plugins/template/tests/functional/op_reference/reduce_sum.cpp +++ b/src/plugins/template/tests/functional/op_reference/reduce_sum.cpp @@ -121,6 +121,28 @@ std::vector generateReductionParams(const bool keep_dims) { reference_tests::Tensor(reduce(Shape{3, 3, 3, 3, 3}, AxisSet{0, 1, 2, 3, 4}, keep_dims), element::Type(IN_ET), std::vector{243}))}; + auto out_shape_from_empty = Shape{2, 1, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2}; + } + params.push_back( + ReductionParams(ReductionType::Sum, + keep_dims, + std::vector{1, 2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{0, 0}))); + + out_shape_from_empty = Shape{2, 0, 1}; + if (keep_dims == false) { + out_shape_from_empty = Shape{2, 0}; + } + params.push_back( + ReductionParams(ReductionType::Sum, + keep_dims, + std::vector{2}, + reference_tests::Tensor({2, 0, 4}, element::Type(IN_ET), std::vector{}), + reference_tests::Tensor(out_shape_from_empty, element::Type(IN_ET), std::vector{}))); + return params; }