Skip to content

Commit 42019eb

Browse files
committed
add docstring for explain scaling setup, combine correctness checks
1 parent 3e387fb commit 42019eb

File tree

2 files changed

+82
-67
lines changed

2 files changed

+82
-67
lines changed

test/test_transforms_v2.py

Lines changed: 61 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2712,21 +2712,74 @@ def fn(value):
27122712
@pytest.mark.parametrize("output_dtype", [torch.float32, torch.float64, torch.uint8, torch.uint16])
27132713
@pytest.mark.parametrize("device", cpu_and_cuda())
27142714
@pytest.mark.parametrize("scale", (True, False))
2715-
def test_image_correctness(self, input_dtype, output_dtype, device, scale):
2715+
@pytest.mark.parametrize(
2716+
"make_input",
2717+
[
2718+
make_image,
2719+
pytest.param(
2720+
make_image_cvcuda, marks=pytest.mark.skipif(not CVCUDA_AVAILABLE, reason="test requires CVCUDA")
2721+
),
2722+
],
2723+
)
2724+
def test_image_correctness(self, input_dtype, output_dtype, device, scale, make_input):
27162725
if input_dtype.is_floating_point and output_dtype == torch.int64:
27172726
pytest.xfail("float to int64 conversion is not supported")
27182727
if input_dtype == torch.uint8 and output_dtype == torch.uint16 and device == "cuda":
27192728
pytest.xfail("uint8 to uint16 conversion is not supported on cuda")
2729+
if input_dtype == torch.uint8 and output_dtype == torch.uint16 and scale and make_input == make_image_cvcuda:
2730+
pytest.xfail("uint8 to uint16 conversion with scale is not supported in F._misc._to_dtype_cvcuda")
27202731

2721-
input = make_image(dtype=input_dtype, device=device)
2722-
2732+
input = make_input(dtype=input_dtype, device=device)
27232733
out = F.to_dtype(input, dtype=output_dtype, scale=scale)
2724-
expected = self.reference_convert_dtype_image_tensor(input, dtype=output_dtype, scale=scale)
27252734

2726-
if input_dtype.is_floating_point and not output_dtype.is_floating_point and scale:
2727-
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2728-
else:
2729-
torch.testing.assert_close(out, expected)
2735+
if isinstance(input, torch.Tensor):
2736+
expected = self.reference_convert_dtype_image_tensor(input, dtype=output_dtype, scale=scale)
2737+
if input_dtype.is_floating_point and not output_dtype.is_floating_point and scale:
2738+
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2739+
else:
2740+
torch.testing.assert_close(out, expected)
2741+
else: # cvcuda.Tensor
2742+
expected = self.reference_convert_dtype_image_tensor(
2743+
F.cvcuda_to_tensor(input), dtype=output_dtype, scale=scale
2744+
)
2745+
out = F.cvcuda_to_tensor(out)
2746+
# there are some differences in dtype conversion between torchvision and cvcuda
2747+
# due to different rounding behavior when converting between types with different bit widths
2748+
# Check if we're converting to a type with more bits (without scaling)
2749+
in_bits = torch.iinfo(input_dtype).bits if not input_dtype.is_floating_point else None
2750+
out_bits = torch.iinfo(output_dtype).bits if not output_dtype.is_floating_point else None
2751+
2752+
if scale:
2753+
if input_dtype.is_floating_point and not output_dtype.is_floating_point:
2754+
# float -> int with scaling: allow for rounding differences
2755+
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2756+
elif input_dtype == torch.uint16 and output_dtype == torch.uint8:
2757+
# uint16 -> uint8 with scaling: allow large differences
2758+
torch.testing.assert_close(out, expected, atol=255, rtol=0)
2759+
else:
2760+
torch.testing.assert_close(out, expected)
2761+
else:
2762+
if in_bits is not None and out_bits is not None and out_bits > in_bits:
2763+
# uint to larger uint without scaling: allow large differences due to bit expansion
2764+
if input_dtype == torch.uint8 and output_dtype == torch.uint16:
2765+
torch.testing.assert_close(out, expected, atol=255, rtol=0)
2766+
else:
2767+
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2768+
elif not input_dtype.is_floating_point and not output_dtype.is_floating_point:
2769+
# uint to uint without scaling (same or smaller bits): allow for rounding
2770+
if input_dtype == torch.uint16 and output_dtype == torch.uint8:
2771+
# uint16 -> uint8 can have large differences due to bit reduction
2772+
torch.testing.assert_close(out, expected, atol=255, rtol=0)
2773+
else:
2774+
torch.testing.assert_close(out, expected)
2775+
elif input_dtype.is_floating_point and not output_dtype.is_floating_point:
2776+
# float -> uint without scaling: allow for rounding differences
2777+
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2778+
elif not input_dtype.is_floating_point and output_dtype.is_floating_point:
2779+
# uint -> float without scaling: allow for rounding differences
2780+
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2781+
else:
2782+
torch.testing.assert_close(out, expected)
27302783

27312784
def was_scaled(self, inpt):
27322785
# this assumes the target dtype is float
@@ -2825,65 +2878,6 @@ def test_uint16(self):
28252878
assert_equal(F.to_dtype(img_float32, torch.uint8, scale=True), img_uint8)
28262879
assert_close(F.to_dtype(img_uint8, torch.float32, scale=True), img_float32, rtol=0, atol=1e-2)
28272880

