netloader 3.11.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- netloader/__init__.py +61 -0
- netloader/architectures/__init__.py +48 -0
- netloader/architectures/base.py +1350 -0
- netloader/architectures/encoder_decoder.py +630 -0
- netloader/architectures/flows.py +501 -0
- netloader/architectures/utils.py +179 -0
- netloader/data.py +1092 -0
- netloader/layers/__init__.py +88 -0
- netloader/layers/base.py +367 -0
- netloader/layers/blocks.py +145 -0
- netloader/layers/convolutional.py +1008 -0
- netloader/layers/flows.py +123 -0
- netloader/layers/linear.py +445 -0
- netloader/layers/misc.py +879 -0
- netloader/layers/multi_layer.py +470 -0
- netloader/layers/pooling.py +298 -0
- netloader/layers/recurrent.py +163 -0
- netloader/layers/utils.py +168 -0
- netloader/loss_funcs.py +201 -0
- netloader/models/__init__.py +22 -0
- netloader/models/convnext.py +582 -0
- netloader/models/misc.py +209 -0
- netloader/network.py +895 -0
- netloader/networks/__init__.py +48 -0
- netloader/schedulers.py +409 -0
- netloader/transforms.py +847 -0
- netloader/utils/__init__.py +46 -0
- netloader/utils/configs.py +241 -0
- netloader/utils/transforms.py +22 -0
- netloader/utils/types.py +130 -0
- netloader/utils/utils.py +677 -0
- netloader-3.11.0.dist-info/METADATA +59 -0
- netloader-3.11.0.dist-info/RECORD +36 -0
- netloader-3.11.0.dist-info/WHEEL +5 -0
- netloader-3.11.0.dist-info/licenses/LICENSE.txt +21 -0
- netloader-3.11.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Collects all classes in the layers module
|
|
3
|
+
"""
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from netloader.layers.linear import Activation, Linear, OrderedBottleneck, Sample, Upsample
|
|
7
|
+
from netloader.layers.multi_layer import Concatenate, Pack, Shortcut, Skip, Unpack
|
|
8
|
+
from netloader.layers.base import BaseLayer, BaseSingleLayer, BaseMultiLayer
|
|
9
|
+
from netloader.layers.pooling import AdaptivePool, Pool, PoolDownscale
|
|
10
|
+
from netloader.layers.blocks import ConvNeXtBlock
|
|
11
|
+
from netloader.layers.recurrent import Recurrent
|
|
12
|
+
from netloader.layers.convolutional import (
|
|
13
|
+
Conv,
|
|
14
|
+
ConvDepth,
|
|
15
|
+
ConvDepthDownscale,
|
|
16
|
+
ConvDownscale,
|
|
17
|
+
ConvTranspose,
|
|
18
|
+
ConvTransposeUpscale,
|
|
19
|
+
ConvUpscale,
|
|
20
|
+
PixelShuffle,
|
|
21
|
+
)
|
|
22
|
+
from netloader.layers.misc import (
|
|
23
|
+
BatchNorm,
|
|
24
|
+
Checkpoint,
|
|
25
|
+
Dropout,
|
|
26
|
+
DropPath,
|
|
27
|
+
Index,
|
|
28
|
+
LayerNorm,
|
|
29
|
+
Pad,
|
|
30
|
+
Reshape,
|
|
31
|
+
Scale,
|
|
32
|
+
)
|
|
33
|
+
from netloader.layers import utils
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = [
|
|
37
|
+
'Activation',
|
|
38
|
+
'AdaptivePool',
|
|
39
|
+
'BaseLayer',
|
|
40
|
+
'BaseMultiLayer',
|
|
41
|
+
'BaseSingleLayer',
|
|
42
|
+
'BatchNorm',
|
|
43
|
+
'Checkpoint',
|
|
44
|
+
'Concatenate',
|
|
45
|
+
'Conv',
|
|
46
|
+
'ConvDepth',
|
|
47
|
+
'ConvDepthDownscale',
|
|
48
|
+
'ConvDownscale',
|
|
49
|
+
'ConvNeXtBlock',
|
|
50
|
+
'ConvTranspose',
|
|
51
|
+
'ConvTransposeUpscale',
|
|
52
|
+
'ConvUpscale',
|
|
53
|
+
'Dropout',
|
|
54
|
+
'DropPath',
|
|
55
|
+
'Index',
|
|
56
|
+
'LayerNorm',
|
|
57
|
+
'Linear',
|
|
58
|
+
'OrderedBottleneck',
|
|
59
|
+
'Pack',
|
|
60
|
+
'Pad',
|
|
61
|
+
'PixelShuffle',
|
|
62
|
+
'Pool',
|
|
63
|
+
'PoolDownscale',
|
|
64
|
+
'Recurrent',
|
|
65
|
+
'Reshape',
|
|
66
|
+
'Sample',
|
|
67
|
+
'Scale',
|
|
68
|
+
'Shortcut',
|
|
69
|
+
'Skip',
|
|
70
|
+
'Unpack',
|
|
71
|
+
'Upsample',
|
|
72
|
+
'utils',
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
_optional_imports: dict[str, set[str]] = {'flow': {'SplineFlow'}}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
from netloader.layers.flows import SplineFlow
|
|
80
|
+
__all__.append('SplineFlow')
|
|
81
|
+
except ImportError:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def __getattr__(name: str) -> Any:
|
|
86
|
+
if name not in __all__ and name in _optional_imports['flow']:
|
|
87
|
+
raise ImportError(f'Cannot import {name}, normalising flow layers require the package Zuko')
|
|
88
|
+
raise AttributeError(f"module {__name__} has no attribute {name}")
|
netloader/layers/base.py
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base classes for network layers
|
|
3
|
+
"""
|
|
4
|
+
import logging as log
|
|
5
|
+
from copy import deepcopy
|
|
6
|
+
from typing import Any, Self, TypeAlias, cast
|
|
7
|
+
|
|
8
|
+
import torch
|
|
9
|
+
import numpy as np
|
|
10
|
+
from torch import nn, Tensor
|
|
11
|
+
|
|
12
|
+
import netloader
|
|
13
|
+
from netloader.data import DataList
|
|
14
|
+
from netloader.utils import Shapes, check_params
|
|
15
|
+
from netloader.utils.types import TensorListLike, ShapeLike
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
ShapeListLike: TypeAlias = list[int] | list['ShapeListLike']
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BaseLayer(nn.Module):
|
|
22
|
+
"""
|
|
23
|
+
Base layer for other layers to inherit.
|
|
24
|
+
|
|
25
|
+
Attributes
|
|
26
|
+
----------
|
|
27
|
+
group : int
|
|
28
|
+
Layer group, if 0 it will always be used, else it will only be used if its group matches the
|
|
29
|
+
Networks
|
|
30
|
+
description : str
|
|
31
|
+
Description of the layer
|
|
32
|
+
"""
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
*,
|
|
36
|
+
idx: int = 0,
|
|
37
|
+
group: int = 0,
|
|
38
|
+
version: str = '',
|
|
39
|
+
description: str = '',
|
|
40
|
+
**kwargs: Any) -> None:
|
|
41
|
+
"""
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
idx : int, Optional
|
|
45
|
+
Layer number, default = 0
|
|
46
|
+
group : int, Optional
|
|
47
|
+
Which group the layer belongs to, if 0 it will always be used, else it will only be used
|
|
48
|
+
if the Network group matches the layer's group, default = 0
|
|
49
|
+
version : str, Optional
|
|
50
|
+
Version of the network, default = netloader.__version__
|
|
51
|
+
description : str, Optional
|
|
52
|
+
Description of the layer
|
|
53
|
+
**kwargs
|
|
54
|
+
Leftover parameters for checking if they are valid
|
|
55
|
+
"""
|
|
56
|
+
super().__init__()
|
|
57
|
+
supported_params: list[str] = [
|
|
58
|
+
'type',
|
|
59
|
+
'root',
|
|
60
|
+
'net_check',
|
|
61
|
+
'net_out',
|
|
62
|
+
'shapes',
|
|
63
|
+
'check_shapes',
|
|
64
|
+
]
|
|
65
|
+
self._ver: str = version or netloader.__version__
|
|
66
|
+
self._device: torch.device = torch.device('cpu')
|
|
67
|
+
self._logger: log.Logger = log.getLogger(__name__)
|
|
68
|
+
self.group: int = group
|
|
69
|
+
self.description: str = description
|
|
70
|
+
|
|
71
|
+
if kwargs:
|
|
72
|
+
check_params(
|
|
73
|
+
f'{self.__class__.__name__} in layer {idx}',
|
|
74
|
+
supported_params,
|
|
75
|
+
np.array(list(kwargs.keys())),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
def __getstate__(self) -> dict[str, Any]:
|
|
79
|
+
"""
|
|
80
|
+
Gets the state of the layer for saving.
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
dict[str, Any]
|
|
85
|
+
State of the layer
|
|
86
|
+
"""
|
|
87
|
+
return {
|
|
88
|
+
'type': self.__class__.__name__,
|
|
89
|
+
'version': self._ver,
|
|
90
|
+
'group': self.group,
|
|
91
|
+
'description': self.description,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def _check_options(name: str, value: str | None, options: set[str | None]) -> None:
|
|
96
|
+
"""
|
|
97
|
+
Checks if a provided option is supported.
|
|
98
|
+
|
|
99
|
+
Parameters
|
|
100
|
+
----------
|
|
101
|
+
name : str
|
|
102
|
+
Name of the option
|
|
103
|
+
value : str | None
|
|
104
|
+
Value provided
|
|
105
|
+
options : set[str | None]
|
|
106
|
+
List of supported options
|
|
107
|
+
"""
|
|
108
|
+
if value not in options:
|
|
109
|
+
raise ValueError(f'{name.title()} ({value}) is unknown, {name} must be one of '
|
|
110
|
+
f'{options}')
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def _check_stride(stride: int | list[int]) -> None:
|
|
114
|
+
"""
|
|
115
|
+
Checks if the stride is greater than 1 if 'same' padding is being used.
|
|
116
|
+
|
|
117
|
+
Parameters
|
|
118
|
+
----------
|
|
119
|
+
stride : int | list[int]
|
|
120
|
+
Stride of the kernel
|
|
121
|
+
"""
|
|
122
|
+
if (np.array(stride) > 1).any():
|
|
123
|
+
raise ValueError(f"'same' padding is not supported for strides > 1 ({stride})")
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def _check_factor_filters(
|
|
127
|
+
shape: list[int],
|
|
128
|
+
*,
|
|
129
|
+
filters: int | None = None,
|
|
130
|
+
factor: float | None = None,
|
|
131
|
+
target: list[int] | None = None) -> list[int]:
|
|
132
|
+
"""
|
|
133
|
+
Checks if factor or filters is provided and calculates the number of filters.
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
shape : list[int]
|
|
138
|
+
Input shape
|
|
139
|
+
filters : int | None, Optional
|
|
140
|
+
Number of convolutional filters, will be used if provided, else factor will be used
|
|
141
|
+
factor : float | None, Optional
|
|
142
|
+
Number of convolutional filters equal to the output channels multiplied by factor,
|
|
143
|
+
won't be used if filters is provided
|
|
144
|
+
target : list[int] | None, Optional
|
|
145
|
+
Target shape that factor is relative to, required only if layer contains factor
|
|
146
|
+
|
|
147
|
+
Returns
|
|
148
|
+
-------
|
|
149
|
+
list[int]
|
|
150
|
+
Input shape with the adjusted number of filters
|
|
151
|
+
"""
|
|
152
|
+
if factor is not None and target is not None:
|
|
153
|
+
shape[0] = max(1, int(target[0] * factor))
|
|
154
|
+
elif filters is not None:
|
|
155
|
+
shape[0] = filters
|
|
156
|
+
else:
|
|
157
|
+
raise ValueError('Either factor or filters is required')
|
|
158
|
+
return shape
|
|
159
|
+
|
|
160
|
+
@staticmethod
|
|
161
|
+
def _check_shape(dims: tuple[int, int], shape: list[int]) -> None:
|
|
162
|
+
"""
|
|
163
|
+
Checks if the input shape has more than 4 dimensions or fewer than 2.
|
|
164
|
+
|
|
165
|
+
Parameters
|
|
166
|
+
----------
|
|
167
|
+
shape : list[int]
|
|
168
|
+
Input shape
|
|
169
|
+
"""
|
|
170
|
+
if not dims[0] <= len(shape) <= dims[1]:
|
|
171
|
+
raise ValueError(f'Tensors with more than {dims[1]} dimensions or less than {dims[0]} '
|
|
172
|
+
f'is not supported, input shape is {shape}')
|
|
173
|
+
|
|
174
|
+
@staticmethod
|
|
175
|
+
def _check_num_outputs(output: TensorListLike, single: bool = True) -> None:
|
|
176
|
+
"""
|
|
177
|
+
Checks if the output is a single tensor or a list of tensors.
|
|
178
|
+
|
|
179
|
+
Parameters
|
|
180
|
+
----------
|
|
181
|
+
output : TensorListLike
|
|
182
|
+
Output from the layer with tensors of shape (N,...) and type float, where N is the
|
|
183
|
+
batch size
|
|
184
|
+
single : bool, Optional
|
|
185
|
+
If the output should be a single tensor, if False it will be a list of tensors,
|
|
186
|
+
default = True
|
|
187
|
+
"""
|
|
188
|
+
if single and isinstance(output, DataList):
|
|
189
|
+
raise ValueError(f'Output must be a single tensor, but {len(output)} tensors were '
|
|
190
|
+
f'provided, use an Unpack layer first')
|
|
191
|
+
if not single and isinstance(output, Tensor):
|
|
192
|
+
raise ValueError('Output must be a list of tensors, but a single tensor was '
|
|
193
|
+
'provided')
|
|
194
|
+
|
|
195
|
+
def forward(self, x: Any, *_: Any, **__: Any) -> Any:
|
|
196
|
+
"""
|
|
197
|
+
Forward pass for child layer ti implement.
|
|
198
|
+
|
|
199
|
+
Parameters
|
|
200
|
+
----------
|
|
201
|
+
x : Any
|
|
202
|
+
Layer input
|
|
203
|
+
|
|
204
|
+
Returns
|
|
205
|
+
-------
|
|
206
|
+
Any
|
|
207
|
+
Layer output
|
|
208
|
+
"""
|
|
209
|
+
return NotImplementedError
|
|
210
|
+
|
|
211
|
+
def to(self, *args: Any, **kwargs: Any) -> Self:
|
|
212
|
+
super().to(*args, **kwargs)
|
|
213
|
+
self._device, *_ = torch._C._nn._parse_to(*args, **kwargs) # pylint: disable=protected-access
|
|
214
|
+
return self
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class BaseSingleLayer(BaseLayer):
|
|
218
|
+
"""
|
|
219
|
+
Base layer for layers that only use the previous layer.
|
|
220
|
+
|
|
221
|
+
Attributes
|
|
222
|
+
----------
|
|
223
|
+
group : int
|
|
224
|
+
Layer group, if 0 it will always be used, else it will only be used if its group matches the
|
|
225
|
+
Network's
|
|
226
|
+
layers : Sequential
|
|
227
|
+
Layers to loop through in the forward pass
|
|
228
|
+
"""
|
|
229
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
230
|
+
"""
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
**kwargs
|
|
234
|
+
Leftover parameters to pass to base layer for checking
|
|
235
|
+
"""
|
|
236
|
+
super().__init__(**kwargs)
|
|
237
|
+
self.layers: nn.Sequential = nn.Sequential()
|
|
238
|
+
|
|
239
|
+
def forward(self, x: Any, *_: Any, **__: Any) -> Any:
|
|
240
|
+
"""
|
|
241
|
+
Forward pass for a generic layer.
|
|
242
|
+
|
|
243
|
+
Parameters
|
|
244
|
+
----------
|
|
245
|
+
x : TensorListLike
|
|
246
|
+
Input with tensors of shape (N,...) and type float, where N is the batch size
|
|
247
|
+
|
|
248
|
+
Returns
|
|
249
|
+
-------
|
|
250
|
+
TensorListLike
|
|
251
|
+
Output with tensors of shape (N,...) and type float
|
|
252
|
+
"""
|
|
253
|
+
return self.layers(x)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class BaseMultiLayer(BaseLayer):
|
|
257
|
+
"""
|
|
258
|
+
Base layer for layers that use earlier layers to inherit.
|
|
259
|
+
|
|
260
|
+
Attributes
|
|
261
|
+
----------
|
|
262
|
+
group : int
|
|
263
|
+
Layer group, if 0 it will always be used, else it will only be used if its group matches the
|
|
264
|
+
Networks
|
|
265
|
+
description : str
|
|
266
|
+
Description of the layer
|
|
267
|
+
"""
|
|
268
|
+
def __init__(
|
|
269
|
+
self,
|
|
270
|
+
net_check: bool,
|
|
271
|
+
layer: int | list[int],
|
|
272
|
+
shapes: Shapes,
|
|
273
|
+
check_shapes: Shapes,
|
|
274
|
+
*,
|
|
275
|
+
checkpoint: bool = False,
|
|
276
|
+
**kwargs: Any) -> None:
|
|
277
|
+
"""
|
|
278
|
+
Parameters
|
|
279
|
+
----------
|
|
280
|
+
net_check : bool
|
|
281
|
+
If layer index should be relative to checkpoint layers
|
|
282
|
+
layer : int | list[int]
|
|
283
|
+
Layer index(es) to concatenate the previous layer output with
|
|
284
|
+
shapes : Shapes
|
|
285
|
+
Shape of the outputs from each layer
|
|
286
|
+
check_shapes : Shapes
|
|
287
|
+
Shape of the outputs from each checkpoint
|
|
288
|
+
checkpoint : bool, Optional
|
|
289
|
+
If layer index should be relative to checkpoint layers, default = False
|
|
290
|
+
**kwargs
|
|
291
|
+
Leftover parameters to pass to base layer for checking
|
|
292
|
+
"""
|
|
293
|
+
super().__init__(**kwargs)
|
|
294
|
+
self._checkpoint: bool = checkpoint or net_check
|
|
295
|
+
self._layer: int | list[int] = layer
|
|
296
|
+
self._shapes: list[list[int]] = []
|
|
297
|
+
self._target: ShapeLike
|
|
298
|
+
i: int
|
|
299
|
+
idx: int = 1 if shapes.check(-1) else len(shapes.get(-1, True))
|
|
300
|
+
shapes_: Shapes = check_shapes if self._checkpoint else shapes
|
|
301
|
+
|
|
302
|
+
self._shapes = self._shape_flatten([
|
|
303
|
+
deepcopy(shapes.get(-1, True)),
|
|
304
|
+
[deepcopy(shapes_.get(i, True))
|
|
305
|
+
for i in ([self._layer] if isinstance(self._layer, int) else self._layer)],
|
|
306
|
+
])
|
|
307
|
+
self._target = self._shapes[idx] \
|
|
308
|
+
if isinstance(self._layer, int) and len(self._shapes) == idx + 1 else self._shapes[idx:]
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def __getstate__(self) -> dict[str, Any]:
|
|
312
|
+
return super().__getstate__() | {'checkpoint': self._checkpoint, 'layer': self._layer}
|
|
313
|
+
|
|
314
|
+
@staticmethod
|
|
315
|
+
def _shape_flatten(shapes: ShapeListLike) -> list[list[int]]:
|
|
316
|
+
"""
|
|
317
|
+
Flattens a list of layer output shapes into a single list of array output shapes.
|
|
318
|
+
|
|
319
|
+
Parameters
|
|
320
|
+
----------
|
|
321
|
+
shapes : ShapeLike | list[ShapeLike]
|
|
322
|
+
Layer output shape or list of layer output shapes to flatten
|
|
323
|
+
|
|
324
|
+
Returns
|
|
325
|
+
-------
|
|
326
|
+
list[list[int]]
|
|
327
|
+
Flattened list of array output shapes
|
|
328
|
+
"""
|
|
329
|
+
new_shapes: list[list[int]] = []
|
|
330
|
+
shape: ShapeLike
|
|
331
|
+
|
|
332
|
+
if isinstance(shapes[0], int):
|
|
333
|
+
return [cast(list[int], shapes)]
|
|
334
|
+
|
|
335
|
+
for shape in shapes:
|
|
336
|
+
if isinstance(shape[0], int):
|
|
337
|
+
new_shapes.append(cast(list[int], shape))
|
|
338
|
+
else:
|
|
339
|
+
new_shapes.extend(BaseMultiLayer._shape_flatten(shape))
|
|
340
|
+
return new_shapes
|
|
341
|
+
|
|
342
|
+
def extra_repr(self) -> str:
|
|
343
|
+
"""
|
|
344
|
+
Displays layer parameters when printing the network.
|
|
345
|
+
|
|
346
|
+
Returns
|
|
347
|
+
-------
|
|
348
|
+
str
|
|
349
|
+
Layer parameters
|
|
350
|
+
"""
|
|
351
|
+
return f'layer={self._layer}, checkpoint={bool(self._checkpoint)}'
|
|
352
|
+
|
|
353
|
+
def forward(
|
|
354
|
+
self,
|
|
355
|
+
x: Tensor,
|
|
356
|
+
outputs: list[TensorListLike],
|
|
357
|
+
checkpoints: list[TensorListLike],
|
|
358
|
+
*_: Any,
|
|
359
|
+
**__: Any) -> TensorListLike:
|
|
360
|
+
outputs_: list[TensorListLike] = checkpoints if self._checkpoint else outputs
|
|
361
|
+
return DataList(sum((
|
|
362
|
+
[outputs_[i]] if isinstance(outputs_[i], Tensor) else list(outputs_[i])
|
|
363
|
+
for i in ([self._layer] if isinstance(self._layer, int) else self._layer)
|
|
364
|
+
), start=[x] if isinstance(x, Tensor) else list(x)))
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
__all__ = ['BaseLayer', 'BaseSingleLayer', 'BaseMultiLayer']
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Composite layer blocks as used in networks such as ConvNeXt
|
|
3
|
+
"""
|
|
4
|
+
from typing import Any, OrderedDict, cast
|
|
5
|
+
|
|
6
|
+
from torch import nn, Tensor
|
|
7
|
+
|
|
8
|
+
from netloader.utils import Shapes
|
|
9
|
+
from netloader.utils.types import TensorListLike
|
|
10
|
+
from netloader.layers.base import BaseSingleLayer
|
|
11
|
+
from netloader.layers.convolutional import Conv, ConvDepth
|
|
12
|
+
from netloader.layers.misc import Checkpoint, DropPath, Scale
|
|
13
|
+
from netloader.layers import Shortcut
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ConvNeXtBlock(BaseSingleLayer):
|
|
17
|
+
"""
|
|
18
|
+
ConvNeXt block using BaseLayer.
|
|
19
|
+
|
|
20
|
+
Original paper implementation: arXiv:2201.03545.
|
|
21
|
+
|
|
22
|
+
Attributes
|
|
23
|
+
----------
|
|
24
|
+
group : int
|
|
25
|
+
Layer group, if 0 it will always be used, else it will only be used if its group matches the
|
|
26
|
+
Networks
|
|
27
|
+
description : str
|
|
28
|
+
Description of the layer
|
|
29
|
+
layers : Sequential
|
|
30
|
+
Layers part of the parent layer to loop through in the forward pass
|
|
31
|
+
shapes : Shapes
|
|
32
|
+
Layer output shapes
|
|
33
|
+
check_shapes : Shapes
|
|
34
|
+
Checkpoint output shapes
|
|
35
|
+
"""
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
net_out: list[int],
|
|
39
|
+
shapes: Shapes,
|
|
40
|
+
*,
|
|
41
|
+
drop_path: float = 0,
|
|
42
|
+
layer_scale: float = 1e-6,
|
|
43
|
+
**kwargs: Any) -> None:
|
|
44
|
+
"""
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
net_out : list[int]
|
|
48
|
+
Shape of the network's output, required only if layer contains factor
|
|
49
|
+
shapes : Shapes
|
|
50
|
+
Shape of the outputs from each layer
|
|
51
|
+
drop_path : float, Optional
|
|
52
|
+
Probability of Drop Path dropout, default = 0
|
|
53
|
+
layer_scale : float, Optional
|
|
54
|
+
Initial scale factor for layer Scale, default = 1e-6
|
|
55
|
+
**kwargs
|
|
56
|
+
Leftover parameters for checking if they are valid
|
|
57
|
+
"""
|
|
58
|
+
super().__init__(**kwargs)
|
|
59
|
+
self._drop_path: float = drop_path
|
|
60
|
+
self._layer_scale: float = layer_scale
|
|
61
|
+
self.shapes: Shapes = shapes[-1:]
|
|
62
|
+
self.check_shapes: Shapes = Shapes([])
|
|
63
|
+
|
|
64
|
+
self.layers = nn.Sequential(OrderedDict([
|
|
65
|
+
('Checkpoint', Checkpoint(self.shapes, self.check_shapes)),
|
|
66
|
+
('ConvDepth', ConvDepth(
|
|
67
|
+
net_out,
|
|
68
|
+
self.shapes,
|
|
69
|
+
layer=-1,
|
|
70
|
+
factor=1,
|
|
71
|
+
kernel=7,
|
|
72
|
+
stride=1,
|
|
73
|
+
padding=3,
|
|
74
|
+
activation=None,
|
|
75
|
+
norm='layer',
|
|
76
|
+
**kwargs,
|
|
77
|
+
)),
|
|
78
|
+
('Conv1', Conv(
|
|
79
|
+
net_out,
|
|
80
|
+
self.shapes,
|
|
81
|
+
layer=-1,
|
|
82
|
+
factor=4,
|
|
83
|
+
kernel=1,
|
|
84
|
+
padding='same',
|
|
85
|
+
activation='GELU',
|
|
86
|
+
**kwargs,
|
|
87
|
+
)),
|
|
88
|
+
('Conv2', Conv(
|
|
89
|
+
net_out,
|
|
90
|
+
self.shapes,
|
|
91
|
+
layer=0,
|
|
92
|
+
factor=1,
|
|
93
|
+
kernel=1,
|
|
94
|
+
padding='same',
|
|
95
|
+
activation=None,
|
|
96
|
+
**kwargs,
|
|
97
|
+
)),
|
|
98
|
+
('Scale', Scale(1, self._layer_scale, self.shapes, **kwargs)),
|
|
99
|
+
('DropPath', DropPath(self._drop_path, shapes=self.shapes, **kwargs)),
|
|
100
|
+
('Shortcut', Shortcut(
|
|
101
|
+
True,
|
|
102
|
+
-1,
|
|
103
|
+
self.shapes,
|
|
104
|
+
self.check_shapes,
|
|
105
|
+
**kwargs | {'checkpoint': True},
|
|
106
|
+
)),
|
|
107
|
+
]))
|
|
108
|
+
shapes.append(self.shapes[-1].copy())
|
|
109
|
+
|
|
110
|
+
def __getstate__(self) -> dict[str, Any]:
|
|
111
|
+
return super().__getstate__() | {
|
|
112
|
+
'drop_path': self._drop_path,
|
|
113
|
+
'layer_scale': self._layer_scale,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
def forward(
|
|
117
|
+
self,
|
|
118
|
+
x: TensorListLike,
|
|
119
|
+
outputs: list[TensorListLike],
|
|
120
|
+
checkpoints: list[TensorListLike],
|
|
121
|
+
*_: Any,
|
|
122
|
+
**__: Any) -> Tensor:
|
|
123
|
+
"""
|
|
124
|
+
Forward pass for the ConvNeXt block
|
|
125
|
+
|
|
126
|
+
Parameters
|
|
127
|
+
----------
|
|
128
|
+
x : TensorListLike
|
|
129
|
+
Input with tensors of shape (N,...) and type float, where N is the batch size
|
|
130
|
+
outputs : list[TensorListLike]
|
|
131
|
+
Output from each layer with tensors of shape (N,...) and type float
|
|
132
|
+
checkpoints : list[TensorListLike]
|
|
133
|
+
List of checkpoint values with tensors of shape (N,...) and type float
|
|
134
|
+
|
|
135
|
+
Returns
|
|
136
|
+
-------
|
|
137
|
+
Tensor
|
|
138
|
+
Output tensor with shape (N,...) and type float
|
|
139
|
+
"""
|
|
140
|
+
for layer in self.layers:
|
|
141
|
+
x = layer(x, outputs=outputs, checkpoints=checkpoints)
|
|
142
|
+
return cast(Tensor, x)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
__all__ = ['ConvNeXtBlock']
|