Skip to content

Commit 1dc0e68

Browse files
garciadiaspre-commit-ci[bot]ericspod
authored
8185 test refactor 2 (#8405)
Fixes #8185 ### Description This PR solves items 2 and 3 on #8185 for a few test folders. I would merge these and proceed with the same type of change in other files if @ericspod approves. I would like to keep these PRs small, so even if they have the same pattern of changes, merging them bit by bit would make them more manageable. A few sentences describing the changes proposed in this pull request. ### Types of changes <!--- Put an `x` in all the boxes that apply, and remove the not applicable items --> - [x] Non-breaking change (fix or new feature that would not break existing functionality). - [ ] Breaking change (fix or new feature that would cause existing functionality to change). - [ ] New tests added to cover the changes. - [x] Integration tests passed locally by running `./runtests.sh -f -u --net --coverage`. - [x] Quick tests passed locally by running `./runtests.sh --quick --unittests --disttests`. - [ ] In-line docstrings updated. - [ ] Documentation updated, tested `make html` command in the `docs/` folder. --------- Signed-off-by: R. Garcia-Dias <[email protected]> Signed-off-by: Rafael Garcia-Dias <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Eric Kerfoot <[email protected]>
1 parent 503b4ed commit 1dc0e68

27 files changed

+890
-1011
lines changed

CONTRIBUTING.md

Lines changed: 47 additions & 20 deletions
Large diffs are not rendered by default.

tests/apps/detection/networks/test_retinanet.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from monai.networks import eval_mode
2121
from monai.networks.nets import resnet10, resnet18, resnet34, resnet50, resnet101, resnet152, resnet200
2222
from monai.utils import ensure_tuple, optional_import
23-
from tests.test_utils import SkipIfBeforePyTorchVersion, skip_if_quick, test_onnx_save, test_script_save
23+
from tests.test_utils import SkipIfBeforePyTorchVersion, dict_product, skip_if_quick, test_onnx_save, test_script_save
2424

2525
_, has_torchvision = optional_import("torchvision")
2626

@@ -86,15 +86,12 @@
8686
(2, 1, 32, 64),
8787
]
8888

89-
TEST_CASES = []
90-
for case in [TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_2_A, TEST_CASE_3_A]:
91-
for model in [resnet10, resnet18, resnet34, resnet50, resnet101, resnet152, resnet200]:
92-
TEST_CASES.append([model, *case])
89+
# Create all test case combinations using dict_product
90+
CASE_LIST = [TEST_CASE_1, TEST_CASE_2, TEST_CASE_3, TEST_CASE_2_A, TEST_CASE_3_A]
91+
MODEL_LIST = [resnet10, resnet18, resnet34, resnet50, resnet101, resnet152, resnet200]
9392

94-
TEST_CASES_TS = []
95-
for case in [TEST_CASE_1]:
96-
for model in [resnet10, resnet18, resnet34, resnet50, resnet101, resnet152, resnet200]:
97-
TEST_CASES_TS.append([model, *case])
93+
TEST_CASES = [[params["model"], *params["case"]] for params in dict_product(model=MODEL_LIST, case=CASE_LIST)]
94+
TEST_CASES_TS = [[params["model"], *params["case"]] for params in dict_product(model=MODEL_LIST, case=[TEST_CASE_1])]
9895

9996

10097
@SkipIfBeforePyTorchVersion((1, 12))

tests/data/meta_tensor/test_meta_tensor.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@
3232
from monai.data.utils import decollate_batch, list_data_collate
3333
from monai.transforms import BorderPadd, Compose, DivisiblePadd, FromMetaTensord, ToMetaTensord
3434
from monai.utils.enums import PostFix
35-
from tests.test_utils import TEST_DEVICES, SkipIfBeforePyTorchVersion, assert_allclose, skip_if_no_cuda
35+
from tests.test_utils import TEST_DEVICES, SkipIfBeforePyTorchVersion, assert_allclose, dict_product, skip_if_no_cuda
3636

