diff --git a/modules/dnn/src/layers/cumsum_layer.cpp b/modules/dnn/src/layers/cumsum_layer.cpp index 9c70f306d4..0104b2d568 100644 --- a/modules/dnn/src/layers/cumsum_layer.cpp +++ b/modules/dnn/src/layers/cumsum_layer.cpp @@ -47,73 +47,76 @@ public: inputs_arr.getMatVector(inputs); outputs_arr.getMatVector(outputs); - // Get x tensor. - const auto &src_mat = inputs[0]; - const auto *src_ptr = src_mat.ptr(); + // Get input tensor. + const auto& src_mat = inputs[0]; + const auto* src_ptr = src_mat.ptr(); - // Get axis. - const int axis = normalize_axis(axis_raw, src_mat.dims); + // Get target axis. + int axis = inputs.size() > 1 ? parseAxis(inputs[1]) : axis_raw; + axis = normalize_axis(axis, src_mat.dims); - // Get y tensor. - auto &dst_mat = outputs[0]; - src_mat.copyTo(dst_mat); - auto *dst_ptr = dst_mat.ptr(); + + // Get output tensor. + auto& dst_mat = outputs[0]; + auto* dst_ptr = dst_mat.ptr(); // Get flags. const auto exclusive = exclusive_raw == 1; const auto reverse = reverse_raw == 1; - // Get parameters to iterate outer dimension. + // Data with [dim_1, .. , dim_k-1, target_dim, dim_k+1, .. , dim_n] + // dimensions is represented here as [outer_dim, target_dim, inner_dim] const size_t outer_size = src_mat.total(0, axis); - const size_t outer_step_length = src_mat.total(axis); + const size_t target_size = src_mat.size[axis]; + const size_t inner_size = src_mat.total(axis + 1); + const size_t outer_step_length = target_size * inner_size; - // Get parameters to iterate inner dimension. - const size_t inner_size = src_mat.size[axis]; + // Calculating steps in target dimensions + const int target_start = reverse ? target_size - 1 : 0; + const int target_stop = reverse ? -1 : target_size; + const int target_delta = reverse ? -1 : 1; + const int target_step = target_delta * inner_size; - if (!inner_size) - return; + // If exclusive, the j-th output element would be the sum of the first (j-1) elements. + // Otherwise, it would be the sum of the first j elements. + const int exclusive_delta = exclusive ? target_step : 0; - const size_t inner_step_length = src_mat.total(axis + 1); - const int inner_step = (reverse ? -1 : 1) * inner_step_length; - const int inner_start = reverse ? inner_size - 1 : 0; - const int inner_stop = reverse ? -1 : inner_size; - const int inner_delta = reverse ? -1 : 1; - - // Get parameters to populate channels. - const size_t num_channels = src_mat.total(axis + 1); - - for (size_t outer_dim = 0; outer_dim < outer_size; outer_dim++) + for (size_t outer_idx = 0; outer_idx < outer_size; outer_idx++) { - const size_t outer_offset = outer_dim * outer_step_length; - size_t src_offset = outer_offset + inner_start * inner_step_length; + const size_t target_offset = outer_idx * outer_step_length; - // Populate first element of inner dimension. - for (size_t channel = 0; channel < num_channels; channel++) + // Handle first element of target dimension. + size_t first_inner_offset = target_offset + target_start * inner_size; + if (exclusive) + for (size_t inner_idx = 0; inner_idx < inner_size; inner_idx++) + dst_ptr[first_inner_offset + inner_idx] = 0.0f; + else + for (size_t inner_idx = 0; inner_idx < inner_size; inner_idx++) + dst_ptr[first_inner_offset + inner_idx] = src_ptr[first_inner_offset + inner_idx]; + + // Handle remaining elements of target dimension. + for (int target_idx = target_start + target_delta; target_idx != target_stop; target_idx += target_delta) { - if (exclusive) + const size_t inner_offset = target_offset + target_idx * inner_size; + + for (size_t inner_idx = 0; inner_idx < inner_size; inner_idx++) { - dst_ptr[src_offset + channel] = 0.0f; - } - else - { - dst_ptr[src_offset + channel] = src_ptr[src_offset + channel]; - src_offset += inner_step; + dst_ptr[inner_offset + inner_idx] = dst_ptr[inner_offset - target_step + inner_idx] + + src_ptr[inner_offset - exclusive_delta + inner_idx]; } } + } + } - // Populate remaining elements of inner dimension. - for (int inner_dim = inner_start + inner_delta; inner_dim != inner_stop; inner_dim += inner_delta) - { - const size_t dst_offset = outer_offset + inner_dim * inner_step_length; - - for (size_t channel = 0; channel < num_channels; channel++) - { - const size_t previous_dst_offset = dst_offset - inner_step; - dst_ptr[dst_offset + channel] = dst_ptr[previous_dst_offset + channel] + - src_ptr[src_offset + channel]; - src_offset += inner_step; - } - } + int parseAxis(const Mat& axis_mat) { + CV_CheckEQ(axis_mat.total(), 1u, "Axis tensor should contain single value"); + if (axis_mat.type() == CV_32SC1) + return axis_mat.at(0); + else + { + Mat axis_mat_int; + axis_mat.convertTo(axis_mat_int, CV_32SC1); + return axis_mat_int.at(0); } } diff --git a/modules/dnn/test/test_onnx_conformance_layer_filter__cuda_denylist.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_filter__cuda_denylist.inl.hpp index 4c05f10305..96778ef5d4 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_filter__cuda_denylist.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_filter__cuda_denylist.inl.hpp @@ -46,6 +46,13 @@ "test_conv_with_strides_and_asymmetric_padding", "test_conv_with_strides_no_padding", "test_conv_with_strides_padding", +"test_cumsum_1d", +"test_cumsum_1d_exclusive", +"test_cumsum_1d_reverse", +"test_cumsum_1d_reverse_exclusive", +"test_cumsum_2d_axis_0", +"test_cumsum_2d_axis_1", +"test_cumsum_2d_negative_axis", "test_div_bcast", "test_div_uint8", "test_dropout_default_ratio", diff --git a/modules/dnn/test/test_onnx_conformance_layer_filter__halide_denylist.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_filter__halide_denylist.inl.hpp index 4924aaf9da..da7170c695 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_filter__halide_denylist.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_filter__halide_denylist.inl.hpp @@ -45,6 +45,13 @@ "test_castlike_FLOAT_to_STRING_expanded", "test_castlike_STRING_to_FLOAT_expanded", "test_ceil", +"test_cumsum_1d", +"test_cumsum_1d_exclusive", +"test_cumsum_1d_reverse", +"test_cumsum_1d_reverse_exclusive", +"test_cumsum_2d_axis_0", +"test_cumsum_2d_axis_1", +"test_cumsum_2d_negative_axis", "test_concat_1d_axis_negative_1", "test_concat_3d_axis_1", "test_div", diff --git a/modules/dnn/test/test_onnx_conformance_layer_filter__vulkan_denylist.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_filter__vulkan_denylist.inl.hpp index 8156686428..6f8d7aef20 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_filter__vulkan_denylist.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_filter__vulkan_denylist.inl.hpp @@ -40,6 +40,13 @@ "test_cast_STRING_to_FLOAT", "test_castlike_FLOAT_to_STRING_expanded", "test_castlike_STRING_to_FLOAT_expanded", +"test_cumsum_1d", +"test_cumsum_1d_exclusive", +"test_cumsum_1d_reverse", +"test_cumsum_1d_reverse_exclusive", +"test_cumsum_2d_axis_0", +"test_cumsum_2d_axis_1", +"test_cumsum_2d_negative_axis", "test_concat_1d_axis_negative_1", "test_div_uint8", "test_flatten_axis0", diff --git a/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp b/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp index d9d3285b32..0556e63c37 100644 --- a/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp +++ b/modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp @@ -89,13 +89,6 @@ "test_convtranspose_pad", "test_convtranspose_pads", "test_convtranspose_with_kernel", -"test_cumsum_1d", -"test_cumsum_1d_exclusive", -"test_cumsum_1d_reverse", -"test_cumsum_1d_reverse_exclusive", -"test_cumsum_2d_axis_0", -"test_cumsum_2d_axis_1", -"test_cumsum_2d_negative_axis", "test_dequantizelinear", "test_dequantizelinear_axis", "test_det_2d",