Skip to content

Commit 2e6a52b

Browse files
committed
Merge branch 'main' of github.com:pytorch/vision into disable-int-rbbox
2 parents a4b2534 + 080bf2f commit 2e6a52b

File tree

4 files changed

+35
-34
lines changed

4 files changed

+35
-34
lines changed

test/test_transforms_v2.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2238,7 +2238,7 @@ def _reference_rotate_bounding_boxes(self, bounding_boxes, *, angle, expand, cen
22382238
@pytest.mark.parametrize("expand", [False, True])
22392239
@pytest.mark.parametrize("center", _CORRECTNESS_AFFINE_KWARGS["center"])
22402240
def test_functional_bounding_boxes_correctness(self, format, angle, expand, center):
2241-
bounding_boxes = make_bounding_boxes(format=format, clamping_mode="none")
2241+
bounding_boxes = make_bounding_boxes(format=format, clamping_mode=None)
22422242

22432243
actual = F.rotate(bounding_boxes, angle=angle, expand=expand, center=center)
22442244
expected = self._reference_rotate_bounding_boxes(bounding_boxes, angle=angle, expand=expand, center=center)
@@ -2250,7 +2250,7 @@ def test_functional_bounding_boxes_correctness(self, format, angle, expand, cent
22502250
@pytest.mark.parametrize("center", _CORRECTNESS_AFFINE_KWARGS["center"])
22512251
@pytest.mark.parametrize("seed", list(range(5)))
22522252
def test_transform_bounding_boxes_correctness(self, format, expand, center, seed):
2253-
bounding_boxes = make_bounding_boxes(format=format, clamping_mode="none")
2253+
bounding_boxes = make_bounding_boxes(format=format, clamping_mode=None)
22542254

22552255
transform = transforms.RandomRotation(**self._CORRECTNESS_TRANSFORM_AFFINE_RANGES, expand=expand, center=center)
22562256

@@ -4441,7 +4441,7 @@ def test_functional_bounding_boxes_correctness(self, format):
44414441
# _reference_resized_crop_bounding_boxes we are fusing the crop and the
44424442
# resize operation, where none of the croppings happen - particularly,
44434443
# the intermediate one.
4444-
bounding_boxes = make_bounding_boxes(self.INPUT_SIZE, format=format, clamping_mode="none")
4444+
bounding_boxes = make_bounding_boxes(self.INPUT_SIZE, format=format, clamping_mode=None)
44454445

44464446
actual = F.resized_crop(bounding_boxes, **self.CROP_KWARGS, size=self.OUTPUT_SIZE)
44474447
expected = self._reference_resized_crop_bounding_boxes(
@@ -5526,7 +5526,7 @@ def test_correctness_image(self, mean, std, dtype, fn):
55265526

55275527
class TestClampBoundingBoxes:
55285528
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
5529-
@pytest.mark.parametrize("clamping_mode", ("hard", "none")) # TODOBB add soft
5529+
@pytest.mark.parametrize("clamping_mode", ("hard", None)) # TODOBB add soft
55305530
@pytest.mark.parametrize("dtype", [torch.int64, torch.float32])
55315531
@pytest.mark.parametrize("device", cpu_and_cuda())
55325532
def test_kernel(self, format, clamping_mode, dtype, device):
@@ -5542,7 +5542,7 @@ def test_kernel(self, format, clamping_mode, dtype, device):
55425542
)
55435543

55445544
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
5545-
@pytest.mark.parametrize("clamping_mode", ("hard", "none")) # TODOBB add soft
5545+
@pytest.mark.parametrize("clamping_mode", ("hard", None)) # TODOBB add soft
55465546
def test_functional(self, format, clamping_mode):
55475547
check_functional(F.clamp_bounding_boxes, make_bounding_boxes(format=format, clamping_mode=clamping_mode))
55485548

@@ -5552,7 +5552,7 @@ def test_errors(self):
55525552
format, canvas_size = input_tv_tensor.format, input_tv_tensor.canvas_size
55535553

55545554
for format_, canvas_size_, clamping_mode_ in itertools.product(
5555-
(format, None), (canvas_size, None), (input_tv_tensor.clamping_mode, None)
5555+
(format, None), (canvas_size, None), (input_tv_tensor.clamping_mode, "auto")
55565556
):
55575557
with pytest.raises(
55585558
ValueError,
@@ -5570,8 +5570,8 @@ def test_transform(self):
55705570
check_transform(transforms.ClampBoundingBoxes(), make_bounding_boxes())
55715571

55725572
@pytest.mark.parametrize("rotated", (True, False))
5573-
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", "none"))
5574-
@pytest.mark.parametrize("clamping_mode", ("hard", "none", None)) # TODOBB add soft here.
5573+
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", None))
5574+
@pytest.mark.parametrize("clamping_mode", ("hard", None, "auto")) # TODOBB add soft here.
55755575
@pytest.mark.parametrize("pass_pure_tensor", (True, False))
55765576
@pytest.mark.parametrize("fn", [F.clamp_bounding_boxes, transform_cls_to_functional(transforms.ClampBoundingBoxes)])
55775577
def test_clamping_mode(self, rotated, constructor_clamping_mode, clamping_mode, pass_pure_tensor, fn):
@@ -5580,15 +5580,15 @@ def test_clamping_mode(self, rotated, constructor_clamping_mode, clamping_mode,
55805580
# functional (or to the class) relies on the box's `.clamping_mode`
55815581
# attribute
55825582
# - That clamping happens when it should, and only when it should, i.e.
5583-
# when the clamping mode is not "none". It doesn't validate the
5584-
# nunmerical results, only that clamping happened. For that, we create
5583+
# when the clamping mode is not None. It doesn't validate the
5584+
# numerical results, only that clamping happened. For that, we create
55855585
# a large 100x100 box inside of a small 10x10 image.
55865586

55875587
if pass_pure_tensor and fn is not F.clamp_bounding_boxes:
55885588
# Only the functional supports pure tensors, not the class
55895589
return
5590-
if pass_pure_tensor and clamping_mode is None:
5591-
# cannot leave clamping_mode=None when passing pure tensor
5590+
if pass_pure_tensor and clamping_mode == "auto":
5591+
# cannot leave clamping_mode="auto" when passing pure tensor
55925592
return
55935593

55945594
if rotated:
@@ -5612,17 +5612,17 @@ def test_clamping_mode(self, rotated, constructor_clamping_mode, clamping_mode,
56125612
else:
56135613
out = fn(boxes, clamping_mode=clamping_mode)
56145614

5615-
clamping_mode_prevailing = constructor_clamping_mode if clamping_mode is None else clamping_mode
5616-
if clamping_mode_prevailing == "none":
5615+
clamping_mode_prevailing = constructor_clamping_mode if clamping_mode == "auto" else clamping_mode
5616+
if clamping_mode_prevailing is None:
56175617
assert_equal(boxes, out) # should be a pass-through
56185618
else:
56195619
assert_equal(out, expected_clamped_output)
56205620

56215621

56225622
class TestSetClampingMode:
56235623
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
5624-
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", "none")) # TODOBB add soft
5625-
@pytest.mark.parametrize("desired_clamping_mode", ("hard", "none")) # TODOBB add soft
5624+
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", None)) # TODOBB add soft
5625+
@pytest.mark.parametrize("desired_clamping_mode", ("hard", None)) # TODOBB add soft
56265626
def test_setter(self, format, constructor_clamping_mode, desired_clamping_mode):
56275627

56285628
in_boxes = make_bounding_boxes(format=format, clamping_mode=constructor_clamping_mode)
@@ -5632,7 +5632,7 @@ def test_setter(self, format, constructor_clamping_mode, desired_clamping_mode):
56325632
assert out_boxes.clamping_mode == desired_clamping_mode
56335633

56345634
@pytest.mark.parametrize("format", list(tv_tensors.BoundingBoxFormat))
5635-
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", "none")) # TODOBB add soft
5635+
@pytest.mark.parametrize("constructor_clamping_mode", ("hard", None)) # TODOBB add soft
56365636
def test_pipeline_no_leak(self, format, constructor_clamping_mode):
56375637
class AssertClampingMode(transforms.Transform):
56385638
def __init__(self, expected_clamping_mode):
@@ -5647,12 +5647,12 @@ def transform(self, inpt, _):
56475647

56485648
t = transforms.Compose(
56495649
[
5650-
transforms.SetClampingMode("none"),
5651-
AssertClampingMode("none"),
5650+
transforms.SetClampingMode(None),
5651+
AssertClampingMode(None),
56525652
transforms.SetClampingMode("hard"),
56535653
AssertClampingMode("hard"),
5654-
transforms.SetClampingMode("none"),
5655-
AssertClampingMode("none"),
5654+
transforms.SetClampingMode(None),
5655+
AssertClampingMode(None),
56565656
transforms.ClampBoundingBoxes("hard"),
56575657
]
56585658
)
@@ -5664,7 +5664,7 @@ def transform(self, inpt, _):
56645664

56655665
# assert that the output boxes clamping_mode is the one set by the last SetClampingMode.
56665666
# ClampBoundingBoxes doesn't set clamping_mode.
5667-
assert out_boxes.clamping_mode == "none"
5667+
assert out_boxes.clamping_mode is None
56685668

56695669

56705670
class TestClampKeyPoints:

torchvision/transforms/v2/_meta.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Optional, Union
1+
from typing import Any, Union
22

33
from torchvision import tv_tensors
44
from torchvision.transforms.v2 import functional as F, Transform
@@ -34,7 +34,9 @@ class ClampBoundingBoxes(Transform):
3434
3535
"""
3636

37-
def __init__(self, clamping_mode: Optional[CLAMPING_MODE_TYPE] = None) -> None:
37+
# TODOBB consider "auto" to be a Literal, make sur torchscript is still happy
38+
# TODOBB validate clamping_mode
39+
def __init__(self, clamping_mode: Union[CLAMPING_MODE_TYPE, str] = "auto") -> None:
3840
super().__init__()
3941
self.clamping_mode = clamping_mode
4042

torchvision/transforms/v2/functional/_meta.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional
1+
from typing import Optional, Union
22

33
import PIL.Image
44
import torch
@@ -376,7 +376,7 @@ def _clamp_bounding_boxes(
376376
canvas_size: tuple[int, int],
377377
clamping_mode: CLAMPING_MODE_TYPE,
378378
) -> torch.Tensor:
379-
if clamping_mode is not None and clamping_mode == "none":
379+
if clamping_mode is None:
380380
return bounding_boxes.clone()
381381
# TODO: Investigate if it makes sense from a performance perspective to have an implementation for every
382382
# BoundingBoxFormat instead of converting back and forth
@@ -479,7 +479,7 @@ def _clamp_y_intercept(
479479
b1 = b2.clamp(b1, b3).clamp(0, canvas_size[0])
480480
b4 = b3.clamp(b2, b4).clamp(0, canvas_size[0])
481481

482-
if clamping_mode == "hard":
482+
if clamping_mode is not None and clamping_mode == "hard":
483483
# Hard clamping: Average b1 and b4, and adjust b2 and b3 for maximum area
484484
b1 = b4 = (b1 + b4) / 2
485485

@@ -595,7 +595,7 @@ def _clamp_rotated_bounding_boxes(
595595
Returns:
596596
torch.Tensor: Clamped bounding boxes in the original format and shape
597597
"""
598-
if clamping_mode is not None and clamping_mode == "none":
598+
if clamping_mode is None:
599599
return bounding_boxes.clone()
600600
original_shape = bounding_boxes.shape
601601
bounding_boxes = bounding_boxes.clone()
@@ -634,15 +634,15 @@ def clamp_bounding_boxes(
634634
inpt: torch.Tensor,
635635
format: Optional[BoundingBoxFormat] = None,
636636
canvas_size: Optional[tuple[int, int]] = None,
637-
clamping_mode: Optional[CLAMPING_MODE_TYPE] = None,
637+
clamping_mode: Union[CLAMPING_MODE_TYPE, str] = "auto",
638638
) -> torch.Tensor:
639639
"""See :func:`~torchvision.transforms.v2.ClampBoundingBoxes` for details."""
640640
if not torch.jit.is_scripting():
641641
_log_api_usage_once(clamp_bounding_boxes)
642642

643643
if torch.jit.is_scripting() or is_pure_tensor(inpt):
644644

645-
if format is None or canvas_size is None or clamping_mode is None:
645+
if format is None or canvas_size is None or (clamping_mode is not None and clamping_mode == "auto"):
646646
raise ValueError("For pure tensor inputs, `format`, `canvas_size` and `clamping_mode` have to be passed.")
647647
if tv_tensors.is_rotated_bounding_format(format):
648648
return _clamp_rotated_bounding_boxes(
@@ -653,7 +653,7 @@ def clamp_bounding_boxes(
653653
elif isinstance(inpt, tv_tensors.BoundingBoxes):
654654
if format is not None or canvas_size is not None:
655655
raise ValueError("For bounding box tv_tensor inputs, `format` and `canvas_size` must not be passed.")
656-
if clamping_mode is None:
656+
if clamping_mode is not None and clamping_mode == "auto":
657657
clamping_mode = inpt.clamping_mode
658658
if tv_tensors.is_rotated_bounding_format(inpt.format):
659659
output = _clamp_rotated_bounding_boxes(

torchvision/tv_tensors/_bounding_boxes.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from collections.abc import Mapping, Sequence
44

55
from enum import Enum
6-
from typing import Any
6+
from typing import Any, Optional
77

88
import torch
99
from torch.utils._pytree import tree_flatten
@@ -48,8 +48,7 @@ def is_rotated_bounding_format(format: BoundingBoxFormat) -> bool:
4848

4949
# TODOBB consider making this a Literal instead. Tried briefly and got
5050
# torchscript errors, leaving to str for now.
51-
# CLAMPING_MODE_TYPE = Literal["hard", "soft", "none"]
52-
CLAMPING_MODE_TYPE = str
51+
CLAMPING_MODE_TYPE = Optional[str]
5352

5453
# TODOBB All docs. Add any new API to rst files, add tutorial[s].
5554

0 commit comments

Comments
 (0)