3737
DTYPES = [[torch.float32], [torch.float64], [torch.float16], [torch.int64], [torch.int32], [None]]
38-
TESTS = []
39-
for _device in TEST_DEVICES:
40-
for _dtype in DTYPES:
41-
TESTS.append((*_device, *_dtype)) # type: ignore
38+
39+
# Replace nested loops with dict_product
40+
41+
TESTS = [(*params["device"], *params["dtype"]) for params in dict_product(device=TEST_DEVICES, dtype=DTYPES)]
4242

4343

4444
def rand_string(min_len=5, max_len=10):

tests/networks/blocks/test_CABlock.py

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,18 @@
2020
from monai.networks import eval_mode
2121
from monai.networks.blocks.cablock import CABlock, FeedForward
2222
from monai.utils import optional_import
23-
from tests.test_utils import SkipIfBeforePyTorchVersion, assert_allclose
23+
from tests.test_utils import SkipIfBeforePyTorchVersion, assert_allclose, dict_product
2424

2525
einops, has_einops = optional_import("einops")
2626

27-
28-
TEST_CASES_CAB = []
29-
for spatial_dims in [2, 3]:
30-
for dim in [32, 64, 128]:
31-
for num_heads in [2, 4, 8]:
32-
for bias in [True, False]:
33-
test_case = [
34-
{
35-
"spatial_dims": spatial_dims,
36-
"dim": dim,
37-
"num_heads": num_heads,
38-
"bias": bias,
39-
"flash_attention": False,
40-
},
41-
(2, dim, *([16] * spatial_dims)),
42-
(2, dim, *([16] * spatial_dims)),
43-
]
44-
TEST_CASES_CAB.append(test_case)
27+
TEST_CASES_CAB = [
28+
[
29+
{**params, "flash_attention": False},
30+
(2, params["dim"], *([16] * params["spatial_dims"])),
31+
(2, params["dim"], *([16] * params["spatial_dims"])),
32+
]
33+
for params in dict_product(spatial_dims=[2, 3], dim=[32, 64, 128], num_heads=[2, 4, 8], bias=[True, False])
34+
]
4535

4636