2828-
@pytest.mark.skipif(not CVCUDA_AVAILABLE, reason="test requires CVCUDA")
2829-
@pytest.mark.parametrize("input_dtype", [torch.float32, torch.float64, torch.uint8, torch.uint16])
2830-
@pytest.mark.parametrize("output_dtype", [torch.float32, torch.float64, torch.uint8, torch.uint16])
2831-
@pytest.mark.parametrize("device", cpu_and_cuda())
2832-
@pytest.mark.parametrize("scale", (True, False))
2833-
def test_cvcuda_parity(self, input_dtype, output_dtype, device, scale):
2834-
if input_dtype.is_floating_point and output_dtype == torch.int64:
2835-
pytest.xfail("float to int64 conversion is not supported")
2836-
if input_dtype == torch.uint8 and output_dtype == torch.uint16 and device == "cuda":
2837-
pytest.xfail("uint8 to uint16 conversion is not supported on cuda")
2838-
if input_dtype == torch.uint8 and output_dtype == torch.uint16 and scale:
2839-
pytest.xfail("uint8 to uint16 conversion with scale is not supported in F.to_dtype_image")
2840-
2841-
cvc_input = make_image_cvcuda(batch_dims=(1,), dtype=input_dtype, device=device)
2842-
torch_input = F.cvcuda_to_tensor(cvc_input)
2843-
2844-
out = F.to_dtype(cvc_input, dtype=output_dtype, scale=scale)
2845-
out = F.cvcuda_to_tensor(out)
2846-
2847-
expected = F.to_dtype(torch_input, dtype=output_dtype, scale=scale)
2848-
2849-
# there are some differences in dtype conversion between torchvision and cvcuda
2850-
# due to different rounding behavior when converting between types with different bit widths
2851-
# Check if we're converting to a type with more bits (without scaling)
2852-
in_bits = torch.iinfo(input_dtype).bits if not input_dtype.is_floating_point else None
2853-
out_bits = torch.iinfo(output_dtype).bits if not output_dtype.is_floating_point else None
2854-
2855-
if scale:
2856-
if input_dtype.is_floating_point and not output_dtype.is_floating_point:
2857-
# float -> int with scaling: allow for rounding differences
2858-
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2859-
elif input_dtype == torch.uint16 and output_dtype == torch.uint8:
2860-
# uint16 -> uint8 with scaling: allow large differences
2861-
torch.testing.assert_close(out, expected, atol=255, rtol=0)
2862-
else:
2863-
torch.testing.assert_close(out, expected)
2864-
else:
2865-
if in_bits is not None and out_bits is not None and out_bits > in_bits:
2866-
# uint to larger uint without scaling: allow large differences due to bit expansion
2867-
if input_dtype == torch.uint8 and output_dtype == torch.uint16:
2868-
torch.testing.assert_close(out, expected, atol=255, rtol=0)
2869-
else:
2870-
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2871-
elif not input_dtype.is_floating_point and not output_dtype.is_floating_point:
2872-
# uint to uint without scaling (same or smaller bits): allow for rounding
2873-
if input_dtype == torch.uint16 and output_dtype == torch.uint8:
2874-
# uint16 -> uint8 can have large differences due to bit reduction
2875-
torch.testing.assert_close(out, expected, atol=255, rtol=0)
2876-
else:
2877-
torch.testing.assert_close(out, expected)
2878-
elif input_dtype.is_floating_point and not output_dtype.is_floating_point:
2879-
# float -> uint without scaling: allow for rounding differences
2880-
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2881-
elif not input_dtype.is_floating_point and output_dtype.is_floating_point:
2882-
# uint -> float without scaling: allow for rounding differences
2883-
torch.testing.assert_close(out, expected, atol=1, rtol=0)
2884-
else:
2885-
torch.testing.assert_close(out, expected)
2886-
28872881

28882882
class TestAdjustBrightness:
28892883
_CORRECTNESS_BRIGHTNESS_FACTORS = [0.5, 0.0, 1.0, 5.0]

torchvision/transforms/v2/functional/_misc.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,27 @@ def _to_dtype_cvcuda(
376376
dtype: torch.dtype,
377377
scale: bool = False,
378378
) -> "cvcuda.Tensor":
379+
"""
380+
Convert the dtype of a CV-CUDA tensor, based on a torch.dtype.
381+
382+
Args:
383+
inpt: The CV-CUDA tensor to convert the dtype of.
384+
dtype: The torch.dtype to convert the dtype to.
385+
scale: Whether to scale the values to the new dtype.
386+
There are four cases for the scaling setup:
387+
1. float -> float
388+
2. int -> int
389+
3. float -> int
390+
4. int -> float
391+
If scale is True, the values will be scaled to the new dtype.
392+
If scale is False, the values will not be scaled.
393+
The scale values for float -> float and int -> int are 1.0 and 0.0 respectively.
394+
The scale values for float -> int and int -> float are the maximum value of the new dtype.
395+
396+
Returns:
397+
out (cvcuda.Tensor): The CV-CUDA tensor with the converted dtype.
398+
399+
"""
379400
cvcuda = _import_cvcuda()
380401

381402
dtype_in = _cvcuda_to_torch_dtypes[inpt.dtype]

0 commit comments

Comments
 (0)