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

allow float fill for integer images in F.pad #7950

Merged
merged 3 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions test/test_transforms_v2_refactored.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,11 +312,12 @@ def adapt_fill(value, *, dtype):
return value

max_value = get_max_value(dtype)
value_type = float if dtype.is_floating_point else int
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If we adapt the fill value, we also want to adapt the type. I've checked and this does not hide the errors that we are fixing here.


if isinstance(value, (int, float)):
return type(value)(value * max_value)
return value_type(value * max_value)
elif isinstance(value, (list, tuple)):
return type(value)(type(v)(v * max_value) for v in value)
return type(value)(value_type(v * max_value) for v in value)
else:
raise ValueError(f"fill should be an int or float, or a list or tuple of the former, but got '{value}'.")

Expand Down Expand Up @@ -417,6 +418,10 @@ def affine_bounding_boxes(bounding_boxes):
)


# turns all warnings into errors for this module
pytestmark = pytest.mark.filterwarnings("error")
Comment on lines +421 to +422
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This makes sure, we never miss a warning coming from the transforms again.



class TestResize:
INPUT_SIZE = (17, 11)
OUTPUT_SIZES = [17, [17], (17,), [12, 13], (12, 13)]
Expand Down Expand Up @@ -2578,14 +2583,18 @@ def test_transform(self, param, value, make_input):
input = make_input(self.INPUT_SIZE)

kwargs = {param: value}
if param == "fill":
if param != "size":
# 1. size is required
# 2. the fill parameter only has an affect if we need padding
kwargs["size"] = [s + 4 for s in self.INPUT_SIZE]

if param == "fill":
if isinstance(input, tv_tensors.Mask) and isinstance(value, (tuple, list)):
pytest.skip("F.pad_mask doesn't support non-scalar fill.")

kwargs["fill"] = adapt_fill(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've missed to adapt the value here.

kwargs["fill"], dtype=input.dtype if isinstance(input, torch.Tensor) else torch.uint8
)

check_transform(
transforms.RandomCrop(**kwargs, pad_if_needed=True),
input,
Expand Down Expand Up @@ -3478,6 +3487,8 @@ def test_transform_errors(self):
def test_image_correctness(self, padding, padding_mode, fill, fn):
image = make_image(dtype=torch.uint8, device="cpu")

fill = adapt_fill(fill, dtype=torch.uint8)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Same as above


actual = fn(image, padding=padding, padding_mode=padding_mode, fill=fill)
expected = F.to_image(F.pad(F.to_pil_image(image), padding=padding, padding_mode=padding_mode, fill=fill))

Expand Down
6 changes: 5 additions & 1 deletion torchvision/transforms/v2/functional/_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -1235,7 +1235,11 @@ def _pad_with_vector_fill(

output = _pad_with_scalar_fill(image, torch_padding, fill=0, padding_mode="constant")
left, right, top, bottom = torch_padding
fill = torch.tensor(fill, dtype=image.dtype, device=image.device).reshape(-1, 1, 1)

# We are creating the tensor in the autodetected dtype first and convert to the right one after to avoid an implicit
# float -> int conversion. That happens for example for the valid input of a uint8 image with floating point fill
# value.
fill = torch.tensor(fill, device=image.device).to(dtype=image.dtype).reshape(-1, 1, 1)

if top > 0:
output[..., :top, :] = fill
Expand Down