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

port sample input smoke test #7962

Merged
merged 32 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
348231d
port tests for F.equalize and transforms.RandomEqualize
pmeier Sep 11, 2023
7882863
port tests for F.uniform_temporal_subsample and transforms.UniformTem…
pmeier Sep 11, 2023
9b5b7c4
port tests for F.normalize and transforms.Normalize
pmeier Sep 11, 2023
c69eb28
cleanup
pmeier Sep 11, 2023
0a6413a
port tests for F.clamp_bounding_boxes and transforms.ClampBoundingBoxes
pmeier Sep 11, 2023
227ca27
fix normalize tests
pmeier Sep 11, 2023
734d0b7
port tests for F.invert and transforms.RandomInvert
pmeier Sep 11, 2023
845ac36
add new tests for F.posterize and transforms.RandomPosterize
pmeier Sep 11, 2023
472ec15
add new tests for F.solarize and transforms.RandomSolarize
pmeier Sep 11, 2023
41cfdad
add new tests for F.autocontrast and transforms.RandomAutocontrast
pmeier Sep 11, 2023
40f21b2
add new tests for F.adjust_sharpness and transforms.RandomAdjustSharp…
pmeier Sep 11, 2023
635c2c4
add new tests for F.adjust_contrast
pmeier Sep 11, 2023
257d0f4
add new tests for F.adjust_gamma
pmeier Sep 11, 2023
c959590
add new tests for F.adjust_hue
pmeier Sep 11, 2023
8cd9fdf
add new tests for F.adjust_saturation
pmeier Sep 11, 2023
555d44a
cleanup
pmeier Sep 11, 2023
0683b1c
fix normalize
pmeier Sep 12, 2023
01992d3
add tests for five / ten crop
pmeier Sep 12, 2023
775e5ec
cleanup
pmeier Sep 13, 2023
7b1ef58
port sample input smoke test
pmeier Sep 14, 2023
af89f73
port tests forr LinearTransform
pmeier Sep 19, 2023
a0e3cee
Merge branch 'main' into transform-sample-test
pmeier Sep 26, 2023
888511d
Merge branch 'main' into transform-sample-test
pmeier Sep 26, 2023
7a48905
fix normalize and five / ten crop
pmeier Sep 28, 2023
5424bf3
put back degenerate box test
pmeier Sep 28, 2023
3f7f529
refactor and improve degenerate box check
pmeier Sep 28, 2023
1173704
Fix error message
NicolasHug Sep 28, 2023
151f195
Revert "Fix error message"
NicolasHug Sep 28, 2023
f694e65
Merge branch 'main' into transform-sample-test
pmeier Sep 28, 2023
59dca42
Merge branch 'transform-sample-test' of github.com:pmeier/vision into…
pmeier Sep 28, 2023
d2f21fd
address comments
pmeier Sep 28, 2023
99e5506
Merge branch 'main' into transform-sample-test
pmeier Sep 28, 2023
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
2 changes: 1 addition & 1 deletion test/common_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ def sample_position(values, max_value):
dtype = dtype or torch.float32

num_objects = 1
h, w = [torch.randint(1, c, (num_objects,)) for c in canvas_size]
h, w = [torch.randint(1, s, (num_objects,)) for s in canvas_size]
y = sample_position(h, canvas_size[0])
x = sample_position(w, canvas_size[1])

Expand Down
267 changes: 2 additions & 265 deletions test/test_transforms_v2.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import itertools
import pathlib
import pickle
import random

import numpy as np
Expand All @@ -11,22 +9,11 @@
import torchvision.transforms.v2 as transforms

from common_utils import assert_equal, cpu_and_cuda
from torch.utils._pytree import tree_flatten, tree_unflatten
from torchvision import tv_tensors
from torchvision.ops.boxes import box_iou
from torchvision.transforms.functional import to_pil_image
from torchvision.transforms.v2 import functional as F
from torchvision.transforms.v2._utils import check_type, is_pure_tensor, query_chw
from transforms_v2_legacy_utils import (
make_bounding_boxes,
make_detection_mask,
make_image,
make_images,
make_multiple_bounding_boxes,
make_segmentation_mask,
make_video,
make_videos,
)
from torchvision.transforms.v2._utils import is_pure_tensor
from transforms_v2_legacy_utils import make_bounding_boxes, make_detection_mask, make_image, make_images, make_videos