4737
TEST_CASES_FEEDFORWARD = [
@@ -53,7 +43,6 @@
5343

5444

5545
class TestFeedForward(unittest.TestCase):
56-
5746
@parameterized.expand(TEST_CASES_FEEDFORWARD)
5847
def test_shape(self, input_param, input_shape):
5948
net = FeedForward(**input_param)
@@ -69,7 +58,6 @@ def test_gating_mechanism(self):
6958

7059

7160
class TestCABlock(unittest.TestCase):
72-
7361
@parameterized.expand(TEST_CASES_CAB)
7462
@skipUnless(has_einops, "Requires einops")
7563
def test_shape(self, input_param, input_shape, expected_shape):

tests/networks/blocks/test_crossattention.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,28 @@
2222
from monai.networks.blocks.crossattention import CrossAttentionBlock
2323
from monai.networks.layers.factories import RelPosEmbedding
2424
from monai.utils import optional_import
25-
from tests.test_utils import SkipIfBeforePyTorchVersion, assert_allclose
25+
from tests.test_utils import SkipIfBeforePyTorchVersion, assert_allclose, dict_product
2626

2727
einops, has_einops = optional_import("einops")
2828

29-
TEST_CASE_CABLOCK = []
30-
for dropout_rate in np.linspace(0, 1, 4):
31-
for hidden_size in [360, 480, 600, 768]:
32-
for num_heads in [4, 6, 8, 12]:
33-
for rel_pos_embedding in [None, RelPosEmbedding.DECOMPOSED]:
34-
for input_size in [(16, 32), (8, 8, 8)]:
35-
for flash_attn in [True, False]:
36-
test_case = [
37-
{
38-
"hidden_size": hidden_size,
39-
"num_heads": num_heads,
40-
"dropout_rate": dropout_rate,
41-
"rel_pos_embedding": rel_pos_embedding if not flash_attn else None,
42-
"input_size": input_size,
43-
"use_flash_attention": flash_attn,
44-
},
45-
(2, 512, hidden_size),
46-
(2, 512, hidden_size),
47-
]
48-
TEST_CASE_CABLOCK.append(test_case)
29+
TEST_CASE_CABLOCK = [
30+
[
31+
{
32+
**{k: v for k, v in params.items() if k not in ["rel_pos_embedding_val"]},
33+
"rel_pos_embedding": params["rel_pos_embedding_val"] if not params["use_flash_attention"] else None,
34+
},
35+
(2, 512, params["hidden_size"]),
36+
(2, 512, params["hidden_size"]),
37+
]
38+
for params in dict_product(
39+
dropout_rate=np.linspace(0, 1, 4),
40+
hidden_size=[360, 480, 600, 768],
41+
num_heads=[4, 6, 8, 12],
42+
rel_pos_embedding_val=[None, RelPosEmbedding.DECOMPOSED],
43+
input_size=[(16, 32), (8, 8, 8)],
44+
use_flash_attention=[True, False],
45+
)
46+
]
4947

5048

5149
class TestResBlock(unittest.TestCase):

tests/networks/blocks/test_dynunet_block.py

Lines changed: 44 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -18,58 +18,55 @@
1818

1919
from monai.networks import eval_mode
2020
from monai.networks.blocks.dynunet_block import UnetBasicBlock, UnetResBlock, UnetUpBlock, get_padding
21-
from tests.test_utils import test_script_save
21+
from tests.test_utils import dict_product, test_script_save
2222

2323
TEST_CASE_RES_BASIC_BLOCK = []
24-
for spatial_dims in range(2, 4):
25-
for kernel_size in [1, 3]:
26-
for stride in [1, 2]:
27-
for norm_name in [("GROUP", {"num_groups": 16}), ("batch", {"track_running_stats": False}), "instance"]:
28-
for in_size in [15, 16]:
29-
padding = get_padding(kernel_size, stride)
30-
if not isinstance(padding, int):
31-
padding = padding[0]
32-
out_size = int((in_size + 2 * padding - kernel_size) / stride) + 1
33-
test_case = [
34-
{
35-
"spatial_dims": spatial_dims,
36-
"in_channels": 16,
37-
"out_channels": 16,
38-
"kernel_size": kernel_size,
39-
"norm_name": norm_name,
40-
"act_name": ("leakyrelu", {"inplace": True, "negative_slope": 0.1}),
41-
"stride": stride,
42-
},
43-
(1, 16, *([in_size] * spatial_dims)),
44-
(1, 16, *([out_size] * spatial_dims)),
45-
]
46-
TEST_CASE_RES_BASIC_BLOCK.append(test_case)
24+
for params in dict_product(
25+
spatial_dims=range(2, 4),
26+
kernel_size=[1, 3],
27+
stride=[1, 2],
28+
norm_name=[("GROUP", {"num_groups": 16}), ("batch", {"track_running_stats": False}), "instance"],
29+
in_size=[15, 16],
30+
):
31+
padding = get_padding(params["kernel_size"], params["stride"])
32+
if not isinstance(padding, int):
33+
padding = padding[0]
34+
out_size = int((params["in_size"] + 2 * padding - params["kernel_size"]) / params["stride"]) + 1
35+
test_case = [
36+
{
37+
**{k: v for k, v in params.items() if k != "in_size"},
38+
"in_channels": 16,
39+
"out_channels": 16,
40+
"act_name": ("leakyrelu", {"inplace": True, "negative_slope": 0.1}),
41+
},
42+
(1, 16, *([params["in_size"]] * params["spatial_dims"])),
43+
(1, 16, *([out_size] * params["spatial_dims"])),
44+
]
45+
TEST_CASE_RES_BASIC_BLOCK.append(test_case)
4746

4847
TEST_UP_BLOCK = []
4948
in_channels, out_channels = 4, 2
50-
for spatial_dims in range(2, 4):
51-
for kernel_size in [1, 3]:
52-
for stride in [1, 2]:
53-
for norm_name in ["batch", "instance"]:
54-
for in_size in [15, 16]:
55-
for trans_bias in [True, False]:
56-
out_size = in_size * stride
57-
test_case = [
58-
{
59-
"spatial_dims": spatial_dims,
60-
"in_channels": in_channels,
61-
"out_channels": out_channels,
62-
"kernel_size": kernel_size,
63-
"norm_name": norm_name,
64-
"stride": stride,
65-
"upsample_kernel_size": stride,
66-
"trans_bias": trans_bias,
67-
},
68-
(1, in_channels, *([in_size] * spatial_dims)),
69-
(1, out_channels, *([out_size] * spatial_dims)),
70-
(1, out_channels, *([in_size * stride] * spatial_dims)),
71-
]
72-
TEST_UP_BLOCK.append(test_case)
49+
for params in dict_product(
50+
spatial_dims=range(2, 4),
51+
kernel_size=[1, 3],
52+
stride=[1, 2],
53+
norm_name=["batch", "instance"],
54+
in_size=[15, 16],
55+
trans_bias=[True, False],
56+
):
57+
out_size = params["in_size"] * params["stride"]
58+
test_case = [
59+
{
60+
**{k: v for k, v in params.items() if k != "in_size"},
61+
"in_channels": in_channels,
62+
"out_channels": out_channels,
63+
"upsample_kernel_size": params["stride"],
64+
},
65+
(1, in_channels, *([params["in_size"]] * params["spatial_dims"])),
66+
(1, out_channels, *([out_size] * params["spatial_dims"])),
67+
(1, out_channels, *([params["in_size"] * params["stride"]] * params["spatial_dims"])),
68+
]
69+
TEST_UP_BLOCK.append(test_case)
7370

7471

7572
class TestResBasicBlock(unittest.TestCase):

tests/networks/blocks/test_patchembedding.py

Lines changed: 32 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,58 +21,41 @@
2121
from monai.networks import eval_mode
2222
from monai.networks.blocks.patchembedding import PatchEmbed, PatchEmbeddingBlock
2323
from monai.utils import optional_import
24-
from tests.test_utils import SkipIfBeforePyTorchVersion
24+
from tests.test_utils import SkipIfBeforePyTorchVersion, dict_product
2525

2626
einops, has_einops = optional_import("einops")
2727

28-
TEST_CASE_PATCHEMBEDDINGBLOCK = []
29-
for dropout_rate in (0.5,):
30-
for in_channels in [1, 4]:
31-
for hidden_size in [96, 288]:
32-
for img_size in [32, 64]:
33-
for patch_size in [8, 16]:
34-
for num_heads in [8, 12]:
35-
for proj_type in ["conv", "perceptron"]:
36-
for pos_embed_type in ["none", "learnable", "sincos"]:
37-
# for classification in (False, True): # TODO: add classification tests
38-
for nd in (2, 3):
39-
test_case = [
40-
{
41-
"in_channels": in_channels,
42-
"img_size": (img_size,) * nd,
43-
"patch_size": (patch_size,) * nd,
44-
"hidden_size": hidden_size,
45-
"num_heads": num_heads,
46-
"proj_type": proj_type,
47-
"pos_embed_type": pos_embed_type,
48-
"dropout_rate": dropout_rate,
49-
},
50-
(2, in_channels, *([img_size] * nd)),
51-
(2, (img_size // patch_size) ** nd, hidden_size),
52-
]
53-
if nd == 2:
54-
test_case[0]["spatial_dims"] = 2 # type: ignore
55-
TEST_CASE_PATCHEMBEDDINGBLOCK.append(test_case)
56-
57-
TEST_CASE_PATCHEMBED = []
58-
for patch_size in [2]:
59-
for in_chans in [1, 4]:
60-
for img_size in [96]:
61-
for embed_dim in [6, 12]:
62-
for norm_layer in [nn.LayerNorm]:
63-
for nd in [2, 3]:
64-
test_case = [
65-
{
66-
"patch_size": (patch_size,) * nd,
67-
"in_chans": in_chans,
68-
"embed_dim": embed_dim,
69-
"norm_layer": norm_layer,
70-
"spatial_dims": nd,
71-
},
72-
(2, in_chans, *([img_size] * nd)),
73-
(2, embed_dim, *([img_size // patch_size] * nd)),
74-
]
75-
TEST_CASE_PATCHEMBED.append(test_case)
28+
29+
TEST_CASE_PATCHEMBEDDINGBLOCK = [
30+
[
31+
params,
32+
(2, params["in_channels"], *([params["img_size"]] * params["spatial_dims"])),
33+
(2, (params["img_size"] // params["patch_size"]) ** params["spatial_dims"], params["hidden_size"]),
34+
]
35+
for params in dict_product(
36+
dropout_rate=[0.5],
37+
in_channels=[1, 4],
38+
hidden_size=[96, 288],
39+
img_size=[32, 64],
40+
patch_size=[8, 16],
41+
num_heads=[8, 12],
42+
proj_type=["conv", "perceptron"],
43+
pos_embed_type=["none", "learnable", "sincos"],
44+
spatial_dims=[2, 3],
45+
)
46+
]
47+
48+
img_size = 96
49+
TEST_CASE_PATCHEMBED = [
50+
[
51+
params,
52+
(2, params["in_chans"], *([img_size] * params["spatial_dims"])),
53+
(2, params["embed_dim"], *([img_size // params["patch_size"]]) * params["spatial_dims"]),
54+
]
55+
for params in dict_product(
56+
patch_size=[2], in_chans=[1, 4], embed_dim=[6, 12], norm_layer=[nn.LayerNorm], spatial_dims=[2, 3]
57+
)
58+
]
7659

7760

7861
@SkipIfBeforePyTorchVersion((1, 11, 1))

tests/networks/blocks/test_segresnet_block.py

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,24 @@
1818

1919
from monai.networks import eval_mode
2020
from monai.networks.blocks.segresnet_block import ResBlock
21-
22-
TEST_CASE_RESBLOCK = []
23-
for spatial_dims in range(2, 4):
24-
for in_channels in range(1, 4):
25-
for kernel_size in [1, 3]:
26-
for norm in [("group", {"num_groups": 1}), "batch", "instance"]:
27-
test_case = [
28-
{
29-
"spatial_dims": spatial_dims,
30-
"in_channels": in_channels,
31-
"kernel_size": kernel_size,
32-
"norm": norm,
33-
},
34-
(2, in_channels, *([16] * spatial_dims)),
35-
(2, in_channels, *([16] * spatial_dims)),
36-
]
37-
TEST_CASE_RESBLOCK.append(test_case)
21+
from tests.test_utils import dict_product
22+
23+
TEST_CASE_RESBLOCK = [
24+
[
25+
params,
26+
(2, params["in_channels"], *([16] * params["spatial_dims"])),
27+
(2, params["in_channels"], *([16] * params["spatial_dims"])),
28+
]
29+
for params in dict_product(
30+
spatial_dims=range(2, 4),
31+
in_channels=range(1, 4),
32+
kernel_size=[1, 3],
33+
norm=[("group", {"num_groups": 1}), "batch", "instance"],
34+
)
35+
]
3836

3937

4038
class TestResBlock(unittest.TestCase):
41-
4239
@parameterized.expand(TEST_CASE_RESBLOCK)
4340
def test_shape(self, input_param, input_shape, expected_shape):
4441
net = ResBlock(**input_param)

0 commit comments

Comments
 (0)