-
Notifications
You must be signed in to change notification settings - Fork 622
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
Add out-of-bounds-policy (including pad support) to Slice/Crop #2000
Conversation
!build |
CI MESSAGE: [1373423]: BUILD STARTED |
CI MESSAGE: [1373423]: BUILD FAILED |
e64a660
to
c217394
Compare
!build |
CI MESSAGE: [1373476]: BUILD STARTED |
CI MESSAGE: [1373476]: BUILD FAILED |
!build |
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>( |
There was a problem hiding this comment.
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> |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
using Impl = SliceBaseCpu<InputType, InputType, Dims>; | ||
if (!impl_) | ||
impl_ = std::make_unique<Impl>(); | ||
FillArgs(reinterpret_cast<Impl*>(impl_.get())->Args(), ws); |
There was a problem hiding this comment.
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)
!build |
CI MESSAGE: [1380987]: BUILD STARTED |
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]) |
There was a problem hiding this comment.
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 || |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- \"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. |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MixedWorkspace
??
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"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); |
There was a problem hiding this comment.
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);
There was a problem hiding this comment.
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>
} | ||
|
||
} // namespace detail | ||
template <> | ||
bool SliceBase<GPUBackend>::SetupImpl(std::vector<OutputDesc> &output_desc, |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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>
a98bd8a
to
7846d9c
Compare
Signed-off-by: Joaquin Anton <janton@nvidia.com>
!build |
CI MESSAGE: [1398972]: BUILD STARTED |
CI MESSAGE: [1398972]: BUILD FAILED |
Signed-off-by: Joaquin Anton <janton@nvidia.com>
!build |
CI MESSAGE: [1401940]: BUILD STARTED |
CI MESSAGE: [1401940]: BUILD PASSED |
Why we need this PR?
Pick one, remove the rest
What happened in this PR?
Fill relevant points, put NA otherwise. Replace anything inside []
Slice and Crop operators has two new arguments:
out_of_bounds_policy
andfill_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 paddingBug fix in Slice GPU kernel for the case where padding is needed, channel dimension is last last and there is no channel slicing
Slice and Crop operators (They share SliceBase implementation)
Bug fix correctness
Python tests logic
Python tests added
Operator schema documentation updated
JIRA TASK: [DALI-1409]