def make_vanilla_tensor_images(*args, **kwargs):
Expand All @@ -41,11 +28,6 @@ def make_pil_images(*args, **kwargs):
yield to_pil_image(image)


def make_vanilla_tensor_bounding_boxes(*args, **kwargs):
for bounding_boxes in make_multiple_bounding_boxes(*args, **kwargs):
yield bounding_boxes.data


def parametrize(transforms_with_inputs):
return pytest.mark.parametrize(
("transform", "input"),
Expand All @@ -61,218 +43,6 @@ def parametrize(transforms_with_inputs):
)


def auto_augment_adapter(transform, input, device):
adapted_input = {}
image_or_video_found = False
for key, value in input.items():
if isinstance(value, (tv_tensors.BoundingBoxes, tv_tensors.Mask)):
# AA transforms don't support bounding boxes or masks
continue
elif check_type(value, (tv_tensors.Image, tv_tensors.Video, is_pure_tensor, PIL.Image.Image)):
if image_or_video_found:
# AA transforms only support a single image or video
continue
image_or_video_found = True
adapted_input[key] = value
return adapted_input


def linear_transformation_adapter(transform, input, device):
flat_inputs = list(input.values())
c, h, w = query_chw(
[
item
for item, needs_transform in zip(flat_inputs, transforms.Transform()._needs_transform_list(flat_inputs))
if needs_transform
]
)
num_elements = c * h * w
transform.transformation_matrix = torch.randn((num_elements, num_elements), device=device)
transform.mean_vector = torch.randn((num_elements,), device=device)
return {key: value for key, value in input.items() if not isinstance(value, PIL.Image.Image)}


def normalize_adapter(transform, input, device):
adapted_input = {}
for key, value in input.items():
if isinstance(value, PIL.Image.Image):
# normalize doesn't support PIL images
continue
elif check_type(value, (tv_tensors.Image, tv_tensors.Video, is_pure_tensor)):
# normalize doesn't support integer images
value = F.to_dtype(value, torch.float32, scale=True)
adapted_input[key] = value
return adapted_input


class TestSmoke:
@pytest.mark.parametrize(
("transform", "adapter"),
[
(transforms.RandomErasing(p=1.0), None),
(transforms.AugMix(), auto_augment_adapter),
(transforms.AutoAugment(), auto_augment_adapter),
(transforms.RandAugment(), auto_augment_adapter),
(transforms.TrivialAugmentWide(), auto_augment_adapter),
(transforms.ColorJitter(brightness=0.1, contrast=0.2, saturation=0.3, hue=0.15), None),
(transforms.RandomAdjustSharpness(sharpness_factor=0.5, p=1.0), None),
(transforms.RandomAutocontrast(p=1.0), None),
(transforms.RandomEqualize(p=1.0), None),
(transforms.RandomInvert(p=1.0), None),
(transforms.RandomChannelPermutation(), None),
(transforms.RandomPosterize(bits=4, p=1.0), None),
(transforms.RandomSolarize(threshold=0.5, p=1.0), None),
(transforms.CenterCrop([16, 16]), None),
(transforms.ElasticTransform(sigma=1.0), None),
(transforms.Pad(4), None),
(transforms.RandomAffine(degrees=30.0), None),
(transforms.RandomCrop([16, 16], pad_if_needed=True), None),
(transforms.RandomHorizontalFlip(p=1.0), None),
(transforms.RandomPerspective(p=1.0), None),
(transforms.RandomResize(min_size=10, max_size=20, antialias=True), None),
(transforms.RandomResizedCrop([16, 16], antialias=True), None),
(transforms.RandomRotation(degrees=30), None),
(transforms.RandomShortestSize(min_size=10, antialias=True), None),
(transforms.RandomVerticalFlip(p=1.0), None),
(transforms.Resize([16, 16], antialias=True), None),
(transforms.ScaleJitter((16, 16), scale_range=(0.8, 1.2), antialias=True), None),
(transforms.ClampBoundingBoxes(), None),
(transforms.ConvertBoundingBoxFormat(tv_tensors.BoundingBoxFormat.CXCYWH), None),
(transforms.ConvertImageDtype(), None),
(transforms.GaussianBlur(kernel_size=3), None),
(
transforms.LinearTransformation(
# These are just dummy values that will be filled by the adapter. We can't define them upfront,
# because for we neither know the spatial size nor the device at this point
transformation_matrix=torch.empty((1, 1)),
mean_vector=torch.empty((1,)),
),
linear_transformation_adapter,
),
(transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), normalize_adapter),
(transforms.ToDtype(torch.float64), None),
(transforms.UniformTemporalSubsample(num_samples=2), None),
],
ids=lambda transform: type(transform).__name__,
)
@pytest.mark.parametrize("container_type", [dict, list, tuple])
@pytest.mark.parametrize(
"image_or_video",
[
make_image(),
make_video(),
next(make_pil_images(color_spaces=["RGB"])),
next(make_vanilla_tensor_images()),
],
)
@pytest.mark.parametrize("de_serialize", [lambda t: t, lambda t: pickle.loads(pickle.dumps(t))])
@pytest.mark.parametrize("device", cpu_and_cuda())
def test_common(self, transform, adapter, container_type, image_or_video, de_serialize, device):
transform = de_serialize(transform)

