Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add out-of-bounds-policy (including pad support) to Slice/Crop #2000

Merged
merged 16 commits into from
Jun 17, 2020

Conversation

jantonguirao
Copy link
Contributor

@jantonguirao jantonguirao commented Jun 5, 2020

Why we need this PR?

Pick one, remove the rest

  • It adds new feature needed to allow cropping windows that are larger than the input shape, or are anchored outside of bounds

What happened in this PR?

Fill relevant points, put NA otherwise. Replace anything inside []

  • What solution was applied:
    Slice and Crop operators has two new arguments: out_of_bounds_policy and fill_values. Out of bounds policy determines how the operator should behave when attempting to slice outside of the input region. Valid arguments are "error" (not allowed), "pad" (the output will be padded), "trim_to_shape" the output will be resized to fit the input bounds. If "pad" is provided, fill_values will determine the value (or values) to use when padding
    Bug fix in Slice GPU kernel for the case where padding is needed, channel dimension is last last and there is no channel slicing
  • Affected modules and functionalities:
    Slice and Crop operators (They share SliceBase implementation)
  • Key points relevant for the review:
    Bug fix correctness
    Python tests logic
  • Validation and testing:
    Python tests added
  • Documentation (including examples):
    Operator schema documentation updated

JIRA TASK: [DALI-1409]

@jantonguirao
Copy link
Contributor Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1373423]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1373423]: BUILD FAILED

@jantonguirao
Copy link
Contributor Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1373476]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1373476]: BUILD FAILED

@jantonguirao
Copy link
Contributor Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1378365]: BUILD STARTED

SliceFunc<NextDims, OutputType, InputType, false>(out, in, out_strides, in_strides, anchor,
in_shape, fill_values, channel_dim, offset,
block_end);
SliceFunc<NextDims, OutputType, InputType, false>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The changes in this file are a bug fix

@@ -242,6 +242,22 @@ struct ArgsGen_CompletelyOutOfBounds{
}
};

template <typename OutputType, int Dims = 3>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

New test case to cover the bug fix

} else {
DALI_FAIL("not supported number of dimensions (" +
std::to_string(input_shape.size()) + ")");
auto crop_shape = input_shape;
Copy link
Contributor Author

@jantonguirao jantonguirao Jun 9, 2020

Choose a reason for hiding this comment

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

Simplified and unified to one place the logic of CropAttr

@jantonguirao jantonguirao changed the title [WIP][DO NOT REVIEW] Add support for pad in Slice/Crop Add out-of-bounds-policy (including pad support) to Slice/Crop Jun 9, 2020
using Impl = SliceBaseCpu<InputType, InputType, Dims>;
if (!impl_)
impl_ = std::make_unique<Impl>();
FillArgs(reinterpret_cast<Impl*>(impl_.get())->Args(), ws);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

A little ugly but IMO better than duplicating the logic to FillArgs (which has nothing to do with CPU/GPU)

@jantonguirao jantonguirao requested a review from a team June 9, 2020 10:01
@jantonguirao
Copy link
Contributor Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1380987]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1380987]: BUILD FAILED

for (int d = 0; d < input_shape.size(); d++) {
if (slice_anchor[d] < 0)
slice_anchor[d] = 0;
if (slice_anchor[d] + slice_shape[d] >= input_shape[d])
Copy link
Contributor

Choose a reason for hiding this comment

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

What if slice_anchor is bigger than the input_shape?

default:
for (int d = 0; d < input_shape.size(); d++) {
auto slice_end = slice_anchor[d] + slice_shape[d];
if (slice_anchor[d] < 0 || slice_anchor[d] > input_shape[d] || slice_end < 0 ||
Copy link
Contributor

Choose a reason for hiding this comment

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

slice_anchor[d] > input_shape[d] make sense only when slice_shape == 0, otherwise it should be covered by slice_end > input_shape[d]).
I would test for slice_shape separately no matter what policy is used.

Supported values are:
- \"error\" (default) : Attempting to slice outside of the bounds of the image will produce an error.
- \"pad\": The input will be padded as needed with zeros or any other value specified with ``fill_values`` argument.
- \"trim_to_shape\": The slice window will be resized so that it stays within the bounds of the input.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- \"trim_to_shape\": The slice window will be resized so that it stays within the bounds of the input.
- \"trim_to_shape\": The slice window will be cut to the bounds of the input.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@@ -58,15 +72,15 @@ class SliceAttr {
}
}

