1
1
import random
2
- from typing import Optional , Callable , List , Union , Tuple
3
-
4
- from ConfigSpace import Configuration , ConfigurationSpace , CategoricalHyperparameter , OrdinalHyperparameter
2
+ from typing import Callable , List , Optional , Tuple , Union
3
+
4
+ from ConfigSpace import (
5
+ CategoricalHyperparameter ,
6
+ Configuration ,
7
+ ConfigurationSpace ,
8
+ OrdinalHyperparameter ,
9
+ )
5
10
from ConfigSpace .hyperparameters import NumericalHyperparameter
6
11
7
12
from openbox .core .ea .base_ea_advisor import Individual , pareto_best , pareto_sort
11
16
12
17
class DifferentialEAAdvisor (ModularEAAdvisor ):
13
18
14
- @deprecate_kwarg ('num_objs' , 'num_objectives' , 'a future version' )
15
- def __init__ (self ,
16
-
17
- config_space : ConfigurationSpace ,
18
- num_objectives = 1 ,
19
- num_constraints = 0 ,
20
- population_size = 30 ,
21
- optimization_strategy = 'ea' ,
22
- batch_size = 1 ,
23
- output_dir = 'logs' ,
24
- task_id = 'OpenBox' ,
25
- random_state = None ,
26
-
27
- required_evaluation_count : Optional [int ] = None ,
28
- auto_step = True ,
29
- strict_auto_step = True ,
30
- skip_gen_population = False ,
31
- filter_gen_population : Optional [Callable [[List [Configuration ]], List [Configuration ]]] = None ,
32
- keep_unexpected_population = True ,
33
- save_cached_configuration = True ,
34
-
35
- constraint_strategy = 'discard' ,
36
-
37
- f : Union [Tuple [float , float ], float ] = 0.5 ,
38
- cr : Union [Tuple [float , float ], float ] = 0.9 ,
39
- ):
19
+ @deprecate_kwarg ("num_objs" , "num_objectives" , "a future version" )
20
+ def __init__ (
21
+ self ,
22
+ config_space : ConfigurationSpace ,
23
+ num_objectives = 1 ,
24
+ num_constraints = 0 ,
25
+ population_size = 30 ,
26
+ optimization_strategy = "ea" ,
27
+ batch_size = 1 ,
28
+ output_dir = "logs" ,
29
+ task_id = "OpenBox" ,
30
+ random_state = None ,
31
+ required_evaluation_count : Optional [int ] = None ,
32
+ auto_step = True ,
33
+ strict_auto_step = True ,
34
+ skip_gen_population = False ,
35
+ filter_gen_population : Optional [
36
+ Callable [[List [Configuration ]], List [Configuration ]]
37
+ ] = None ,
38
+ keep_unexpected_population = True ,
39
+ save_cached_configuration = True ,
40
+ constraint_strategy = "discard" ,
41
+ f : Union [Tuple [float , float ], float ] = 0.5 ,
42
+ cr : Union [Tuple [float , float ], float ] = 0.9 ,
43
+ ):
40
44
"""
41
45
f is the hyperparameter for DEA that X = A + (B - C) * f
42
46
cr is the cross rate
43
47
f and cr may be a tuple of two floats, such as (0.1,0.9)
44
48
If so, these two values are adjusted automatically within this range.
45
49
"""
46
- super ().__init__ (config_space = config_space , num_objectives = num_objectives , num_constraints = num_constraints ,
47
- population_size = population_size , optimization_strategy = optimization_strategy ,
48
- batch_size = batch_size , output_dir = output_dir , task_id = task_id ,
49
- random_state = random_state ,
50
-
51
- required_evaluation_count = required_evaluation_count , auto_step = auto_step ,
52
- strict_auto_step = strict_auto_step , skip_gen_population = skip_gen_population ,
53
- filter_gen_population = filter_gen_population ,
54
- keep_unexpected_population = keep_unexpected_population ,
55
- save_cached_configuration = save_cached_configuration
56
- )
50
+ super ().__init__ (
51
+ config_space = config_space ,
52
+ num_objectives = num_objectives ,
53
+ num_constraints = num_constraints ,
54
+ population_size = population_size ,
55
+ optimization_strategy = optimization_strategy ,
56
+ batch_size = batch_size ,
57
+ output_dir = output_dir ,
58
+ task_id = task_id ,
59
+ random_state = random_state ,
60
+ required_evaluation_count = required_evaluation_count ,
61
+ auto_step = auto_step ,
62
+ strict_auto_step = strict_auto_step ,
63
+ skip_gen_population = skip_gen_population ,
64
+ filter_gen_population = filter_gen_population ,
65
+ keep_unexpected_population = keep_unexpected_population ,
66
+ save_cached_configuration = save_cached_configuration ,
67
+ )
57
68
58
69
self .constraint_strategy = constraint_strategy
59
- assert self .constraint_strategy in {' discard' }
70
+ assert self .constraint_strategy in {" discard" }
60
71
61
72
self .f = f
62
73
self .cr = cr
@@ -76,25 +87,32 @@ def _gen(self, count=1) -> List[Configuration]:
76
87
next_config = self .sample_random_config (excluded_configs = self .all_configs )
77
88
nid = - 1
78
89
else :
79
- xi = self .population [self .cur ][' config' ]
80
- xi_score = self .population [self .cur ][' perf' ]
90
+ xi = self .population [self .cur ][" config" ]
91
+ xi_score = self .population [self .cur ][" perf" ]
81
92
82
93
# Randomly sample 3 other values: x1, x2, x3
83
94
lst = list (range (self .population_size ))
84
95
lst .remove (self .cur )
85
96
random .shuffle (lst )
86
97
lst = lst [:3 ]
87
-
88
98
if self .dynamic_f :
89
- lst .sort (key = lambda a : self .population [a ][' perf' ])
99
+ lst .sort (key = lambda a : self .population [a ][" perf" ][ 0 ])
90
100
91
101
i1 , i2 , i3 = lst [0 ], lst [1 ], lst [2 ]
92
- x1 , x2 , x3 = self .population [i1 ]['config' ], self .population [i2 ]['config' ], self .population [i3 ]['config' ]
102
+ x1 , x2 , x3 = (
103
+ self .population [i1 ]["config" ],
104
+ self .population [i2 ]["config" ],
105
+ self .population [i3 ]["config" ],
106
+ )
93
107
94
108
# Mutation: xt = x1 + (x2 - x3) * f
95
109
if self .dynamic_f :
96
110
# Dynamic f
97
- f1 , f2 , f3 = self .population [i1 ]['perf' ], self .population [i2 ]['perf' ], self .population [i3 ]['perf' ]
111
+ f1 , f2 , f3 = (
112
+ self .population [i1 ]["perf" ][0 ],
113
+ self .population [i2 ]["perf" ][0 ],
114
+ self .population [i3 ]["perf" ][0 ],
115
+ )
98
116
if f1 == f3 :
99
117
f = self .f [0 ]
100
118
else :
@@ -108,14 +126,14 @@ def _gen(self, count=1) -> List[Configuration]:
108
126
# Cross over between xi and xt, get xn
109
127
if self .dynamic_cr :
110
128
# Dynamic cr
111
- scores = [a [' perf' ] for a in self .population ]
129
+ scores = [a [" perf" ][ 0 ] for a in self .population ]
112
130
scores_avg = sum (scores ) / len (scores )
113
-
114
- if xi_score < scores_avg :
131
+ if xi_score [0 ] < scores_avg :
115
132
scores_mx = max (scores )
116
133
scores_mn = min (scores )
117
- cr = self .cr [0 ] + (self .cr [1 ] - self .cr [0 ]) * (scores_mx - xi_score ) / max (
118
- scores_mx - scores_mn , 1e-10 )
134
+ cr = self .cr [0 ] + (self .cr [1 ] - self .cr [0 ]) * (
135
+ scores_mx - xi_score [0 ]
136
+ ) / max (scores_mx - scores_mn , 1e-10 )
119
137
else :
120
138
cr = self .cr [0 ]
121
139
else :
@@ -132,12 +150,11 @@ def _gen(self, count=1) -> List[Configuration]:
132
150
next_config = xn
133
151
nid = self .cur
134
152
self .cur = (self .cur + 1 ) % self .population_size
135
-
136
153
self .nid_map [next_config ] = nid
137
154
return [next_config ]
138
155
139
156
def _sel (self , parent : List [Individual ], sub : List [Individual ]) -> List [Individual ]:
140
- if self .constraint_strategy == ' discard' and self .num_constraints > 0 :
157
+ if self .constraint_strategy == " discard" and self .num_constraints > 0 :
141
158
sub = [x for x in sub if x .constraints_satisfied ]
142
159
143
160
for conf in sub :
@@ -153,26 +170,37 @@ def _sel(self, parent: List[Individual], sub: List[Individual]) -> List[Individu
153
170
for conf in sub :
154
171
if conf not in self .nid_map or self .nid_map [conf ] == - 1 :
155
172
parent .append (conf )
156
-
157
173
parent = pareto_sort (parent )
158
- parent = parent [:self .population_size ]
174
+ parent = parent [: self .population_size ]
159
175
random .shuffle (parent )
160
176
161
177
return parent
162
178
163
- def mutate (self , config_a : Configuration , config_b : Configuration , config_c : Configuration , f : float ):
179
+ def mutate (
180
+ self ,
181
+ config_a : Configuration ,
182
+ config_b : Configuration ,
183
+ config_c : Configuration ,
184
+ f : float ,
185
+ ):
164
186
"""
165
187
Compute A + (B - C) * f. Basically element-wise.
166
188
For ranged int/float values, the result will be clamped into [lower, upper].
167
189
For categorical/ordinal values, the values are converted to ints and the result is (mod SIZE).
168
190
e. g. in ["A", "B", "C", "D"], "D" + "B" - "A" => 3 + 1 - 0 => 4 => 0 (mod 4) => "A"
169
191
"""
170
- new_array = config_a .get_array () + (config_b .get_array () - config_c .get_array ()) * f
192
+ new_array = (
193
+ config_a .get_array () + (config_b .get_array () - config_c .get_array ()) * f
194
+ )
171
195
172
196
for i , key in enumerate (self .config_space .keys ()):
173
197
hp_type = self .config_space .get_hyperparameter (key )
174
- if isinstance (hp_type , CategoricalHyperparameter ) or isinstance (hp_type , OrdinalHyperparameter ):
175
- v = (round (new_array [i ]) % hp_type .get_size () + hp_type .get_size ()) % hp_type .get_size ()
198
+ if isinstance (hp_type , CategoricalHyperparameter ) or isinstance (
199
+ hp_type , OrdinalHyperparameter
200
+ ):
201
+ v = (
202
+ round (new_array [i ]) % hp_type .get_size () + hp_type .get_size ()
203
+ ) % hp_type .get_size ()
176
204
new_array [i ] = v
177
205
elif isinstance (hp_type , NumericalHyperparameter ):
178
206
# new_array[i] = max(0, min(new_array[i], 1))
0 commit comments