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,630 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Classes for encoder, decoder, or autoencoder type architectures
|
|
3
|
+
"""
|
|
4
|
+
from warnings import warn
|
|
5
|
+
from typing import Any, Self, Literal, cast
|
|
6
|
+
|
|
7
|
+
import torch
|
|
8
|
+
import numpy as np
|
|
9
|
+
from numpy import ndarray
|
|
10
|
+
from torch import Tensor, nn
|
|
11
|
+
|
|
12
|
+
from netloader.data import DataList
|
|
13
|
+
from netloader.utils import label_change
|
|
14
|
+
from netloader.transforms import BaseTransform
|
|
15
|
+
from netloader.network import Network, CompatibleNetwork
|
|
16
|
+
from netloader.architectures.base import BaseArchitecture
|
|
17
|
+
from netloader.loss_funcs import BaseLoss, MSELoss, CrossEntropyLoss
|
|
18
|
+
from netloader.utils.types import TensorListLike, NDArrayListLike, TensorT
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BaseEncoder(BaseArchitecture):
|
|
22
|
+
"""
|
|
23
|
+
Base encoder architecture for predicting low-dimensional data from high-dimensional inputs.
|
|
24
|
+
|
|
25
|
+
Attributes
|
|
26
|
+
----------
|
|
27
|
+
description : str
|
|
28
|
+
Description of the architecture
|
|
29
|
+
version : str
|
|
30
|
+
Version of the architecture
|
|
31
|
+
losses : tuple[list[LossCT], list[LossCT]]
|
|
32
|
+
Architecture training and validation losses as a float or dictionary of losses for each loss
|
|
33
|
+
function
|
|
34
|
+
transforms : dict[str, list[BaseTransform] | BaseTransform | None]
|
|
35
|
+
Keys for the output data from predict and corresponding transforms
|
|
36
|
+
idxs: ndarray | None
|
|
37
|
+
Training data indices with shape (N) and type int, where N is the number of elements in the
|
|
38
|
+
training dataset
|
|
39
|
+
classes : Tensor | None
|
|
40
|
+
Unique classes of shape (C) and type int/float, where C is the number of classes
|
|
41
|
+
optimiser : Optimizer
|
|
42
|
+
Architecture optimiser
|
|
43
|
+
scheduler : LRScheduler
|
|
44
|
+
Optimiser scheduler
|
|
45
|
+
net : Network | CompatibleNetwork
|
|
46
|
+
Neural network
|
|
47
|
+
"""
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
save_num: int | str,
|
|
51
|
+
states_dir: str,
|
|
52
|
+
net: nn.Module | Network | CompatibleNetwork,
|
|
53
|
+
*,
|
|
54
|
+
overwrite: bool = False,
|
|
55
|
+
mix_precision: bool = False,
|
|
56
|
+
learning_rate: float = 1e-3,
|
|
57
|
+
description: str = '',
|
|
58
|
+
verbose: Literal['epoch', 'full', 'plot', 'progress', None] = 'epoch',
|
|
59
|
+
classes: Tensor | None = None,
|
|
60
|
+
loss_func: BaseLoss | None = None,
|
|
61
|
+
transform: list[BaseTransform] | BaseTransform | None = None,
|
|
62
|
+
in_transform: list[BaseTransform] | BaseTransform | None = None,
|
|
63
|
+
optimiser_kwargs: dict[str, Any] | None = None,
|
|
64
|
+
scheduler_kwargs: dict[str, Any] | None = None) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
save_num : int | str
|
|
69
|
+
File number or name to save the architecture
|
|
70
|
+
states_dir : str
|
|
71
|
+
Directory to save the architecture
|
|
72
|
+
net : Module | Network | CompatibleNetwork
|
|
73
|
+
Network to predict low-dimensional data
|
|
74
|
+
overwrite : bool, Optional
|
|
75
|
+
If saving can overwrite an existing save file, if True and file with the same name
|
|
76
|
+
exists, an error will be raised, default = False
|
|
77
|
+
mix_precision: bool, Optional
|
|
78
|
+
If mixed precision should be used, default = False
|
|
79
|
+
learning_rate : float, Optional
|
|
80
|
+
Optimiser initial learning rate, if None, no optimiser or scheduler will be set,
|
|
81
|
+
default = 1e-3
|
|
82
|
+
description : str, Optional
|
|
83
|
+
Description of the architecture training
|
|
84
|
+
verbose : {'full', 'progress', None}
|
|
85
|
+
If details about epoch should be printed ('full'), just a progress bar ('progress'),
|
|
86
|
+
or nothing (None)
|
|
87
|
+
classes : Tensor, Optional
|
|
88
|
+
Unique classes of shape (C) and type int/float, where C is the number of classes, if
|
|
89
|
+
using class classification
|
|
90
|
+
loss_func : BaseLoss | None, Optional
|
|
91
|
+
Loss function for the encoder, if None MSELoss will be used if classes is None, else
|
|
92
|
+
CrossEntropyLoss will be used
|
|
93
|
+
transform : BaseTransform, Optional
|
|
94
|
+
Transformation of the low-dimensional data
|
|
95
|
+
in_transform : BaseTransform, Optional
|
|
96
|
+
Transformation for the input data
|
|
97
|
+
optimiser_kwargs : dict[str, Any] | None, Optional
|
|
98
|
+
Optional keyword arguments to pass to init_optimiser
|
|
99
|
+
scheduler_kwargs : dict[str, Any] | None, Optional
|
|
100
|
+
Optional keyword arguments to pass to init_scheduler
|
|
101
|
+
"""
|
|
102
|
+
super().__init__(
|
|
103
|
+
save_num,
|
|
104
|
+
states_dir,
|
|
105
|
+
net,
|
|
106
|
+
overwrite=overwrite,
|
|
107
|
+
mix_precision=mix_precision,
|
|
108
|
+
learning_rate=learning_rate,
|
|
109
|
+
description=description,
|
|
110
|
+
verbose=verbose,
|
|
111
|
+
transform=transform,
|
|
112
|
+
in_transform=in_transform,
|
|
113
|
+
optimiser_kwargs=optimiser_kwargs,
|
|
114
|
+
scheduler_kwargs=scheduler_kwargs,
|
|
115
|
+
)
|
|
116
|
+
self._loss_func_: BaseLoss
|
|
117
|
+
self.classes: Tensor | None = classes
|
|
118
|
+
|
|
119
|
+
if self.classes is None:
|
|
120
|
+
self._loss_func_ = loss_func or MSELoss()
|
|
121
|
+
else:
|
|
122
|
+
self.classes = self.classes.to(self._device)
|
|
123
|
+
self._loss_func_ = loss_func or CrossEntropyLoss()
|
|
124
|
+
|
|
125
|
+
def __getstate__(self) -> dict[str, Any]:
|
|
126
|
+
return super().__getstate__() | {'classes': self.classes, 'loss_func': self._loss_func_}
|
|
127
|
+
|
|
128
|
+
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
129
|
+
super().__setstate__(state)
|
|
130
|
+
self.classes = state['classes']
|
|
131
|
+
|
|
132
|
+
if 'loss_func' in state:
|
|
133
|
+
self._loss_func_ = state['loss_func']
|
|
134
|
+
else:
|
|
135
|
+
warn(
|
|
136
|
+
f'{self.__class__.__name__} is saved in old non-weights safe format and is '
|
|
137
|
+
'deprecated, please resave the architecture in the new format using '
|
|
138
|
+
'BaseArchitecture.save()',
|
|
139
|
+
DeprecationWarning,
|
|
140
|
+
stacklevel=2,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if self.classes is None:
|
|
144
|
+
self._loss_func_ = MSELoss()
|
|
145
|
+
else:
|
|
146
|
+
self._loss_func_ = CrossEntropyLoss()
|
|
147
|
+
|
|
148
|
+
def _loss_tensor(
|
|
149
|
+
self,
|
|
150
|
+
in_data: TensorListLike,
|
|
151
|
+
target: TensorListLike,
|
|
152
|
+
_: Any) -> dict[str, Tensor] | Tensor:
|
|
153
|
+
"""
|
|
154
|
+
Calculates the loss from the architecture's predictions.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
in_data : TensorListLike
|
|
159
|
+
Input high dimensional data of shape (N, ...) and type float, where N is the batch size
|
|
160
|
+
target : TensorListLike
|
|
161
|
+
Target low dimensional data of shape (N, ...) and type float
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
dict[str, Tensor] | Tensor
|
|
166
|
+
Loss from the architecture's predictions
|
|
167
|
+
"""
|
|
168
|
+
# Default shape is (N, L), but cross entropy expects (N)
|
|
169
|
+
if self.classes is not None and isinstance(target, Tensor):
|
|
170
|
+
target = label_change(target.squeeze(), self.classes)
|
|
171
|
+
return self._loss_func_(self.net(in_data), target)
|
|
172
|
+
|
|
173
|
+
def get_hyperparams(self) -> dict[str, Any]:
|
|
174
|
+
"""
|
|
175
|
+
Get the hyperparameters of the encoder.
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
dict[str, Any]
|
|
180
|
+
Hyperparameters of the encoder
|
|
181
|
+
"""
|
|
182
|
+
return super().get_hyperparams() | {
|
|
183
|
+
'classes': int(self.classes.size(0)) if self.classes is not None else None,
|
|
184
|
+
'loss_func': self._loss_func_.__class__.__name__,
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
def extra_repr(self) -> str:
|
|
188
|
+
"""
|
|
189
|
+
Additional representation of the architecture.
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
str
|
|
194
|
+
Architecture specific representation
|
|
195
|
+
"""
|
|
196
|
+
return f'loss_func: {self._loss_func_}'
|
|
197
|
+
|
|
198
|
+
def to(self, *args: Any, **kwargs: Any) -> Self:
|
|
199
|
+
super().to(*args, **kwargs)
|
|
200
|
+
|
|
201
|
+
if self.classes is not None:
|
|
202
|
+
self.classes = self.classes.to(self._device)
|
|
203
|
+
return self
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class Autoencoder(BaseArchitecture):
|
|
207
|
+
"""
|
|
208
|
+
Architecture handler for autoencoder type architectures.
|
|
209
|
+
|
|
210
|
+
Attributes
|
|
211
|
+
----------
|
|
212
|
+
description : str
|
|
213
|
+
Description of the architecture
|
|
214
|
+
losses : tuple[list[LossCT], list[LossCT]]
|
|
215
|
+
Architecture training and validation losses as a float or dictionary of losses for each loss
|
|
216
|
+
function
|
|
217
|
+
transforms : dict[str, list[BaseTransform] | BaseTransform | None]
|
|
218
|
+
Keys for the output data from predict and corresponding transforms
|
|
219
|
+
idxs: ndarray | None
|
|
220
|
+
Training data indices with shape (N) and type int, where N is the number of elements in the
|
|
221
|
+
training dataset
|
|
222
|
+
optimiser : Optimizer
|
|
223
|
+
Architecture optimiser
|
|
224
|
+
scheduler : LRScheduler
|
|
225
|
+
Optimiser scheduler
|
|
226
|
+
net : Network | CompatibleNetwork
|
|
227
|
+
Neural network
|
|
228
|
+
reconstruct_func : BaseLoss
|
|
229
|
+
Loss function for the reconstruction loss
|
|
230
|
+
latent_func : BaseLoss
|
|
231
|
+
Loss function for the latent loss
|
|
232
|
+
"""
|
|
233
|
+
def __init__(
|
|
234
|
+
self,
|
|
235
|
+
save_num: int | str,
|
|
236
|
+
states_dir: str,
|
|
237
|
+
net: nn.Module | Network | CompatibleNetwork,
|
|
238
|
+
*,
|
|
239
|
+
overwrite: bool = False,
|
|
240
|
+
mix_precision: bool = False,
|
|
241
|
+
learning_rate: float = 1e-3,
|
|
242
|
+
description: str = '',
|
|
243
|
+
verbose: Literal['epoch', 'full', 'plot', 'progress', None] = 'epoch',
|
|
244
|
+
transform: list[BaseTransform] | BaseTransform | None = None,
|
|
245
|
+
latent_transform: list[BaseTransform] | BaseTransform | None = None,
|
|
246
|
+
optimiser_kwargs: dict[str, Any] | None = None,
|
|
247
|
+
scheduler_kwargs: dict[str, Any] | None = None) -> None:
|
|
248
|
+
"""
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
save_num : int | str
|
|
252
|
+
File number or name to save the architecture
|
|
253
|
+
states_dir : str
|
|
254
|
+
Directory to save the architecture
|
|
255
|
+
net : Module | Network | CompatibleNetwork
|
|
256
|
+
Network to predict low-dimensional data
|
|
257
|
+
overwrite : bool, Optional
|
|
258
|
+
If saving can overwrite an existing save file, if True and file with the same name
|
|
259
|
+
exists, an error will be raised, default = False
|
|
260
|
+
mix_precision: bool, Optional
|
|
261
|
+
If mixed precision should be used, default = False
|
|
262
|
+
learning_rate : float, Optional
|
|
263
|
+
Optimiser initial learning rate, default = 1e-3
|
|
264
|
+
description : str, Optional
|
|
265
|
+
Description of the architecture training
|
|
266
|
+
verbose : {'full', 'progress', None}
|
|
267
|
+
If details about epoch should be printed ('full'), just a progress bar ('progress'),
|
|
268
|
+
or nothing (None)
|
|
269
|
+
transform : BaseTransform, Optional
|
|
270
|
+
Transformation applied to the input data
|
|
271
|
+
latent_transform : BaseTransform, Optional
|
|
272
|
+
Transformation applied to the latent space
|
|
273
|
+
optimiser_kwargs : dict[str, Any] | None, Optional
|
|
274
|
+
Optional keyword arguments to pass to init_optimiser
|
|
275
|
+
scheduler_kwargs : dict[str, Any] | None, Optional
|
|
276
|
+
Optional keyword arguments to pass to init_scheduler
|
|
277
|
+
"""
|
|
278
|
+
super().__init__(
|
|
279
|
+
save_num,
|
|
280
|
+
states_dir,
|
|
281
|
+
net,
|
|
282
|
+
overwrite=overwrite,
|
|
283
|
+
mix_precision=mix_precision,
|
|
284
|
+
learning_rate=learning_rate,
|
|
285
|
+
description=description,
|
|
286
|
+
verbose=verbose,
|
|
287
|
+
transform=transform,
|
|
288
|
+
in_transform=transform,
|
|
289
|
+
optimiser_kwargs=optimiser_kwargs,
|
|
290
|
+
scheduler_kwargs=scheduler_kwargs,
|
|
291
|
+
)
|
|
292
|
+
self.reconstruct_func: BaseLoss = MSELoss()
|
|
293
|
+
self.latent_func: BaseLoss = MSELoss()
|
|
294
|
+
|
|
295
|
+
self._loss_weights = {'reconstruct': 1, 'latent': 1e-2, 'bound': 1e-3, 'kl': 1e-1}
|
|
296
|
+
self.transforms['latent'] = latent_transform
|
|
297
|
+
self.transforms['targets'] = latent_transform
|
|
298
|
+
|
|
299
|
+
def __getstate__(self) -> dict[str, Any]:
|
|
300
|
+
return super().__getstate__() | {
|
|
301
|
+
'reconstruct_func': self.reconstruct_func,
|
|
302
|
+
'latent_func': self.latent_func,
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
306
|
+
super().__setstate__(state)
|
|
307
|
+
self._loss_weights = state.get('loss_weights', {
|
|
308
|
+
'reconstruct': state.get('reconstruct_loss', 1),
|
|
309
|
+
'latent': state.get('latent_loss', 1),
|
|
310
|
+
'bound': state.get('bound_loss', 1),
|
|
311
|
+
'kl': state.get('kl_loss', 1),
|
|
312
|
+
})
|
|
313
|
+
self.reconstruct_func = state['reconstruct_func']
|
|
314
|
+
self.latent_func = state['latent_func']
|
|
315
|
+
|
|
316
|
+
def __getattr__(self, item: str) -> Any:
|
|
317
|
+
if item in {'reconstruct_loss', 'latent_loss', 'bound_loss', 'kl_loss'}:
|
|
318
|
+
warn(
|
|
319
|
+
'Accessing loss weights directly is deprecated, please use '
|
|
320
|
+
'Autoencoder.get_loss_weights() instead',
|
|
321
|
+
DeprecationWarning,
|
|
322
|
+
stacklevel=2,
|
|
323
|
+
)
|
|
324
|
+
return self._loss_weights[item.replace('_loss', '')]
|
|
325
|
+
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{item}'")
|
|
326
|
+
|
|
327
|
+
def _loss_tensor(
|
|
328
|
+
self,
|
|
329
|
+
in_data: TensorListLike,
|
|
330
|
+
target: TensorListLike,
|
|
331
|
+
_: Any) -> dict[str, Tensor]:
|
|
332
|
+
"""
|
|
333
|
+
Calculates the loss from the autoencoder's predictions.
|
|
334
|
+
|
|
335
|
+
Parameters
|
|
336
|
+
----------
|
|
337
|
+
in_data : TensorListLike
|
|
338
|
+
Input high dimensional data of shape (N, ...) and type float, where N is the batch size
|
|
339
|
+
target : TensorListLike
|
|
340
|
+
Latent target low dimensional data of shape (N, ...) and type float
|
|
341
|
+
|
|
342
|
+
Returns
|
|
343
|
+
-------
|
|
344
|
+
dict[str, Tensor]
|
|
345
|
+
Loss function terms from the autoencoder's predictions
|
|
346
|
+
"""
|
|
347
|
+
loss: dict[str, Tensor] = {}
|
|
348
|
+
latent: Tensor | None = None
|
|
349
|
+
bounds: Tensor = torch.tensor([0., 1.]).to(self._device)
|
|
350
|
+
output: Tensor = self.net(in_data)
|
|
351
|
+
|
|
352
|
+
if self.net.checkpoints and isinstance(self.net.checkpoints[-1], DataList):
|
|
353
|
+
raise ValueError(f'Autoencoder networks cannot have multiple latent space tensors '
|
|
354
|
+
f'({len(self.net.checkpoints[-1])})')
|
|
355
|
+
if self.net.checkpoints:
|
|
356
|
+
latent = cast(Tensor, self.net.checkpoints[-1])
|
|
357
|
+
|
|
358
|
+
if self.get_loss_weights('reconstruct'):
|
|
359
|
+
loss['reconstruct'] = self.reconstruct_func(output, in_data)
|
|
360
|
+
|
|
361
|
+
if self.get_loss_weights('latent') and latent is not None:
|
|
362
|
+
loss['latent'] = self.latent_func(latent, target)
|
|
363
|
+
|
|
364
|
+
if self.get_loss_weights('bound') and latent is not None:
|
|
365
|
+
loss['bound'] = torch.mean(torch.cat((
|
|
366
|
+
(bounds[0] - latent) ** 2 * (latent < bounds[0]),
|
|
367
|
+
(latent - bounds[1]) ** 2 * (latent > bounds[1]),
|
|
368
|
+
)))
|
|
369
|
+
|
|
370
|
+
if self.get_loss_weights('kl'):
|
|
371
|
+
loss['kl'] = self.net.kl_loss
|
|
372
|
+
return loss
|
|
373
|
+
|
|
374
|
+
def batch_predict(self, data: TensorListLike, **_: Any) -> tuple[NDArrayListLike | None, ...]:
|
|
375
|
+
"""
|
|
376
|
+
Generates predictions for the given data batch.
|
|
377
|
+
|
|
378
|
+
Parameters
|
|
379
|
+
----------
|
|
380
|
+
data : TensorListLike
|
|
381
|
+
Data to generate predictions for of shape (N, ...) and type float, where N is the batch
|
|
382
|
+
size
|
|
383
|
+
|
|
384
|
+
Returns
|
|
385
|
+
-------
|
|
386
|
+
tuple[NDArrayListLike | None, ...]
|
|
387
|
+
Predictions of shape (N, ...) and type float for the given data
|
|
388
|
+
"""
|
|
389
|
+
output: NDArrayListLike = self.net(data).detach().cpu().numpy()
|
|
390
|
+
return (
|
|
391
|
+
output,
|
|
392
|
+
cast(NDArrayListLike, self.net.checkpoints[-1].detach().cpu().numpy()),
|
|
393
|
+
cast(NDArrayListLike, data.detach().cpu().numpy()),
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
def extra_repr(self) -> str:
|
|
397
|
+
"""
|
|
398
|
+
Additional representation of the architecture.
|
|
399
|
+
|
|
400
|
+
Returns
|
|
401
|
+
-------
|
|
402
|
+
str
|
|
403
|
+
Architecture specific representation
|
|
404
|
+
"""
|
|
405
|
+
return f'reconstruct_func: {self.reconstruct_func}, latent_func: {self.latent_func}'
|
|
406
|
+
|
|
407
|
+
def get_hyperparams(self) -> dict[str, Any]:
|
|
408
|
+
"""
|
|
409
|
+
Get the hyperparameters of the autoencoder.
|
|
410
|
+
|
|
411
|
+
Returns
|
|
412
|
+
-------
|
|
413
|
+
dict[str, Any]
|
|
414
|
+
Hyperparameters of the autoencoder
|
|
415
|
+
"""
|
|
416
|
+
return super().get_hyperparams() | {
|
|
417
|
+
'reconstruct_func': self.reconstruct_func.__class__.__name__,
|
|
418
|
+
'latent_func': self.latent_func.__class__.__name__,
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
class Decoder(BaseArchitecture):
|
|
423
|
+
"""
|
|
424
|
+
Decoder architecture for predicting high-dimensional data from low-dimensional inputs.
|
|
425
|
+
|
|
426
|
+
Attributes
|
|
427
|
+
----------
|
|
428
|
+
description : str
|
|
429
|
+
Description of the architecture
|
|
430
|
+
losses : tuple[list[LossCT], list[LossCT]]
|
|
431
|
+
Architecture training and validation losses as a float or dictionary of losses for each loss
|
|
432
|
+
function
|
|
433
|
+
transforms : dict[str, list[BaseTransform] | BaseTransform | None]
|
|
434
|
+
Keys for the output data from predict and corresponding transforms
|
|
435
|
+
loss_func : BaseLoss
|
|
436
|
+
Loss function for the reconstructions
|
|
437
|
+
idxs: ndarray | None
|
|
438
|
+
Training data indices with shape (N) and type int, where N is the number of elements in the
|
|
439
|
+
training dataset
|
|
440
|
+
optimiser : Optimizer
|
|
441
|
+
Architecture optimiser
|
|
442
|
+
scheduler : LRScheduler
|
|
443
|
+
Optimiser scheduler
|
|
444
|
+
net : Network | CompatibleNetwork
|
|
445
|
+
Neural network
|
|
446
|
+
"""
|
|
447
|
+
def __init__(
|
|
448
|
+
self,
|
|
449
|
+
save_num: int | str,
|
|
450
|
+
states_dir: str,
|
|
451
|
+
net: nn.Module | Network | CompatibleNetwork,
|
|
452
|
+
*,
|
|
453
|
+
overwrite: bool = False,
|
|
454
|
+
mix_precision: bool = False,
|
|
455
|
+
learning_rate: float = 1e-3,
|
|
456
|
+
description: str = '',
|
|
457
|
+
verbose: Literal['epoch', 'full', 'plot', 'progress', None] = 'epoch',
|
|
458
|
+
transform: BaseTransform | None = None,
|
|
459
|
+
in_transform: BaseTransform | None = None,
|
|
460
|
+
optimiser_kwargs: dict[str, Any] | None = None,
|
|
461
|
+
scheduler_kwargs: dict[str, Any] | None = None) -> None:
|
|
462
|
+
"""
|
|
463
|
+
Parameters
|
|
464
|
+
----------
|
|
465
|
+
save_num : int | str
|
|
466
|
+
File number or name to save the architecture
|
|
467
|
+
states_dir : str
|
|
468
|
+
Directory to save the architecture
|
|
469
|
+
net : Module | Network | CompatibleNetwork
|
|
470
|
+
Network to predict low-dimensional data
|
|
471
|
+
overwrite : bool, Optional
|
|
472
|
+
If saving can overwrite an existing save file, if True and file with the same name
|
|
473
|
+
exists, an error will be raised, default = False
|
|
474
|
+
mix_precision: bool, Optional
|
|
475
|
+
If mixed precision should be used, default = False
|
|
476
|
+
learning_rate : float, Optional
|
|
477
|
+
Optimiser initial learning rate, if None, no optimiser or scheduler will be set,
|
|
478
|
+
default = 1e-3
|
|
479
|
+
description : str, Optional
|
|
480
|
+
Description of the architecture
|
|
481
|
+
verbose : {'epoch', 'full', 'progress', None}
|
|
482
|
+
If details about each epoch should be printed ('epoch'), details about epoch and epoch
|
|
483
|
+
progress (full), just total progress ('progress'), or nothing (None)
|
|
484
|
+
transform : BaseTransform, Optional
|
|
485
|
+
Transformation of the architecture's output
|
|
486
|
+
in_transform : BaseTransform, Optional
|
|
487
|
+
Transformation for the input data
|
|
488
|
+
optimiser_kwargs : dict[str, Any] | None, Optional
|
|
489
|
+
Optional keyword arguments to pass to init_optimiser
|
|
490
|
+
scheduler_kwargs : dict[str, Any] | None, Optional
|
|
491
|
+
Optional keyword arguments to pass to init_scheduler
|
|
492
|
+
"""
|
|
493
|
+
super().__init__(
|
|
494
|
+
save_num,
|
|
495
|
+
states_dir,
|
|
496
|
+
net,
|
|
497
|
+
overwrite=overwrite,
|
|
498
|
+
mix_precision=mix_precision,
|
|
499
|
+
learning_rate=learning_rate,
|
|
500
|
+
description=description,
|
|
501
|
+
verbose=verbose,
|
|
502
|
+
transform=transform,
|
|
503
|
+
in_transform=in_transform,
|
|
504
|
+
optimiser_kwargs=optimiser_kwargs,
|
|
505
|
+
scheduler_kwargs=scheduler_kwargs,
|
|
506
|
+
)
|
|
507
|
+
self.loss_func: BaseLoss = MSELoss()
|
|
508
|
+
|
|
509
|
+
def __getstate__(self) -> dict[str, Any]:
|
|
510
|
+
return super().__getstate__() | {'loss_func': self.loss_func}
|
|
511
|
+
|
|
512
|
+
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
513
|
+
super().__setstate__(state)
|
|
514
|
+
self.loss_func = state['loss_func']
|
|
515
|
+
|
|
516
|
+
@staticmethod
|
|
517
|
+
def _data_loader_translation(low_dim: TensorT, high_dim: TensorT) -> tuple[TensorT, TensorT]:
|
|
518
|
+
"""
|
|
519
|
+
Orders low and high dimensional tensors from the data loader as inputs and targets for the
|
|
520
|
+
network.
|
|
521
|
+
|
|
522
|
+
Parameters
|
|
523
|
+
----------
|
|
524
|
+
low_dim : TensorT
|
|
525
|
+
Low dimensional tensor from the data loader of shape (N,...) and type float, where N is
|
|
526
|
+
the batch size
|
|
527
|
+
high_dim : TensorT
|
|
528
|
+
High dimensional tensor from the data loader of shape (N,...) and type float
|
|
529
|
+
|
|
530
|
+
Returns
|
|
531
|
+
-------
|
|
532
|
+
tuple[TensorT, TensorT]
|
|
533
|
+
Input and output target tensors of shape (N,...) and type float
|
|
534
|
+
"""
|
|
535
|
+
return low_dim, high_dim
|
|
536
|
+
|
|
537
|
+
def _loss_tensor(
|
|
538
|
+
self,
|
|
539
|
+
in_data: TensorListLike,
|
|
540
|
+
target: TensorListLike,
|
|
541
|
+
_: Any) -> dict[str, Tensor] | Tensor:
|
|
542
|
+
"""
|
|
543
|
+
Calculates the loss from the architecture's predictions.
|
|
544
|
+
|
|
545
|
+
Parameters
|
|
546
|
+
----------
|
|
547
|
+
in_data : TensorListLike
|
|
548
|
+
Input low dimensional data of shape (N, ...) and type float, where N is the batch size
|
|
549
|
+
target : TensorListLike
|
|
550
|
+
Target high dimensional data of shape (N, ...) and type float
|
|
551
|
+
|
|
552
|
+
Returns
|
|
553
|
+
-------
|
|
554
|
+
dict[str, Tensor] | Tensor
|
|
555
|
+
Loss from the architecture's predictions
|
|
556
|
+
"""
|
|
557
|
+
return self.loss_func(self.net(in_data), target)
|
|
558
|
+
|
|
559
|
+
def extra_repr(self) -> str:
|
|
560
|
+
"""
|
|
561
|
+
Additional representation of the architecture.
|
|
562
|
+
|
|
563
|
+
Returns
|
|
564
|
+
-------
|
|
565
|
+
str
|
|
566
|
+
Architecture specific representation
|
|
567
|
+
"""
|
|
568
|
+
return f'loss_func: {self.loss_func}'
|
|
569
|
+
|
|
570
|
+
def get_hyperparams(self) -> dict[str, Any]:
|
|
571
|
+
"""
|
|
572
|
+
Get the hyperparameters of the decoder.
|
|
573
|
+
|
|
574
|
+
Returns
|
|
575
|
+
-------
|
|
576
|
+
dict[str, Any]
|
|
577
|
+
Hyperparameters of the decoder
|
|
578
|
+
"""
|
|
579
|
+
return super().get_hyperparams() | {'loss_func': self.loss_func.__class__.__name__}
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
class Encoder(BaseEncoder):
|
|
583
|
+
"""
|
|
584
|
+
Encoder architecture for predicting low-dimensional data from high-dimensional inputs.
|
|
585
|
+
|
|
586
|
+
Attributes
|
|
587
|
+
----------
|
|
588
|
+
description : str
|
|
589
|
+
Description of the architecture
|
|
590
|
+
losses : tuple[list[LossCT], list[LossCT]]
|
|
591
|
+
Architecture training and validation losses as a float or dictionary of losses for each loss
|
|
592
|
+
function
|
|
593
|
+
transforms : dict[str, list[BaseTransform] | BaseTransform | None]
|
|
594
|
+
Keys for the output data from predict and corresponding transforms
|
|
595
|
+
idxs: ndarray | None
|
|
596
|
+
Training data indices with shape (N) and type int, where N is the number of elements in the
|
|
597
|
+
training dataset
|
|
598
|
+
classes : Tensor | None
|
|
599
|
+
Unique classes of shape (C) and type int/float, where C is the number of classes
|
|
600
|
+
optimiser : Optimizer
|
|
601
|
+
Architecture optimiser
|
|
602
|
+
scheduler : LRScheduler
|
|
603
|
+
Optimiser scheduler
|
|
604
|
+
net : Network | CompatibleNetwork
|
|
605
|
+
Neural network
|
|
606
|
+
"""
|
|
607
|
+
def batch_predict(self, data: TensorListLike, **_: Any) -> tuple[NDArrayListLike | None, ...]:
|
|
608
|
+
"""
|
|
609
|
+
Generates predictions for the given data.
|
|
610
|
+
|
|
611
|
+
Parameters
|
|
612
|
+
----------
|
|
613
|
+
data : TensorListLike
|
|
614
|
+
Data to generate predictions for of shape (N, ...) and type float, where N is the batch
|
|
615
|
+
size
|
|
616
|
+
|
|
617
|
+
Returns
|
|
618
|
+
-------
|
|
619
|
+
tuple[NDArrayListLike | None, ...]
|
|
620
|
+
Predictions of shape (N,...) and type float for the given data
|
|
621
|
+
"""
|
|
622
|
+
output: NDArrayListLike | None = super().batch_predict(data)[0]
|
|
623
|
+
assert isinstance(output, ndarray)
|
|
624
|
+
|
|
625
|
+
if isinstance(self._loss_func_, nn.CrossEntropyLoss):
|
|
626
|
+
output = np.argmax(output, axis=-1, keepdims=True)
|
|
627
|
+
return (output,)
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
__all__ = ['BaseEncoder', 'Autoencoder', 'Decoder', 'Encoder']
|