canvas_size = F.get_size(image_or_video)
input = dict(
image_or_video=image_or_video,
image_tv_tensor=make_image(size=canvas_size),
video_tv_tensor=make_video(size=canvas_size),
image_pil=next(make_pil_images(sizes=[canvas_size], color_spaces=["RGB"])),
bounding_boxes_xyxy=make_bounding_boxes(
format=tv_tensors.BoundingBoxFormat.XYXY, canvas_size=canvas_size, batch_dims=(3,)
),
bounding_boxes_xywh=make_bounding_boxes(
format=tv_tensors.BoundingBoxFormat.XYWH, canvas_size=canvas_size, batch_dims=(4,)
),
bounding_boxes_cxcywh=make_bounding_boxes(
format=tv_tensors.BoundingBoxFormat.CXCYWH, canvas_size=canvas_size, batch_dims=(5,)
),
bounding_boxes_degenerate_xyxy=tv_tensors.BoundingBoxes(
[
[0, 0, 0, 0], # no height or width
[0, 0, 0, 1], # no height
[0, 0, 1, 0], # no width
[2, 0, 1, 1], # x1 > x2, y1 < y2
[0, 2, 1, 1], # x1 < x2, y1 > y2
[2, 2, 1, 1], # x1 > x2, y1 > y2
],
format=tv_tensors.BoundingBoxFormat.XYXY,
canvas_size=canvas_size,
),
bounding_boxes_degenerate_xywh=tv_tensors.BoundingBoxes(
[
[0, 0, 0, 0], # no height or width
[0, 0, 0, 1], # no height
[0, 0, 1, 0], # no width
[0, 0, 1, -1], # negative height
[0, 0, -1, 1], # negative width
[0, 0, -1, -1], # negative height and width
],
format=tv_tensors.BoundingBoxFormat.XYWH,
canvas_size=canvas_size,
),
bounding_boxes_degenerate_cxcywh=tv_tensors.BoundingBoxes(
[
[0, 0, 0, 0], # no height or width
[0, 0, 0, 1], # no height
[0, 0, 1, 0], # no width
[0, 0, 1, -1], # negative height
[0, 0, -1, 1], # negative width
[0, 0, -1, -1], # negative height and width
],
format=tv_tensors.BoundingBoxFormat.CXCYWH,
canvas_size=canvas_size,
),
detection_mask=make_detection_mask(size=canvas_size),
segmentation_mask=make_segmentation_mask(size=canvas_size),
int=0,
float=0.0,
bool=True,
none=None,
str="str",
path=pathlib.Path.cwd(),
object=object(),
tensor=torch.empty(5),
array=np.empty(5),
)
if adapter is not None:
input = adapter(transform, input, device)

if container_type in {tuple, list}:
input = container_type(input.values())