void ProcessArguments(DeviceWorkspace &ws) {

void ProcessArguments(const MixedWorkspace &ws) {
Copy link
Contributor

Choose a reason for hiding this comment

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

MixedWorkspace ??

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, remember this is used by ImageDecoderSlice as well

Copy link
Contributor

Choose a reason for hiding this comment

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

But DeviceWorkspace variant is gone. Is it intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's in line 50.

@@ -1,4 +1,4 @@
// Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
// Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
// Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.

int w_dim = shape_layout.find('W');

DALI_ENFORCE(h_dim >= 0 && w_dim >= 0,
"Height and Width must be present in the layout. Got: " + shape_layout.str());
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"Height and Width must be present in the layout. Got: " + shape_layout.str());
"[H]eight and [W]idth must be present in the layout. Got: " + shape_layout.str());

template <typename OutputType, int Dims>
void FillArgs(std::vector<kernels::SliceArgs<OutputType, Dims>>& slice_args,
const workspace_t<Backend> &ws) {
this->DataDependentSetup(ws);
Copy link
Contributor

Choose a reason for hiding this comment

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

I might be nitpicky, but this will be more general comment to the code structure in the FillArgs function.

The DataDependentSetup does some magic, but in fact it just obtains the cropping information from the arguments (passed in a crop or slice way). Maybe more direct call to Slice/Crop attr here would be clearer, or some other name that highlights that fact.

Shouldn't the fill_values be validated once against the number of channels, preferably by OutOfBoundsAttrs?

This fills a little bit boilerplatey, without the channel business and by adding a function to convert from CropWindow to SliceChannels it would be compacted to basically:

this->ProcessCroppingAttrs(ws);
for (samples_idx : samples) {
  auto crop_win_gen = this->GetCropWindowGenerator(i);
  CropWindow win = crop_win_gen(in_shape[i], in_layout);
  ApplySliceBoundsPolicy(out_of_bounds_policy_, in_shape[i], win.anchor, win.shape);
  slice_args[i] = ToSliceArgs(win);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Basically, your ToSliceArgs would do what this FillArgs does, except for maybe the validation of fill_values that could happen somewhere else. That and the name change from DataDependentSetup to ProcessCroppingAttrs. Correct?

Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
}

} // namespace detail
template <>
bool SliceBase<GPUBackend>::SetupImpl(std::vector<OutputDesc> &output_desc,
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this the same as for CPU? (Same with RunImpl).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, pretty much, except for the usage of GPU and CPU kernel respective. I don't want to include both kernels in the same header

args.shape[1] = 2 * input_shape[1];
args.shape[2] = input_shape[2];
args.fill_values = {128};
args.channel_dim = -1;
Copy link
Contributor

Choose a reason for hiding this comment

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

From the description of the PR the bug was supposed to happen, when the channel dim is last, but there is no channel slicing. Doesn't this specify a no-channel variant with the -1?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, channel_dim=-1 means I don't care which dimension is channels. That is because we have a single pad value (128 in this case) so the channel dimension doesn't need special treatment

outs = pipe.run()

def test_slice_with_out_of_bounds_error():
in_shape = (40, 80, 3)
Copy link
Contributor

Choose a reason for hiding this comment

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

Could there be any reason to test slice with non-uniform batch?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Doesn't make much sense for this particular test case. Do you mean generally speaking?

Signed-off-by: Joaquin Anton <janton@nvidia.com>
Signed-off-by: Joaquin Anton <janton@nvidia.com>
@jantonguirao
Copy link
Contributor Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1398972]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1398972]: BUILD FAILED

Signed-off-by: Joaquin Anton <janton@nvidia.com>
@jantonguirao
Copy link
Contributor Author

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1401940]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1401940]: BUILD PASSED

@jantonguirao jantonguirao merged commit 1ab0238 into NVIDIA:master Jun 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants