Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
vision
Commits
0e496155
"torchvision/vscode:/vscode.git/clone" did not exist on "433283ebbf629c8b5bf27e28af7265267ac0af00"
Unverified
Commit
0e496155
authored
Jun 30, 2023
by
Philip Meier
Committed by
GitHub
Jun 30, 2023
Browse files
port affine tests (#7708)
parent
22d981f4
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
453 additions
and
416 deletions
+453
-416
test/test_transforms_v2.py
test/test_transforms_v2.py
+0
-124
test/test_transforms_v2_functional.py
test/test_transforms_v2_functional.py
+0
-83
test/test_transforms_v2_refactored.py
test/test_transforms_v2_refactored.py
+453
-12
test/transforms_v2_dispatcher_infos.py
test/transforms_v2_dispatcher_infos.py
+0
-15
test/transforms_v2_kernel_infos.py
test/transforms_v2_kernel_infos.py
+0
-182
No files found.
test/test_transforms_v2.py
View file @
0e496155
...
@@ -668,130 +668,6 @@ class TestRandomRotation:
...
@@ -668,130 +668,6 @@ class TestRandomRotation:
assert
out_img
.
spatial_size
==
out_bbox
.
spatial_size
assert
out_img
.
spatial_size
==
out_bbox
.
spatial_size
class
TestRandomAffine
:
def
test_assertions
(
self
):
with
pytest
.
raises
(
ValueError
,
match
=
"is a single number, it must be positive"
):
transforms
.
RandomAffine
(
-
0.7
)
for
d
in
[[
-
0.7
],
[
-
0.7
,
0
,
0.7
]]:
with
pytest
.
raises
(
ValueError
,
match
=
"degrees should be a sequence of length 2"
):
transforms
.
RandomAffine
(
d
)
with
pytest
.
raises
(
TypeError
,
match
=
"Got inappropriate fill arg"
):
transforms
.
RandomAffine
(
12
,
fill
=
"abc"
)
with
pytest
.
raises
(
TypeError
,
match
=
"Got inappropriate fill arg"
):
transforms
.
RandomAffine
(
12
,
fill
=
"abc"
)
for
kwargs
in
[
{
"center"
:
12
},
{
"translate"
:
12
},
{
"scale"
:
12
},
]:
with
pytest
.
raises
(
TypeError
,
match
=
"should be a sequence of length"
):
transforms
.
RandomAffine
(
12
,
**
kwargs
)
for
kwargs
in
[{
"center"
:
[
1
,
2
,
3
]},
{
"translate"
:
[
1
,
2
,
3
]},
{
"scale"
:
[
1
,
2
,
3
]}]:
with
pytest
.
raises
(
ValueError
,
match
=
"should be a sequence of length"
):
transforms
.
RandomAffine
(
12
,
**
kwargs
)
with
pytest
.
raises
(
ValueError
,
match
=
"translation values should be between 0 and 1"
):
transforms
.
RandomAffine
(
12
,
translate
=
[
-
1.0
,
2.0
])
with
pytest
.
raises
(
ValueError
,
match
=
"scale values should be positive"
):
transforms
.
RandomAffine
(
12
,
scale
=
[
-
1.0
,
2.0
])
with
pytest
.
raises
(
ValueError
,
match
=
"is a single number, it must be positive"
):
transforms
.
RandomAffine
(
12
,
shear
=-
10
)
for
s
in
[[
-
0.7
],
[
-
0.7
,
0
,
0.7
]]:
with
pytest
.
raises
(
ValueError
,
match
=
"shear should be a sequence of length 2"
):
transforms
.
RandomAffine
(
12
,
shear
=
s
)
@
pytest
.
mark
.
parametrize
(
"degrees"
,
[
23
,
[
0
,
45
],
(
0
,
45
)])
@
pytest
.
mark
.
parametrize
(
"translate"
,
[
None
,
[
0.1
,
0.2
]])
@
pytest
.
mark
.
parametrize
(
"scale"
,
[
None
,
[
0.7
,
1.2
]])
@
pytest
.
mark
.
parametrize
(
"shear"
,
[
None
,
2.0
,
[
5.0
,
15.0
],
[
1.0
,
2.0
,
3.0
,
4.0
]])
def
test__get_params
(
self
,
degrees
,
translate
,
scale
,
shear
,
mocker
):
image
=
mocker
.
MagicMock
(
spec
=
datapoints
.
Image
)
image
.
num_channels
=
3
image
.
spatial_size
=
(
24
,
32
)
h
,
w
=
image
.
spatial_size
transform
=
transforms
.
RandomAffine
(
degrees
,
translate
=
translate
,
scale
=
scale
,
shear
=
shear
)
params
=
transform
.
_get_params
([
image
])
if
not
isinstance
(
degrees
,
(
list
,
tuple
)):
assert
-
degrees
<=
params
[
"angle"
]
<=
degrees
else
:
assert
degrees
[
0
]
<=
params
[
"angle"
]
<=
degrees
[
1
]
if
translate
is
not
None
:
w_max
=
int
(
round
(
translate
[
0
]
*
w
))
h_max
=
int
(
round
(
translate
[
1
]
*
h
))
assert
-
w_max
<=
params
[
"translate"
][
0
]
<=
w_max
assert
-
h_max
<=
params
[
"translate"
][
1
]
<=
h_max
else
:
assert
params
[
"translate"
]
==
(
0
,
0
)
if
scale
is
not
None
:
assert
scale
[
0
]
<=
params
[
"scale"
]
<=
scale
[
1
]
else
:
assert
params
[
"scale"
]
==
1.0
if
shear
is
not
None
:
if
isinstance
(
shear
,
float
):
assert
-
shear
<=
params
[
"shear"
][
0
]
<=
shear
assert
params
[
"shear"
][
1
]
==
0.0
elif
len
(
shear
)
==
2
:
assert
shear
[
0
]
<=
params
[
"shear"
][
0
]
<=
shear
[
1
]
assert
params
[
"shear"
][
1
]
==
0.0
else
:
assert
shear
[
0
]
<=
params
[
"shear"
][
0
]
<=
shear
[
1
]
assert
shear
[
2
]
<=
params
[
"shear"
][
1
]
<=
shear
[
3
]
else
:
assert
params
[
"shear"
]
==
(
0
,
0
)
@
pytest
.
mark
.
parametrize
(
"degrees"
,
[
23
,
[
0
,
45
],
(
0
,
45
)])
@
pytest
.
mark
.
parametrize
(
"translate"
,
[
None
,
[
0.1
,
0.2
]])
@
pytest
.
mark
.
parametrize
(
"scale"
,
[
None
,
[
0.7
,
1.2
]])
@
pytest
.
mark
.
parametrize
(
"shear"
,
[
None
,
2.0
,
[
5.0
,
15.0
],
[
1.0
,
2.0
,
3.0
,
4.0
]])
@
pytest
.
mark
.
parametrize
(
"fill"
,
[
0
,
[
1
,
2
,
3
],
(
2
,
3
,
4
)])
@
pytest
.
mark
.
parametrize
(
"center"
,
[
None
,
[
2.0
,
3.0
]])
def
test__transform
(
self
,
degrees
,
translate
,
scale
,
shear
,
fill
,
center
,
mocker
):
interpolation
=
InterpolationMode
.
BILINEAR
transform
=
transforms
.
RandomAffine
(
degrees
,
translate
=
translate
,
scale
=
scale
,
shear
=
shear
,
interpolation
=
interpolation
,
fill
=
fill
,
center
=
center
,
)
if
isinstance
(
degrees
,
(
tuple
,
list
)):
assert
transform
.
degrees
==
[
float
(
degrees
[
0
]),
float
(
degrees
[
1
])]
else
:
assert
transform
.
degrees
==
[
float
(
-
degrees
),
float
(
degrees
)]
fn
=
mocker
.
patch
(
"torchvision.transforms.v2.functional.affine"
)
inpt
=
mocker
.
MagicMock
(
spec
=
datapoints
.
Image
)
inpt
.
num_channels
=
3
inpt
.
spatial_size
=
(
24
,
32
)
# vfdev-5, Feature Request: let's store params as Transform attribute
# This could be also helpful for users
# Otherwise, we can mock transform._get_params
torch
.
manual_seed
(
12
)
_
=
transform
(
inpt
)
torch
.
manual_seed
(
12
)
params
=
transform
.
_get_params
([
inpt
])
fill
=
transforms
.
_utils
.
_convert_fill_arg
(
fill
)
fn
.
assert_called_once_with
(
inpt
,
**
params
,
interpolation
=
interpolation
,
fill
=
fill
,
center
=
center
)
class
TestRandomCrop
:
class
TestRandomCrop
:
def
test_assertions
(
self
):
def
test_assertions
(
self
):
with
pytest
.
raises
(
ValueError
,
match
=
"Please provide only two dimensions"
):
with
pytest
.
raises
(
ValueError
,
match
=
"Please provide only two dimensions"
):
...
...
test/test_transforms_v2_functional.py
View file @
0e496155
...
@@ -665,77 +665,6 @@ def _compute_affine_matrix(angle_, translate_, scale_, shear_, center_):
...
@@ -665,77 +665,6 @@ def _compute_affine_matrix(angle_, translate_, scale_, shear_, center_):
return
true_matrix
return
true_matrix
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_correctness_affine_bounding_box_on_fixed_input
(
device
):
# Check transformation against known expected output
format
=
datapoints
.
BoundingBoxFormat
.
XYXY
spatial_size
=
(
64
,
64
)
in_boxes
=
[
[
20
,
25
,
35
,
45
],
[
50
,
5
,
70
,
22
],
[
spatial_size
[
1
]
//
2
-
10
,
spatial_size
[
0
]
//
2
-
10
,
spatial_size
[
1
]
//
2
+
10
,
spatial_size
[
0
]
//
2
+
10
],
[
1
,
1
,
5
,
5
],
]
in_boxes
=
torch
.
tensor
(
in_boxes
,
dtype
=
torch
.
float64
,
device
=
device
)
# Tested parameters
angle
=
63
scale
=
0.89
dx
=
0.12
dy
=
0.23
# Expected bboxes computed using albumentations:
# from albumentations.augmentations.geometric.functional import bbox_shift_scale_rotate
# from albumentations.augmentations.geometric.functional import normalize_bbox, denormalize_bbox
# expected_bboxes = []
# for in_box in in_boxes:
# n_in_box = normalize_bbox(in_box, *spatial_size)
# n_out_box = bbox_shift_scale_rotate(n_in_box, -angle, scale, dx, dy, *spatial_size)
# out_box = denormalize_bbox(n_out_box, *spatial_size)
# expected_bboxes.append(out_box)
expected_bboxes
=
[
(
24.522435977922218
,
34.375689508290854
,
46.443125279998114
,
54.3516575015695
),
(
54.88288587110401
,
50.08453280875634
,
76.44484547743795
,
72.81332520036864
),
(
27.709526487041554
,
34.74952648704156
,
51.650473512958435
,
58.69047351295844
),
(
48.56528888843238
,
9.611532109828834
,
53.35347829361575
,
14.39972151501221
),
]
expected_bboxes
=
clamp_bounding_box
(
datapoints
.
BoundingBox
(
expected_bboxes
,
format
=
"XYXY"
,
spatial_size
=
spatial_size
)
).
tolist
()
output_boxes
=
F
.
affine_bounding_box
(
in_boxes
,
format
=
format
,
spatial_size
=
spatial_size
,
angle
=
angle
,
translate
=
(
dx
*
spatial_size
[
1
],
dy
*
spatial_size
[
0
]),
scale
=
scale
,
shear
=
(
0
,
0
),
)
torch
.
testing
.
assert_close
(
output_boxes
.
tolist
(),
expected_bboxes
)
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_correctness_affine_segmentation_mask_on_fixed_input
(
device
):
# Check transformation against known expected output and CPU/CUDA devices
# Create a fixed input segmentation mask with 2 square masks
# in top-left, bottom-left corners
mask
=
torch
.
zeros
(
1
,
32
,
32
,
dtype
=
torch
.
long
,
device
=
device
)
mask
[
0
,
2
:
10
,
2
:
10
]
=
1
mask
[
0
,
32
-
9
:
32
-
3
,
3
:
9
]
=
2
# Rotate 90 degrees and scale
expected_mask
=
torch
.
rot90
(
mask
,
k
=-
1
,
dims
=
(
-
2
,
-
1
))
expected_mask
=
torch
.
nn
.
functional
.
interpolate
(
expected_mask
[
None
,
:].
float
(),
size
=
(
64
,
64
),
mode
=
"nearest"
)
expected_mask
=
expected_mask
[
0
,
:,
16
:
64
-
16
,
16
:
64
-
16
].
long
()
out_mask
=
F
.
affine_mask
(
mask
,
90
,
[
0.0
,
0.0
],
64.0
/
32.0
,
[
0.0
,
0.0
])
torch
.
testing
.
assert_close
(
out_mask
,
expected_mask
)
@
pytest
.
mark
.
parametrize
(
"angle"
,
range
(
-
90
,
90
,
56
))
@
pytest
.
mark
.
parametrize
(
"angle"
,
range
(
-
90
,
90
,
56
))
@
pytest
.
mark
.
parametrize
(
"expand, center"
,
[(
True
,
None
),
(
False
,
None
),
(
False
,
(
12
,
14
))])
@
pytest
.
mark
.
parametrize
(
"expand, center"
,
[(
True
,
None
),
(
False
,
None
),
(
False
,
(
12
,
14
))])
def
test_correctness_rotate_bounding_box
(
angle
,
expand
,
center
):
def
test_correctness_rotate_bounding_box
(
angle
,
expand
,
center
):
...
@@ -950,18 +879,6 @@ def test_correctness_crop_bounding_box(device, format, top, left, height, width,
...
@@ -950,18 +879,6 @@ def test_correctness_crop_bounding_box(device, format, top, left, height, width,
torch
.
testing
.
assert_close
(
output_spatial_size
,
spatial_size
)
torch
.
testing
.
assert_close
(
output_spatial_size
,
spatial_size
)
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_correctness_horizontal_flip_segmentation_mask_on_fixed_input
(
device
):
mask
=
torch
.
zeros
((
3
,
3
,
3
),
dtype
=
torch
.
long
,
device
=
device
)
mask
[:,
:,
0
]
=
1
out_mask
=
F
.
horizontal_flip_mask
(
mask
)
expected_mask
=
torch
.
zeros
((
3
,
3
,
3
),
dtype
=
torch
.
long
,
device
=
device
)
expected_mask
[:,
:,
-
1
]
=
1
torch
.
testing
.
assert_close
(
out_mask
,
expected_mask
)
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_correctness_vertical_flip_segmentation_mask_on_fixed_input
(
device
):
def
test_correctness_vertical_flip_segmentation_mask_on_fixed_input
(
device
):
mask
=
torch
.
zeros
((
3
,
3
,
3
),
dtype
=
torch
.
long
,
device
=
device
)
mask
=
torch
.
zeros
((
3
,
3
,
3
),
dtype
=
torch
.
long
,
device
=
device
)
...
...
test/test_transforms_v2_refactored.py
View file @
0e496155
import
contextlib
import
contextlib
import
inspect
import
inspect
import
math
import
re
import
re
from
typing
import
get_type_hints
from
typing
import
get_type_hints
from
unittest
import
mock
from
unittest
import
mock
...
@@ -25,6 +26,8 @@ from common_utils import (
...
@@ -25,6 +26,8 @@ from common_utils import (
)
)
from
torch.testing
import
assert_close
from
torch.testing
import
assert_close
from
torchvision
import
datapoints
from
torchvision
import
datapoints
from
torchvision.transforms._functional_tensor
import
_max_value
as
get_max_value
from
torchvision.transforms.functional
import
pil_modes_mapping
from
torchvision.transforms.functional
import
pil_modes_mapping
from
torchvision.transforms.v2
import
functional
as
F
from
torchvision.transforms.v2
import
functional
as
F
...
@@ -162,7 +165,7 @@ def _check_dispatcher_dispatch(dispatcher, kernel, input, *args, **kwargs):
...
@@ -162,7 +165,7 @@ def _check_dispatcher_dispatch(dispatcher, kernel, input, *args, **kwargs):
if
isinstance
(
input
,
datapoints
.
_datapoint
.
Datapoint
):
if
isinstance
(
input
,
datapoints
.
_datapoint
.
Datapoint
):
# Due to our complex dispatch architecture for datapoints, we cannot spy on the kernel directly,
# Due to our complex dispatch architecture for datapoints, we cannot spy on the kernel directly,
# but rather have to patch the `Datapoint.__F` attribute to contain the spied on kernel.
# but rather have to patch the `Datapoint.__F` attribute to contain the spied on kernel.
spy
=
mock
.
MagicMock
(
wraps
=
kernel
)
spy
=
mock
.
MagicMock
(
wraps
=
kernel
,
name
=
kernel
.
__name__
)
with
mock
.
patch
.
object
(
F
,
kernel
.
__name__
,
spy
):
with
mock
.
patch
.
object
(
F
,
kernel
.
__name__
,
spy
):
# Due to Python's name mangling, the `Datapoint.__F` attribute is only accessible from inside the class.
# Due to Python's name mangling, the `Datapoint.__F` attribute is only accessible from inside the class.
# Since that is not the case here, we need to prefix f"_{cls.__name__}"
# Since that is not the case here, we need to prefix f"_{cls.__name__}"
...
@@ -473,10 +476,9 @@ class TestResize:
...
@@ -473,10 +476,9 @@ class TestResize:
)
)
@
pytest
.
mark
.
parametrize
(
@
pytest
.
mark
.
parametrize
(
"dtype
_and_
make_mask"
,
[(
torch
.
uint8
,
make_segmentation_mask
),
(
torch
.
bool
,
make_detection_mask
)]
(
"dtype
"
,
"
make_mask"
)
,
[(
torch
.
uint8
,
make_segmentation_mask
),
(
torch
.
bool
,
make_detection_mask
)]
)
)
def
test_kernel_mask
(
self
,
dtype_and_make_mask
):
def
test_kernel_mask
(
self
,
dtype
,
make_mask
):
dtype
,
make_mask
=
dtype_and_make_mask
check_kernel
(
F
.
resize_mask
,
make_mask
(
dtype
=
dtype
),
size
=
self
.
OUTPUT_SIZES
[
-
1
])
check_kernel
(
F
.
resize_mask
,
make_mask
(
dtype
=
dtype
),
size
=
self
.
OUTPUT_SIZES
[
-
1
])
def
test_kernel_video
(
self
):
def
test_kernel_video
(
self
):
...
@@ -744,7 +746,7 @@ class TestHorizontalFlip:
...
@@ -744,7 +746,7 @@ class TestHorizontalFlip:
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
uint8
])
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
uint8
])
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_kernel_image_tensor
(
self
,
dtype
,
device
):
def
test_kernel_image_tensor
(
self
,
dtype
,
device
):
check_kernel
(
F
.
horizontal_flip_image_tensor
,
self
.
_make_input
(
torch
.
Tensor
))
check_kernel
(
F
.
horizontal_flip_image_tensor
,
self
.
_make_input
(
torch
.
Tensor
,
dtype
=
dtype
,
device
=
device
))
@
pytest
.
mark
.
parametrize
(
"format"
,
list
(
datapoints
.
BoundingBoxFormat
))
@
pytest
.
mark
.
parametrize
(
"format"
,
list
(
datapoints
.
BoundingBoxFormat
))
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
int64
])
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
int64
])
...
@@ -785,16 +787,16 @@ class TestHorizontalFlip:
...
@@ -785,16 +787,16 @@ class TestHorizontalFlip:
@
pytest
.
mark
.
parametrize
(
@
pytest
.
mark
.
parametrize
(
(
"input_type"
,
"kernel"
),
(
"input_type"
,
"kernel"
),
[
[
(
torch
.
Tensor
,
F
.
resize
_image_tensor
),
(
torch
.
Tensor
,
F
.
horizontal_flip
_image_tensor
),
(
PIL
.
Image
.
Image
,
F
.
resize
_image_pil
),
(
PIL
.
Image
.
Image
,
F
.
horizontal_flip
_image_pil
),
(
datapoints
.
Image
,
F
.
resize
_image_tensor
),
(
datapoints
.
Image
,
F
.
horizontal_flip
_image_tensor
),
(
datapoints
.
BoundingBox
,
F
.
resize
_bounding_box
),
(
datapoints
.
BoundingBox
,
F
.
horizontal_flip
_bounding_box
),
(
datapoints
.
Mask
,
F
.
resize
_mask
),
(
datapoints
.
Mask
,
F
.
horizontal_flip
_mask
),
(
datapoints
.
Video
,
F
.
resize
_video
),
(
datapoints
.
Video
,
F
.
horizontal_flip
_video
),
],
],
)
)
def
test_dispatcher_signature
(
self
,
kernel
,
input_type
):
def
test_dispatcher_signature
(
self
,
kernel
,
input_type
):
check_dispatcher_signatures_match
(
F
.
resize
,
kernel
=
kernel
,
input_type
=
input_type
)
check_dispatcher_signatures_match
(
F
.
horizontal_flip
,
kernel
=
kernel
,
input_type
=
input_type
)
@
pytest
.
mark
.
parametrize
(
@
pytest
.
mark
.
parametrize
(
"input_type"
,
"input_type"
,
...
@@ -860,3 +862,442 @@ class TestHorizontalFlip:
...
@@ -860,3 +862,442 @@ class TestHorizontalFlip:
output
=
transform
(
input
)
output
=
transform
(
input
)
assert_equal
(
output
,
input
)
assert_equal
(
output
,
input
)
class
TestAffine
:
def
_make_input
(
self
,
input_type
,
*
,
dtype
=
None
,
device
=
"cpu"
,
spatial_size
=
(
17
,
11
),
mask_type
=
"segmentation"
,
**
kwargs
):
if
input_type
in
{
torch
.
Tensor
,
PIL
.
Image
.
Image
,
datapoints
.
Image
}:
input
=
make_image
(
size
=
spatial_size
,
dtype
=
dtype
or
torch
.
uint8
,
device
=
device
,
**
kwargs
)
if
input_type
is
torch
.
Tensor
:
input
=
input
.
as_subclass
(
torch
.
Tensor
)
elif
input_type
is
PIL
.
Image
.
Image
:
input
=
F
.
to_image_pil
(
input
)
elif
input_type
is
datapoints
.
BoundingBox
:
kwargs
.
setdefault
(
"format"
,
datapoints
.
BoundingBoxFormat
.
XYXY
)
input
=
make_bounding_box
(
dtype
=
dtype
or
torch
.
float32
,
device
=
device
,
spatial_size
=
spatial_size
,
**
kwargs
,
)
elif
input_type
is
datapoints
.
Mask
:
if
mask_type
==
"segmentation"
:
make_mask
=
make_segmentation_mask
default_dtype
=
torch
.
uint8
elif
mask_type
==
"detection"
:
make_mask
=
make_detection_mask
default_dtype
=
torch
.
bool
input
=
make_mask
(
size
=
spatial_size
,
dtype
=
dtype
or
default_dtype
,
device
=
device
,
**
kwargs
)
elif
input_type
is
datapoints
.
Video
:
input
=
make_video
(
size
=
spatial_size
,
dtype
=
dtype
or
torch
.
uint8
,
device
=
device
,
**
kwargs
)
return
input
def
_adapt_fill
(
self
,
value
,
*
,
dtype
):
"""Adapt fill values in the range [0.0, 1.0] to the value range of the dtype"""
if
value
is
None
:
return
value
max_value
=
get_max_value
(
dtype
)
if
isinstance
(
value
,
(
int
,
float
)):
return
type
(
value
)(
value
*
max_value
)
elif
isinstance
(
value
,
(
list
,
tuple
)):
return
type
(
value
)(
type
(
v
)(
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
}
'"
)
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
=
dict
(
# float, int
angle
=
[
-
10.9
,
18
],
# two-list of float, two-list of int, two-tuple of float, two-tuple of int
translate
=
[[
6.3
,
-
0.6
],
[
1
,
-
3
],
(
16.6
,
-
6.6
),
(
-
2
,
4
)],
# float
scale
=
[
0.5
],
# float, int,
# one-list of float, one-list of int, one-tuple of float, one-tuple of int
# two-list of float, two-list of int, two-tuple of float, two-tuple of int
shear
=
[
35.6
,
38
,
[
-
37.7
],
[
-
23
],
(
5.3
,),
(
-
52
,),
[
5.4
,
21.8
],
[
-
47
,
51
],
(
-
11.2
,
36.7
),
(
8
,
-
53
)],
# None
# two-list of float, two-list of int, two-tuple of float, two-tuple of int
center
=
[
None
,
[
1.2
,
4.9
],
[
-
3
,
1
],
(
2.5
,
-
4.7
),
(
3
,
2
)],
)
# The special case for shear makes sure we pick a value that is supported while JIT scripting
_MINIMAL_AFFINE_KWARGS
=
{
k
:
vs
[
0
]
if
k
!=
"shear"
else
next
(
v
for
v
in
vs
if
isinstance
(
v
,
list
))
for
k
,
vs
in
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
.
items
()
}
_CORRECTNESS_AFFINE_KWARGS
=
{
k
:
[
v
for
v
in
vs
if
v
is
None
or
isinstance
(
v
,
float
)
or
(
isinstance
(
v
,
list
)
and
len
(
v
)
>
1
)]
for
k
,
vs
in
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
.
items
()
}
_EXHAUSTIVE_TYPE_FILLS
=
[
None
,
1
,
0.5
,
[
1
],
[
0.2
],
(
0
,),
(
0.7
,),
[
1
,
0
,
1
],
[
0.1
,
0.2
,
0.3
],
(
0
,
1
,
0
),
(
0.9
,
0.234
,
0.314
),
]
_CORRECTNESS_FILL
=
[
v
for
v
in
_EXHAUSTIVE_TYPE_FILLS
if
v
is
None
or
isinstance
(
v
,
float
)
or
(
isinstance
(
v
,
list
)
and
len
(
v
)
>
1
)
]
_EXHAUSTIVE_TYPE_TRANSFORM_AFFINE_RANGES
=
dict
(
degrees
=
[
30
,
(
-
15
,
20
)],
translate
=
[
None
,
(
0.5
,
0.5
)],
scale
=
[
None
,
(
0.75
,
1.25
)],
shear
=
[
None
,
(
12
,
30
,
-
17
,
5
),
10
,
(
-
5
,
12
)],
)
_CORRECTNESS_TRANSFORM_AFFINE_RANGES
=
{
k
:
next
(
v
for
v
in
vs
if
v
is
not
None
)
for
k
,
vs
in
_EXHAUSTIVE_TYPE_TRANSFORM_AFFINE_RANGES
.
items
()
}
def
_check_kernel
(
self
,
kernel
,
input
,
*
args
,
**
kwargs
):
kwargs_
=
self
.
_MINIMAL_AFFINE_KWARGS
.
copy
()
kwargs_
.
update
(
kwargs
)
check_kernel
(
kernel
,
input
,
*
args
,
**
kwargs_
)
@
pytest
.
mark
.
parametrize
(
(
"param"
,
"value"
),
[
(
param
,
value
)
for
param
,
values
in
[
(
"angle"
,
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
[
"angle"
]),
(
"translate"
,
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
[
"translate"
]),
(
"shear"
,
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
[
"shear"
]),
(
"center"
,
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
[
"center"
]),
(
"interpolation"
,
[
transforms
.
InterpolationMode
.
NEAREST
,
transforms
.
InterpolationMode
.
BILINEAR
]),
(
"fill"
,
_EXHAUSTIVE_TYPE_FILLS
),
]
for
value
in
values
],
)
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
uint8
])
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_kernel_image_tensor
(
self
,
param
,
value
,
dtype
,
device
):
if
param
==
"fill"
:
value
=
self
.
_adapt_fill
(
value
,
dtype
=
dtype
)
self
.
_check_kernel
(
F
.
affine_image_tensor
,
self
.
_make_input
(
torch
.
Tensor
,
dtype
=
dtype
,
device
=
device
),
**
{
param
:
value
},
check_scripted_vs_eager
=
not
(
param
in
{
"shear"
,
"fill"
}
and
isinstance
(
value
,
(
int
,
float
))),
check_cuda_vs_cpu
=
dict
(
atol
=
1
,
rtol
=
0
)
if
dtype
is
torch
.
uint8
and
param
==
"interpolation"
and
value
is
transforms
.
InterpolationMode
.
BILINEAR
else
True
,
)
@
pytest
.
mark
.
parametrize
(
(
"param"
,
"value"
),
[
(
param
,
value
)
for
param
,
values
in
[
(
"angle"
,
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
[
"angle"
]),
(
"translate"
,
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
[
"translate"
]),
(
"shear"
,
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
[
"shear"
]),
(
"center"
,
_EXHAUSTIVE_TYPE_AFFINE_KWARGS
[
"center"
]),
]
for
value
in
values
],
)
@
pytest
.
mark
.
parametrize
(
"format"
,
list
(
datapoints
.
BoundingBoxFormat
))
@
pytest
.
mark
.
parametrize
(
"dtype"
,
[
torch
.
float32
,
torch
.
int64
])
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_kernel_bounding_box
(
self
,
param
,
value
,
format
,
dtype
,
device
):
bounding_box
=
self
.
_make_input
(
datapoints
.
BoundingBox
,
format
=
format
,
dtype
=
dtype
,
device
=
device
)
self
.
_check_kernel
(
F
.
affine_bounding_box
,
self
.
_make_input
(
datapoints
.
BoundingBox
,
format
=
format
,
dtype
=
dtype
,
device
=
device
),
format
=
format
,
spatial_size
=
bounding_box
.
spatial_size
,
**
{
param
:
value
},
check_scripted_vs_eager
=
not
(
param
==
"shear"
and
isinstance
(
value
,
(
int
,
float
))),
)
@
pytest
.
mark
.
parametrize
(
"mask_type"
,
[
"segmentation"
,
"detection"
])
def
test_kernel_mask
(
self
,
mask_type
):
check_kernel
(
F
.
affine_mask
,
self
.
_make_input
(
datapoints
.
Mask
,
mask_type
=
mask_type
),
**
self
.
_MINIMAL_AFFINE_KWARGS
)
def
test_kernel_video
(
self
):
check_kernel
(
F
.
affine_video
,
self
.
_make_input
(
datapoints
.
Video
),
**
self
.
_MINIMAL_AFFINE_KWARGS
)
@
pytest
.
mark
.
parametrize
(
(
"input_type"
,
"kernel"
),
[
(
torch
.
Tensor
,
F
.
affine_image_tensor
),
(
PIL
.
Image
.
Image
,
F
.
affine_image_pil
),
(
datapoints
.
Image
,
F
.
affine_image_tensor
),
(
datapoints
.
BoundingBox
,
F
.
affine_bounding_box
),
(
datapoints
.
Mask
,
F
.
affine_mask
),
(
datapoints
.
Video
,
F
.
affine_video
),
],
)
def
test_dispatcher
(
self
,
kernel
,
input_type
):
check_dispatcher
(
F
.
affine
,
kernel
,
self
.
_make_input
(
input_type
),
**
self
.
_MINIMAL_AFFINE_KWARGS
)
@
pytest
.
mark
.
parametrize
(
(
"input_type"
,
"kernel"
),
[
(
torch
.
Tensor
,
F
.
affine_image_tensor
),
(
PIL
.
Image
.
Image
,
F
.
affine_image_pil
),
(
datapoints
.
Image
,
F
.
affine_image_tensor
),
(
datapoints
.
BoundingBox
,
F
.
affine_bounding_box
),
(
datapoints
.
Mask
,
F
.
affine_mask
),
(
datapoints
.
Video
,
F
.
affine_video
),
],
)
def
test_dispatcher_signature
(
self
,
kernel
,
input_type
):
check_dispatcher_signatures_match
(
F
.
affine
,
kernel
=
kernel
,
input_type
=
input_type
)
@
pytest
.
mark
.
parametrize
(
"input_type"
,
[
torch
.
Tensor
,
PIL
.
Image
.
Image
,
datapoints
.
Image
,
datapoints
.
BoundingBox
,
datapoints
.
Mask
,
datapoints
.
Video
],
)
@
pytest
.
mark
.
parametrize
(
"device"
,
cpu_and_cuda
())
def
test_transform
(
self
,
input_type
,
device
):
input
=
self
.
_make_input
(
input_type
,
device
=
device
)
check_transform
(
transforms
.
RandomAffine
,
input
,
**
self
.
_CORRECTNESS_TRANSFORM_AFFINE_RANGES
)
@
pytest
.
mark
.
parametrize
(
"angle"
,
_CORRECTNESS_AFFINE_KWARGS
[
"angle"
])
@
pytest
.
mark
.
parametrize
(
"translate"
,
_CORRECTNESS_AFFINE_KWARGS
[
"translate"
])
@
pytest
.
mark
.
parametrize
(
"scale"
,
_CORRECTNESS_AFFINE_KWARGS
[
"scale"
])
@
pytest
.
mark
.
parametrize
(
"shear"
,
_CORRECTNESS_AFFINE_KWARGS
[
"shear"
])
@
pytest
.
mark
.
parametrize
(
"center"
,
_CORRECTNESS_AFFINE_KWARGS
[
"center"
])
@
pytest
.
mark
.
parametrize
(
"interpolation"
,
[
transforms
.
InterpolationMode
.
NEAREST
,
transforms
.
InterpolationMode
.
BILINEAR
]
)
@
pytest
.
mark
.
parametrize
(
"fill"
,
_CORRECTNESS_FILL
)
def
test_functional_image_correctness
(
self
,
angle
,
translate
,
scale
,
shear
,
center
,
interpolation
,
fill
):
image
=
self
.
_make_input
(
torch
.
Tensor
,
dtype
=
torch
.
uint8
,
device
=
"cpu"
)
fill
=
self
.
_adapt_fill
(
fill
,
dtype
=
torch
.
uint8
)
actual
=
F
.
affine
(
image
,
angle
=
angle
,
translate
=
translate
,
scale
=
scale
,
shear
=
shear
,
center
=
center
,
interpolation
=
interpolation
,
fill
=
fill
,
)
expected
=
F
.
to_image_tensor
(
F
.
affine
(
F
.
to_image_pil
(
image
),
angle
=
angle
,
translate
=
translate
,
scale
=
scale
,
shear
=
shear
,
center
=
center
,
interpolation
=
interpolation
,
fill
=
fill
,
)
)
mae
=
(
actual
.
float
()
-
expected
.
float
()).
abs
().
mean
()
assert
mae
<
2
if
interpolation
is
transforms
.
InterpolationMode
.
NEAREST
else
8
@
pytest
.
mark
.
parametrize
(
"center"
,
_CORRECTNESS_AFFINE_KWARGS
[
"center"
])
@
pytest
.
mark
.
parametrize
(
"interpolation"
,
[
transforms
.
InterpolationMode
.
NEAREST
,
transforms
.
InterpolationMode
.
BILINEAR
]
)
@
pytest
.
mark
.
parametrize
(
"fill"
,
_CORRECTNESS_FILL
)
@
pytest
.
mark
.
parametrize
(
"seed"
,
list
(
range
(
5
)))
def
test_transform_image_correctness
(
self
,
center
,
interpolation
,
fill
,
seed
):
image
=
self
.
_make_input
(
torch
.
Tensor
,
dtype
=
torch
.
uint8
,
device
=
"cpu"
)
fill
=
self
.
_adapt_fill
(
fill
,
dtype
=
torch
.
uint8
)
transform
=
transforms
.
RandomAffine
(
**
self
.
_CORRECTNESS_TRANSFORM_AFFINE_RANGES
,
center
=
center
,
interpolation
=
interpolation
,
fill
=
fill
)
torch
.
manual_seed
(
seed
)
actual
=
transform
(
image
)
torch
.
manual_seed
(
seed
)
expected
=
F
.
to_image_tensor
(
transform
(
F
.
to_image_pil
(
image
)))
mae
=
(
actual
.
float
()
-
expected
.
float
()).
abs
().
mean
()
assert
mae
<
2
if
interpolation
is
transforms
.
InterpolationMode
.
NEAREST
else
8
def
_compute_affine_matrix
(
self
,
*
,
angle
,
translate
,
scale
,
shear
,
center
):
rot
=
math
.
radians
(
angle
)
cx
,
cy
=
center
tx
,
ty
=
translate
sx
,
sy
=
[
math
.
radians
(
s
)
for
s
in
([
shear
,
0.0
]
if
isinstance
(
shear
,
(
int
,
float
))
else
shear
)]
c_matrix
=
np
.
array
([[
1
,
0
,
cx
],
[
0
,
1
,
cy
],
[
0
,
0
,
1
]])
t_matrix
=
np
.
array
([[
1
,
0
,
tx
],
[
0
,
1
,
ty
],
[
0
,
0
,
1
]])
c_matrix_inv
=
np
.
linalg
.
inv
(
c_matrix
)
rs_matrix
=
np
.
array
(
[
[
scale
*
math
.
cos
(
rot
),
-
scale
*
math
.
sin
(
rot
),
0
],
[
scale
*
math
.
sin
(
rot
),
scale
*
math
.
cos
(
rot
),
0
],
[
0
,
0
,
1
],
]
)
shear_x_matrix
=
np
.
array
([[
1
,
-
math
.
tan
(
sx
),
0
],
[
0
,
1
,
0
],
[
0
,
0
,
1
]])
shear_y_matrix
=
np
.
array
([[
1
,
0
,
0
],
[
-
math
.
tan
(
sy
),
1
,
0
],
[
0
,
0
,
1
]])
rss_matrix
=
np
.
matmul
(
rs_matrix
,
np
.
matmul
(
shear_y_matrix
,
shear_x_matrix
))
true_matrix
=
np
.
matmul
(
t_matrix
,
np
.
matmul
(
c_matrix
,
np
.
matmul
(
rss_matrix
,
c_matrix_inv
)))
return
true_matrix
def
_reference_affine_bounding_box
(
self
,
bounding_box
,
*
,
angle
,
translate
,
scale
,
shear
,
center
):
if
center
is
None
:
center
=
[
s
*
0.5
for
s
in
bounding_box
.
spatial_size
[::
-
1
]]
affine_matrix
=
self
.
_compute_affine_matrix
(
angle
=
angle
,
translate
=
translate
,
scale
=
scale
,
shear
=
shear
,
center
=
center
)
affine_matrix
=
affine_matrix
[:
2
,
:]
expected_bboxes
=
reference_affine_bounding_box_helper
(
bounding_box
,
format
=
bounding_box
.
format
,
spatial_size
=
bounding_box
.
spatial_size
,
affine_matrix
=
affine_matrix
,
)
return
expected_bboxes
@
pytest
.
mark
.
parametrize
(
"format"
,
list
(
datapoints
.
BoundingBoxFormat
))
@
pytest
.
mark
.
parametrize
(
"angle"
,
_CORRECTNESS_AFFINE_KWARGS
[
"angle"
])
@
pytest
.
mark
.
parametrize
(
"translate"
,
_CORRECTNESS_AFFINE_KWARGS
[
"translate"
])
@
pytest
.
mark
.
parametrize
(
"scale"
,
_CORRECTNESS_AFFINE_KWARGS
[
"scale"
])
@
pytest
.
mark
.
parametrize
(
"shear"
,
_CORRECTNESS_AFFINE_KWARGS
[
"shear"
])
@
pytest
.
mark
.
parametrize
(
"center"
,
_CORRECTNESS_AFFINE_KWARGS
[
"center"
])
def
test_functional_bounding_box_correctness
(
self
,
format
,
angle
,
translate
,
scale
,
shear
,
center
):
bounding_box
=
self
.
_make_input
(
datapoints
.
BoundingBox
,
format
=
format
)
actual
=
F
.
affine
(
bounding_box
,
angle
=
angle
,
translate
=
translate
,
scale
=
scale
,
shear
=
shear
,
center
=
center
,
)
expected
=
self
.
_reference_affine_bounding_box
(
bounding_box
,
angle
=
angle
,
translate
=
translate
,
scale
=
scale
,
shear
=
shear
,
center
=
center
,
)
torch
.
testing
.
assert_close
(
actual
,
expected
)
@
pytest
.
mark
.
parametrize
(
"format"
,
list
(
datapoints
.
BoundingBoxFormat
))
@
pytest
.
mark
.
parametrize
(
"center"
,
_CORRECTNESS_AFFINE_KWARGS
[
"center"
])
@
pytest
.
mark
.
parametrize
(
"seed"
,
list
(
range
(
5
)))
def
test_transform_bounding_box_correctness
(
self
,
format
,
center
,
seed
):
bounding_box
=
self
.
_make_input
(
datapoints
.
BoundingBox
,
format
=
format
)
transform
=
transforms
.
RandomAffine
(
**
self
.
_CORRECTNESS_TRANSFORM_AFFINE_RANGES
,
center
=
center
)
torch
.
manual_seed
(
seed
)
params
=
transform
.
_get_params
([
bounding_box
])
torch
.
manual_seed
(
seed
)
actual
=
transform
(
bounding_box
)
expected
=
self
.
_reference_affine_bounding_box
(
bounding_box
,
**
params
,
center
=
center
)
torch
.
testing
.
assert_close
(
actual
,
expected
)
@
pytest
.
mark
.
parametrize
(
"degrees"
,
_EXHAUSTIVE_TYPE_TRANSFORM_AFFINE_RANGES
[
"degrees"
])
@
pytest
.
mark
.
parametrize
(
"translate"
,
_EXHAUSTIVE_TYPE_TRANSFORM_AFFINE_RANGES
[
"translate"
])
@
pytest
.
mark
.
parametrize
(
"scale"
,
_EXHAUSTIVE_TYPE_TRANSFORM_AFFINE_RANGES
[
"scale"
])
@
pytest
.
mark
.
parametrize
(
"shear"
,
_EXHAUSTIVE_TYPE_TRANSFORM_AFFINE_RANGES
[
"shear"
])
@
pytest
.
mark
.
parametrize
(
"seed"
,
list
(
range
(
10
)))
def
test_transform_get_params_bounds
(
self
,
degrees
,
translate
,
scale
,
shear
,
seed
):
image
=
self
.
_make_input
(
torch
.
Tensor
)
height
,
width
=
F
.
get_spatial_size
(
image
)
transform
=
transforms
.
RandomAffine
(
degrees
=
degrees
,
translate
=
translate
,
scale
=
scale
,
shear
=
shear
)
torch
.
manual_seed
(
seed
)
params
=
transform
.
_get_params
([
image
])
if
isinstance
(
degrees
,
(
int
,
float
)):
assert
-
degrees
<=
params
[
"angle"
]
<=
degrees
else
:
assert
degrees
[
0
]
<=
params
[
"angle"
]
<=
degrees
[
1
]
if
translate
is
not
None
:
width_max
=
int
(
round
(
translate
[
0
]
*
width
))
height_max
=
int
(
round
(
translate
[
1
]
*
height
))
assert
-
width_max
<=
params
[
"translate"
][
0
]
<=
width_max
assert
-
height_max
<=
params
[
"translate"
][
1
]
<=
height_max
else
:
assert
params
[
"translate"
]
==
(
0
,
0
)
if
scale
is
not
None
:
assert
scale
[
0
]
<=
params
[
"scale"
]
<=
scale
[
1
]
else
:
assert
params
[
"scale"
]
==
1.0
if
shear
is
not
None
:
if
isinstance
(
shear
,
(
int
,
float
)):
assert
-
shear
<=
params
[
"shear"
][
0
]
<=
shear
assert
params
[
"shear"
][
1
]
==
0.0
elif
len
(
shear
)
==
2
:
assert
shear
[
0
]
<=
params
[
"shear"
][
0
]
<=
shear
[
1
]
assert
params
[
"shear"
][
1
]
==
0.0
elif
len
(
shear
)
==
4
:
assert
shear
[
0
]
<=
params
[
"shear"
][
0
]
<=
shear
[
1
]
assert
shear
[
2
]
<=
params
[
"shear"
][
1
]
<=
shear
[
3
]
else
:
assert
params
[
"shear"
]
==
(
0
,
0
)
@
pytest
.
mark
.
parametrize
(
"param"
,
[
"degrees"
,
"translate"
,
"scale"
,
"shear"
,
"center"
])
@
pytest
.
mark
.
parametrize
(
"value"
,
[
0
,
[
0
],
[
0
,
0
,
0
]])
def
test_transform_sequence_len_errors
(
self
,
param
,
value
):
if
param
in
{
"degrees"
,
"shear"
}
and
not
isinstance
(
value
,
list
):
return
kwargs
=
{
param
:
value
}
if
param
!=
"degrees"
:
kwargs
[
"degrees"
]
=
0
with
pytest
.
raises
(
ValueError
if
isinstance
(
value
,
list
)
else
TypeError
,
match
=
f
"
{
param
}
should be a sequence of length 2"
):
transforms
.
RandomAffine
(
**
kwargs
)
def
test_transform_negative_degrees_error
(
self
):
with
pytest
.
raises
(
ValueError
,
match
=
"If degrees is a single number, it must be positive"
):
transforms
.
RandomAffine
(
degrees
=-
1
)
@
pytest
.
mark
.
parametrize
(
"translate"
,
[[
-
1
,
0
],
[
2
,
0
],
[
-
1
,
2
]])
def
test_transform_translate_range_error
(
self
,
translate
):
with
pytest
.
raises
(
ValueError
,
match
=
"translation values should be between 0 and 1"
):
transforms
.
RandomAffine
(
degrees
=
0
,
translate
=
translate
)
@
pytest
.
mark
.
parametrize
(
"scale"
,
[[
-
1
,
0
],
[
0
,
-
1
],
[
-
1
,
-
1
]])
def
test_transform_scale_range_error
(
self
,
scale
):
with
pytest
.
raises
(
ValueError
,
match
=
"scale values should be positive"
):
transforms
.
RandomAffine
(
degrees
=
0
,
scale
=
scale
)
def
test_transform_negative_shear_error
(
self
):
with
pytest
.
raises
(
ValueError
,
match
=
"If shear is a single number, it must be positive"
):
transforms
.
RandomAffine
(
degrees
=
0
,
shear
=-
1
)
def
test_transform_unknown_fill_error
(
self
):
with
pytest
.
raises
(
TypeError
,
match
=
"Got inappropriate fill arg"
):
transforms
.
RandomAffine
(
degrees
=
0
,
fill
=
"fill"
)
test/transforms_v2_dispatcher_infos.py
View file @
0e496155
...
@@ -138,21 +138,6 @@ xfails_pil_if_fill_sequence_needs_broadcast = xfails_pil(
...
@@ -138,21 +138,6 @@ xfails_pil_if_fill_sequence_needs_broadcast = xfails_pil(
DISPATCHER_INFOS
=
[
DISPATCHER_INFOS
=
[
DispatcherInfo
(
F
.
affine
,
kernels
=
{
datapoints
.
Image
:
F
.
affine_image_tensor
,
datapoints
.
Video
:
F
.
affine_video
,
datapoints
.
BoundingBox
:
F
.
affine_bounding_box
,
datapoints
.
Mask
:
F
.
affine_mask
,
},
pil_kernel_info
=
PILKernelInfo
(
F
.
affine_image_pil
),
test_marks
=
[
*
xfails_pil_if_fill_sequence_needs_broadcast
,
xfail_jit_python_scalar_arg
(
"shear"
),
xfail_jit_python_scalar_arg
(
"fill"
),
],
),
DispatcherInfo
(
DispatcherInfo
(
F
.
vertical_flip
,
F
.
vertical_flip
,
kernels
=
{
kernels
=
{
...
...
test/transforms_v2_kernel_infos.py
View file @
0e496155
import
decimal
import
decimal
import
functools
import
functools
import
itertools
import
itertools
import
math
import
numpy
as
np
import
numpy
as
np
import
PIL.Image
import
PIL.Image
...
@@ -156,46 +155,6 @@ def xfail_jit_python_scalar_arg(name, *, reason=None):
...
@@ -156,46 +155,6 @@ def xfail_jit_python_scalar_arg(name, *, reason=None):
KERNEL_INFOS
=
[]
KERNEL_INFOS
=
[]
_AFFINE_KWARGS
=
combinations_grid
(
angle
=
[
-
87
,
15
,
90
],
translate
=
[(
5
,
5
),
(
-
5
,
-
5
)],
scale
=
[
0.77
,
1.27
],
shear
=
[(
12
,
12
),
(
0
,
0
)],
)
def
_diversify_affine_kwargs_types
(
affine_kwargs
):
angle
=
affine_kwargs
[
"angle"
]
for
diverse_angle
in
[
int
(
angle
),
float
(
angle
)]:
yield
dict
(
affine_kwargs
,
angle
=
diverse_angle
)
shear
=
affine_kwargs
[
"shear"
]
for
diverse_shear
in
[
tuple
(
shear
),
list
(
shear
),
int
(
shear
[
0
]),
float
(
shear
[
0
])]:
yield
dict
(
affine_kwargs
,
shear
=
diverse_shear
)
def
_full_affine_params
(
**
partial_params
):
partial_params
.
setdefault
(
"angle"
,
0.0
)
partial_params
.
setdefault
(
"translate"
,
[
0.0
,
0.0
])
partial_params
.
setdefault
(
"scale"
,
1.0
)
partial_params
.
setdefault
(
"shear"
,
[
0.0
,
0.0
])
partial_params
.
setdefault
(
"center"
,
None
)
return
partial_params
_DIVERSE_AFFINE_PARAMS
=
[
_full_affine_params
(
**
{
name
:
arg
})
for
name
,
args
in
[
(
"angle"
,
[
1.0
,
2
]),
(
"translate"
,
[[
1.0
,
0.5
],
[
1
,
2
],
(
1.0
,
0.5
),
(
1
,
2
)]),
(
"scale"
,
[
0.5
]),
(
"shear"
,
[
1.0
,
2
,
[
1.0
],
[
2
],
(
1.0
,),
(
2
,),
[
1.0
,
0.5
],
[
1
,
2
],
(
1.0
,
0.5
),
(
1
,
2
)]),
(
"center"
,
[
None
,
[
1.0
,
0.5
],
[
1
,
2
],
(
1.0
,
0.5
),
(
1
,
2
)]),
]
for
arg
in
args
]
def
get_fills
(
*
,
num_channels
,
dtype
):
def
get_fills
(
*
,
num_channels
,
dtype
):
yield
None
yield
None
...
@@ -226,72 +185,6 @@ def float32_vs_uint8_fill_adapter(other_args, kwargs):
...
@@ -226,72 +185,6 @@ def float32_vs_uint8_fill_adapter(other_args, kwargs):
return
other_args
,
dict
(
kwargs
,
fill
=
fill
)
return
other_args
,
dict
(
kwargs
,
fill
=
fill
)
def
sample_inputs_affine_image_tensor
():
make_affine_image_loaders
=
functools
.
partial
(
make_image_loaders
,
sizes
=
[
"random"
],
color_spaces
=
[
"RGB"
],
dtypes
=
[
torch
.
float32
]
)
for
image_loader
,
affine_params
in
itertools
.
product
(
make_affine_image_loaders
(),
_DIVERSE_AFFINE_PARAMS
):
yield
ArgsKwargs
(
image_loader
,
**
affine_params
)
for
image_loader
in
make_affine_image_loaders
():
for
fill
in
get_fills
(
num_channels
=
image_loader
.
num_channels
,
dtype
=
image_loader
.
dtype
):
yield
ArgsKwargs
(
image_loader
,
**
_full_affine_params
(),
fill
=
fill
)
for
image_loader
,
interpolation
in
itertools
.
product
(
make_affine_image_loaders
(),
[
F
.
InterpolationMode
.
NEAREST
,
F
.
InterpolationMode
.
BILINEAR
,
],
):
yield
ArgsKwargs
(
image_loader
,
**
_full_affine_params
(),
fill
=
0
)
def
reference_inputs_affine_image_tensor
():
for
image_loader
,
affine_kwargs
in
itertools
.
product
(
make_image_loaders_for_interpolation
(),
_AFFINE_KWARGS
):
yield
ArgsKwargs
(
image_loader
,
interpolation
=
F
.
InterpolationMode
.
NEAREST
,
**
affine_kwargs
,
)
def
sample_inputs_affine_bounding_box
():
for
bounding_box_loader
,
affine_params
in
itertools
.
product
(
make_bounding_box_loaders
(
formats
=
[
datapoints
.
BoundingBoxFormat
.
XYXY
]),
_DIVERSE_AFFINE_PARAMS
):
yield
ArgsKwargs
(
bounding_box_loader
,
format
=
bounding_box_loader
.
format
,
spatial_size
=
bounding_box_loader
.
spatial_size
,
**
affine_params
,
)
def
_compute_affine_matrix
(
angle
,
translate
,
scale
,
shear
,
center
):
rot
=
math
.
radians
(
angle
)
cx
,
cy
=
center
tx
,
ty
=
translate
sx
,
sy
=
[
math
.
radians
(
sh_
)
for
sh_
in
shear
]
c_matrix
=
np
.
array
([[
1
,
0
,
cx
],
[
0
,
1
,
cy
],
[
0
,
0
,
1
]])
t_matrix
=
np
.
array
([[
1
,
0
,
tx
],
[
0
,
1
,
ty
],
[
0
,
0
,
1
]])
c_matrix_inv
=
np
.
linalg
.
inv
(
c_matrix
)
rs_matrix
=
np
.
array
(
[
[
scale
*
math
.
cos
(
rot
),
-
scale
*
math
.
sin
(
rot
),
0
],
[
scale
*
math
.
sin
(
rot
),
scale
*
math
.
cos
(
rot
),
0
],
[
0
,
0
,
1
],
]
)
shear_x_matrix
=
np
.
array
([[
1
,
-
math
.
tan
(
sx
),
0
],
[
0
,
1
,
0
],
[
0
,
0
,
1
]])
shear_y_matrix
=
np
.
array
([[
1
,
0
,
0
],
[
-
math
.
tan
(
sy
),
1
,
0
],
[
0
,
0
,
1
]])
rss_matrix
=
np
.
matmul
(
rs_matrix
,
np
.
matmul
(
shear_y_matrix
,
shear_x_matrix
))
true_matrix
=
np
.
matmul
(
t_matrix
,
np
.
matmul
(
c_matrix
,
np
.
matmul
(
rss_matrix
,
c_matrix_inv
)))
return
true_matrix
def
reference_affine_bounding_box_helper
(
bounding_box
,
*
,
format
,
spatial_size
,
affine_matrix
):
def
reference_affine_bounding_box_helper
(
bounding_box
,
*
,
format
,
spatial_size
,
affine_matrix
):
def
transform
(
bbox
,
affine_matrix_
,
format_
,
spatial_size_
):
def
transform
(
bbox
,
affine_matrix_
,
format_
,
spatial_size_
):
# Go to float before converting to prevent precision loss in case of CXCYWH -> XYXY and W or H is 1
# Go to float before converting to prevent precision loss in case of CXCYWH -> XYXY and W or H is 1
...
@@ -342,81 +235,6 @@ def reference_affine_bounding_box_helper(bounding_box, *, format, spatial_size,
...
@@ -342,81 +235,6 @@ def reference_affine_bounding_box_helper(bounding_box, *, format, spatial_size,
return
expected_bboxes
return
expected_bboxes
def
reference_affine_bounding_box
(
bounding_box
,
*
,
format
,
spatial_size
,
angle
,
translate
,
scale
,
shear
,
center
=
None
):
if
center
is
None
:
center
=
[
s
*
0.5
for
s
in
spatial_size
[::
-
1
]]
affine_matrix
=
_compute_affine_matrix
(
angle
,
translate
,
scale
,
shear
,
center
)
affine_matrix
=
affine_matrix
[:
2
,
:]
expected_bboxes
=
reference_affine_bounding_box_helper
(
bounding_box
,
format
=
format
,
spatial_size
=
spatial_size
,
affine_matrix
=
affine_matrix
)
return
expected_bboxes
def
reference_inputs_affine_bounding_box
():
for
bounding_box_loader
,
affine_kwargs
in
itertools
.
product
(
make_bounding_box_loaders
(
extra_dims
=
[()]),
_AFFINE_KWARGS
,
):
yield
ArgsKwargs
(
bounding_box_loader
,
format
=
bounding_box_loader
.
format
,
spatial_size
=
bounding_box_loader
.
spatial_size
,
**
affine_kwargs
,
)
def
sample_inputs_affine_mask
():
for
mask_loader
in
make_mask_loaders
(
sizes
=
[
"random"
],
num_categories
=
[
"random"
],
num_objects
=
[
"random"
]):
yield
ArgsKwargs
(
mask_loader
,
**
_full_affine_params
())
def
sample_inputs_affine_video
():
for
video_loader
in
make_video_loaders
(
sizes
=
[
"random"
],
num_frames
=
[
"random"
]):
yield
ArgsKwargs
(
video_loader
,
**
_full_affine_params
())
KERNEL_INFOS
.
extend
(
[
KernelInfo
(
F
.
affine_image_tensor
,
sample_inputs_fn
=
sample_inputs_affine_image_tensor
,
reference_fn
=
pil_reference_wrapper
(
F
.
affine_image_pil
),
reference_inputs_fn
=
reference_inputs_affine_image_tensor
,
float32_vs_uint8
=
True
,
closeness_kwargs
=
pil_reference_pixel_difference
(
10
,
mae
=
True
),
test_marks
=
[
xfail_jit_python_scalar_arg
(
"shear"
),
xfail_jit_python_scalar_arg
(
"fill"
),
],
),
KernelInfo
(
F
.
affine_bounding_box
,
sample_inputs_fn
=
sample_inputs_affine_bounding_box
,
reference_fn
=
reference_affine_bounding_box
,
reference_inputs_fn
=
reference_inputs_affine_bounding_box
,
test_marks
=
[
xfail_jit_python_scalar_arg
(
"shear"
),
],
),
KernelInfo
(
F
.
affine_mask
,
sample_inputs_fn
=
sample_inputs_affine_mask
,
test_marks
=
[
xfail_jit_python_scalar_arg
(
"shear"
),
],
),
KernelInfo
(
F
.
affine_video
,
sample_inputs_fn
=
sample_inputs_affine_video
,
),
]
)
def
sample_inputs_convert_format_bounding_box
():
def
sample_inputs_convert_format_bounding_box
():
formats
=
list
(
datapoints
.
BoundingBoxFormat
)
formats
=
list
(
datapoints
.
BoundingBoxFormat
)
for
bounding_box_loader
,
new_format
in
itertools
.
product
(
make_bounding_box_loaders
(
formats
=
formats
),
formats
):
for
bounding_box_loader
,
new_format
in
itertools
.
product
(
make_bounding_box_loaders
(
formats
=
formats
),
formats
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment