netloader 3.11.4__tar.gz → 3.12.0__tar.gz
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-3.11.4 → netloader-3.12.0}/PKG-INFO +1 -1
- {netloader-3.11.4 → netloader-3.12.0}/netloader/__init__.py +1 -1
- {netloader-3.11.4 → netloader-3.12.0}/netloader/architectures/base.py +11 -1
- netloader-3.12.0/netloader/data/__init__.py +8 -0
- netloader-3.12.0/netloader/data/datasets.py +270 -0
- netloader-3.11.4/netloader/data.py → netloader-3.12.0/netloader/data/structures.py +219 -310
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/base.py +5 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/misc.py +5 -5
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/multi_layer.py +1 -1
- {netloader-3.11.4 → netloader-3.12.0}/netloader/models/misc.py +9 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/network.py +60 -5
- {netloader-3.11.4 → netloader-3.12.0}/netloader/transforms.py +23 -5
- {netloader-3.11.4 → netloader-3.12.0}/netloader/utils/utils.py +36 -7
- {netloader-3.11.4 → netloader-3.12.0}/netloader.egg-info/PKG-INFO +1 -1
- {netloader-3.11.4 → netloader-3.12.0}/netloader.egg-info/SOURCES.txt +3 -1
- {netloader-3.11.4 → netloader-3.12.0}/LICENSE.txt +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/README.md +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/architectures/__init__.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/architectures/encoder_decoder.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/architectures/flows.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/architectures/utils.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/__init__.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/blocks.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/convolutional.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/flows.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/linear.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/pooling.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/recurrent.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/layers/utils.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/loss_funcs.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/models/__init__.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/models/convnext.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/networks/__init__.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/schedulers.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/utils/__init__.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/utils/configs.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/utils/transforms.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader/utils/types.py +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader.egg-info/dependency_links.txt +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader.egg-info/requires.txt +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/netloader.egg-info/top_level.txt +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/pyproject.toml +0 -0
- {netloader-3.11.4 → netloader-3.12.0}/setup.cfg +0 -0
|
@@ -6,7 +6,7 @@ import logging
|
|
|
6
6
|
import warnings
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
__version__ = '3.
|
|
9
|
+
__version__ = '3.12.0'
|
|
10
10
|
__author__ = 'Ethan Tregidga'
|
|
11
11
|
logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARNING)
|
|
12
12
|
warnings.filterwarnings('once', category=DeprecationWarning, module=r'^netloader(\.|$)')
|
|
@@ -46,6 +46,8 @@ class BaseArchitecture(UtilityMixin, ABC, Generic[LossCT, TensorLossCT]):
|
|
|
46
46
|
|
|
47
47
|
Attributes
|
|
48
48
|
----------
|
|
49
|
+
checkpoints : bool
|
|
50
|
+
If checkpoints should be saved after network forward pass
|
|
49
51
|
description : str
|
|
50
52
|
Description of the architecture
|
|
51
53
|
version : str
|
|
@@ -81,6 +83,7 @@ class BaseArchitecture(UtilityMixin, ABC, Generic[LossCT, TensorLossCT]):
|
|
|
81
83
|
_scheduler_kwargs: dict[str, Any]
|
|
82
84
|
_logger: log.Logger = log.getLogger(__name__)
|
|
83
85
|
_device: torch.device = torch.device('cpu')
|
|
86
|
+
checkpoints: bool = False
|
|
84
87
|
description: str
|
|
85
88
|
version: str = netloader.__version__
|
|
86
89
|
losses: tuple[list[LossCT], list[LossCT]]
|
|
@@ -285,7 +288,7 @@ class BaseArchitecture(UtilityMixin, ABC, Generic[LossCT, TensorLossCT]):
|
|
|
285
288
|
self.net = state['net']
|
|
286
289
|
self.run = state.get('run', None)
|
|
287
290
|
|
|
288
|
-
if not utils.compare_versions(self.version, netloader.__version__):
|
|
291
|
+
if not utils.compare_versions(self.version, netloader.__version__, level='minor'):
|
|
289
292
|
warn(
|
|
290
293
|
f'Architecture version ({self.version}) is older than the current '
|
|
291
294
|
f'NetLoader version ({netloader.__version__}), please resave the architecture '
|
|
@@ -515,6 +518,9 @@ class BaseArchitecture(UtilityMixin, ABC, Generic[LossCT, TensorLossCT]):
|
|
|
515
518
|
|
|
516
519
|
self._update(loss['total'] if isinstance(loss, dict) else loss)
|
|
517
520
|
|
|
521
|
+
if not self.checkpoints:
|
|
522
|
+
self.net.clear_checkpoints()
|
|
523
|
+
|
|
518
524
|
if isinstance(loss, dict):
|
|
519
525
|
return {key: value.item() for key, value in loss.items()} # type: ignore[return-value]
|
|
520
526
|
return loss.item() # type: ignore[return-value]
|
|
@@ -1069,6 +1075,9 @@ class BaseArchitecture(UtilityMixin, ABC, Generic[LossCT, TensorLossCT]):
|
|
|
1069
1075
|
]))
|
|
1070
1076
|
self._predict_print(i, time() - t_initial, loader)
|
|
1071
1077
|
|
|
1078
|
+
if not self.checkpoints:
|
|
1079
|
+
self.net.clear_checkpoints()
|
|
1080
|
+
|
|
1072
1081
|
# Transforms all data and saves it to a dictionary
|
|
1073
1082
|
for (key, transform), datum_ in zip(transforms.items(), zip(*data)):
|
|
1074
1083
|
if datum_[0] is None:
|
|
@@ -1087,6 +1096,7 @@ class BaseArchitecture(UtilityMixin, ABC, Generic[LossCT, TensorLossCT]):
|
|
|
1087
1096
|
datum,
|
|
1088
1097
|
transform if isinstance(transform, list) else repeat(transform),
|
|
1089
1098
|
)],
|
|
1099
|
+
names=datum.get_names(),
|
|
1090
1100
|
)
|
|
1091
1101
|
elif isinstance(transform, BaseTransform):
|
|
1092
1102
|
assert not isinstance(datum, DataList)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base dataset classes and data structures for NetLoader.
|
|
3
|
+
"""
|
|
4
|
+
from netloader.data.datasets import BaseDataset, loader_init
|
|
5
|
+
from netloader.data.structures import ApplyFunc, Data, DataList, data_collation
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
__all__ = ['ApplyFunc', 'Data', 'DataList', 'BaseDataset', 'data_collation', 'loader_init']
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base dataset classes for use with BaseArchitecture.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
import logging as log
|
|
6
|
+
from typing import Any, Generic, Literal, Sequence, cast, overload
|
|
7
|
+
|
|
8
|
+
import torch
|
|
9
|
+
import numpy as np
|
|
10
|
+
from torch.utils.data import Dataset, DataLoader, Subset
|
|
11
|
+
from numpy import ndarray
|
|
12
|
+
|
|
13
|
+
from netloader.utils.types import ArrayLike, DatasetT, DataListT
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class BaseDatasetMeta(type):
|
|
17
|
+
"""
|
|
18
|
+
Automatically creates an index for each sample in the dataset after the dataset has been
|
|
19
|
+
initialised.
|
|
20
|
+
"""
|
|
21
|
+
def __call__(cls: type[DatasetT], *args: Any, **kwargs: Any) -> DatasetT:
|
|
22
|
+
"""
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
cls : type[DatasetT]
|
|
26
|
+
Class that inherited BaseDatasetMeta
|
|
27
|
+
*args
|
|
28
|
+
Optional arguments to pass to BaseDataset class
|
|
29
|
+
**kwargs
|
|
30
|
+
Optional keyword arguments to pass to BaseDataset class
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
DatasetT
|
|
35
|
+
Dataset instance from the class that inherited BaseDatasetMeta
|
|
36
|
+
"""
|
|
37
|
+
instance: DatasetT = type.__call__(cls, *args, **kwargs)
|
|
38
|
+
|
|
39
|
+
if hasattr(instance, 'idxs') and instance.idxs.dtype != np.int_:
|
|
40
|
+
raise ValueError(f'idxs attribute already exists and does not have type int '
|
|
41
|
+
f'({instance.idxs.dtype}), idxs attribute must be reserved for sample '
|
|
42
|
+
f'index')
|
|
43
|
+
|
|
44
|
+
if not hasattr(instance, 'high_dim') or instance.high_dim is None:
|
|
45
|
+
raise ValueError(f'{instance.__class__.__name__} has no high_dim attribute which is '
|
|
46
|
+
f'required by BaseDatasetMeta for creating idxs attribute')
|
|
47
|
+
|
|
48
|
+
if len(instance.idxs) == 0:
|
|
49
|
+
instance.idxs = np.arange(len(instance.high_dim))
|
|
50
|
+
elif len(instance.idxs) != len(instance.high_dim):
|
|
51
|
+
log.getLogger(__name__).warning(f'Length of idxs ({len(instance.idxs)}) and length of '
|
|
52
|
+
f'high_dim ({len(instance.high_dim)}) does not match, '
|
|
53
|
+
f'idxs will be sent to a range of high_dim length')
|
|
54
|
+
instance.idxs = np.arange(len(instance.high_dim))
|
|
55
|
+
|
|
56
|
+
for attribute in ('extra', 'low_dim', 'high_dim'):
|
|
57
|
+
if (getattr(instance, attribute) is not None and
|
|
58
|
+
len(getattr(instance, attribute)) != len(instance.idxs)):
|
|
59
|
+
raise ValueError(f'Length of attribute {attribute} '
|
|
60
|
+
f'({len(getattr(instance, attribute))}) and idxs '
|
|
61
|
+
f'({len(instance.idxs)}) does not match')
|
|
62
|
+
return instance
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class BaseDataset(
|
|
66
|
+
Dataset[tuple[int, DataListT, DataListT, Any]],
|
|
67
|
+
Generic[DataListT],
|
|
68
|
+
metaclass=BaseDatasetMeta):
|
|
69
|
+
"""
|
|
70
|
+
Base dataset class for use with BaseNetwork.
|
|
71
|
+
|
|
72
|
+
Attributes
|
|
73
|
+
----------
|
|
74
|
+
extra : list[Any] | ArrayLike | None
|
|
75
|
+
Additional data for each sample in the dataset of length N with shape (N,...) and type Any
|
|
76
|
+
idxs : ndarray
|
|
77
|
+
Index for each sample in the dataset with shape (N) and type int
|
|
78
|
+
low_dim : DataListT | None
|
|
79
|
+
Low dimensional data for each sample in the dataset with shape (N,...)
|
|
80
|
+
high_dim : DataListT | None
|
|
81
|
+
High dimensional data for each sample in the dataset with shape (N,...), this is required
|
|
82
|
+
"""
|
|
83
|
+
def __init__(self) -> None:
|
|
84
|
+
super().__init__()
|
|
85
|
+
self.extra: list[Any] | ArrayLike | None = None
|
|
86
|
+
self.idxs: ndarray = np.array([], dtype=np.int_)
|
|
87
|
+
self.low_dim: DataListT | None = None
|
|
88
|
+
self.high_dim: DataListT | None = None
|
|
89
|
+
|
|
90
|
+
def __len__(self) -> int:
|
|
91
|
+
"""
|
|
92
|
+
Returns the number of samples in the dataset
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
int
|
|
97
|
+
Number of samples in the dataset
|
|
98
|
+
"""
|
|
99
|
+
return len(self.idxs)
|
|
100
|
+
|
|
101
|
+
def __getitem__(self, idx: int) -> tuple[int, DataListT, DataListT, Any]:
|
|
102
|
+
"""
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
idx : int
|
|
106
|
+
Sample index
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
tuple[int, DataListT, DataListT, Any]
|
|
111
|
+
Sample index, low dimensional data, high dimensional data, and extra data
|
|
112
|
+
"""
|
|
113
|
+
return self.idxs[idx], self.get_low_dim(idx), self.get_high_dim(idx), self.get_extra(idx)
|
|
114
|
+
|
|
115
|
+
def get_extra(self, idx: int) -> Any:
|
|
116
|
+
"""
|
|
117
|
+
Gets extra data for the sample of the given index
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
idx : int
|
|
122
|
+
Sample index
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
Any
|
|
127
|
+
Sample extra data
|
|
128
|
+
"""
|
|
129
|
+
return torch.tensor(()) if self.extra is None else self.extra[idx]
|
|
130
|
+
|
|
131
|
+
def get_high_dim(self, idx: int) -> DataListT:
|
|
132
|
+
"""
|
|
133
|
+
Gets a high dimensional sample of the given index
|
|
134
|
+
|
|
135
|
+
Parameters
|
|
136
|
+
----------
|
|
137
|
+
idx : int
|
|
138
|
+
Sample index
|
|
139
|
+
|
|
140
|
+
Returns
|
|
141
|
+
-------
|
|
142
|
+
DataListT
|
|
143
|
+
High dimensional sample
|
|
144
|
+
"""
|
|
145
|
+
assert self.high_dim is not None
|
|
146
|
+
return cast(DataListT, self.high_dim[idx])
|
|
147
|
+
|
|
148
|
+
def get_low_dim(self, idx: int) -> DataListT:
|
|
149
|
+
"""
|
|
150
|
+
Gets a low dimensional sample of the given index
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
----------
|
|
154
|
+
idx : int
|
|
155
|
+
Sample index
|
|
156
|
+
|
|
157
|
+
Returns
|
|
158
|
+
-------
|
|
159
|
+
DataListT
|
|
160
|
+
Low dimensional sample
|
|
161
|
+
"""
|
|
162
|
+
return cast(DataListT, torch.tensor(()) if self.low_dim is None else self.low_dim[idx])
|
|
163
|
+
|
|
164
|
+
def step(self, epoch: float) -> None:
|
|
165
|
+
"""
|
|
166
|
+
Step the dataset for each training iteration.
|
|
167
|
+
|
|
168
|
+
Parameters
|
|
169
|
+
----------
|
|
170
|
+
epoch : float
|
|
171
|
+
Current epoch number
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@overload
|
|
176
|
+
def loader_init(
|
|
177
|
+
dataset: DatasetT,
|
|
178
|
+
*,
|
|
179
|
+
return_idxs: Literal[False],
|
|
180
|
+
batch_size: int = ...,
|
|
181
|
+
ratios: list[float] | tuple[float, ...] | None = ...,
|
|
182
|
+
idxs: list[ndarray] | tuple[ndarray, ...] | ndarray | None = ...,
|
|
183
|
+
**kwargs: Any) -> tuple[DataLoader[tuple[int, DataListT, DataListT, Any]], ...]: ...
|
|
184
|
+
|
|
185
|
+
@overload
|
|
186
|
+
def loader_init(
|
|
187
|
+
dataset: DatasetT,
|
|
188
|
+
*,
|
|
189
|
+
return_idxs: Literal[True],
|
|
190
|
+
batch_size: int = ...,
|
|
191
|
+
ratios: list[float] | tuple[float, ...] | None = ...,
|
|
192
|
+
idxs: list[ndarray] | tuple[ndarray, ...] | ndarray | None = ...,
|
|
193
|
+
**kwargs: Any) -> tuple[
|
|
194
|
+
tuple[DataLoader[tuple[int, DataListT, DataListT, Any]], ...],
|
|
195
|
+
tuple[Sequence[int], ...]]: ...
|
|
196
|
+
|
|
197
|
+
def loader_init(
|
|
198
|
+
dataset: DatasetT,
|
|
199
|
+
*,
|
|
200
|
+
return_idxs: bool = False,
|
|
201
|
+
batch_size: int = 64,
|
|
202
|
+
ratios: list[float] | tuple[float, ...] | None = None,
|
|
203
|
+
idxs: list[ndarray] | tuple[ndarray, ...] | ndarray | None = None,
|
|
204
|
+
**kwargs: Any,
|
|
205
|
+
) -> (tuple[DataLoader[tuple[int, DataListT, DataListT, Any]], ...] |
|
|
206
|
+
tuple[
|
|
207
|
+
tuple[DataLoader[tuple[int, DataListT, DataListT, Any]], ...],
|
|
208
|
+
tuple[Sequence[int], ...]]):
|
|
209
|
+
# pylint: disable=line-too-long
|
|
210
|
+
"""
|
|
211
|
+
Initialises data loaders from a subset of the dataset with the given ratios.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
dataset : DatasetT
|
|
216
|
+
Dataset to create data loaders from
|
|
217
|
+
return_idxs : bool, Optional
|
|
218
|
+
If the indexes for each data loader should be returned, default = False
|
|
219
|
+
batch_size : int, Optional
|
|
220
|
+
Batch size when sampling from the data loaders, default = 64
|
|
221
|
+
ratios : list[float] | tuple[float, ...] | None, Optional
|
|
222
|
+
Ratios of length M to split up the dataset into subsets, if idxs is provided, dataset will
|
|
223
|
+
first be split up using idxs and ratios will be used on the remaining samples,
|
|
224
|
+
default = (0.8,0.2)
|
|
225
|
+
idxs : list[ndarray] | tuple[ndarray, ...] | ndarray | None, Optional
|
|
226
|
+
Dataset indexes for creating the subsets with shape (N,S), where N is the number of subsets
|
|
227
|
+
and S is the number of samples in each subset
|
|
228
|
+
**kwargs : Any
|
|
229
|
+
Optional keyword arguments to pass to DataLoader
|
|
230
|
+
|
|
231
|
+
Returns
|
|
232
|
+
-------
|
|
233
|
+
tuple[DataLoader[tuple[int, DataListT, DataListT, Any]], ...] | tuple[tuple[DataLoader[tuple[int, DataListT, DataListT, Any]], ...], tuple[Sequence[int], ...]]
|
|
234
|
+
Data loaders for each subset of length N + M and optionally indexes used for each subset
|
|
235
|
+
"""
|
|
236
|
+
# pylint: enable=line-too-long
|
|
237
|
+
num: int
|
|
238
|
+
slice_: float | ndarray
|
|
239
|
+
loaders: list[DataLoader[tuple[int, DataListT, DataListT, Any]]] = []
|
|
240
|
+
data_idxs: ndarray = np.arange(len(dataset))
|
|
241
|
+
loader: DataLoader[tuple[int, DataListT, DataListT, Any]]
|
|
242
|
+
idxs = [] if idxs is None else list(idxs) \
|
|
243
|
+
if isinstance(idxs, (tuple, list)) or np.ndim(idxs) > 1 else [idxs]
|
|
244
|
+
ratios = (0.8, 1) if ratios is None else list(np.cumsum(np.array(ratios) / np.sum(ratios)))
|
|
245
|
+
np.random.shuffle(data_idxs)
|
|
246
|
+
|
|
247
|
+
for slice_ in idxs + list(ratios):
|
|
248
|
+
if isinstance(slice_, (int, float)):
|
|
249
|
+
num = max(int(len(data_idxs) * slice_), 1)
|
|
250
|
+
slice_ = data_idxs[:num]
|
|
251
|
+
|
|
252
|
+
if not np.isin(data_idxs, slice_).any():
|
|
253
|
+
continue
|
|
254
|
+
|
|
255
|
+
loaders.append(DataLoader(
|
|
256
|
+
Subset(
|
|
257
|
+
cast(Dataset[tuple[int, DataListT, DataListT, Any]], dataset),
|
|
258
|
+
data_idxs[np.isin(data_idxs, slice_)].tolist(),
|
|
259
|
+
),
|
|
260
|
+
batch_size=batch_size,
|
|
261
|
+
**{'shuffle': True} | kwargs,
|
|
262
|
+
))
|
|
263
|
+
data_idxs = np.delete(data_idxs, np.isin(data_idxs, slice_))
|
|
264
|
+
|
|
265
|
+
if return_idxs:
|
|
266
|
+
return tuple(loaders), tuple(cast(Subset, loader.dataset).indices for loader in loaders)
|
|
267
|
+
return tuple(loaders)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
__all__ = ['BaseDataset', 'loader_init']
|