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,501 @@
1
+ """
2
+ Classes that contain normalising flow-based architectures
3
+ """
4
+ from typing import Any, Literal, cast
5
+
6
+ import torch
7
+ import numpy as np
8
+ from numpy import ndarray
9
+ from torch import optim, nn, Tensor
10
+ from torch.utils.data import DataLoader
11
+ from torch.optim.optimizer import ParamsT
12
+ from zuko.distributions import NormalizingFlow
13
+
14
+ from netloader.data import Data
15
+ from netloader.utils import label_change
16
+ from netloader.loss_funcs import BaseLoss
17
+ from netloader.transforms import BaseTransform
18
+ from netloader.network import Network, CompatibleNetwork
19
+ from netloader.architectures.base import BaseArchitecture
20
+ from netloader.architectures.encoder_decoder import BaseEncoder
21
+ from netloader.utils.types import NDArrayLike, TensorListLike, NDArrayListLike, TensorT
22
+
23
+
24
+ class NormFlow(BaseArchitecture):
25
+ """
26
+ Transforms a simple distribution into a distribution that reflects the input data
27
+
28
+ Requires last layer to be a normalising flow and will not pass input data through the network.
29
+
30
+ Attributes
31
+ ----------
32
+ net : Network | CompatibleNetwork
33
+ Neural spline flow
34
+ description : str
35
+ Description of the architecture
36
+ losses : tuple[list[LossCT], list[LossCT]]
37
+ Architecture training and validation losses as a float or dictionary of losses for each loss
38
+ function
39
+ transforms : dict[str, list[BaseTransform] | BaseTransform | None]
40
+ Keys for the output data from predict and corresponding transforms
41
+ idxs: ndarray | None
42
+ Training data indices with shape (N) and type int, where N is the number of elements in the
43
+ training dataset
44
+ optimiser : Optimizer
45
+ Architecture optimiser
46
+ scheduler : LRScheduler
47
+ Optimiser scheduler
48
+ """
49
+ @staticmethod
50
+ def _data_loader_translation(low_dim: TensorT, high_dim: TensorT) -> tuple[TensorT, TensorT]:
51
+ """
52
+ Orders low and high dimensional tensors from the data loader as inputs and targets for the
53
+ network.
54
+
55
+ Parameters
56
+ ----------
57
+ low_dim : TensorT
58
+ Low dimensional tensor from the data loader of shape (N, ...) and type float, where N is
59
+ the batch size
60
+ high_dim : TensorT
61
+ High dimensional tensor from the data loader of shape (N, ...) and type float
62
+
63
+ Returns
64
+ -------
65
+ tuple[TensorT, TensorT]
66
+ Input and output target tensors of shape (N, ...) and type float
67
+ """
68
+ return low_dim, high_dim
69
+
70
+ def _loss_tensor(self, _: Any, target: TensorListLike, __: Any) -> Tensor:
71
+ """
72
+ Calculates the loss from the flow's predictions.
73
+
74
+ Parameters
75
+ ----------
76
+ target : TensorListLike
77
+ Target high dimensional data of shape (N, ...) and type float, where N is the batch size
78
+
79
+ Returns
80
+ -------
81
+ Tensor
82
+ Loss from the flow's predictions
83
+ """
84
+ return -self.net().log_prob(target).mean()
85
+
86
+ def predict(
87
+ self,
88
+ loader: DataLoader[Any] | None = None,
89
+ *,
90
+ path: str = '',
91
+ num: list[int] | None = None,
92
+ **__: Any) -> dict[str, NDArrayLike]:
93
+ """
94
+ Generates probability distributions for a dataset and can save to a file.
95
+
96
+ Parameters
97
+ ----------
98
+ loader : DataLoader[Any] | None, Optional
99
+ Unused, present for compatibility with BaseArchitecture
100
+ path : str, Optional
101
+ Path as pkl file to save the predictions if they should be saved
102
+ num : list[int] | None, Optional
103
+ Number of samples, S, to generate, default = [1e3]
104
+
105
+ Returns
106
+ -------
107
+ dict[str, NDArrayLike]
108
+ Predicted distribution, with shape (N,...,S) and type float for dataset of size N
109
+ """
110
+ assert isinstance(self.transforms['preds'], (BaseTransform, type(None)))
111
+ data: dict[str, NDArrayLike]
112
+ samples: ndarray
113
+ transform: BaseTransform | None = self.transforms['preds']
114
+
115
+ if num is None:
116
+ num = [int(1e3)]
117
+
118
+ samples = self.net().sample(num).moveaxis(0, -1).detach().cpu().numpy()
119
+ data = {'samples': samples if transform is None else transform(samples, back=True)}
120
+ self._save_predictions(path, data)
121
+ return data
122
+
123
+
124
+ class NormFlowEncoder(BaseEncoder):
125
+ """
126
+ Calculates the loss for a network and normalising flow that takes high-dimensional data
127
+ and predicts a low-dimensional data distribution.
128
+
129
+ Requires the normalising flow to be the last layer in the network.
130
+
131
+ Attributes
132
+ ----------
133
+ description : str
134
+ Description of the architecture
135
+ losses : tuple[list[LossCT], list[LossCT]]
136
+ Architecture training and validation losses as a float or dictionary of losses for each loss
137
+ function
138
+ transforms : dict[str, list[BaseTransform] | BaseTransform | None]
139
+ Keys for the output data from predict and corresponding transforms
140
+ idxs: ndarray | None
141
+ Training data indices with shape (N) and type int, where N is the number of elements in the
142
+ training dataset
143
+ classes : Tensor | None
144
+ Unique classes of shape (C) and type int/float, where C is the number of classes
145
+ optimiser : Optimizer
146
+ Architecture optimiser
147
+ scheduler : LRScheduler
148
+ Optimiser scheduler
149
+ net : Network | CompatibleNetwork
150
+ Neural network
151
+ """
152
+ def __init__(
153
+ self,
154
+ save_num: int | str,
155
+ states_dir: str,
156
+ net: nn.Module | Network | CompatibleNetwork,
157
+ *,
158
+ overwrite: bool = False,
159
+ mix_precision: bool = False,
160
+ net_checkpoint: int | None = None,
161
+ description: str = '',
162
+ verbose: Literal['epoch', 'full', 'plot', 'progress', None] = 'epoch',
163
+ train_epochs: tuple[int, int] = (0, -1),
164
+ learning_rate: tuple[float, float] = (1e-3,) * 2,
165
+ classes: Tensor | None = None,
166
+ loss_func: BaseLoss | None = None,
167
+ transform: list[BaseTransform] | BaseTransform | None = None,
168
+ in_transform: list[BaseTransform] | BaseTransform | None = None,
169
+ optimiser_kwargs: dict[str, Any] | None = None,
170
+ scheduler_kwargs: dict[str, Any] | None = None) -> None:
171
+ """
172
+ Parameters
173
+ ----------
174
+ save_num : int | str
175
+ File number or name to save the flow
176
+ states_dir : str
177
+ Directory to save the architecture and flow
178
+ net : Module | Network | CompatibleNetwork
179
+ Normalising flow to predict low-dimensional data distribution
180
+ overwrite : bool, Optional
181
+ If saving can overwrite an existing save file, if True and file with the same name
182
+ exists, an error will be raised, default = False
183
+ mix_precision: bool, Optional
184
+ If mixed precision should be used, default = False
185
+ net_checkpoint : int, Optional
186
+ Network checkpoint for calculating the encoder's loss, if none, will use output from the
187
+ network if output is a Tensor, else no encoder loss will be used
188
+ description : str, Optional
189
+ Description of the architecture training
190
+ verbose : {'full', 'progress', None}
191
+ If details about epoch should be printed ('full'), just a progress bar ('progress'),
192
+ or nothing (None)
193
+ train_epochs : tuple[int, int], Optional
194
+ Epoch when to start training the normalising flow and epoch when to stop training the
195
+ encoder, if both are zero, then flow will be trained from the beginning and encoder will
196
+ not be trained, if both are -1, then flow will never be trained and encoder will always
197
+ be trained, default = (0,-1)
198
+ learning_rate : tuple[float, float], Optional
199
+ Optimiser initial learning rate for encoder and normalising flow, if None, no optimiser
200
+ or scheduler will be set, default = (1e-3,1e-3)
201
+ classes : Tensor, Optional
202
+ Unique classes of shape (C) and type int/float, where C is the number of classes
203
+ loss_func : BaseLoss | None, Optional
204
+ Loss function for the encoder, if None MSELoss will be used if classes is None, else
205
+ CrossEntropyLoss will be used
206
+ in_transform : BaseTransform, Optional
207
+ Transformation for the input data
208
+ optimiser_kwargs : dict[str, Any] | None, Optional
209
+ Optional keyword arguments to pass to init_optimiser
210
+ scheduler_kwargs : dict[str, Any] | None, Optional
211
+ Optional keyword arguments to pass to init_scheduler
212
+ """
213
+ super().__init__(
214
+ save_num,
215
+ states_dir,
216
+ net,
217
+ overwrite=overwrite,
218
+ mix_precision=mix_precision,
219
+ learning_rate=0,
220
+ description=description,
221
+ verbose=verbose,
222
+ classes=classes,
223
+ loss_func=loss_func,
224
+ transform=transform,
225
+ in_transform=in_transform,
226
+ optimiser_kwargs=optimiser_kwargs,
227
+ scheduler_kwargs=scheduler_kwargs,
228
+ )
229
+ self._train_flow: bool
230
+ self._train_encoder: bool
231
+ self._checkpoint: int | None = net_checkpoint
232
+ self._epochs: tuple[int, int] = train_epochs
233
+
234
+ self._train_flow = not self._epochs[0]
235
+ self._train_encoder = bool(self._epochs[-1])
236
+ self._loss_weights = {'flow': 1, 'encoder': 1}
237
+ self.transforms |= {
238
+ 'distributions': transform,
239
+ 'probs': None,
240
+ 'max': transform,
241
+ 'meds': transform,
242
+ }
243
+
244
+ if not self._train_encoder:
245
+ self.net.layers[:-1].requires_grad_(False)
246
+
247
+ if not self._train_flow:
248
+ self.net.layers[-1].requires_grad_(False)
249
+
250
+ self.optimiser = self.init_optimiser(
251
+ self.get_param_groups(learning_rate),
252
+ **optimiser_kwargs or {},
253
+ )
254
+ self.scheduler = self.init_scheduler(self.optimiser, **scheduler_kwargs or {})
255
+
256
+ if isinstance(self.scheduler, optim.lr_scheduler.ReduceLROnPlateau):
257
+ self.scheduler.load_state_dict(
258
+ {'factor': 0.5, 'min_lr': min(learning_rate) * 1e-3} | (scheduler_kwargs or {}),
259
+ )
260
+
261
+ def __getstate__(self) -> dict[str, Any]:
262
+ return super().__getstate__() | {
263
+ 'train_flow': self._train_flow,
264
+ 'train_encoder': self._train_encoder,
265
+ 'checkpoint': self._checkpoint,
266
+ 'epochs': self._epochs,
267
+ }
268
+
269
+ def __setstate__(self, state: dict[str, Any]) -> None:
270
+ super().__setstate__(state)
271
+ self._train_flow = state['train_flow']
272
+ self._train_encoder = state['train_encoder']
273
+ self._checkpoint = state['checkpoint']
274
+ self._epochs = state['epochs']
275
+ self._loss_weights = state.get(
276
+ 'loss_weights',
277
+ {'flow': state.get('flow_loss', 1), 'encoder': state.get('encoder_loss', 1)},
278
+ )
279
+
280
+ def __getattr__(self, item: str) -> Any:
281
+ if item == 'flow_loss':
282
+ return self._loss_weights.get('flow', 0)
283
+ if item == 'encoder_loss':
284
+ return self._loss_weights.get('encoder', 0)
285
+ raise AttributeError(f"'{type(self).__name__}' object has no attribute '{item}'")
286
+
287
+ def _loss_tensor(
288
+ self,
289
+ in_data: TensorListLike,
290
+ target: TensorListLike,
291
+ _: Any) -> dict[str, Tensor]:
292
+ """
293
+ Calculates the loss from the network and flow's predictions.
294
+
295
+ Parameters
296
+ ----------
297
+ in_data : TensorListLike
298
+ Input high dimensional data of shape (N, ...) and type float, where N is the batch size
299
+ target : TensorListLike
300
+ Target low dimensional data of shape (N, ...) and type float
301
+
302
+ Returns
303
+ -------
304
+ dict[str, Tensor]
305
+ Dictionary of losses for encoder and flow
306
+ """
307
+ loss: dict[str, Tensor] = {}
308
+ output: Tensor | NormalizingFlow = self.net(in_data)
309
+
310
+ if not isinstance(target, Tensor):
311
+ raise ValueError(f'{self.__class__.__name__} requires target to be a Tensor, got '
312
+ f'{type(target)}')
313
+
314
+ if isinstance(output, NormalizingFlow) and self.get_loss_weights('flow'):
315
+ loss['flow'] = -output.log_prob(target).mean()
316
+
317
+ if isinstance(output, NormalizingFlow) and self._checkpoint:
318
+ output = self.net.checkpoints[self._checkpoint]
319
+
320
+ # Default shape is (N, L), but cross entropy expects (N)
321
+ if self.get_loss_weights('encoder') and self.classes is not None and \
322
+ isinstance(output, Tensor):
323
+ target = label_change(target.squeeze(), self.classes)
324
+
325
+ if self.get_loss_weights('encoder') and isinstance(output, Tensor):
326
+ loss['encoder'] = self._loss_func_(output, target)
327
+ return loss
328
+
329
+ def _update_epoch(self) -> None:
330
+ """
331
+ Updates network and flow epoch if they are being trained
332
+ """
333
+ super()._update_epoch()
334
+
335
+ if not self._train_flow and self._epoch >= self._epochs[0] != -1:
336
+ self._train_flow = True
337
+ self.net.layers[-1].requires_grad_(True)
338
+
339
+ if self._train_encoder and self._epoch >= self._epochs[-1] != -1:
340
+ self._train_encoder = False
341
+ self.net.layers[:-1].requires_grad_(False)
342
+
343
+ def batch_predict(
344
+ self,
345
+ data: TensorListLike,
346
+ *,
347
+ num: list[int] | None = None,
348
+ **_: Any) -> tuple[NDArrayListLike | None, ndarray | None]:
349
+ """
350
+ Generates probability distributions for the data batch
351
+
352
+ Parameters
353
+ ----------
354
+ data : TensorListLike
355
+ Data of shape (N,...) and type float to generate distributions for, where N is the batch
356
+ size
357
+ num : list[int] | None, Optional
358
+ Number of samples, S, to generate, default = [1e3]
359
+
360
+ Returns
361
+ -------
362
+ tuple[NDArrayListLike | None, ndarray | None]
363
+ Architecture output with shape (N,...) and type float and samples of shape (N,S) and type
364
+ float from each probability distribution
365
+ """
366
+ samples: ndarray | None = None
367
+ output: NormalizingFlow | TensorListLike | None = self.net(data)
368
+
369
+ if num is None:
370
+ num = [int(1e3)]
371
+
372
+ # Generate samples
373
+ if isinstance(output, NormalizingFlow):
374
+ samples = torch.transpose(
375
+ output.sample(num).squeeze(-1),
376
+ 0,
377
+ 1,
378
+ ).detach().cpu().numpy()
379
+ output = None
380
+
381
+ if output is None and self._checkpoint:
382
+ output = self.net.checkpoints[self._checkpoint]
383
+
384
+ assert not isinstance(output, NormalizingFlow)
385
+ return (None if output is None else
386
+ cast(NDArrayListLike, output.detach().cpu().numpy()),
387
+ samples)
388
+
389
+ def extra_repr(self) -> str:
390
+ """
391
+ Additional representation of the architecture.
392
+
393
+ Returns
394
+ -------
395
+ str
396
+ Architecture specific representation
397
+ """
398
+ return f'{super().extra_repr()}, train_epochs: {self._epochs}'
399
+
400
+ def get_hyperparams(self) -> dict[str, Any]:
401
+ """
402
+ Get the hyperparameters of the normalising flow encoder.
403
+
404
+ Returns
405
+ -------
406
+ dict[str, Any]
407
+ Hyperparameters of the normalising flow encoder
408
+ """
409
+ return super().get_hyperparams() | {
410
+ 'checkpoint': self._checkpoint,
411
+ 'train_epochs': self._epochs,
412
+ }
413
+
414
+ def predict(
415
+ self,
416
+ loader: DataLoader[Any],
417
+ *_: Any,
418
+ inputs: bool = False,
419
+ bin_num: int = 100,
420
+ path: str = '',
421
+ num: list[int] | None = None,
422
+ **__: Any) -> dict[str, NDArrayLike]:
423
+ """
424
+ Generates probability distributions for a dataset and can save to a file
425
+
426
+ Parameters
427
+ ----------
428
+ loader : DataLoader
429
+ Dataset to generate predictions for
430
+ inputs : bool, Optional
431
+ If the input data should be returned and saved, default = False,
432
+ bin_num : int, Optional
433
+ Number of bins for calculating the probability of the target and maximum of the
434
+ distribution, higher is more precise but requires more samples, default = 100
435
+ path : str, Optional
436
+ Path as a pkl file to save the predictions if they should be saved
437
+ num : list[int] | None, Optional
438
+ Number of samples, S, to generate from the predicted distribution, default = [1e3]
439
+
440
+ Returns
441
+ -------
442
+ dict[str, NDArrayLike]
443
+ Prediction IDs of shape (N), Optional inputs, target values, target probability,
444
+ distribution maximum, distribution median of shape (N,...), and predicted distribution
445
+ of shape (N,...,S) and type float for dataset of size N
446
+ """
447
+ probs: list[ndarray] = []
448
+ maxima: list[ndarray] = []
449
+ data: dict[str, NDArrayLike] = super().predict(loader, inputs=inputs, num=num)
450
+ hist: ndarray
451
+ bins: ndarray
452
+ prob: ndarray
453
+ distribution: ndarray
454
+ target: ndarray
455
+
456
+ if 'distributions' not in data:
457
+ self._save_predictions(path, data)
458
+ return data
459
+
460
+ assert (isinstance(data['distributions'], ndarray) and
461
+ isinstance(data['targets'], (ndarray, Data)))
462
+
463
+ for target, distribution in zip(
464
+ data['targets'] if isinstance(data['targets'], ndarray) else data['targets'].data,
465
+ data['distributions']):
466
+ hist, bins = np.histogram(distribution, bins=bin_num, density=True)
467
+ prob = hist * (bins[1] - bins[0])
468
+ bins[-1] += 1e-6
469
+ probs.append(prob[np.clip(np.digitize(target, bins) - 1, 0, bin_num - 1)])
470
+ maxima.append(bins[np.argmax(hist)])
471
+
472
+ data['probs'] = np.stack(probs)
473
+ data['max'] = np.stack(maxima)
474
+ data['meds'] = np.median(data['distributions'], axis=-1)
475
+ self._save_predictions(path, data)
476
+ return data
477
+
478
+ def get_param_groups(self, learning_rate: tuple[float, float] | None) -> ParamsT:
479
+ """
480
+ Sets the optimiser for the architecture, by default AdamW.
481
+
482
+ Parameters
483
+ ----------
484
+ learning_rate : tuple[float, float] | None, Optional
485
+ Learning rate for the encoder and normalising flow, if None, learning rate is set to 0
486
+ **kwargs
487
+ Optional keyword arguments to pass to the optimiser
488
+
489
+ Returns
490
+ -------
491
+ Optimizer
492
+ Architecture optimiser
493
+ """
494
+ learning_rate = learning_rate or (0,) * 2
495
+ return [
496
+ {'params': self.net.layers[:-1].parameters(), 'lr': learning_rate[0]},
497
+ {'params': self.net.layers[-1:].parameters(), 'lr': learning_rate[1]},
498
+ ]
499
+
500
+
501
+ __all__ = ['NormFlow', 'NormFlowEncoder']
@@ -0,0 +1,179 @@
1
+ """
2
+ Utility mixin for architecture classes and helper functions for optimisers and schedulers.
3
+ """
4
+ import pickle
5
+ import logging as log
6
+ from warnings import warn
7
+ from typing import Any, Callable
8
+
9
+ from torch import optim, Tensor
10
+ from torch.optim.optimizer import ParamsT
11
+
12
+ from netloader.utils.types import Param, TensorT
13
+
14
+ logger: log.Logger = log.getLogger(__name__)
15
+
16
+
17
+ class UtilityMixin:
18
+ """
19
+ Mixin class providing utility functions for architecture classes.
20
+ """
21
+ @staticmethod
22
+ def _data_loader_translation(low_dim: TensorT, high_dim: TensorT) -> tuple[TensorT, TensorT]:
23
+ """
24
+ Orders low and high dimensional tensors from the data loader as inputs and targets for the
25
+ network.
26
+
27
+ Parameters
28
+ ----------
29
+ low_dim : TensorT
30
+ Low dimensional data from the data loader of shape (N,...) and type float, where N is
31
+ the number of elements
32
+ high_dim : TensorT
33
+ High dimensional data from the data loader of shape (N,...) and type float
34
+
35
+ Returns
36
+ -------
37
+ tuple[TensorT, TensorT]
38
+ Input and output target tensors of shape (N,...) and type float
39
+ """
40
+ return high_dim, low_dim
41
+
42
+ @staticmethod
43
+ def _param_device(params: dict[Tensor, Param] | Param, *args: Any, **kwargs: Any) -> None:
44
+ """
45
+ Sends parameters to the device, such as the parameters in the optimiser.
46
+
47
+ Parameters
48
+ ----------
49
+ params : dict[Tensor, Param] | Param
50
+ Parameters to move/cast
51
+ *args, **kwargs
52
+ Arguments to pass to torch.Tensor.to
53
+ """
54
+ param: Tensor | Param
55
+
56
+ for param in params.values():
57
+ if isinstance(param, dict):
58
+ UtilityMixin._param_device(param, *args, **kwargs)
59
+ elif isinstance(param, Tensor):
60
+ param.data = param.data.to(*args, **kwargs)
61
+
62
+ # pylint: disable=protected-access
63
+ if param._grad is not None:
64
+ param._grad.data = param._grad.data.to(*args, **kwargs)
65
+ # pylint: enable=protected-access
66
+
67
+ @staticmethod
68
+ def _save_predictions(path: str, data: dict[str, Any]) -> None:
69
+ """
70
+ Saves architecture predictions to pickle file if path is provided.
71
+
72
+ Parameters
73
+ ----------
74
+ path : str
75
+ Path to save architecture predictions
76
+ data : dict[str, Any]
77
+ Architecture predictions of shape (N,...) to save
78
+ """
79
+ if not path:
80
+ return
81
+
82
+ with open(path + '' if '.pkl' in path else '.pkl', 'wb') as file:
83
+ pickle.dump(data, file)
84
+
85
+ def _method_override(self, name: str, owner: type) -> bool:
86
+ """
87
+ Checks if a method is overridden in a subclass.
88
+
89
+ Parameters
90
+ ----------
91
+ name : str
92
+ Name of the method to check
93
+ owner : type
94
+ Class to check for method override
95
+
96
+ Returns
97
+ -------
98
+ bool
99
+ True if the method is overridden, False otherwise
100
+ """
101
+ method: Callable = getattr(self, name, None)
102
+
103
+ if method is None:
104
+ logger.warning(f'Method {name} not found in {type(self).__name__}')
105
+ return False
106
+ return method.__qualname__.split('.')[0] != owner.__name__
107
+
108
+ @staticmethod
109
+ def init_optimiser(parameters: ParamsT, **kwargs: Any) -> optim.Optimizer:
110
+ """
111
+ Sets the optimiser for the architecture, by default AdamW.
112
+
113
+ Parameters
114
+ ----------
115
+ parameters : ParamsT
116
+ Architecture parameters to optimise
117
+ **kwargs
118
+ Optional keyword arguments to pass to the optimiser
119
+
120
+ Returns
121
+ -------
122
+ Optimizer
123
+ Architecture optimiser
124
+ """
125
+ return optim.AdamW(parameters, **kwargs)
126
+
127
+ @staticmethod
128
+ def init_scheduler(optimiser: optim.Optimizer, **kwargs: Any) -> optim.lr_scheduler.LRScheduler:
129
+ """
130
+ Initialise the scheduler for the architecture, by default ReduceLROnPlateau.
131
+
132
+ Parameters
133
+ ----------
134
+ optimiser : Optimizer
135
+ Architecture optimiser
136
+ **kwargs
137
+ Optional keyword arguments to pass to the scheduler
138
+
139
+ Returns
140
+ -------
141
+ LRScheduler
142
+ Optimiser scheduler
143
+ """
144
+ return optim.lr_scheduler.ReduceLROnPlateau(optimiser, **kwargs)
145
+
146
+ @staticmethod
147
+ def set_optimiser(parameters: ParamsT, **kwargs: Any) -> optim.Optimizer:
148
+ """
149
+ Deprecated alias of :meth:`init_optimiser`.
150
+
151
+ .. deprecated:: 3.11.0
152
+ Use :meth:`init_optimiser` instead.
153
+ """
154
+ warn(
155
+ "UtilityMixin.set_optimiser is deprecated, use UtilityMixin.init_optimiser "
156
+ "instead",
157
+ DeprecationWarning,
158
+ stacklevel=2,
159
+ )
160
+ return UtilityMixin.init_optimiser(parameters, **kwargs)
161
+
162
+ @staticmethod
163
+ def set_scheduler(optimiser: optim.Optimizer, **kwargs: Any) -> optim.lr_scheduler.LRScheduler:
164
+ """
165
+ Deprecated alias of :meth:`init_scheduler`.
166
+
167
+ .. deprecated:: 3.11.0
168
+ Use :meth:`init_scheduler` instead.
169
+ """
170
+ warn(
171
+ "UtilityMixin.set_scheduler is deprecated, use UtilityMixin.init_scheduler "
172
+ "instead",
173
+ DeprecationWarning,
174
+ stacklevel=2,
175
+ )
176
+ return UtilityMixin.init_scheduler(optimiser, **kwargs)
177
+
178
+
179
+ __all__ = ['UtilityMixin']