We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add Padding as an Argument to AutoEncoder
**Is your feature request related to a problem? Please describe.**
In the current implementation of the AutoEncoder class in the `monai.networks.nets` module, the padding parameter is not customizable. This limits the model's flexibility, as different padding strategies might suit different data-sizes. 
https://github.com/Project-MONAI/MONAI/blob/18a671a7f12389dd8263a4c2232196dcca814bb9/monai/networks/nets/autoencoder.py#L90

**Describe the solution you'd like**
I would like to propose adding a padding argument to the AutoEncoder class constructor. This would allow users to specify the padding strategy when instantiating the model. 

**Describe alternatives you've considered**
An alternative solution could be to create a subclass of AutoEncoder (like CustomAE) whenever a different padding strategy is needed. See below,
```{python}
class CustomAE(AutoEncoder):
    def __init__(self, padding, **kwargs):
        self.padding = padding
        super().__init__(**kwargs)
    
    def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Module:
        # ...
        mod = Convolution(
            spatial_dims=self.dimensions,
            in_channels=in_channels,
            out_channels=out_channels,
            strides=strides,
            kernel_size=self.kernel_size,
            padding=self.padding,
            # ...
        )
        return mod

```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `monai/networks/nets/autoencoder.py`
Content:
```
1 # Copyright (c) MONAI Consortium
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 #     http://www.apache.org/licenses/LICENSE-2.0
6 # Unless required by applicable law or agreed to in writing, software
7 # distributed under the License is distributed on an "AS IS" BASIS,
8 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 # See the License for the specific language governing permissions and
10 # limitations under the License.
11 
12 from __future__ import annotations
13 
14 from collections.abc import Sequence
15 from typing import Any
16 
17 import torch
18 import torch.nn as nn
19 
20 from monai.networks.blocks import Convolution, ResidualUnit
21 from monai.networks.layers.factories import Act, Norm
22 
23 __all__ = ["AutoEncoder"]
24 
25 
26 class AutoEncoder(nn.Module):
27     """
28     Simple definition of an autoencoder and base class for the architecture implementing
29     :py:class:`monai.networks.nets.VarAutoEncoder`. The network is composed of an encode sequence of blocks, followed
30     by an intermediary sequence of blocks, and finally a decode sequence of blocks. The encode and decode blocks are
31     default :py:class:`monai.networks.blocks.Convolution` instances with the encode blocks having the given stride
32     and the decode blocks having transpose convolutions with the same stride. If `num_res_units` is given residual
33     blocks are used instead.
34 
35     By default the intermediary sequence is empty but if `inter_channels` is given to specify the output channels of
36     blocks then this will be become a sequence of Convolution blocks or of residual blocks if `num_inter_units` is
37     given. The optional parameter `inter_dilations` can be used to specify the dilation values of the convolutions in
38     these blocks, this allows a network to use dilated kernels in this  middle section. Since the intermediary section
39     isn't meant to change the size of the output the strides for all these kernels is 1.
40 
41     Args:
42         spatial_dims: number of spatial dimensions.
43         in_channels: number of input channels.
44         out_channels: number of output channels.
45         channels: sequence of channels. Top block first. The length of `channels` should be no less than 2.
46         strides: sequence of convolution strides. The length of `stride` should equal to `len(channels) - 1`.
47         kernel_size: convolution kernel size, the value(s) should be odd. If sequence,
48             its length should equal to dimensions. Defaults to 3.
49         up_kernel_size: upsampling convolution kernel size, the value(s) should be odd. If sequence,
50             its length should equal to dimensions. Defaults to 3.
51         num_res_units: number of residual units. Defaults to 0.
52         inter_channels: sequence of channels defining the blocks in the intermediate layer between encode and decode.
53         inter_dilations: defines the dilation value for each block of the intermediate layer. Defaults to 1.
54         num_inter_units: number of residual units for each block of the intermediate layer. Defaults to 0.
55         act: activation type and arguments. Defaults to PReLU.
56         norm: feature normalization type and arguments. Defaults to instance norm.
57         dropout: dropout ratio. Defaults to no dropout.
58         bias: whether to have a bias term in convolution blocks. Defaults to True.
59             According to `Performance Tuning Guide <https://pytorch.org/tutorials/recipes/recipes/tuning_guide.html>`_,
60             if a conv layer is directly followed by a batch norm layer, bias should be False.
61 
62     Examples::
63 
64         from monai.networks.nets import AutoEncoder
65 
66         # 3 layers each down/up sampling their inputs by a factor 2 with no intermediate layer
67         net = AutoEncoder(
68             spatial_dims=2,
69             in_channels=1,
70             out_channels=1,
71             channels=(2, 4, 8),
72             strides=(2, 2, 2)
73         )
74 
75         # 1 layer downsampling by 2, followed by a sequence of residual units with 2 convolutions defined by
76         # progressively increasing dilations, then final upsample layer
77         net = AutoEncoder(
78                 spatial_dims=2,
79                 in_channels=1,
80                 out_channels=1,
81                 channels=(4,),
82                 strides=(2,),
83                 inter_channels=(8, 8, 8),
84                 inter_dilations=(1, 2, 4),
85                 num_inter_units=2
86             )
87 
88     """
89 
90     def __init__(
91         self,
92         spatial_dims: int,
93         in_channels: int,
94         out_channels: int,
95         channels: Sequence[int],
96         strides: Sequence[int],
97         kernel_size: Sequence[int] | int = 3,
98         up_kernel_size: Sequence[int] | int = 3,
99         num_res_units: int = 0,
100         inter_channels: list | None = None,
101         inter_dilations: list | None = None,
102         num_inter_units: int = 2,
103         act: tuple | str | None = Act.PRELU,
104         norm: tuple | str = Norm.INSTANCE,
105         dropout: tuple | str | float | None = None,
106         bias: bool = True,
107     ) -> None:
108         super().__init__()
109         self.dimensions = spatial_dims
110         self.in_channels = in_channels
111         self.out_channels = out_channels
112         self.channels = list(channels)
113         self.strides = list(strides)
114         self.kernel_size = kernel_size
115         self.up_kernel_size = up_kernel_size
116         self.num_res_units = num_res_units
117         self.act = act
118         self.norm = norm
119         self.dropout = dropout
120         self.bias = bias
121         self.num_inter_units = num_inter_units
122         self.inter_channels = inter_channels if inter_channels is not None else []
123         self.inter_dilations = list(inter_dilations or [1] * len(self.inter_channels))
124 
125         # The number of channels and strides should match
126         if len(channels) != len(strides):
127             raise ValueError("Autoencoder expects matching number of channels and strides")
128 
129         self.encoded_channels = in_channels
130         decode_channel_list = list(channels[-2::-1]) + [out_channels]
131 
132         self.encode, self.encoded_channels = self._get_encode_module(self.encoded_channels, channels, strides)
133         self.intermediate, self.encoded_channels = self._get_intermediate_module(self.encoded_channels, num_inter_units)
134         self.decode, _ = self._get_decode_module(self.encoded_channels, decode_channel_list, strides[::-1] or [1])
135 
136     def _get_encode_module(
137         self, in_channels: int, channels: Sequence[int], strides: Sequence[int]
138     ) -> tuple[nn.Sequential, int]:
139         """
140         Returns the encode part of the network by building up a sequence of layers returned by `_get_encode_layer`.
141         """
142         encode = nn.Sequential()
143         layer_channels = in_channels
144 
145         for i, (c, s) in enumerate(zip(channels, strides)):
146             layer = self._get_encode_layer(layer_channels, c, s, False)
147             encode.add_module("encode_%i" % i, layer)
148             layer_channels = c
149 
150         return encode, layer_channels
151 
152     def _get_intermediate_module(self, in_channels: int, num_inter_units: int) -> tuple[nn.Module, int]:
153         """
154         Returns the intermediate block of the network which accepts input from the encoder and whose output goes
155         to the decoder.
156         """
157         # Define some types
158         intermediate: nn.Module
159         unit: nn.Module
160 
161         intermediate = nn.Identity()
162         layer_channels = in_channels
163 
164         if self.inter_channels:
165             intermediate = nn.Sequential()
166 
167             for i, (dc, di) in enumerate(zip(self.inter_channels, self.inter_dilations)):
168                 if self.num_inter_units > 0:
169                     unit = ResidualUnit(
170                         spatial_dims=self.dimensions,
171                         in_channels=layer_channels,
172                         out_channels=dc,
173                         strides=1,
174                         kernel_size=self.kernel_size,
175                         subunits=self.num_inter_units,
176                         act=self.act,
177                         norm=self.norm,
178                         dropout=self.dropout,
179                         dilation=di,
180                         bias=self.bias,
181                     )
182                 else:
183                     unit = Convolution(
184                         spatial_dims=self.dimensions,
185                         in_channels=layer_channels,
186                         out_channels=dc,
187                         strides=1,
188                         kernel_size=self.kernel_size,
189                         act=self.act,
190                         norm=self.norm,
191                         dropout=self.dropout,
192                         dilation=di,
193                         bias=self.bias,
194                     )
195 
196                 intermediate.add_module("inter_%i" % i, unit)
197                 layer_channels = dc
198 
199         return intermediate, layer_channels
200 
201     def _get_decode_module(
202         self, in_channels: int, channels: Sequence[int], strides: Sequence[int]
203     ) -> tuple[nn.Sequential, int]:
204         """
205         Returns the decode part of the network by building up a sequence of layers returned by `_get_decode_layer`.
206         """
207         decode = nn.Sequential()
208         layer_channels = in_channels
209 
210         for i, (c, s) in enumerate(zip(channels, strides)):
211             layer = self._get_decode_layer(layer_channels, c, s, i == (len(strides) - 1))
212             decode.add_module("decode_%i" % i, layer)
213             layer_channels = c
214 
215         return decode, layer_channels
216 
217     def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Module:
218         """
219         Returns a single layer of the encoder part of the network.
220         """
221         mod: nn.Module
222         if self.num_res_units > 0:
223             mod = ResidualUnit(
224                 spatial_dims=self.dimensions,
225                 in_channels=in_channels,
226                 out_channels=out_channels,
227                 strides=strides,
228                 kernel_size=self.kernel_size,
229                 subunits=self.num_res_units,
230                 act=self.act,
231                 norm=self.norm,
232                 dropout=self.dropout,
233                 bias=self.bias,
234                 last_conv_only=is_last,
235             )
236             return mod
237         mod = Convolution(
238             spatial_dims=self.dimensions,
239             in_channels=in_channels,
240             out_channels=out_channels,
241             strides=strides,
242             kernel_size=self.kernel_size,
243             act=self.act,
244             norm=self.norm,
245             dropout=self.dropout,
246             bias=self.bias,
247             conv_only=is_last,
248         )
249         return mod
250 
251     def _get_decode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Sequential:
252         """
253         Returns a single layer of the decoder part of the network.
254         """
255         decode = nn.Sequential()
256 
257         conv = Convolution(
258             spatial_dims=self.dimensions,
259             in_channels=in_channels,
260             out_channels=out_channels,
261             strides=strides,
262             kernel_size=self.up_kernel_size,
263             act=self.act,
264             norm=self.norm,
265             dropout=self.dropout,
266             bias=self.bias,
267             conv_only=is_last and self.num_res_units == 0,
268             is_transposed=True,
269         )
270 
271         decode.add_module("conv", conv)
272 
273         if self.num_res_units > 0:
274             ru = ResidualUnit(
275                 spatial_dims=self.dimensions,
276                 in_channels=out_channels,
277                 out_channels=out_channels,
278                 strides=1,
279                 kernel_size=self.kernel_size,
280                 subunits=1,
281                 act=self.act,
282                 norm=self.norm,
283                 dropout=self.dropout,
284                 bias=self.bias,
285                 last_conv_only=is_last,
286             )
287 
288             decode.add_module("resunit", ru)
289 
290         return decode
291 
292     def forward(self, x: torch.Tensor) -> Any:
293         x = self.encode(x)
294         x = self.intermediate(x)
295         x = self.decode(x)
296         return x
297
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/monai/networks/nets/autoencoder.py b/monai/networks/nets/autoencoder.py
--- a/monai/networks/nets/autoencoder.py
+++ b/monai/networks/nets/autoencoder.py
@@ -58,6 +58,8 @@
         bias: whether to have a bias term in convolution blocks. Defaults to True.
             According to `Performance Tuning Guide <https://pytorch.org/tutorials/recipes/recipes/tuning_guide.html>`_,
             if a conv layer is directly followed by a batch norm layer, bias should be False.
+        padding: controls the amount of implicit zero-paddings on both sides for padding number of points
+            for each dimension in convolution blocks. Defaults to None.
 
     Examples::
 
@@ -104,6 +106,7 @@
         norm: tuple | str = Norm.INSTANCE,
         dropout: tuple | str | float | None = None,
         bias: bool = True,
+        padding: Sequence[int] | int | None = None,
     ) -> None:
         super().__init__()
         self.dimensions = spatial_dims
@@ -118,6 +121,7 @@
         self.norm = norm
         self.dropout = dropout
         self.bias = bias
+        self.padding = padding
         self.num_inter_units = num_inter_units
         self.inter_channels = inter_channels if inter_channels is not None else []
         self.inter_dilations = list(inter_dilations or [1] * len(self.inter_channels))
@@ -178,6 +182,7 @@
                         dropout=self.dropout,
                         dilation=di,
                         bias=self.bias,
+                        padding=self.padding,
                     )
                 else:
                     unit = Convolution(
@@ -191,6 +196,7 @@
                         dropout=self.dropout,
                         dilation=di,
                         bias=self.bias,
+                        padding=self.padding,
                     )
 
                 intermediate.add_module("inter_%i" % i, unit)
@@ -231,6 +237,7 @@
                 norm=self.norm,
                 dropout=self.dropout,
                 bias=self.bias,
+                padding=self.padding,
                 last_conv_only=is_last,
             )
             return mod
@@ -244,6 +251,7 @@
             norm=self.norm,
             dropout=self.dropout,
             bias=self.bias,
+            padding=self.padding,
             conv_only=is_last,
         )
         return mod
@@ -264,6 +272,7 @@
             norm=self.norm,
             dropout=self.dropout,
             bias=self.bias,
+            padding=self.padding,
             conv_only=is_last and self.num_res_units == 0,
             is_transposed=True,
         )
@@ -282,6 +291,7 @@
                 norm=self.norm,
                 dropout=self.dropout,
                 bias=self.bias,
+                padding=self.padding,
                 last_conv_only=is_last,
             )

{"golden_diff": "diff --git a/monai/networks/nets/autoencoder.py b/monai/networks/nets/autoencoder.py\n--- a/monai/networks/nets/autoencoder.py\n+++ b/monai/networks/nets/autoencoder.py\n@@ -58,6 +58,8 @@\n         bias: whether to have a bias term in convolution blocks. Defaults to True.\n             According to `Performance Tuning Guide <https://pytorch.org/tutorials/recipes/recipes/tuning_guide.html>`_,\n             if a conv layer is directly followed by a batch norm layer, bias should be False.\n+        padding: controls the amount of implicit zero-paddings on both sides for padding number of points\n+            for each dimension in convolution blocks. Defaults to None.\n \n     Examples::\n \n@@ -104,6 +106,7 @@\n         norm: tuple | str = Norm.INSTANCE,\n         dropout: tuple | str | float | None = None,\n         bias: bool = True,\n+        padding: Sequence[int] | int | None = None,\n     ) -> None:\n         super().__init__()\n         self.dimensions = spatial_dims\n@@ -118,6 +121,7 @@\n         self.norm = norm\n         self.dropout = dropout\n         self.bias = bias\n+        self.padding = padding\n         self.num_inter_units = num_inter_units\n         self.inter_channels = inter_channels if inter_channels is not None else []\n         self.inter_dilations = list(inter_dilations or [1] * len(self.inter_channels))\n@@ -178,6 +182,7 @@\n                         dropout=self.dropout,\n                         dilation=di,\n                         bias=self.bias,\n+                        padding=self.padding,\n                     )\n                 else:\n                     unit = Convolution(\n@@ -191,6 +196,7 @@\n                         dropout=self.dropout,\n                         dilation=di,\n                         bias=self.bias,\n+                        padding=self.padding,\n                     )\n \n                 intermediate.add_module(\"inter_%i\" % i, unit)\n@@ -231,6 +237,7 @@\n                 norm=self.norm,\n                 dropout=self.dropout,\n                 bias=self.bias,\n+                padding=self.padding,\n                 last_conv_only=is_last,\n             )\n             return mod\n@@ -244,6 +251,7 @@\n             norm=self.norm,\n             dropout=self.dropout,\n             bias=self.bias,\n+            padding=self.padding,\n             conv_only=is_last,\n         )\n         return mod\n@@ -264,6 +272,7 @@\n             norm=self.norm,\n             dropout=self.dropout,\n             bias=self.bias,\n+            padding=self.padding,\n             conv_only=is_last and self.num_res_units == 0,\n             is_transposed=True,\n         )\n@@ -282,6 +291,7 @@\n                 norm=self.norm,\n                 dropout=self.dropout,\n                 bias=self.bias,\n+                padding=self.padding,\n                 last_conv_only=is_last,\n             )\n", "issue": "Add Padding as an Argument to AutoEncoder\n**Is your feature request related to a problem? Please describe.**\r\nIn the current implementation of the AutoEncoder class in the `monai.networks.nets` module, the padding parameter is not customizable. This limits the model's flexibility, as different padding strategies might suit different data-sizes. \r\nhttps://github.com/Project-MONAI/MONAI/blob/18a671a7f12389dd8263a4c2232196dcca814bb9/monai/networks/nets/autoencoder.py#L90\r\n\r\n**Describe the solution you'd like**\r\nI would like to propose adding a padding argument to the AutoEncoder class constructor. This would allow users to specify the padding strategy when instantiating the model. \r\n\r\n**Describe alternatives you've considered**\r\nAn alternative solution could be to create a subclass of AutoEncoder (like CustomAE) whenever a different padding strategy is needed. See below,\r\n```{python}\r\nclass CustomAE(AutoEncoder):\r\n    def __init__(self, padding, **kwargs):\r\n        self.padding = padding\r\n        super().__init__(**kwargs)\r\n    \r\n    def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Module:\r\n        # ...\r\n        mod = Convolution(\r\n            spatial_dims=self.dimensions,\r\n            in_channels=in_channels,\r\n            out_channels=out_channels,\r\n            strides=strides,\r\n            kernel_size=self.kernel_size,\r\n            padding=self.padding,\r\n            # ...\r\n        )\r\n        return mod\r\n\r\n```\r\n\n", "before_files": [{"content": "# Copyright (c) MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom __future__ import annotations\n\nfrom collections.abc import Sequence\nfrom typing import Any\n\nimport torch\nimport torch.nn as nn\n\nfrom monai.networks.blocks import Convolution, ResidualUnit\nfrom monai.networks.layers.factories import Act, Norm\n\n__all__ = [\"AutoEncoder\"]\n\n\nclass AutoEncoder(nn.Module):\n    \"\"\"\n    Simple definition of an autoencoder and base class for the architecture implementing\n    :py:class:`monai.networks.nets.VarAutoEncoder`. The network is composed of an encode sequence of blocks, followed\n    by an intermediary sequence of blocks, and finally a decode sequence of blocks. The encode and decode blocks are\n    default :py:class:`monai.networks.blocks.Convolution` instances with the encode blocks having the given stride\n    and the decode blocks having transpose convolutions with the same stride. If `num_res_units` is given residual\n    blocks are used instead.\n\n    By default the intermediary sequence is empty but if `inter_channels` is given to specify the output channels of\n    blocks then this will be become a sequence of Convolution blocks or of residual blocks if `num_inter_units` is\n    given. The optional parameter `inter_dilations` can be used to specify the dilation values of the convolutions in\n    these blocks, this allows a network to use dilated kernels in this  middle section. Since the intermediary section\n    isn't meant to change the size of the output the strides for all these kernels is 1.\n\n    Args:\n        spatial_dims: number of spatial dimensions.\n        in_channels: number of input channels.\n        out_channels: number of output channels.\n        channels: sequence of channels. Top block first. The length of `channels` should be no less than 2.\n        strides: sequence of convolution strides. The length of `stride` should equal to `len(channels) - 1`.\n        kernel_size: convolution kernel size, the value(s) should be odd. If sequence,\n            its length should equal to dimensions. Defaults to 3.\n        up_kernel_size: upsampling convolution kernel size, the value(s) should be odd. If sequence,\n            its length should equal to dimensions. Defaults to 3.\n        num_res_units: number of residual units. Defaults to 0.\n        inter_channels: sequence of channels defining the blocks in the intermediate layer between encode and decode.\n        inter_dilations: defines the dilation value for each block of the intermediate layer. Defaults to 1.\n        num_inter_units: number of residual units for each block of the intermediate layer. Defaults to 0.\n        act: activation type and arguments. Defaults to PReLU.\n        norm: feature normalization type and arguments. Defaults to instance norm.\n        dropout: dropout ratio. Defaults to no dropout.\n        bias: whether to have a bias term in convolution blocks. Defaults to True.\n            According to `Performance Tuning Guide <https://pytorch.org/tutorials/recipes/recipes/tuning_guide.html>`_,\n            if a conv layer is directly followed by a batch norm layer, bias should be False.\n\n    Examples::\n\n        from monai.networks.nets import AutoEncoder\n\n        # 3 layers each down/up sampling their inputs by a factor 2 with no intermediate layer\n        net = AutoEncoder(\n            spatial_dims=2,\n            in_channels=1,\n            out_channels=1,\n            channels=(2, 4, 8),\n            strides=(2, 2, 2)\n        )\n\n        # 1 layer downsampling by 2, followed by a sequence of residual units with 2 convolutions defined by\n        # progressively increasing dilations, then final upsample layer\n        net = AutoEncoder(\n                spatial_dims=2,\n                in_channels=1,\n                out_channels=1,\n                channels=(4,),\n                strides=(2,),\n                inter_channels=(8, 8, 8),\n                inter_dilations=(1, 2, 4),\n                num_inter_units=2\n            )\n\n    \"\"\"\n\n    def __init__(\n        self,\n        spatial_dims: int,\n        in_channels: int,\n        out_channels: int,\n        channels: Sequence[int],\n        strides: Sequence[int],\n        kernel_size: Sequence[int] | int = 3,\n        up_kernel_size: Sequence[int] | int = 3,\n        num_res_units: int = 0,\n        inter_channels: list | None = None,\n        inter_dilations: list | None = None,\n        num_inter_units: int = 2,\n        act: tuple | str | None = Act.PRELU,\n        norm: tuple | str = Norm.INSTANCE,\n        dropout: tuple | str | float | None = None,\n        bias: bool = True,\n    ) -> None:\n        super().__init__()\n        self.dimensions = spatial_dims\n        self.in_channels = in_channels\n        self.out_channels = out_channels\n        self.channels = list(channels)\n        self.strides = list(strides)\n        self.kernel_size = kernel_size\n        self.up_kernel_size = up_kernel_size\n        self.num_res_units = num_res_units\n        self.act = act\n        self.norm = norm\n        self.dropout = dropout\n        self.bias = bias\n        self.num_inter_units = num_inter_units\n        self.inter_channels = inter_channels if inter_channels is not None else []\n        self.inter_dilations = list(inter_dilations or [1] * len(self.inter_channels))\n\n        # The number of channels and strides should match\n        if len(channels) != len(strides):\n            raise ValueError(\"Autoencoder expects matching number of channels and strides\")\n\n        self.encoded_channels = in_channels\n        decode_channel_list = list(channels[-2::-1]) + [out_channels]\n\n        self.encode, self.encoded_channels = self._get_encode_module(self.encoded_channels, channels, strides)\n        self.intermediate, self.encoded_channels = self._get_intermediate_module(self.encoded_channels, num_inter_units)\n        self.decode, _ = self._get_decode_module(self.encoded_channels, decode_channel_list, strides[::-1] or [1])\n\n    def _get_encode_module(\n        self, in_channels: int, channels: Sequence[int], strides: Sequence[int]\n    ) -> tuple[nn.Sequential, int]:\n        \"\"\"\n        Returns the encode part of the network by building up a sequence of layers returned by `_get_encode_layer`.\n        \"\"\"\n        encode = nn.Sequential()\n        layer_channels = in_channels\n\n        for i, (c, s) in enumerate(zip(channels, strides)):\n            layer = self._get_encode_layer(layer_channels, c, s, False)\n            encode.add_module(\"encode_%i\" % i, layer)\n            layer_channels = c\n\n        return encode, layer_channels\n\n    def _get_intermediate_module(self, in_channels: int, num_inter_units: int) -> tuple[nn.Module, int]:\n        \"\"\"\n        Returns the intermediate block of the network which accepts input from the encoder and whose output goes\n        to the decoder.\n        \"\"\"\n        # Define some types\n        intermediate: nn.Module\n        unit: nn.Module\n\n        intermediate = nn.Identity()\n        layer_channels = in_channels\n\n        if self.inter_channels:\n            intermediate = nn.Sequential()\n\n            for i, (dc, di) in enumerate(zip(self.inter_channels, self.inter_dilations)):\n                if self.num_inter_units > 0:\n                    unit = ResidualUnit(\n                        spatial_dims=self.dimensions,\n                        in_channels=layer_channels,\n                        out_channels=dc,\n                        strides=1,\n                        kernel_size=self.kernel_size,\n                        subunits=self.num_inter_units,\n                        act=self.act,\n                        norm=self.norm,\n                        dropout=self.dropout,\n                        dilation=di,\n                        bias=self.bias,\n                    )\n                else:\n                    unit = Convolution(\n                        spatial_dims=self.dimensions,\n                        in_channels=layer_channels,\n                        out_channels=dc,\n                        strides=1,\n                        kernel_size=self.kernel_size,\n                        act=self.act,\n                        norm=self.norm,\n                        dropout=self.dropout,\n                        dilation=di,\n                        bias=self.bias,\n                    )\n\n                intermediate.add_module(\"inter_%i\" % i, unit)\n                layer_channels = dc\n\n        return intermediate, layer_channels\n\n    def _get_decode_module(\n        self, in_channels: int, channels: Sequence[int], strides: Sequence[int]\n    ) -> tuple[nn.Sequential, int]:\n        \"\"\"\n        Returns the decode part of the network by building up a sequence of layers returned by `_get_decode_layer`.\n        \"\"\"\n        decode = nn.Sequential()\n        layer_channels = in_channels\n\n        for i, (c, s) in enumerate(zip(channels, strides)):\n            layer = self._get_decode_layer(layer_channels, c, s, i == (len(strides) - 1))\n            decode.add_module(\"decode_%i\" % i, layer)\n            layer_channels = c\n\n        return decode, layer_channels\n\n    def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Module:\n        \"\"\"\n        Returns a single layer of the encoder part of the network.\n        \"\"\"\n        mod: nn.Module\n        if self.num_res_units > 0:\n            mod = ResidualUnit(\n                spatial_dims=self.dimensions,\n                in_channels=in_channels,\n                out_channels=out_channels,\n                strides=strides,\n                kernel_size=self.kernel_size,\n                subunits=self.num_res_units,\n                act=self.act,\n                norm=self.norm,\n                dropout=self.dropout,\n                bias=self.bias,\n                last_conv_only=is_last,\n            )\n            return mod\n        mod = Convolution(\n            spatial_dims=self.dimensions,\n            in_channels=in_channels,\n            out_channels=out_channels,\n            strides=strides,\n            kernel_size=self.kernel_size,\n            act=self.act,\n            norm=self.norm,\n            dropout=self.dropout,\n            bias=self.bias,\n            conv_only=is_last,\n        )\n        return mod\n\n    def _get_decode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Sequential:\n        \"\"\"\n        Returns a single layer of the decoder part of the network.\n        \"\"\"\n        decode = nn.Sequential()\n\n        conv = Convolution(\n            spatial_dims=self.dimensions,\n            in_channels=in_channels,\n            out_channels=out_channels,\n            strides=strides,\n            kernel_size=self.up_kernel_size,\n            act=self.act,\n            norm=self.norm,\n            dropout=self.dropout,\n            bias=self.bias,\n            conv_only=is_last and self.num_res_units == 0,\n            is_transposed=True,\n        )\n\n        decode.add_module(\"conv\", conv)\n\n        if self.num_res_units > 0:\n            ru = ResidualUnit(\n                spatial_dims=self.dimensions,\n                in_channels=out_channels,\n                out_channels=out_channels,\n                strides=1,\n                kernel_size=self.kernel_size,\n                subunits=1,\n                act=self.act,\n                norm=self.norm,\n                dropout=self.dropout,\n                bias=self.bias,\n                last_conv_only=is_last,\n            )\n\n            decode.add_module(\"resunit\", ru)\n\n        return decode\n\n    def forward(self, x: torch.Tensor) -> Any:\n        x = self.encode(x)\n        x = self.intermediate(x)\n        x = self.decode(x)\n        return x\n", "path": "monai/networks/nets/autoencoder.py"}], "after_files": [{"content": "# Copyright (c) MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom __future__ import annotations\n\nfrom collections.abc import Sequence\nfrom typing import Any\n\nimport torch\nimport torch.nn as nn\n\nfrom monai.networks.blocks import Convolution, ResidualUnit\nfrom monai.networks.layers.factories import Act, Norm\n\n__all__ = [\"AutoEncoder\"]\n\n\nclass AutoEncoder(nn.Module):\n    \"\"\"\n    Simple definition of an autoencoder and base class for the architecture implementing\n    :py:class:`monai.networks.nets.VarAutoEncoder`. The network is composed of an encode sequence of blocks, followed\n    by an intermediary sequence of blocks, and finally a decode sequence of blocks. The encode and decode blocks are\n    default :py:class:`monai.networks.blocks.Convolution` instances with the encode blocks having the given stride\n    and the decode blocks having transpose convolutions with the same stride. If `num_res_units` is given residual\n    blocks are used instead.\n\n    By default the intermediary sequence is empty but if `inter_channels` is given to specify the output channels of\n    blocks then this will be become a sequence of Convolution blocks or of residual blocks if `num_inter_units` is\n    given. The optional parameter `inter_dilations` can be used to specify the dilation values of the convolutions in\n    these blocks, this allows a network to use dilated kernels in this  middle section. Since the intermediary section\n    isn't meant to change the size of the output the strides for all these kernels is 1.\n\n    Args:\n        spatial_dims: number of spatial dimensions.\n        in_channels: number of input channels.\n        out_channels: number of output channels.\n        channels: sequence of channels. Top block first. The length of `channels` should be no less than 2.\n        strides: sequence of convolution strides. The length of `stride` should equal to `len(channels) - 1`.\n        kernel_size: convolution kernel size, the value(s) should be odd. If sequence,\n            its length should equal to dimensions. Defaults to 3.\n        up_kernel_size: upsampling convolution kernel size, the value(s) should be odd. If sequence,\n            its length should equal to dimensions. Defaults to 3.\n        num_res_units: number of residual units. Defaults to 0.\n        inter_channels: sequence of channels defining the blocks in the intermediate layer between encode and decode.\n        inter_dilations: defines the dilation value for each block of the intermediate layer. Defaults to 1.\n        num_inter_units: number of residual units for each block of the intermediate layer. Defaults to 0.\n        act: activation type and arguments. Defaults to PReLU.\n        norm: feature normalization type and arguments. Defaults to instance norm.\n        dropout: dropout ratio. Defaults to no dropout.\n        bias: whether to have a bias term in convolution blocks. Defaults to True.\n            According to `Performance Tuning Guide <https://pytorch.org/tutorials/recipes/recipes/tuning_guide.html>`_,\n            if a conv layer is directly followed by a batch norm layer, bias should be False.\n        padding: controls the amount of implicit zero-paddings on both sides for padding number of points\n            for each dimension in convolution blocks. Defaults to None.\n\n    Examples::\n\n        from monai.networks.nets import AutoEncoder\n\n        # 3 layers each down/up sampling their inputs by a factor 2 with no intermediate layer\n        net = AutoEncoder(\n            spatial_dims=2,\n            in_channels=1,\n            out_channels=1,\n            channels=(2, 4, 8),\n            strides=(2, 2, 2)\n        )\n\n        # 1 layer downsampling by 2, followed by a sequence of residual units with 2 convolutions defined by\n        # progressively increasing dilations, then final upsample layer\n        net = AutoEncoder(\n                spatial_dims=2,\n                in_channels=1,\n                out_channels=1,\n                channels=(4,),\n                strides=(2,),\n                inter_channels=(8, 8, 8),\n                inter_dilations=(1, 2, 4),\n                num_inter_units=2\n            )\n\n    \"\"\"\n\n    def __init__(\n        self,\n        spatial_dims: int,\n        in_channels: int,\n        out_channels: int,\n        channels: Sequence[int],\n        strides: Sequence[int],\n        kernel_size: Sequence[int] | int = 3,\n        up_kernel_size: Sequence[int] | int = 3,\n        num_res_units: int = 0,\n        inter_channels: list | None = None,\n        inter_dilations: list | None = None,\n        num_inter_units: int = 2,\n        act: tuple | str | None = Act.PRELU,\n        norm: tuple | str = Norm.INSTANCE,\n        dropout: tuple | str | float | None = None,\n        bias: bool = True,\n        padding: Sequence[int] | int | None = None,\n    ) -> None:\n        super().__init__()\n        self.dimensions = spatial_dims\n        self.in_channels = in_channels\n        self.out_channels = out_channels\n        self.channels = list(channels)\n        self.strides = list(strides)\n        self.kernel_size = kernel_size\n        self.up_kernel_size = up_kernel_size\n        self.num_res_units = num_res_units\n        self.act = act\n        self.norm = norm\n        self.dropout = dropout\n        self.bias = bias\n        self.padding = padding\n        self.num_inter_units = num_inter_units\n        self.inter_channels = inter_channels if inter_channels is not None else []\n        self.inter_dilations = list(inter_dilations or [1] * len(self.inter_channels))\n\n        # The number of channels and strides should match\n        if len(channels) != len(strides):\n            raise ValueError(\"Autoencoder expects matching number of channels and strides\")\n\n        self.encoded_channels = in_channels\n        decode_channel_list = list(channels[-2::-1]) + [out_channels]\n\n        self.encode, self.encoded_channels = self._get_encode_module(self.encoded_channels, channels, strides)\n        self.intermediate, self.encoded_channels = self._get_intermediate_module(self.encoded_channels, num_inter_units)\n        self.decode, _ = self._get_decode_module(self.encoded_channels, decode_channel_list, strides[::-1] or [1])\n\n    def _get_encode_module(\n        self, in_channels: int, channels: Sequence[int], strides: Sequence[int]\n    ) -> tuple[nn.Sequential, int]:\n        \"\"\"\n        Returns the encode part of the network by building up a sequence of layers returned by `_get_encode_layer`.\n        \"\"\"\n        encode = nn.Sequential()\n        layer_channels = in_channels\n\n        for i, (c, s) in enumerate(zip(channels, strides)):\n            layer = self._get_encode_layer(layer_channels, c, s, False)\n            encode.add_module(\"encode_%i\" % i, layer)\n            layer_channels = c\n\n        return encode, layer_channels\n\n    def _get_intermediate_module(self, in_channels: int, num_inter_units: int) -> tuple[nn.Module, int]:\n        \"\"\"\n        Returns the intermediate block of the network which accepts input from the encoder and whose output goes\n        to the decoder.\n        \"\"\"\n        # Define some types\n        intermediate: nn.Module\n        unit: nn.Module\n\n        intermediate = nn.Identity()\n        layer_channels = in_channels\n\n        if self.inter_channels:\n            intermediate = nn.Sequential()\n\n            for i, (dc, di) in enumerate(zip(self.inter_channels, self.inter_dilations)):\n                if self.num_inter_units > 0:\n                    unit = ResidualUnit(\n                        spatial_dims=self.dimensions,\n                        in_channels=layer_channels,\n                        out_channels=dc,\n                        strides=1,\n                        kernel_size=self.kernel_size,\n                        subunits=self.num_inter_units,\n                        act=self.act,\n                        norm=self.norm,\n                        dropout=self.dropout,\n                        dilation=di,\n                        bias=self.bias,\n                        padding=self.padding,\n                    )\n                else:\n                    unit = Convolution(\n                        spatial_dims=self.dimensions,\n                        in_channels=layer_channels,\n                        out_channels=dc,\n                        strides=1,\n                        kernel_size=self.kernel_size,\n                        act=self.act,\n                        norm=self.norm,\n                        dropout=self.dropout,\n                        dilation=di,\n                        bias=self.bias,\n                        padding=self.padding,\n                    )\n\n                intermediate.add_module(\"inter_%i\" % i, unit)\n                layer_channels = dc\n\n        return intermediate, layer_channels\n\n    def _get_decode_module(\n        self, in_channels: int, channels: Sequence[int], strides: Sequence[int]\n    ) -> tuple[nn.Sequential, int]:\n        \"\"\"\n        Returns the decode part of the network by building up a sequence of layers returned by `_get_decode_layer`.\n        \"\"\"\n        decode = nn.Sequential()\n        layer_channels = in_channels\n\n        for i, (c, s) in enumerate(zip(channels, strides)):\n            layer = self._get_decode_layer(layer_channels, c, s, i == (len(strides) - 1))\n            decode.add_module(\"decode_%i\" % i, layer)\n            layer_channels = c\n\n        return decode, layer_channels\n\n    def _get_encode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Module:\n        \"\"\"\n        Returns a single layer of the encoder part of the network.\n        \"\"\"\n        mod: nn.Module\n        if self.num_res_units > 0:\n            mod = ResidualUnit(\n                spatial_dims=self.dimensions,\n                in_channels=in_channels,\n                out_channels=out_channels,\n                strides=strides,\n                kernel_size=self.kernel_size,\n                subunits=self.num_res_units,\n                act=self.act,\n                norm=self.norm,\n                dropout=self.dropout,\n                bias=self.bias,\n                padding=self.padding,\n                last_conv_only=is_last,\n            )\n            return mod\n        mod = Convolution(\n            spatial_dims=self.dimensions,\n            in_channels=in_channels,\n            out_channels=out_channels,\n            strides=strides,\n            kernel_size=self.kernel_size,\n            act=self.act,\n            norm=self.norm,\n            dropout=self.dropout,\n            bias=self.bias,\n            padding=self.padding,\n            conv_only=is_last,\n        )\n        return mod\n\n    def _get_decode_layer(self, in_channels: int, out_channels: int, strides: int, is_last: bool) -> nn.Sequential:\n        \"\"\"\n        Returns a single layer of the decoder part of the network.\n        \"\"\"\n        decode = nn.Sequential()\n\n        conv = Convolution(\n            spatial_dims=self.dimensions,\n            in_channels=in_channels,\n            out_channels=out_channels,\n            strides=strides,\n            kernel_size=self.up_kernel_size,\n            act=self.act,\n            norm=self.norm,\n            dropout=self.dropout,\n            bias=self.bias,\n            padding=self.padding,\n            conv_only=is_last and self.num_res_units == 0,\n            is_transposed=True,\n        )\n\n        decode.add_module(\"conv\", conv)\n\n        if self.num_res_units > 0:\n            ru = ResidualUnit(\n                spatial_dims=self.dimensions,\n                in_channels=out_channels,\n                out_channels=out_channels,\n                strides=1,\n                kernel_size=self.kernel_size,\n                subunits=1,\n                act=self.act,\n                norm=self.norm,\n                dropout=self.dropout,\n                bias=self.bias,\n                padding=self.padding,\n                last_conv_only=is_last,\n            )\n\n            decode.add_module(\"resunit\", ru)\n\n        return decode\n\n    def forward(self, x: torch.Tensor) -> Any:\n        x = self.encode(x)\n        x = self.intermediate(x)\n        x = self.decode(x)\n        return x\n", "path": "monai/networks/nets/autoencoder.py"}]}