Skip to content

Commit 49a1e34

Browse files
7994-enhance-mlpblock (#7995)
Fixes #7994 . ### Description The current implementation does not support tuple input of "GEGLU" since it only change the out features of the first linear layer when the input is a string of "GEGLU". This PR enhances it, and also enable "vista3d" mode to support #7987 Tests are added to cover the changes. ### 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). - [x] New tests added to cover the changes. - [ ] Integration tests passed locally by running `./runtests.sh -f -u --net --coverage`. - [ ] Quick tests passed locally by running `./runtests.sh --quick --unittests --disttests`. - [x] In-line docstrings updated. - [ ] Documentation updated, tested `make html` command in the `docs/` folder. --------- Signed-off-by: Yiheng Wang <vennw@nvidia.com> Signed-off-by: YunLiu <55491388+KumoLiu@users.noreply.github.com> Co-authored-by: YunLiu <55491388+KumoLiu@users.noreply.github.com>
1 parent 6c23fd0 commit 49a1e34

3 files changed

Lines changed: 45 additions & 4 deletions

File tree

.github/workflows/pythonapp.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ jobs:
9999
name: Install itk pre-release (Linux only)
100100
run: |
101101
python -m pip install --pre -U itk
102+
find /opt/hostedtoolcache/* -maxdepth 0 ! -name 'Python' -exec rm -rf {} \;
102103
- name: Install the dependencies
103104
run: |
104105
python -m pip install --user --upgrade pip wheel

monai/networks/blocks/mlp.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,15 @@
1111

1212
from __future__ import annotations
1313

14+
from typing import Union
15+
1416
import torch.nn as nn
1517

1618
from monai.networks.layers import get_act_layer
19+
from monai.networks.layers.factories import split_args
1720
from monai.utils import look_up_option
1821

19-
SUPPORTED_DROPOUT_MODE = {"vit", "swin"}
22+
SUPPORTED_DROPOUT_MODE = {"vit", "swin", "vista3d"}
2023

2124

2225
class MLPBlock(nn.Module):
@@ -39,7 +42,7 @@ def __init__(
3942
https://github.com/google-research/vision_transformer/blob/main/vit_jax/models.py#L87
4043
"swin" corresponds to one instance as implemented in
4144
https://github.com/microsoft/Swin-Transformer/blob/main/models/swin_mlp.py#L23
42-
45+
"vista3d" mode does not use dropout.
4346
4447
"""
4548

@@ -48,15 +51,24 @@ def __init__(
4851
if not (0 <= dropout_rate <= 1):
4952
raise ValueError("dropout_rate should be between 0 and 1.")
5053
mlp_dim = mlp_dim or hidden_size
51-
self.linear1 = nn.Linear(hidden_size, mlp_dim) if act != "GEGLU" else nn.Linear(hidden_size, mlp_dim * 2)
54+
act_name, _ = split_args(act)
55+
self.linear1 = nn.Linear(hidden_size, mlp_dim) if act_name != "GEGLU" else nn.Linear(hidden_size, mlp_dim * 2)
5256
self.linear2 = nn.Linear(mlp_dim, hidden_size)
5357
self.fn = get_act_layer(act)
54-
self.drop1 = nn.Dropout(dropout_rate)
58+
# Use Union[nn.Dropout, nn.Identity] for type annotations
59+
self.drop1: Union[nn.Dropout, nn.Identity]
60+
self.drop2: Union[nn.Dropout, nn.Identity]
61+
5562
dropout_opt = look_up_option(dropout_mode, SUPPORTED_DROPOUT_MODE)
5663
if dropout_opt == "vit":
64+
self.drop1 = nn.Dropout(dropout_rate)
5765
self.drop2 = nn.Dropout(dropout_rate)
5866
elif dropout_opt == "swin":
67+
self.drop1 = nn.Dropout(dropout_rate)
5968
self.drop2 = self.drop1
69+
elif dropout_opt == "vista3d":
70+
self.drop1 = nn.Identity()
71+
self.drop2 = nn.Identity()
6072
else:
6173
raise ValueError(f"dropout_mode should be one of {SUPPORTED_DROPOUT_MODE}")
6274

tests/test_mlp.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515

1616
import numpy as np
1717
import torch
18+
import torch.nn as nn
1819
from parameterized import parameterized
1920

2021
from monai.networks import eval_mode
2122
from monai.networks.blocks.mlp import MLPBlock
23+
from monai.networks.layers.factories import split_args
2224

2325
TEST_CASE_MLP = []
2426
for dropout_rate in np.linspace(0, 1, 4):
@@ -31,6 +33,14 @@
3133
]
3234
TEST_CASE_MLP.append(test_case)
3335

36+
# test different activation layers
37+
TEST_CASE_ACT = []
38+
for act in ["GELU", "GEGLU", ("GEGLU", {})]: # type: ignore
39+
TEST_CASE_ACT.append([{"hidden_size": 128, "mlp_dim": 0, "act": act}, (2, 512, 128), (2, 512, 128)])
40+
41+
# test different dropout modes
42+
TEST_CASE_DROP = [["vit", nn.Dropout], ["swin", nn.Dropout], ["vista3d", nn.Identity]]
43+
3444

3545
class TestMLPBlock(unittest.TestCase):
3646

@@ -45,6 +55,24 @@ def test_ill_arg(self):
4555
with self.assertRaises(ValueError):
4656
MLPBlock(hidden_size=128, mlp_dim=512, dropout_rate=5.0)
4757

58+
@parameterized.expand(TEST_CASE_ACT)
59+
def test_act(self, input_param, input_shape, expected_shape):
60+
net = MLPBlock(**input_param)
61+
with eval_mode(net):
62+
result = net(torch.randn(input_shape))
63+
self.assertEqual(result.shape, expected_shape)
64+
act_name, _ = split_args(input_param["act"])
65+
if act_name == "GEGLU":
66+
self.assertEqual(net.linear1.in_features, net.linear1.out_features // 2)
67+
else:
68+
self.assertEqual(net.linear1.in_features, net.linear1.out_features)
69+
70+
@parameterized.expand(TEST_CASE_DROP)
71+
def test_dropout_mode(self, dropout_mode, dropout_layer):
72+
net = MLPBlock(hidden_size=128, mlp_dim=512, dropout_rate=0.1, dropout_mode=dropout_mode)
73+
self.assertTrue(isinstance(net.drop1, dropout_layer))
74+
self.assertTrue(isinstance(net.drop2, dropout_layer))
75+
4876

4977
if __name__ == "__main__":
5078
unittest.main()

0 commit comments

Comments
 (0)