Merge pull request #24353 from alexlyulkov:al/fixed-cumsum-layer

Fixed CumSum dnn layer #24353

Fixes #20110

The algorithm had several errors, so I rewrote it.
Also the layer didn't work with non constant axis tensor. Fixed it.
Enabled CumSum layer tests from ONNX conformance.
pull/24351/head
alexlyulkov 2 years ago committed by GitHub
parent 4e60392040
commit 9bd14d5417
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 103
      modules/dnn/src/layers/cumsum_layer.cpp
  2. 7
      modules/dnn/test/test_onnx_conformance_layer_filter__cuda_denylist.inl.hpp
  3. 7
      modules/dnn/test/test_onnx_conformance_layer_filter__halide_denylist.inl.hpp
  4. 7
      modules/dnn/test/test_onnx_conformance_layer_filter__vulkan_denylist.inl.hpp
  5. 7
      modules/dnn/test/test_onnx_conformance_layer_parser_denylist.inl.hpp

@ -47,76 +47,79 @@ 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<float>();
// Get input tensor.
const auto& src_mat = inputs[0];
const auto* src_ptr = src_mat.ptr<float>();
// 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<float>();
// Get output tensor.
auto& dst_mat = outputs[0];
auto* dst_ptr = dst_mat.ptr<float>();
// 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);
// Get parameters to iterate inner dimension.
const size_t inner_size = src_mat.size[axis];
if (!inner_size)
return;
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;
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;
// 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;
// Get parameters to populate channels.
const size_t num_channels = src_mat.total(axis + 1);
// 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;
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;
// Populate first element of inner dimension.
for (size_t channel = 0; channel < num_channels; channel++)
{
if (exclusive)
{
dst_ptr[src_offset + channel] = 0.0f;
}
else
{
dst_ptr[src_offset + channel] = src_ptr[src_offset + channel];
src_offset += inner_step;
}
}
// 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 target_offset = outer_idx * outer_step_length;
// 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)
{
const size_t dst_offset = outer_offset + inner_dim * inner_step_length;
const size_t inner_offset = target_offset + target_idx * inner_size;
for (size_t channel = 0; channel < num_channels; channel++)
for (size_t inner_idx = 0; inner_idx < inner_size; inner_idx++)
{
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;
dst_ptr[inner_offset + inner_idx] = dst_ptr[inner_offset - target_step + inner_idx] +
src_ptr[inner_offset - exclusive_delta + inner_idx];
}
}
}
}
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<int32_t>(0);
else
{
Mat axis_mat_int;
axis_mat.convertTo(axis_mat_int, CV_32SC1);
return axis_mat_int.at<int32_t>(0);
}
}
int axis_raw;
int exclusive_raw;
int reverse_raw;

@ -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",

@ -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",

@ -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",

@ -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",

Loading…
Cancel
Save