Skip to content

Commit 4ac707a

Browse files
authored
port tests for F.resized_crop and RandomResizedCrop (#7934)
1 parent 4103552 commit 4ac707a

File tree

6 files changed

+133
-220
lines changed

6 files changed

+133
-220
lines changed

test/test_transforms_v2.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -328,22 +328,6 @@ def test_auto_augment(self, transform, input):
328328
def test_normalize(self, transform, input):
329329
transform(input)
330330

331-
@parametrize(
332-
[
333-
(
334-
transforms.RandomResizedCrop([16, 16], antialias=True),
335-
itertools.chain(
336-
make_images(extra_dims=[(4,)]),
337-
make_vanilla_tensor_images(),
338-
make_pil_images(),
339-
make_videos(extra_dims=[()]),
340-
),
341-
)
342-
]
343-
)
344-
def test_random_resized_crop(self, transform, input):
345-
transform(input)
346-
347331

348332
@pytest.mark.parametrize(
349333
"flat_inputs",

test/test_transforms_v2_consistency.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -252,30 +252,6 @@ def __init__(
252252
# Use default tolerances of `torch.testing.assert_close`
253253
closeness_kwargs=dict(rtol=None, atol=None),
254254
),
255-
ConsistencyConfig(
256-
v2_transforms.RandomResizedCrop,
257-
legacy_transforms.RandomResizedCrop,
258-
[
259-
ArgsKwargs(16),
260-
ArgsKwargs(17, scale=(0.3, 0.7)),
261-
ArgsKwargs(25, ratio=(0.5, 1.5)),
262-
ArgsKwargs((31, 28), interpolation=v2_transforms.InterpolationMode.NEAREST),
263-
ArgsKwargs((31, 28), interpolation=PIL.Image.NEAREST),
264-
ArgsKwargs((29, 32), antialias=False),
265-
ArgsKwargs((28, 31), antialias=True),
266-
],
267-
# atol=1 due to Resize v2 is using native uint8 interpolate path for bilinear and nearest modes
268-
closeness_kwargs=dict(rtol=0, atol=1),
269-
),
270-
ConsistencyConfig(
271-
v2_transforms.RandomResizedCrop,
272-
legacy_transforms.RandomResizedCrop,
273-
[
274-
ArgsKwargs((33, 26), interpolation=v2_transforms.InterpolationMode.BICUBIC, antialias=True),
275-
ArgsKwargs((33, 26), interpolation=PIL.Image.BICUBIC, antialias=True),
276-
],
277-
closeness_kwargs=dict(rtol=0, atol=21),
278-
),
279255
ConsistencyConfig(
280256
v2_transforms.ColorJitter,
281257
legacy_transforms.ColorJitter,
@@ -535,7 +511,6 @@ def test_call_consistency(config, args_kwargs):
535511
id=transform_cls.__name__,
536512
)
537513
for transform_cls, get_params_args_kwargs in [
538-
(v2_transforms.RandomResizedCrop, ArgsKwargs(make_image(), scale=[0.3, 0.7], ratio=[0.5, 1.5])),
539514
(v2_transforms.ColorJitter, ArgsKwargs(brightness=None, contrast=None, saturation=None, hue=None)),
540515
(v2_transforms.GaussianBlur, ArgsKwargs(0.3, 1.4)),
541516
(v2_transforms.RandomPerspective, ArgsKwargs(23, 17, 0.5)),

test/test_transforms_v2_functional.py

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import inspect
2-
import math
32
import os
43
import re
54

@@ -526,88 +525,6 @@ def test_tv_tensor_explicit_metadata(self, metadata):
526525
# `transforms_v2_kernel_infos.py`
527526

528527

529-
def _compute_affine_matrix(angle_, translate_, scale_, shear_, center_):
530-
rot = math.radians(angle_)
531-
cx, cy = center_
532-
tx, ty = translate_
533-
sx, sy = [math.radians(sh_) for sh_ in shear_]
534-
535-
c_matrix = np.array([[1, 0, cx], [0, 1, cy], [0, 0, 1]])
536-
t_matrix = np.array([[1, 0, tx], [0, 1, ty], [0, 0, 1]])
537-
c_matrix_inv = np.linalg.inv(c_matrix)
538-
rs_matrix = np.array(
539-
[
540-
[scale_ * math.cos(rot), -scale_ * math.sin(rot), 0],
541-
[scale_ * math.sin(rot), scale_ * math.cos(rot), 0],
542-
[0, 0, 1],
543-
]
544-
)
545-
shear_x_matrix = np.array([[1, -math.tan(sx), 0], [0, 1, 0], [0, 0, 1]])
546-
shear_y_matrix = np.array([[1, 0, 0], [-math.tan(sy), 1, 0], [0, 0, 1]])
547-
rss_matrix = np.matmul(rs_matrix, np.matmul(shear_y_matrix, shear_x_matrix))
548-
true_matrix = np.matmul(t_matrix, np.matmul(c_matrix, np.matmul(rss_matrix, c_matrix_inv)))
549-
return true_matrix
550-
551-
552-
@pytest.mark.parametrize("device", cpu_and_cuda())
553-
def test_correctness_vertical_flip_segmentation_mask_on_fixed_input(device):
554-
mask = torch.zeros((3, 3, 3), dtype=torch.long, device=device)
555-
mask[:, 0, :] = 1
556-
557-
out_mask = F.vertical_flip_mask(mask)
558-
559-
expected_mask = torch.zeros((3, 3, 3), dtype=torch.long, device=device)
560-
expected_mask[:, -1, :] = 1
561-
torch.testing.assert_close(out_mask, expected_mask)
562-
563-
564-
@pytest.mark.parametrize("device", cpu_and_cuda())
565-
@pytest.mark.parametrize(
566-
"format",
567-
[tv_tensors.BoundingBoxFormat.XYXY, tv_tensors.BoundingBoxFormat.XYWH, tv_tensors.BoundingBoxFormat.CXCYWH],
568-
)
569-
@pytest.mark.parametrize(
570-
"top, left, height, width, size",
571-
[
572-
[0, 0, 30, 30, (60, 60)],
573-
[-5, 5, 35, 45, (32, 34)],
574-
],
575-
)
576-
def test_correctness_resized_crop_bounding_boxes(device, format, top, left, height, width, size):
577-
def _compute_expected_bbox(bbox, top_, left_, height_, width_, size_):
578-
# bbox should be xyxy
579-
bbox[0] = (bbox[0] - left_) * size_[1] / width_
580-
bbox[1] = (bbox[1] - top_) * size_[0] / height_
581-
bbox[2] = (bbox[2] - left_) * size_[1] / width_
582-
bbox[3] = (bbox[3] - top_) * size_[0] / height_
583-
return bbox
584-
585-
format = tv_tensors.BoundingBoxFormat.XYXY
586-
canvas_size = (100, 100)
587-
in_boxes = [
588-
[10.0, 10.0, 20.0, 20.0],
589-
[5.0, 10.0, 15.0, 20.0],
590-
]
591-
expected_bboxes = []
592-
for in_box in in_boxes:
593-
expected_bboxes.append(_compute_expected_bbox(list(in_box), top, left, height, width, size))
594-
expected_bboxes = torch.tensor(expected_bboxes, device=device)
595-
596-
in_boxes = tv_tensors.BoundingBoxes(
597-
in_boxes, format=tv_tensors.BoundingBoxFormat.XYXY, canvas_size=canvas_size, device=device
598-
)
599-
if format != tv_tensors.BoundingBoxFormat.XYXY:
600-
in_boxes = convert_bounding_box_format(in_boxes, tv_tensors.BoundingBoxFormat.XYXY, format)
601-
602-
output_boxes, output_canvas_size = F.resized_crop_bounding_boxes(in_boxes, format, top, left, height, width, size)
603-
604-
if format != tv_tensors.BoundingBoxFormat.XYXY:
605-
output_boxes = convert_bounding_box_format(output_boxes, format, tv_tensors.BoundingBoxFormat.XYXY)
606-
607-
torch.testing.assert_close(output_boxes, expected_bboxes)
608-
torch.testing.assert_close(output_canvas_size, size)
609-
610-
611528
def _parse_padding(padding):
612529
if isinstance(padding, int):
613530
return [padding] * 4

test/test_transforms_v2_refactored.py

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3110,3 +3110,136 @@ def test_errors(self):
31103110
F.convert_bounding_box_format(
31113111
input_tv_tensor, old_format=input_tv_tensor.format, new_format=input_tv_tensor.format
31123112
)
3113+
3114+
3115+
class TestResizedCrop:
3116+
INPUT_SIZE = (17, 11)
3117+
CROP_KWARGS = dict(top=2, left=2, height=5, width=7)
3118+
OUTPUT_SIZE = (19, 32)
3119+
3120+
@pytest.mark.parametrize(
3121+
("kernel", "make_input"),
3122+
[
3123+
(F.resized_crop_image, make_image),
3124+
(F.resized_crop_bounding_boxes, make_bounding_boxes),
3125+
(F.resized_crop_mask, make_segmentation_mask),
3126+
(F.resized_crop_mask, make_detection_mask),
3127+
(F.resized_crop_video, make_video),
3128+
],
3129+
)
3130+
def test_kernel(self, kernel, make_input):
3131+
input = make_input(self.INPUT_SIZE)
3132+
if isinstance(input, tv_tensors.BoundingBoxes):
3133+
extra_kwargs = dict(format=input.format)
3134+
elif isinstance(input, tv_tensors.Mask):
3135+
extra_kwargs = dict()
3136+
else:
3137+
extra_kwargs = dict(antialias=True)
3138+
3139+
check_kernel(kernel, input, **self.CROP_KWARGS, size=self.OUTPUT_SIZE, **extra_kwargs)
3140+
3141+
@pytest.mark.parametrize(
3142+
"make_input",
3143+
[make_image_tensor, make_image_pil, make_image, make_bounding_boxes, make_segmentation_mask, make_video],
3144+
)
3145+
def test_functional(self, make_input):
3146+
check_functional(
3147+
F.resized_crop, make_input(self.INPUT_SIZE), **self.CROP_KWARGS, size=self.OUTPUT_SIZE, antialias=True
3148+
)
3149+
3150+
@pytest.mark.parametrize(
3151+
("kernel", "input_type"),
3152+
[
3153+
(F.resized_crop_image, torch.Tensor),
3154+
(F._resized_crop_image_pil, PIL.Image.Image),
3155+
(F.resized_crop_image, tv_tensors.Image),
3156+
(F.resized_crop_bounding_boxes, tv_tensors.BoundingBoxes),
3157+
(F.resized_crop_mask, tv_tensors.Mask),
3158+
(F.resized_crop_video, tv_tensors.Video),
3159+
],
3160+
)
3161+
def test_functional_signature(self, kernel, input_type):
3162+
check_functional_kernel_signature_match(F.resized_crop, kernel=kernel, input_type=input_type)
3163+
3164+
@param_value_parametrization(
3165+
scale=[(0.1, 0.2), [0.0, 1.0]],
3166+
ratio=[(0.3, 0.7), [0.1, 5.0]],
3167+
)
3168+
@pytest.mark.parametrize(
3169+
"make_input",
3170+
[make_image_tensor, make_image_pil, make_image, make_bounding_boxes, make_segmentation_mask, make_video],
3171+
)
3172+
def test_transform(self, param, value, make_input):
3173+
check_transform(
3174+
transforms.RandomResizedCrop(size=self.OUTPUT_SIZE, **{param: value}, antialias=True),
3175+
make_input(self.INPUT_SIZE),
3176+
check_v1_compatibility=dict(rtol=0, atol=1),
3177+
)
3178+
3179+
# `InterpolationMode.NEAREST` is modeled after the buggy `INTER_NEAREST` interpolation of CV2.
3180+
# The PIL equivalent of `InterpolationMode.NEAREST` is `InterpolationMode.NEAREST_EXACT`
3181+
@pytest.mark.parametrize("interpolation", set(INTERPOLATION_MODES) - {transforms.InterpolationMode.NEAREST})
3182+
def test_functional_image_correctness(self, interpolation):
3183+
image = make_image(self.INPUT_SIZE, dtype=torch.uint8)
3184+
3185+
actual = F.resized_crop(
3186+
image, **self.CROP_KWARGS, size=self.OUTPUT_SIZE, interpolation=interpolation, antialias=True
3187+
)
3188+
expected = F.to_image(
3189+
F.resized_crop(
3190+
F.to_pil_image(image), **self.CROP_KWARGS, size=self.OUTPUT_SIZE, interpolation=interpolation
3191+
)
3192+
)
3193+
3194+
torch.testing.assert_close(actual, expected, atol=1, rtol=0)
3195+
3196+
def _reference_resized_crop_bounding_boxes(self, bounding_boxes, *, top, left, height, width, size):
3197+
new_height, new_width = size
3198+
3199+
crop_affine_matrix = np.array(
3200+
[
3201+
[1, 0, -left],
3202+
[0, 1, -top],
3203+
[0, 0, 1],
3204+
],
3205+
)
3206+
resize_affine_matrix = np.array(
3207+
[
3208+
[new_width / width, 0, 0],
3209+
[0, new_height / height, 0],
3210+
[0, 0, 1],
3211+
],
3212+
)
3213+
affine_matrix = (resize_affine_matrix @ crop_affine_matrix)[:2, :]
3214+
3215+
return reference_affine_bounding_boxes_helper(
3216+
bounding_boxes,
3217+
affine_matrix=affine_matrix,
3218+
new_canvas_size=size,
3219+
)
3220+
3221+
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
3222+
def test_functional_bounding_boxes_correctness(self, format):
3223+
bounding_boxes = make_bounding_boxes(self.INPUT_SIZE, format=format)
3224+
3225+
actual = F.resized_crop(bounding_boxes, **self.CROP_KWARGS, size=self.OUTPUT_SIZE)
3226+
expected = self._reference_resized_crop_bounding_boxes(
3227+
bounding_boxes, **self.CROP_KWARGS, size=self.OUTPUT_SIZE
3228+
)
3229+
3230+
assert_equal(actual, expected)
3231+
assert_equal(F.get_size(actual), F.get_size(expected))
3232+
3233+
def test_transform_errors_warnings(self):
3234+
with pytest.raises(ValueError, match="provide only two dimensions"):
3235+
transforms.RandomResizedCrop(size=(1, 2, 3))
3236+
3237+
with pytest.raises(TypeError, match="Scale should be a sequence"):
3238+
transforms.RandomResizedCrop(size=self.INPUT_SIZE, scale=123)
3239+
3240+
with pytest.raises(TypeError, match="Ratio should be a sequence"):
3241+
transforms.RandomResizedCrop(size=self.INPUT_SIZE, ratio=123)
3242+
3243+
for param in ["scale", "ratio"]:
3244+
with pytest.warns(match="Scale and ratio should be of kind"):
3245+
transforms.RandomResizedCrop(size=self.INPUT_SIZE, **{param: [1, 0]})

test/transforms_v2_dispatcher_infos.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,16 +111,6 @@ def xfail_jit_python_scalar_arg(name, *, reason=None):
111111

112112

113113
DISPATCHER_INFOS = [
114-
DispatcherInfo(
115-
F.resized_crop,
116-
kernels={
117-
tv_tensors.Image: F.resized_crop_image,
118-
tv_tensors.Video: F.resized_crop_video,
119-
tv_tensors.BoundingBoxes: F.resized_crop_bounding_boxes,
120-
tv_tensors.Mask: F.resized_crop_mask,
121-
},
122-
pil_kernel_info=PILKernelInfo(F._resized_crop_image_pil),
123-
),
124114
DispatcherInfo(
125115
F.pad,
126116
kernels={

0 commit comments

Comments
 (0)