input_flat, input_spec = tree_flatten(input)
input_flat = [item.to(device) if isinstance(item, torch.Tensor) else item for item in input_flat]
input = tree_unflatten(input_flat, input_spec)

torch.manual_seed(0)
output = transform(input)
output_flat, output_spec = tree_flatten(output)

assert output_spec == input_spec

for output_item, input_item, should_be_transformed in zip(
output_flat, input_flat, transforms.Transform()._needs_transform_list(input_flat)
):
if should_be_transformed:
assert type(output_item) is type(input_item)
else:
assert output_item is input_item

if isinstance(input_item, tv_tensors.BoundingBoxes) and not isinstance(
transform, transforms.ConvertBoundingBoxFormat
):
assert output_item.format == input_item.format

# Enforce that the transform does not turn a degenerate box marked by RandomIoUCrop (or any other future
# transform that does this), back into a valid one.
# TODO: we should test that against all degenerate boxes above
for format in list(tv_tensors.BoundingBoxFormat):
sample = dict(
boxes=tv_tensors.BoundingBoxes([[0, 0, 0, 0]], format=format, canvas_size=(224, 244)),
labels=torch.tensor([3]),
)
assert transforms.SanitizeBoundingBoxes()(sample)["boxes"].shape == (0, 4)


@pytest.mark.parametrize(
"flat_inputs",
itertools.permutations(
Expand Down Expand Up @@ -543,39 +313,6 @@ def test__get_params(self, min_size, max_size):
assert shorter in min_size


class TestLinearTransformation:
def test_assertions(self):
with pytest.raises(ValueError, match="transformation_matrix should be square"):
transforms.LinearTransformation(torch.rand(2, 3), torch.rand(5))

with pytest.raises(ValueError, match="mean_vector should have the same length"):
transforms.LinearTransformation(torch.rand(3, 3), torch.rand(5))

@pytest.mark.parametrize(
"inpt",
[
122 * torch.ones(1, 3, 8, 8),
122.0 * torch.ones(1, 3, 8, 8),
tv_tensors.Image(122 * torch.ones(1, 3, 8, 8)),
PIL.Image.new("RGB", (8, 8), (122, 122, 122)),
],
)
def test__transform(self, inpt):

v = 121 * torch.ones(3 * 8 * 8)
m = torch.ones(3 * 8 * 8, 3 * 8 * 8)
transform = transforms.LinearTransformation(m, v)

if isinstance(inpt, PIL.Image.Image):
with pytest.raises(TypeError, match="does not support PIL images"):
transform(inpt)
else:
output = transform(inpt)
assert isinstance(output, torch.Tensor)
assert output.unique() == 3 * 8 * 8
assert output.dtype == inpt.dtype


class TestRandomResize:
def test__get_params(self):
min_size = 3
Expand Down
22 changes: 0 additions & 22 deletions test/test_transforms_v2_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,28 +72,6 @@ def __init__(
LINEAR_TRANSFORMATION_MATRIX = torch.rand([LINEAR_TRANSFORMATION_MEAN.numel()] * 2)

CONSISTENCY_CONFIGS = [
*[
ConsistencyConfig(
v2_transforms.LinearTransformation,
legacy_transforms.LinearTransformation,
[
ArgsKwargs(LINEAR_TRANSFORMATION_MATRIX.to(matrix_dtype), LINEAR_TRANSFORMATION_MEAN.to(matrix_dtype)),
],
# Make sure that the product of the height, width and number of channels matches the number of elements in
# `LINEAR_TRANSFORMATION_MEAN`. For example 2 * 6 * 3 == 4 * 3 * 3 == 36.
make_images_kwargs=dict(
DEFAULT_MAKE_IMAGES_KWARGS, sizes=[(2, 6), (4, 3)], color_spaces=["RGB"], dtypes=[image_dtype]
),
supports_pil=False,
)
for matrix_dtype, image_dtype in [
(torch.float32, torch.float32),
(torch.float64, torch.float64),
(torch.float32, torch.uint8),
(torch.float64, torch.float32),
(torch.float32, torch.float64),
]
],
ConsistencyConfig(
v2_transforms.ToPILImage,
legacy_transforms.ToPILImage,
Expand Down
Loading
Loading