Skip to content

dnn: support ONNX Slice with negative steps by adding and using cv::flipND#22898

Merged
asmorkalov merged 1 commit intoopencv:4.xfrom
fengyuentau:slice_neg_steps
Dec 23, 2022
Merged

dnn: support ONNX Slice with negative steps by adding and using cv::flipND#22898
asmorkalov merged 1 commit intoopencv:4.xfrom
fengyuentau:slice_neg_steps

Conversation

@fengyuentau
Copy link
Copy Markdown
Member

@fengyuentau fengyuentau commented Dec 1, 2022

Fixes #22794

Merge with opencv/opencv_extra#1023.

Current workaround for negative steps is computing the forward indexing range for slice and flip at axis with negative step:

x of shape [5, 10], x[5:0:-1, 10:1:-3] <=> np.flip(x[1:5:1, 2:10:3], aixs=(0, 1))

We can also extend Range to support backward indexing and steps like Python list, which needs more effort to do so I think.

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • The PR is proposed to the proper branch
  • There is a reference to the original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

@fengyuentau
Copy link
Copy Markdown
Member Author

@alalek I have added tests for both flipND and Slice with negative steps. Any test is missing here?

@alalek
Copy link
Copy Markdown
Member

alalek commented Dec 5, 2022

@fengyuentau Labels test and pr: needs test are different.

@fengyuentau
Copy link
Copy Markdown
Member Author

fengyuentau commented Dec 5, 2022 via email

Copy link
Copy Markdown
Member

@rogday rogday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution! I think in the future we should split this kind of PRs in two. One in core only, and another one to dnn.

Copy link
Copy Markdown
Member

@rogday rogday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! 👍

@asmorkalov
Copy link
Copy Markdown
Contributor

@alalek May we merge this patch?

}
else
{
flipNDImpl(src.ptr(), shape, step, dst.ptr(), axis);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dst step is not handled and not checked.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean I should check whether dst steps are the same with src steps?

Copy link
Copy Markdown
Member

@rogday rogday Dec 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, btw in case of ROI we could just overlap not from the beggining. @alalek do we have a method that checks if mats are non-overlapping?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps there is no such method.
We could do simple check overlap between .data / .dataend here (it is not fully accurate, e.g. for 1d cases)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just check if .datas are equal (if it's the start of the allocation, might be .datastart instead). It's not ideal for roi-to-roi in the same matrix without overlaps, but I'm not sure there is a platform-independent solution to check if memory regions overlap(without UB).

Copy link
Copy Markdown
Member Author

@fengyuentau fengyuentau Dec 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally speaking, we should check ROI overlaps but who would do that intentionally? Such operations do not make sense. Or if we are talking about unintentionally mis-operation, it is what it is as long as it does not trigger crashing.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally I agree, but in this case it doesn't cost us anything to change ptr() to datastart.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I re-implemented with dst in-place flip and also ensuring both src and dst are continuous. In this case, I suppose we can skip checking whether steps are equal, can't we?

Comment on lines +2265 to +2269
INSTANTIATE_TEST_CASE_P(Arithm, FlipND, testing::Combine(
testing::Values(std::vector<int>{5, 10}, std::vector<int>{2, 3, 4}),
testing::Values(perf::MatType(CV_8UC1), CV_32FC1)
));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ROI handing of src/dst/src+dst should be added.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand what ROI handling is here. Examples?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look on OCL_TEST_P(Transpose, Mat) test design (input data generation).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if I understand correctly, case of non continuous input mat should be tested. Correct me if I am wrong.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. ROI means region of interest - it is a sub-matrix from larger matrix.

However, for ND case this may be not really useful. In 2D case we have flip().
Anyway, we still need to provide checks for that (contiguous data assumption) in the source code of implementation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, we still need to provide checks for that (contiguous data assumption) in the source code of implementation.

I don't think the implementation assumes that data is contiguous.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still need checks for ROI handling since in the latest impl src and dst are assumed to be continuous?

Copy link
Copy Markdown
Member

@rogday rogday left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing major, looks good.

size_t offset = 0;
size_t offset_increment = axis == 0 ? 0 : step[axis - 1];
for (int i = 0; i < total; ++i, offset += offset_increment)
for (int j = 0, k = shape_at_axis - 1; j < (shape_at_axis + 1) / 2; ++j, --k)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't +1 redundant? In case of shape [A, 3, B]: (3+1)/2=2, but we need only 1 swap.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. +1 is removed in the latest commit.

int axis = (_axis + ndim) % ndim;

// return the src if it has only one element on the flip axis
if (shape[axis] == 1)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this special case, I think.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It serves like an early stop to improve efficiency, doesn't it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I don't know what we are winning here - one function frame that will do exactly this? I think copying is much slower than calling a function. @alalek can you elaborate?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think copying is much slower than calling a function

function itself is heavier than simple copying.


There is no problem with that part. Refer to convertTo() implementation.

CV_INSTRUMENT_REGION();

Mat src = _src.getMat();
CV_Assert(src.isContinuous());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we can lift that restriction.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so. I also lifted the restriction for dst since it will be covered by calling src.copyTo(dst) and be continuous in the end.

Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

core part looks good to merge 👍

@asmorkalov
Copy link
Copy Markdown
Contributor

@fengyuentau please squash commits before merge.

@fengyuentau
Copy link
Copy Markdown
Member Author

@asmorkalov Commits are squashed. Ready to be merged.

@asmorkalov asmorkalov merged commit 4930516 into opencv:4.x Dec 23, 2022
@alalek alalek mentioned this pull request Jan 8, 2023
@fengyuentau fengyuentau mentioned this pull request Mar 14, 2023
48 tasks
@fengyuentau fengyuentau deleted the slice_neg_steps branch June 15, 2023 02:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenCV cannot import ONNX model: step >= 1 in function 'cv::dnn::SliceLayerImpl::SliceLayerImpl'

4 participants