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.
@@ -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}")
@@ -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']