Skip to content

Commit 48b8bdb

Browse files
alpha
1 parent 94f5f35 commit 48b8bdb

13 files changed

Lines changed: 650 additions & 294 deletions

notebooks/00_spotPython_tests.ipynb

Lines changed: 247 additions & 35 deletions
Large diffs are not rendered by default.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
77

88
[project]
99
name = "spotpython"
10-
version = "0.23.0_alpha"
10+
version = "0.23.1"
1111
authors = [
1212
{ name="T. Bartz-Beielstein", email="tbb@bartzundbartz.de" }
1313
]

src/spotpython/hyperparameters/values.py

Lines changed: 60 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,66 @@
3131
# End Important
3232

3333

34+
def assign_values(X: np.array, var_list: list) -> dict:
35+
"""
36+
This function takes an np.array X and a list of variable names as input arguments
37+
and returns a dictionary where the keys are the variable names and the values are assigned from X.
38+
39+
Args:
40+
X (np.array):
41+
A 2D numpy array where each column represents a variable.
42+
var_list (list):
43+
A list of strings representing variable names.
44+
45+
Returns:
46+
dict:
47+
A dictionary where keys are variable names and values are assigned from X.
48+
49+
Raises:
50+
ValueError: If the length of var_list does not match the number of columns in X.
51+
52+
Examples:
53+
>>> import numpy as np
54+
>>> from spotpython.hyperparameters.values import assign_values
55+
>>> X = np.array([[1, 2], [3, 4], [5, 6]])
56+
>>> var_list = ['a', 'b']
57+
>>> result = assign_values(X, var_list)
58+
>>> print(result)
59+
{'a': array([1, 3, 5]), 'b': array([2, 4, 6])}
60+
"""
61+
if X.shape[1] != len(var_list):
62+
raise ValueError("Length of var_list does not match the number of columns in X.")
63+
64+
result = {var_list[i]: X[:, i] for i in range(len(var_list))}
65+
return result
66+
67+
68+
def get_tuned_architecture(spot_tuner, force_minX=False) -> dict:
69+
"""
70+
Returns the tuned architecture. If the spot tuner has noise,
71+
it returns the architecture with the lowest mean (.min_mean_X),
72+
otherwise it returns the architecture with the lowest value (.min_X).
73+
74+
Args:
75+
spot_tuner (object):
76+
spot tuner object.
77+
force_minX (bool):
78+
If True, return the architecture with the lowest value (.min_X).
79+
80+
Returns:
81+
(dict):
82+
dictionary containing the tuned architecture.
83+
"""
84+
if not spot_tuner.noise or force_minX:
85+
X = spot_tuner.to_all_dim(spot_tuner.min_X.reshape(1, -1))
86+
else:
87+
# noise or force_minX is False:
88+
X = spot_tuner.to_all_dim(spot_tuner.min_mean_X.reshape(1, -1))
89+
fun_control = copy(spot_tuner.fun_control)
90+
config = get_one_config_from_X(X, fun_control)
91+
return config
92+
93+
3494
def generate_one_config_from_var_dict(
3595
var_dict: Dict[str, np.ndarray],
3696
fun_control: Dict[str, Union[List[str], str]],
@@ -275,36 +335,6 @@ def get_dict_with_levels_and_types(fun_control: Dict[str, Any], v: Dict[str, Any
275335
return new_dict
276336

277337

278-
def assign_values(X: np.array, var_list: list) -> dict:
279-
"""
280-
This function takes an np.array X and a list of variable names as input arguments
281-
and returns a dictionary where the keys are the variable names and the values are assigned from X.
282-
283-
Args:
284-
X (np.array):
285-
A 2D numpy array where each column represents a variable.
286-
var_list (list):
287-
A list of strings representing variable names.
288-
289-
Returns:
290-
dict:
291-
A dictionary where keys are variable names and values are assigned from X.
292-
293-
Examples:
294-
>>> import numpy as np
295-
>>> from spotpython.hyperparameters.values import assign_values
296-
>>> X = np.array([[1, 2], [3, 4], [5, 6]])
297-
>>> var_list = ['a', 'b']
298-
>>> result = assign_values(X, var_list)
299-
>>> print(result)
300-
{'a': array([1, 3, 5]), 'b': array([2, 4, 6])}
301-
"""
302-
result = {}
303-
for i, var_name in enumerate(var_list):
304-
result[var_name] = X[:, i]
305-
return result
306-
307-
308338
def modify_boolean_hyper_parameter_levels(fun_control, hyperparameter, levels) -> None:
309339
"""
310340
This function modifies the levels of a boolean hyperparameter in the fun_control dictionary.
@@ -983,68 +1013,6 @@ def get_default_hyperparameters_as_array(fun_control) -> np.array:
9831013
return X0
9841014

9851015

986-
# def get_default_hyperparameters_for_core_model(fun_control) -> dict:
987-
# """Get the default hyper parameters for the core model.
988-
989-
# Args:
990-
# fun_control (dict):
991-
# The function control dictionary.
992-
993-
# Returns:
994-
# (dict):
995-
# The default hyper parameters for the core model.
996-
997-
# Examples:
998-
# >>> from river.tree import HoeffdingAdaptiveTreeRegressor
999-
# from spotriver.data.river_hyper_dict import RiverHyperDict
1000-
# fun_control = {}
1001-
# add_core_model_to_fun_control(core_model=HoeffdingAdaptiveTreeRegressor,
1002-
# fun_control=func_control,
1003-
# hyper_dict=RiverHyperDict,
1004-
# filename=None)
1005-
# get_default_hyperparameters_for_core_model(fun_control)
1006-
# {'leaf_prediction': 'mean',
1007-
# 'leaf_model': 'NBAdaptive',
1008-
# 'splitter': 'HoeffdingAdaptiveTreeSplitter',
1009-
# 'binary_split': 'info_gain',
1010-
# 'stop_mem_management': False}
1011-
# """
1012-
# values = get_default_values(fun_control)
1013-
# print(f"values: {values}")
1014-
# pprint.pprint(fun_control)
1015-
# values = get_dict_with_levels_and_types(fun_control=fun_control, v=values, default=True)
1016-
# values = convert_keys(values, fun_control["var_type"])
1017-
# values = transform_hyper_parameter_values(fun_control=fun_control, hyper_parameter_values=values)
1018-
# return values
1019-
1020-
1021-
def get_tuned_architecture(spot_tuner, fun_control, force_minX=False) -> dict:
1022-
"""
1023-
Returns the tuned architecture. If the spot tuner has noise,
1024-
it returns the architecture with the lowest mean (.min_mean_X),
1025-
otherwise it returns the architecture with the lowest value (.min_X).
1026-
1027-
Args:
1028-
spot_tuner (object):
1029-
spot tuner object.
1030-
fun_control (dict):
1031-
dictionary containing control parameters for the hyperparameter tuning.
1032-
force_minX (bool):
1033-
If True, return the architecture with the lowest value (.min_X).
1034-
1035-
Returns:
1036-
(dict):
1037-
dictionary containing the tuned architecture.
1038-
"""
1039-
if not spot_tuner.noise or force_minX:
1040-
X = spot_tuner.to_all_dim(spot_tuner.min_X.reshape(1, -1))
1041-
else:
1042-
# noise or force_minX is False:
1043-
X = spot_tuner.to_all_dim(spot_tuner.min_mean_X.reshape(1, -1))
1044-
config = get_one_config_from_X(X, fun_control)
1045-
return config
1046-
1047-
10481016
def create_model(config, fun_control, **kwargs) -> object:
10491017
"""
10501018
Creates a model for the given configuration and control parameters.

src/spotpython/spot/spot.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,23 +1135,10 @@ def save_experiment(self, filename=None, path=None, overwrite=True, unpickleable
11351135
self._close_and_del_spot_writer()
11361136
self._remove_logger_handlers()
11371137

1138-
# Create deep copies of control dictionaries
1139-
fun_control = copy.deepcopy(self.fun_control)
1140-
optimizer_control = copy.deepcopy(self.optimizer_control)
1141-
surrogate_control = copy.deepcopy(self.surrogate_control)
1142-
design_control = copy.deepcopy(self.design_control)
1143-
1144-
# Prepare an experiment dictionary excluding any explicitly unpickable components
1145-
experiment = {
1146-
"design_control": design_control,
1147-
"fun_control": fun_control,
1148-
"optimizer_control": optimizer_control,
1149-
"spot_tuner": self._get_pickle_safe_spot_tuner(unpickleables=unpickleables, verbosity=verbosity),
1150-
"surrogate_control": surrogate_control,
1151-
}
1138+
S = self._get_pickle_safe_spot_tuner(unpickleables=unpickleables, verbosity=verbosity)
11521139

11531140
# Determine the filename based on PREFIX if not provided
1154-
PREFIX = fun_control.get("PREFIX", "experiment")
1141+
PREFIX = self.fun_control.get("PREFIX", "experiment")
11551142
if filename is None:
11561143
filename = get_experiment_filename(PREFIX)
11571144

@@ -1169,7 +1156,7 @@ def save_experiment(self, filename=None, path=None, overwrite=True, unpickleable
11691156
if filename is not None:
11701157
with open(filename, "wb") as handle:
11711158
try:
1172-
pickle.dump(experiment, handle, protocol=pickle.HIGHEST_PROTOCOL)
1159+
pickle.dump(S, handle, protocol=pickle.HIGHEST_PROTOCOL)
11731160
except Exception as e:
11741161
print(f"Error during pickling: {e}")
11751162
raise e

src/spotpython/utils/file.py

Lines changed: 15 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import json
66
import sys
77
import importlib
8-
from spotpython.hyperparameters.values import get_tuned_architecture
98
from spotpython.utils.eda import gen_design_table
109
from spotpython.utils.init import setup_paths
1110

@@ -120,19 +119,29 @@ def get_result_filename(PREFIX) -> str:
120119
return filename
121120

122121

123-
def load_result(PREFIX) -> tuple:
122+
def _handle_filneame(filename, PREFIX):
123+
if filename is None:
124+
if PREFIX is None:
125+
raise ValueError("No PREFIX provided.")
126+
filename = get_result_filename(PREFIX)
127+
return filename
128+
129+
130+
def load_result(PREFIX=None, filename=None) -> tuple:
124131
"""Loads the result from a pickle file with the name
125132
PREFIX + "_res.pkl".
126133
This is the standard filename for the result file,
127134
when it is saved by the spot tuner using `save_result()`, i.e.,
128135
when fun_control["save_result"] is set to True.
136+
If a filename is provided, the result is loaded from this file.
129137
130138
Args:
131-
PREFIX (str): Prefix of the experiment.
139+
PREFIX (str): Prefix of the experiment. Defaults to None.
140+
filename (str): Name of the pickle file. Defaults to None.
132141
133142
Returns:
134143
spot_tuner (Spot): The spot tuner object.
135-
144+
136145
Notes:
137146
The corresponding save_result function is part of the class spot.
138147
@@ -141,9 +150,7 @@ def load_result(PREFIX) -> tuple:
141150
>>> load_result("branin")
142151
143152
"""
144-
if PREFIX is None:
145-
raise ValueError("No PREFIX provided.")
146-
filename = get_result_filename(PREFIX)
153+
filename = _handle_filneame(filename, PREFIX)
147154
spot_tuner = load_experiment(filename=filename)
148155
return spot_tuner
149156

@@ -172,15 +179,13 @@ def load_experiment(PREFIX=None, filename=None):
172179
>>> spot_tuner, fun_control, design_control, _, _ = load_experiment(filename="RUN_0.pkl")
173180
174181
"""
175-
if filename is None and PREFIX is not None:
176-
filename = get_experiment_filename(PREFIX)
182+
filename = _handle_filneame(filename, PREFIX)
177183
with open(filename, "rb") as handle:
178184
spot_tuner = pickle.load(handle)
179185
print(f"Loaded experiment from {filename}")
180186
return spot_tuner
181187

182188

183-
184189
def load_dict_from_file(coremodel, dirname="userModel"):
185190
"""Loads a dictionary from a json file.
186191
@@ -220,43 +225,6 @@ def load_core_model_from_file(coremodel, dirname="userModel"):
220225
return core_model
221226

222227

223-
def get_experiment_from_PREFIX(PREFIX, return_dict=True) -> dict:
224-
"""
225-
Setup the experiment based on the PREFIX provided and return the relevant configuration
226-
and control objects.
227-
228-
Args:
229-
PREFIX (str):
230-
The prefix for the experiment filename.
231-
return_dict (bool, optional):
232-
Whether to return the configuration and control objects as a dictionary.
233-
If False, a tuple is returned:
234-
"(config, fun_control, design_control, surrogate_control, optimizer_control)."
235-
Defaults to True.
236-
237-
Returns:
238-
dict: Dictionary containing the configuration and control objects.
239-
240-
Example:
241-
>>> from spotpython.utils.file import get_experiment_from_PREFIX
242-
>>> config = get_experiment_from_PREFIX("100")["config"]
243-
244-
"""
245-
experiment_name = get_experiment_filename(PREFIX)
246-
spot_tuner = load_experiment(experiment_name)
247-
config = get_tuned_architecture(spot_tuner, fun_control)
248-
if return_dict:
249-
return {
250-
"config": config,
251-
"fun_control": fun_control,
252-
"design_control": design_control,
253-
"surrogate_control": surrogate_control,
254-
"optimizer_control": optimizer_control,
255-
}
256-
else:
257-
return config, fun_control, design_control, surrogate_control, optimizer_control
258-
259-
260228
def load_and_run_spot_python_experiment(spot_filename) -> tuple:
261229
"""Loads and runs a spot experiment.
262230

src/spotpython/utils/init.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def fun_control_init(
2222
_L_out=None,
2323
_L_cond=None,
2424
_torchmetric=None,
25-
PREFIX="00",
25+
PREFIX=None,
2626
TENSORBOARD_CLEAN=False,
2727
accelerator="auto",
2828
converters=None,
@@ -381,6 +381,9 @@ def fun_control_init(
381381
# Setting the seed
382382
L.seed_everything(seed)
383383

384+
if PREFIX is None:
385+
PREFIX = _init_PREFIX()
386+
384387
CHECKPOINT_PATH, DATASET_PATH, RESULTS_PATH, TENSORBOARD_PATH = setup_paths(TENSORBOARD_CLEAN)
385388
spot_tensorboard_path = create_spot_tensorboard_path(tensorboard_log, PREFIX)
386389

@@ -518,6 +521,23 @@ def fun_control_init(
518521
return fun_control
519522

520523

524+
def _init_PREFIX() -> str:
525+
"""Initialize the PREFIX for the experiment name.
526+
527+
Returns:
528+
PREFIX (str):
529+
The PREFIX for the experiment name.
530+
531+
Examples:
532+
>>> from spotpython.utils.init import _init_PREFIX
533+
>>> _init_PREFIX()
534+
'00'
535+
"""
536+
# set the prefix to the actual date and time
537+
PREFIX = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
538+
return PREFIX
539+
540+
521541
def setup_paths(tensorboard_clean) -> tuple:
522542
"""
523543
Setup paths for checkpoints, datasets, results, and tensorboard files.

src/spotpython/utils/transform.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def transform_hyper_parameter_values(fun_control, hyper_parameter_values):
311311
'lr_mult': 1.0,
312312
'patience': 3,
313313
'batch_norm': 0,
314-
'initialization': 'Default',
314+
'initialization': 'Default',
315315
}
316316
transform_hyper_parameter_values(fun_control, hyper_parameter_values)
317317
{'l1': 4,
@@ -323,7 +323,7 @@ def transform_hyper_parameter_values(fun_control, hyper_parameter_values):
323323
'lr_mult': 1.0,
324324
'patience': 8,
325325
'batch_norm': 0,
326-
'initialization': 'Default'}
326+
'initialization': 'Default'}
327327
"""
328328
hyper_parameter_values = copy.deepcopy(hyper_parameter_values)
329329
for key, value in hyper_parameter_values.items():

0 commit comments

Comments
 (0)