spotoptim 3.1.0__tar.gz → 3.3.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.
- {spotoptim-3.1.0 → spotoptim-3.3.0}/PKG-INFO +2 -1
- {spotoptim-3.1.0 → spotoptim-3.3.0}/pyproject.toml +2 -1
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/data/__init__.py +7 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/data/manydataset.py +141 -2
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/nn/__init__.py +4 -0
- spotoptim-3.3.0/src/spotoptim/nn/training.py +234 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/surrogate/kriging.py +32 -6
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/__init__.py +3 -0
- spotoptim-3.3.0/src/spotoptim/utils/seed.py +60 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/README.md +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/SpotOptim.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/core/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/core/data.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/core/experiment.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/core/protocol.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/core/storage.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/data/base.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/data/diabetes.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/datasets/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/datasets/py.typed +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/datasets/test01.csv +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/datasets/test02.csv +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/datasets/test11.csv +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/eda/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/eda/plots.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/factor_analyzer/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/factor_analyzer/confirmatory_factor_analyzer.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/factor_analyzer/factor_analyzer.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/factor_analyzer/factor_analyzer_rotator.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/factor_analyzer/factor_analyzer_utils.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/function/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/function/cd_data.csv +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/function/forr08a.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/function/mo.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/function/remote.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/function/sequence_cv_objective.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/function/so.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/function/torch_objective.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/hyperparameters/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/hyperparameters/parameters.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/hyperparameters/repr_helpers.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/inspection/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/inspection/importance.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/inspection/predictions.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/mo/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/mo/mo_mm.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/mo/pareto.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/nn/linear_regressor.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/nn/many_to_many_rnn.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/nn/mlp.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/nn/optimizer.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/optimizer/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/optimizer/acquisition.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/optimizer/schedule_free.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/optimizer/wrapper.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/plot/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/plot/contour.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/plot/mo.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/plot/visualization.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/py.typed +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/reporting/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/reporting/analysis.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/reporting/results.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/sampling/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/sampling/design.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/sampling/effects.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/sampling/lhs.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/sampling/mm.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/surrogate/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/surrogate/kernels.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/surrogate/mlp_surrogate.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/surrogate/nystroem.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/surrogate/pipeline.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/surrogate/simple_kriging.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/tricands/__init__.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/tricands/tricands.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/boundaries.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/convert.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/dimreduction.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/eval.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/file.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/mapping.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/ocba.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/pca.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/scaler.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/serialization.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/stats.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/tensorboard.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/transform.py +0 -0
- {spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/utils/variables.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: spotoptim
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Sequential Parameter Optimization Toolbox
|
|
5
5
|
Author: bartzbeielstein
|
|
6
6
|
Author-email: bartzbeielstein <32470350+bartzbeielstein@users.noreply.github.com>
|
|
@@ -36,6 +36,7 @@ Requires-Dist: requests>=2.32.3 ; extra == 'remote'
|
|
|
36
36
|
Requires-Dist: statsmodels>=0.14.6 ; extra == 'stats'
|
|
37
37
|
Requires-Dist: torch>=2.9.1 ; extra == 'torch'
|
|
38
38
|
Requires-Dist: tensorboard>=2.20.0 ; extra == 'torch'
|
|
39
|
+
Requires-Dist: torchmetrics>=1.8.2 ; extra == 'torch'
|
|
39
40
|
Requires-Dist: matplotlib>=3.10.7 ; extra == 'viz'
|
|
40
41
|
Requires-Dist: seaborn>=0.13.2 ; extra == 'viz'
|
|
41
42
|
Requires-Python: >=3.13
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "spotoptim"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.3.0"
|
|
4
4
|
description = "Sequential Parameter Optimization Toolbox"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "AGPL-3.0-or-later" }
|
|
@@ -44,6 +44,7 @@ dev = [
|
|
|
44
44
|
torch = [
|
|
45
45
|
"torch>=2.9.1",
|
|
46
46
|
"tensorboard>=2.20.0",
|
|
47
|
+
"torchmetrics>=1.8.2",
|
|
47
48
|
]
|
|
48
49
|
viz = [
|
|
49
50
|
"matplotlib>=3.10.7",
|
|
@@ -19,6 +19,8 @@ __all__ = [
|
|
|
19
19
|
"ManyToOneDataset",
|
|
20
20
|
"PadSequenceManyToMany",
|
|
21
21
|
"PadSequenceManyToOne",
|
|
22
|
+
"load_sequence_data",
|
|
23
|
+
"load_pooled_sequence_data",
|
|
22
24
|
]
|
|
23
25
|
|
|
24
26
|
_lazy_map = {
|
|
@@ -28,6 +30,11 @@ _lazy_map = {
|
|
|
28
30
|
"ManyToOneDataset": ("spotoptim.data.manydataset", "ManyToOneDataset"),
|
|
29
31
|
"PadSequenceManyToMany": ("spotoptim.data.manydataset", "PadSequenceManyToMany"),
|
|
30
32
|
"PadSequenceManyToOne": ("spotoptim.data.manydataset", "PadSequenceManyToOne"),
|
|
33
|
+
"load_sequence_data": ("spotoptim.data.manydataset", "load_sequence_data"),
|
|
34
|
+
"load_pooled_sequence_data": (
|
|
35
|
+
"spotoptim.data.manydataset",
|
|
36
|
+
"load_pooled_sequence_data",
|
|
37
|
+
),
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
|
|
@@ -13,12 +13,12 @@ classes provided here.
|
|
|
13
13
|
Requires the ``torch`` optional extra (``pip install 'spotoptim[torch]'``).
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
-
from typing import List, Optional, Union
|
|
16
|
+
from typing import List, Optional, Tuple, Union
|
|
17
17
|
|
|
18
18
|
import pandas as pd
|
|
19
19
|
import torch
|
|
20
20
|
from torch.nn.utils.rnn import pad_sequence
|
|
21
|
-
from torch.utils.data import Dataset
|
|
21
|
+
from torch.utils.data import ConcatDataset, Dataset
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
class ManyToManyDataset(Dataset):
|
|
@@ -234,3 +234,142 @@ class PadSequenceManyToOne:
|
|
|
234
234
|
lengths = torch.tensor([len(x) for x in batch_x])
|
|
235
235
|
|
|
236
236
|
return padded_batch_x, lengths, torch.tensor(batch_y)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def load_sequence_data(
|
|
240
|
+
data: pd.DataFrame,
|
|
241
|
+
target: str,
|
|
242
|
+
group_by: str,
|
|
243
|
+
drop: Optional[Union[str, List[str]]] = None,
|
|
244
|
+
input_features: Optional[List[str]] = None,
|
|
245
|
+
feature_scaling=None,
|
|
246
|
+
target_scaling=None,
|
|
247
|
+
dataset_type: str = "many_to_many",
|
|
248
|
+
) -> Tuple[Dataset, pd.DataFrame]:
|
|
249
|
+
"""Group a DataFrame into a variable-length sequence dataset.
|
|
250
|
+
|
|
251
|
+
Splits ``data`` by the values of ``group_by`` (e.g. one compressor speed
|
|
252
|
+
line per group) and wraps the groups in a `ManyToManyDataset` or
|
|
253
|
+
`ManyToOneDataset`. Ported from the schu25a study's ``load_data`` helper
|
|
254
|
+
(``src/rnn/utils.py``); the experiment-specific column defaults were
|
|
255
|
+
removed.
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
data (pd.DataFrame): Input data; one row per time step.
|
|
259
|
+
target (str): The target column name.
|
|
260
|
+
group_by (str): Column whose values define the sequences.
|
|
261
|
+
drop (Optional[Union[str, List[str]]]): Column(s) to drop from the
|
|
262
|
+
groups before extracting features. Defaults to None.
|
|
263
|
+
input_features (Optional[List[str]]): Columns scaled by
|
|
264
|
+
``feature_scaling``. Only used when ``feature_scaling`` is given;
|
|
265
|
+
the dataset features are always all columns except ``drop`` and
|
|
266
|
+
``target``. Defaults to None.
|
|
267
|
+
feature_scaling: Optional sklearn-style scaler; applied in place to
|
|
268
|
+
``data[input_features]`` via ``fit_transform``. Defaults to None.
|
|
269
|
+
target_scaling: Optional sklearn-style scaler; applied in place to
|
|
270
|
+
``data[target]`` via ``fit_transform``. Defaults to None.
|
|
271
|
+
dataset_type (str, optional): Dataset flavor. Options:
|
|
272
|
+
- "many_to_many": one target value per time step.
|
|
273
|
+
- "many_to_one": one scalar target per sequence.
|
|
274
|
+
Defaults to "many_to_many".
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
tuple: ``(dataset, data)`` — the sequence dataset and the (possibly
|
|
278
|
+
scaled) DataFrame.
|
|
279
|
+
|
|
280
|
+
Raises:
|
|
281
|
+
ValueError: If ``dataset_type`` is not "many_to_many" or "many_to_one".
|
|
282
|
+
|
|
283
|
+
Examples:
|
|
284
|
+
```{python}
|
|
285
|
+
import pandas as pd
|
|
286
|
+
from spotoptim.data.manydataset import load_sequence_data
|
|
287
|
+
|
|
288
|
+
df = pd.DataFrame({
|
|
289
|
+
"line": [1, 1, 1, 2, 2],
|
|
290
|
+
"x": [0.1, 0.2, 0.3, 0.4, 0.5],
|
|
291
|
+
"y": [1.0, 2.0, 3.0, 4.0, 5.0],
|
|
292
|
+
})
|
|
293
|
+
ds, df = load_sequence_data(df, target="y", group_by="line", drop="line")
|
|
294
|
+
print(len(ds), ds[0][0].shape)
|
|
295
|
+
```
|
|
296
|
+
"""
|
|
297
|
+
if feature_scaling is not None:
|
|
298
|
+
data[input_features] = feature_scaling.fit_transform(data[input_features])
|
|
299
|
+
|
|
300
|
+
if target_scaling is not None:
|
|
301
|
+
data[target] = target_scaling.fit_transform(data[target])
|
|
302
|
+
|
|
303
|
+
groups = [group for _, group in data.groupby(group_by)]
|
|
304
|
+
|
|
305
|
+
if dataset_type == "many_to_many":
|
|
306
|
+
return ManyToManyDataset(groups, target=target, drop=drop), data
|
|
307
|
+
elif dataset_type == "many_to_one":
|
|
308
|
+
return ManyToOneDataset(groups, target=target, drop=drop), data
|
|
309
|
+
raise ValueError(
|
|
310
|
+
f"dataset_type {dataset_type!r} not supported. "
|
|
311
|
+
"Options: 'many_to_many', 'many_to_one'."
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def load_pooled_sequence_data(
|
|
316
|
+
data_list: List[pd.DataFrame],
|
|
317
|
+
target: str,
|
|
318
|
+
group_by: str,
|
|
319
|
+
drop: Optional[Union[str, List[str]]] = None,
|
|
320
|
+
input_features: Optional[List[str]] = None,
|
|
321
|
+
feature_scaling=None,
|
|
322
|
+
target_scaling=None,
|
|
323
|
+
dataset_type: str = "many_to_many",
|
|
324
|
+
) -> ConcatDataset:
|
|
325
|
+
"""Pool several DataFrames into one concatenated sequence dataset.
|
|
326
|
+
|
|
327
|
+
Applies `load_sequence_data` to every DataFrame (e.g. one compressor map
|
|
328
|
+
each) and concatenates the resulting sequence datasets — the pooled
|
|
329
|
+
training set of the schu25a "global training" workflow (ported from
|
|
330
|
+
``load_pretrain_data`` in ``src/rnn/utils.py``).
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
data_list (List[pd.DataFrame]): Input DataFrames; one per map.
|
|
334
|
+
target (str): The target column name.
|
|
335
|
+
group_by (str): Column whose values define the sequences.
|
|
336
|
+
drop (Optional[Union[str, List[str]]]): Column(s) to drop from the
|
|
337
|
+
groups before extracting features. Defaults to None.
|
|
338
|
+
input_features (Optional[List[str]]): Columns scaled by
|
|
339
|
+
``feature_scaling``; see `load_sequence_data`. Defaults to None.
|
|
340
|
+
feature_scaling: Optional sklearn-style scaler, applied per DataFrame.
|
|
341
|
+
Defaults to None.
|
|
342
|
+
target_scaling: Optional sklearn-style scaler, applied per DataFrame.
|
|
343
|
+
Defaults to None.
|
|
344
|
+
dataset_type (str, optional): "many_to_many" or "many_to_one".
|
|
345
|
+
Defaults to "many_to_many".
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
ConcatDataset: The concatenation of the per-DataFrame sequence datasets.
|
|
349
|
+
|
|
350
|
+
Examples:
|
|
351
|
+
```{python}
|
|
352
|
+
import pandas as pd
|
|
353
|
+
from spotoptim.data.manydataset import load_pooled_sequence_data
|
|
354
|
+
|
|
355
|
+
df1 = pd.DataFrame({"line": [1, 1, 2], "x": [0.1, 0.2, 0.3], "y": [1.0, 2.0, 3.0]})
|
|
356
|
+
df2 = pd.DataFrame({"line": [1, 1], "x": [0.4, 0.5], "y": [4.0, 5.0]})
|
|
357
|
+
pooled = load_pooled_sequence_data([df1, df2], target="y", group_by="line", drop="line")
|
|
358
|
+
print(len(pooled))
|
|
359
|
+
```
|
|
360
|
+
"""
|
|
361
|
+
ds_ls = []
|
|
362
|
+
for data in data_list:
|
|
363
|
+
ds, _ = load_sequence_data(
|
|
364
|
+
data,
|
|
365
|
+
target=target,
|
|
366
|
+
group_by=group_by,
|
|
367
|
+
drop=drop,
|
|
368
|
+
input_features=input_features,
|
|
369
|
+
feature_scaling=feature_scaling,
|
|
370
|
+
target_scaling=target_scaling,
|
|
371
|
+
dataset_type=dataset_type,
|
|
372
|
+
)
|
|
373
|
+
ds_ls.append(ds)
|
|
374
|
+
|
|
375
|
+
return ConcatDataset(ds_ls)
|
|
@@ -11,6 +11,8 @@ __all__ = [
|
|
|
11
11
|
"ManyToManyRNNRegressor",
|
|
12
12
|
"get_activation",
|
|
13
13
|
"optimizer_handler",
|
|
14
|
+
"train_sequences",
|
|
15
|
+
"evaluate_sequences",
|
|
14
16
|
]
|
|
15
17
|
|
|
16
18
|
_lazy_map = {
|
|
@@ -23,6 +25,8 @@ _lazy_map = {
|
|
|
23
25
|
),
|
|
24
26
|
"get_activation": ("spotoptim.nn.many_to_many_rnn", "get_activation"),
|
|
25
27
|
"optimizer_handler": ("spotoptim.nn.optimizer", "optimizer_handler"),
|
|
28
|
+
"train_sequences": ("spotoptim.nn.training", "train_sequences"),
|
|
29
|
+
"evaluate_sequences": ("spotoptim.nn.training", "evaluate_sequences"),
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 bartzbeielstein
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
"""Plain training and evaluation loops for variable-length sequence models.
|
|
6
|
+
|
|
7
|
+
Ported op-for-op from the ``train``/``evaluate_many`` helpers of the schu25a
|
|
8
|
+
compressor-map study (``src/rnn/train.py``), so that runs seeded with
|
|
9
|
+
`spotoptim.utils.seed.seed_everything` reproduce the original results
|
|
10
|
+
bit-identically on the same device. The models are called as
|
|
11
|
+
``model(x, lengths)`` on padded batches (e.g.
|
|
12
|
+
`spotoptim.nn.many_to_many_rnn.ManyToManyRNN` with batches collated by
|
|
13
|
+
`spotoptim.data.manydataset.PadSequenceManyToMany`); losses and metrics are
|
|
14
|
+
computed on the squeezed padded tensors, exactly as in the original. The
|
|
15
|
+
original's unused ``seed`` parameters were dropped.
|
|
16
|
+
|
|
17
|
+
Requires the ``torch`` optional extra (``pip install 'spotoptim[torch]'``),
|
|
18
|
+
which includes ``torchmetrics``.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from typing import List, Literal, Optional, Tuple, Union, overload
|
|
22
|
+
|
|
23
|
+
import numpy as np
|
|
24
|
+
import torch
|
|
25
|
+
import torch.nn as nn
|
|
26
|
+
from torch.utils.data import DataLoader
|
|
27
|
+
from torchmetrics.regression import MeanAbsolutePercentageError, MeanSquaredError
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def train_sequences(
|
|
31
|
+
model: nn.Module,
|
|
32
|
+
train_loader: DataLoader,
|
|
33
|
+
optimizer: torch.optim.Optimizer,
|
|
34
|
+
criterion: nn.Module,
|
|
35
|
+
val_loader: Optional[DataLoader] = None,
|
|
36
|
+
epochs: int = 10,
|
|
37
|
+
device: str = "cpu",
|
|
38
|
+
verbose: bool = True,
|
|
39
|
+
) -> Union[Tuple[nn.Module, List[float]], Tuple[nn.Module, List[float], List[float]]]:
|
|
40
|
+
"""Train a sequence model with a plain epoch loop.
|
|
41
|
+
|
|
42
|
+
One optimizer step per batch; the loss is computed between
|
|
43
|
+
``model(x, lengths).squeeze()`` and the (padded) target batch. The
|
|
44
|
+
recorded training loss is the batch-mean loss per epoch.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
model (nn.Module): Model called as ``model(x, lengths)``.
|
|
48
|
+
train_loader (DataLoader): Loader yielding ``(x, lengths, y)`` batches,
|
|
49
|
+
e.g. collated by `PadSequenceManyToMany`.
|
|
50
|
+
optimizer (torch.optim.Optimizer): Optimizer over ``model.parameters()``.
|
|
51
|
+
criterion (nn.Module): Loss module, e.g. ``nn.MSELoss()``.
|
|
52
|
+
val_loader (Optional[DataLoader]): Optional validation loader; when
|
|
53
|
+
given, the mean per-batch RMSE from `evaluate_sequences` is
|
|
54
|
+
recorded after every epoch. Defaults to None.
|
|
55
|
+
epochs (int, optional): Number of epochs. Defaults to 10.
|
|
56
|
+
device (str, optional): Training device. Defaults to "cpu".
|
|
57
|
+
verbose (bool, optional): Print per-epoch losses. Defaults to True.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
tuple: ``(model, train_loss_ls)`` without a validation loader, or
|
|
61
|
+
``(model, train_loss_ls, val_loss_ls)`` with one.
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
```{python}
|
|
65
|
+
import pandas as pd
|
|
66
|
+
import torch
|
|
67
|
+
import torch.nn as nn
|
|
68
|
+
from torch.utils.data import DataLoader
|
|
69
|
+
from spotoptim.data.manydataset import ManyToManyDataset, PadSequenceManyToMany
|
|
70
|
+
from spotoptim.nn.many_to_many_rnn import ManyToManyRNN
|
|
71
|
+
from spotoptim.nn.training import train_sequences
|
|
72
|
+
from spotoptim.utils.seed import seed_everything
|
|
73
|
+
|
|
74
|
+
seed_everything(42)
|
|
75
|
+
frames = [
|
|
76
|
+
pd.DataFrame({"x": [0.1, 0.2, 0.3], "y": [1.0, 2.0, 3.0]}),
|
|
77
|
+
pd.DataFrame({"x": [0.4, 0.5], "y": [4.0, 5.0]}),
|
|
78
|
+
]
|
|
79
|
+
ds = ManyToManyDataset(frames, target="y")
|
|
80
|
+
dl = DataLoader(ds, batch_size=2, shuffle=False, collate_fn=PadSequenceManyToMany())
|
|
81
|
+
model = ManyToManyRNN(input_size=1, rnn_units=8, fc_units=8)
|
|
82
|
+
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
|
|
83
|
+
model, losses = train_sequences(
|
|
84
|
+
model, dl, optimizer, nn.MSELoss(), epochs=2, verbose=False
|
|
85
|
+
)
|
|
86
|
+
print(len(losses))
|
|
87
|
+
```
|
|
88
|
+
"""
|
|
89
|
+
model.train()
|
|
90
|
+
model.to(device)
|
|
91
|
+
|
|
92
|
+
train_loss_ls = []
|
|
93
|
+
val_loss_ls = []
|
|
94
|
+
|
|
95
|
+
for epoch in range(epochs):
|
|
96
|
+
model.train()
|
|
97
|
+
train_loss = 0.0
|
|
98
|
+
for batch_x, lengths, batch_y in train_loader:
|
|
99
|
+
batch_x = batch_x.to(device)
|
|
100
|
+
batch_y = batch_y.to(device)
|
|
101
|
+
|
|
102
|
+
optimizer.zero_grad()
|
|
103
|
+
outputs = model(batch_x, lengths)
|
|
104
|
+
outputs = outputs.squeeze()
|
|
105
|
+
|
|
106
|
+
loss = criterion(outputs, batch_y)
|
|
107
|
+
loss.backward()
|
|
108
|
+
|
|
109
|
+
optimizer.step()
|
|
110
|
+
train_loss += loss.item()
|
|
111
|
+
|
|
112
|
+
train_loss /= len(train_loader)
|
|
113
|
+
train_loss_ls.append(train_loss)
|
|
114
|
+
|
|
115
|
+
if val_loader is not None:
|
|
116
|
+
_, _, _, mape, rmse = evaluate_sequences(model, val_loader, device=device)
|
|
117
|
+
val_loss_ls.append(float(np.mean(np.array(rmse))))
|
|
118
|
+
else:
|
|
119
|
+
mape = None
|
|
120
|
+
rmse = None
|
|
121
|
+
|
|
122
|
+
if verbose:
|
|
123
|
+
print(f"Epoch: {epoch + 1}/{epochs}, Train Loss: {train_loss:.4f}", end="")
|
|
124
|
+
if mape is not None:
|
|
125
|
+
print(
|
|
126
|
+
f", Validation: MAPE: {np.mean(np.array(mape)):.4f}, "
|
|
127
|
+
f"RMSE: {np.mean(np.array(rmse)):.4f}"
|
|
128
|
+
)
|
|
129
|
+
else:
|
|
130
|
+
print()
|
|
131
|
+
|
|
132
|
+
if val_loader is not None:
|
|
133
|
+
return model, train_loss_ls, val_loss_ls
|
|
134
|
+
return model, train_loss_ls
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@overload
|
|
138
|
+
def evaluate_sequences(
|
|
139
|
+
model: nn.Module,
|
|
140
|
+
val_loader: DataLoader,
|
|
141
|
+
device: str = "cpu",
|
|
142
|
+
metrics_only: Literal[False] = False,
|
|
143
|
+
) -> Tuple[list, list, list, List[float], List[float]]: ...
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@overload
|
|
147
|
+
def evaluate_sequences(
|
|
148
|
+
model: nn.Module,
|
|
149
|
+
val_loader: DataLoader,
|
|
150
|
+
device: str = "cpu",
|
|
151
|
+
*,
|
|
152
|
+
metrics_only: Literal[True],
|
|
153
|
+
) -> Tuple[float, float]: ...
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def evaluate_sequences(
|
|
157
|
+
model: nn.Module,
|
|
158
|
+
val_loader: DataLoader,
|
|
159
|
+
device: str = "cpu",
|
|
160
|
+
metrics_only: bool = False,
|
|
161
|
+
) -> Union[Tuple[float, float], Tuple[list, list, list, List[float], List[float]]]:
|
|
162
|
+
"""Evaluate a sequence model with per-batch MAPE and RMSE.
|
|
163
|
+
|
|
164
|
+
Metrics are the torchmetrics ``MeanAbsolutePercentageError`` and
|
|
165
|
+
``MeanSquaredError(squared=False)`` between ``model(x, lengths).squeeze()``
|
|
166
|
+
and the squeezed target batch, as in the schu25a original. Inputs,
|
|
167
|
+
predictions, and targets are additionally returned as nested Python lists
|
|
168
|
+
for plotting.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
model (nn.Module): Model called as ``model(x, lengths)``.
|
|
172
|
+
val_loader (DataLoader): Loader yielding ``(x, lengths, y)`` batches.
|
|
173
|
+
Batches are converted to NumPy, so ``device`` should be "cpu"
|
|
174
|
+
unless ``metrics_only=True``.
|
|
175
|
+
device (str, optional): Evaluation device. Defaults to "cpu".
|
|
176
|
+
metrics_only (bool, optional): Return only ``(mean_mape, mean_rmse)``.
|
|
177
|
+
Defaults to False.
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
tuple: ``(x_ls, y_hat_ls, y_ls, mape_loss_ls, rmse_loss_ls)`` with one
|
|
181
|
+
entry per batch, or ``(mean_mape, mean_rmse)`` if ``metrics_only``.
|
|
182
|
+
|
|
183
|
+
Examples:
|
|
184
|
+
```{python}
|
|
185
|
+
import pandas as pd
|
|
186
|
+
import torch
|
|
187
|
+
from torch.utils.data import DataLoader
|
|
188
|
+
from spotoptim.data.manydataset import ManyToManyDataset, PadSequenceManyToMany
|
|
189
|
+
from spotoptim.nn.many_to_many_rnn import ManyToManyRNN
|
|
190
|
+
from spotoptim.nn.training import evaluate_sequences
|
|
191
|
+
from spotoptim.utils.seed import seed_everything
|
|
192
|
+
|
|
193
|
+
seed_everything(42)
|
|
194
|
+
frames = [pd.DataFrame({"x": [0.1, 0.2, 0.3], "y": [1.0, 2.0, 3.0]})]
|
|
195
|
+
ds = ManyToManyDataset(frames, target="y")
|
|
196
|
+
dl = DataLoader(ds, batch_size=1, shuffle=False, collate_fn=PadSequenceManyToMany())
|
|
197
|
+
model = ManyToManyRNN(input_size=1, rnn_units=8, fc_units=8)
|
|
198
|
+
x, y_hat, y, mape, rmse = evaluate_sequences(model, dl)
|
|
199
|
+
print(len(y_hat), len(mape), len(rmse))
|
|
200
|
+
```
|
|
201
|
+
"""
|
|
202
|
+
mean_abs_percentage_error = MeanAbsolutePercentageError().to(device)
|
|
203
|
+
rmse_loss = MeanSquaredError(squared=False).to(device)
|
|
204
|
+
|
|
205
|
+
model.eval()
|
|
206
|
+
model.to(device)
|
|
207
|
+
|
|
208
|
+
x_ls = []
|
|
209
|
+
y_hat_ls = []
|
|
210
|
+
y_ls = []
|
|
211
|
+
mape_loss_ls = []
|
|
212
|
+
rmse_loss_ls = []
|
|
213
|
+
|
|
214
|
+
with torch.no_grad():
|
|
215
|
+
for batch_x, lengths, batch_y in val_loader:
|
|
216
|
+
batch_x = batch_x.to(device)
|
|
217
|
+
batch_y = batch_y.to(device)
|
|
218
|
+
|
|
219
|
+
y_hat = model(batch_x, lengths)
|
|
220
|
+
y_hat = y_hat.squeeze()
|
|
221
|
+
|
|
222
|
+
mape = mean_abs_percentage_error(y_hat, batch_y.squeeze())
|
|
223
|
+
rmse = rmse_loss(y_hat, batch_y.squeeze())
|
|
224
|
+
|
|
225
|
+
mape_loss_ls.append(mape.item())
|
|
226
|
+
rmse_loss_ls.append(rmse.item())
|
|
227
|
+
|
|
228
|
+
x_ls.append(batch_x.squeeze().detach().numpy().tolist())
|
|
229
|
+
y_hat_ls.append(y_hat.squeeze().detach().numpy().tolist())
|
|
230
|
+
y_ls.append(batch_y.squeeze().detach().numpy().tolist())
|
|
231
|
+
|
|
232
|
+
if metrics_only:
|
|
233
|
+
return float(np.mean(mape_loss_ls)), float(np.mean(rmse_loss_ls))
|
|
234
|
+
return x_ls, y_hat_ls, y_ls, mape_loss_ls, rmse_loss_ls
|
|
@@ -73,8 +73,17 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
73
73
|
theta_init_zero (bool, optional): Initialize theta to zero. Defaults to False.
|
|
74
74
|
n_p (int, optional): Number of p parameters (currently not optimized). Defaults to 1.
|
|
75
75
|
optim_p (bool, optional): Optimize p parameters (currently not supported). Defaults to False.
|
|
76
|
-
min_Lambda (float, optional): Minimum log10(Lambda) bound
|
|
76
|
+
min_Lambda (float, optional): Minimum log10(Lambda) bound; the admissible
|
|
77
|
+
nugget range is [10**min_Lambda, 10**max_Lambda] regardless of
|
|
78
|
+
``lambda_scale``. Defaults to -9.0.
|
|
77
79
|
max_Lambda (float, optional): Maximum log10(Lambda) bound. Defaults to 0.0.
|
|
80
|
+
lambda_scale (str, optional): Search parametrization of the nugget Lambda
|
|
81
|
+
within [10**min_Lambda, 10**max_Lambda]. Options:
|
|
82
|
+
- "log10": the optimizer searches the exponent log10(Lambda)
|
|
83
|
+
uniformly, emphasizing small nuggets (near-interpolation).
|
|
84
|
+
- "linear": the optimizer searches Lambda itself uniformly,
|
|
85
|
+
emphasizing larger nuggets (more smoothing on noisy data).
|
|
86
|
+
Defaults to "log10".
|
|
78
87
|
metric_factorial (str, optional): Distance metric for factor variables.
|
|
79
88
|
Defaults to ``"hamming"``. Hamming is a true nominal (order-agnostic) metric;
|
|
80
89
|
canberra distance on integer level indices is order-dependent and singles out
|
|
@@ -86,7 +95,9 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
86
95
|
X_ (ndarray): Training data, shape (n_samples, n_features).
|
|
87
96
|
y_ (ndarray): Training targets, shape (n_samples,).
|
|
88
97
|
theta_ (ndarray): Optimized log10(theta) parameters.
|
|
89
|
-
Lambda_ (float or None): Optimized
|
|
98
|
+
Lambda_ (float or None): Optimized Lambda parameter in the search scale
|
|
99
|
+
(the log10 exponent for ``lambda_scale="log10"``, the linear value
|
|
100
|
+
for ``lambda_scale="linear"``) for regression methods.
|
|
90
101
|
mu_ (float): Mean of Kriging predictor.
|
|
91
102
|
sigma2_ (float): Variance of Kriging predictor.
|
|
92
103
|
U_ (ndarray): Cholesky factor of correlation matrix.
|
|
@@ -162,6 +173,7 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
162
173
|
optim_p: bool = False,
|
|
163
174
|
min_Lambda: float = -9.0,
|
|
164
175
|
max_Lambda: float = 0.0,
|
|
176
|
+
lambda_scale: str = "log10",
|
|
165
177
|
metric_factorial: str = "hamming",
|
|
166
178
|
isotropic: bool = False,
|
|
167
179
|
theta: Optional[np.ndarray] = None,
|
|
@@ -183,6 +195,9 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
183
195
|
self.max_theta = max_theta
|
|
184
196
|
self.min_Lambda = min_Lambda
|
|
185
197
|
self.max_Lambda = max_Lambda
|
|
198
|
+
if lambda_scale not in ["log10", "linear"]:
|
|
199
|
+
raise ValueError("lambda_scale must be 'log10' or 'linear'")
|
|
200
|
+
self.lambda_scale = lambda_scale
|
|
186
201
|
self.n_theta = n_theta
|
|
187
202
|
self.isotropic = isotropic
|
|
188
203
|
self.n_p = n_p
|
|
@@ -216,6 +231,18 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
216
231
|
"""Get square root of machine epsilon."""
|
|
217
232
|
return np.sqrt(np.finfo(float).eps)
|
|
218
233
|
|
|
234
|
+
def _lambda_bounds(self) -> Tuple[float, float]:
|
|
235
|
+
"""Search bounds of the Lambda parameter in the configured scale."""
|
|
236
|
+
if self.lambda_scale == "linear":
|
|
237
|
+
return (10.0**self.min_Lambda, 10.0**self.max_Lambda)
|
|
238
|
+
return (self.min_Lambda, self.max_Lambda)
|
|
239
|
+
|
|
240
|
+
def _lambda_value(self, param: float) -> float:
|
|
241
|
+
"""Nugget value Lambda from its search-scale parameter."""
|
|
242
|
+
if self.lambda_scale == "linear":
|
|
243
|
+
return param
|
|
244
|
+
return 10.0**param
|
|
245
|
+
|
|
219
246
|
def _set_variable_types(self) -> None:
|
|
220
247
|
"""Set variable type masks for different variable types.
|
|
221
248
|
|
|
@@ -298,7 +325,7 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
298
325
|
bounds = [(self.min_theta, self.max_theta)] * self.n_theta
|
|
299
326
|
|
|
300
327
|
if self.method in ["regression", "reinterpolation"]:
|
|
301
|
-
bounds += [
|
|
328
|
+
bounds += [self._lambda_bounds()]
|
|
302
329
|
|
|
303
330
|
if self.optim_p:
|
|
304
331
|
bounds += [(1.0, 2.0)] * self.n_p
|
|
@@ -431,8 +458,7 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
431
458
|
self.theta_ = params[: self.n_theta]
|
|
432
459
|
|
|
433
460
|
if self.method in ["regression", "reinterpolation"]:
|
|
434
|
-
|
|
435
|
-
lambda_ = 10.0**lambda_log
|
|
461
|
+
lambda_ = self._lambda_value(params[self.n_theta : self.n_theta + 1][0])
|
|
436
462
|
else:
|
|
437
463
|
lambda_ = self.noise
|
|
438
464
|
|
|
@@ -536,7 +562,7 @@ class Kriging(BaseEstimator, RegressorMixin):
|
|
|
536
562
|
>>> y_pred, y_std = k.predict_single(x_new)
|
|
537
563
|
"""
|
|
538
564
|
if self.method in ["regression", "reinterpolation"]:
|
|
539
|
-
lambda_ =
|
|
565
|
+
lambda_ = self._lambda_value(self.Lambda_)
|
|
540
566
|
else:
|
|
541
567
|
lambda_ = self.noise
|
|
542
568
|
|
|
@@ -27,6 +27,7 @@ __all__ = [
|
|
|
27
27
|
"get_loading_scores",
|
|
28
28
|
"plot_loading_scores",
|
|
29
29
|
"TorchStandardScaler",
|
|
30
|
+
"seed_everything",
|
|
30
31
|
]
|
|
31
32
|
|
|
32
33
|
_lazy_map = {
|
|
@@ -44,6 +45,8 @@ _lazy_map = {
|
|
|
44
45
|
"plot_loading_scores": ("spotoptim.utils.pca", "plot_loading_scores"),
|
|
45
46
|
# scaler (pulls torch)
|
|
46
47
|
"TorchStandardScaler": ("spotoptim.utils.scaler", "TorchStandardScaler"),
|
|
48
|
+
# seed (pulls torch)
|
|
49
|
+
"seed_everything": ("spotoptim.utils.seed", "seed_everything"),
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 bartzbeielstein
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
"""Global seeding for fully reproducible torch experiments.
|
|
6
|
+
|
|
7
|
+
Ported from the ``seed_everything`` helper of the schu25a compressor-map
|
|
8
|
+
study (``src/rnn/utils.py``): seeds Python, NumPy, and torch (CPU, CUDA, and
|
|
9
|
+
MPS) and switches cuDNN to deterministic mode, so that repeated runs on the
|
|
10
|
+
same device produce bit-identical results.
|
|
11
|
+
|
|
12
|
+
Requires the ``torch`` optional extra (``pip install 'spotoptim[torch]'``).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import random
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
import torch
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def seed_everything(seed: int) -> None:
|
|
23
|
+
"""Seed every random number generator relevant to a torch experiment.
|
|
24
|
+
|
|
25
|
+
Seeds Python's ``random``, ``PYTHONHASHSEED``, NumPy, and torch (CPU and
|
|
26
|
+
CUDA unconditionally, MPS when available), and sets
|
|
27
|
+
``torch.backends.cudnn.deterministic = True`` and
|
|
28
|
+
``torch.backends.cudnn.benchmark = False``.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
seed (int): The seed value.
|
|
32
|
+
|
|
33
|
+
Note:
|
|
34
|
+
- cuDNN determinism and benchmark flags are process-global side
|
|
35
|
+
effects; they may slow down convolutional workloads.
|
|
36
|
+
- Unlike the schu25a original, the MPS generator is only seeded when
|
|
37
|
+
the MPS backend is available, so the function also works on
|
|
38
|
+
CPU-only Linux hosts.
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
```{python}
|
|
42
|
+
import torch
|
|
43
|
+
from spotoptim.utils.seed import seed_everything
|
|
44
|
+
|
|
45
|
+
seed_everything(42)
|
|
46
|
+
a = torch.rand(3)
|
|
47
|
+
seed_everything(42)
|
|
48
|
+
b = torch.rand(3)
|
|
49
|
+
print(torch.equal(a, b))
|
|
50
|
+
```
|
|
51
|
+
"""
|
|
52
|
+
random.seed(seed)
|
|
53
|
+
os.environ["PYTHONHASHSEED"] = str(seed)
|
|
54
|
+
np.random.seed(seed)
|
|
55
|
+
torch.manual_seed(seed)
|
|
56
|
+
torch.cuda.manual_seed(seed)
|
|
57
|
+
if torch.backends.mps.is_available():
|
|
58
|
+
torch.mps.manual_seed(seed)
|
|
59
|
+
torch.backends.cudnn.deterministic = True
|
|
60
|
+
torch.backends.cudnn.benchmark = False
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/factor_analyzer/confirmatory_factor_analyzer.py
RENAMED
|
File without changes
|
|
File without changes
|
{spotoptim-3.1.0 → spotoptim-3.3.0}/src/spotoptim/factor_analyzer/factor_analyzer_rotator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|