Skip to content
This repository was archived by the owner on Feb 26, 2025. It is now read-only.

Commit 67d4195

Browse files
author
damart
committed
Reorganization and syntax fixes
1 parent 62a98f1 commit 67d4195

File tree

5 files changed

+97
-118
lines changed

5 files changed

+97
-118
lines changed

bluepyopt/deapext/CMA_MO.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,13 @@ def __init__(self,
133133
self.stopping_conditions = [MaxNGen(max_ngen)]
134134

135135
def hyper_volume(self, front):
136-
136+
"""Compute the hypervolume contribution of each individual"""
137137
wobj = numpy.array([ind.fitness.values for ind in front])
138138
obj_ranges = (numpy.max(wobj, axis=0) - numpy.min(wobj, axis=0))
139139
ref = numpy.max(wobj, axis=0) + 1
140140

141-
# Above 23 dim, hypervolume is too slow, so I settle for an approximation
141+
# Above 23 dimension, the hypervolume computation is too slow,
142+
# we settle for the 23 dimension showing the largest range of values
142143
max_ndim = 23
143144
if len(ref) > max_ndim:
144145
idxs = list(range(len(ref)))
@@ -148,15 +149,21 @@ def hyper_volume(self, front):
148149
wobj = wobj[:, idxs]
149150
ref = ref[idxs]
150151

151-
to_evaluate = []
152+
# Prepare the data and send it to multiprocess
152153
for i in range(len(front)):
153154
to_evaluate.append([i, numpy.copy(wobj), numpy.copy(ref)])
154-
155155
contrib_values = self.toolbox.map(contribution, to_evaluate)
156156

157157
return list(contrib_values)
158158

159159
def _select(self, candidates):
160+
"""Select the best candidates of the population
161+
162+
Fill the next population (chosen) with the Pareto fronts until there is
163+
not enouch space. When an entire front does not fit in the space left
164+
we rely on the hypervolume for this front. The remaining fronts are
165+
explicitly not chosen"""
166+
160167
if len(candidates) <= self.mu:
161168
return candidates, []
162169

@@ -167,10 +174,6 @@ def _select(self, candidates):
167174
mid_front = None
168175
not_chosen = list()
169176

170-
# Fill the next population (chosen) with the fronts until there is not enouch space
171-
# When an entire front does not fit in the space left we rely on the hypervolume
172-
# for this front
173-
# The remaining fronts are explicitly not chosen
174177
full = False
175178
for front in pareto_fronts:
176179
if len(chosen) + len(front) <= self.mu and not full:
@@ -182,6 +185,8 @@ def _select(self, candidates):
182185
else:
183186
not_chosen += front
184187

188+
# Hypervolume contribution to get the best candidates on the remaining
189+
# front
185190
k = self.mu - len(chosen)
186191
if k > 0:
187192
hyperv = self.hyper_volume(mid_front)

bluepyopt/deapext/CMA_SO.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ def update(self, population):
104104
"""Update the current covariance matrix strategy from the
105105
population"""
106106

107-
population.sort(key=lambda ind: ind.fitness.reduce_weight, reverse=True)
107+
population.sort(key=lambda ind: ind.fitness.reduce_weight,
108+
reverse=True)
108109

109110
old_centroid = self.centroid
110111
self.centroid = numpy.dot(self.weights, population[0:self.mu])

bluepyopt/deapext/optimisations.py

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -44,51 +44,6 @@
4444
# settings of the algorithm can be stored in objects of these classes
4545

4646

47-
class WeightedSumFitness(deap.base.Fitness):
48-
49-
"""Fitness that compares by weighted sum"""
50-
51-
def __init__(self, values=(), obj_size=None):
52-
self.weights = [-1.0] * obj_size if obj_size is not None else [-1]
53-
54-
super(WeightedSumFitness, self).__init__(values)
55-
56-
@property
57-
def weighted_sum(self):
58-
"""Weighted sum of wvalues"""
59-
return sum(self.wvalues)
60-
61-
@property
62-
def sum(self):
63-
"""Weighted sum of values"""
64-
return sum(self.values)
65-
66-
def __le__(self, other):
67-
return self.weighted_sum <= other.weighted_sum
68-
69-
def __lt__(self, other):
70-
return self.weighted_sum < other.weighted_sum
71-
72-
def __deepcopy__(self, _):
73-
"""Override deepcopy"""
74-
75-
cls = self.__class__
76-
result = cls.__new__(cls)
77-
result.__dict__.update(self.__dict__)
78-
return result
79-
80-
81-
class WSListIndividual(list):
82-
83-
"""Individual consisting of list with weighted sum field"""
84-
85-
def __init__(self, *args, **kwargs):
86-
"""Constructor"""
87-
self.fitness = WeightedSumFitness(obj_size=kwargs['obj_size'])
88-
del kwargs['obj_size']
89-
super(WSListIndividual, self).__init__(*args, **kwargs)
90-
91-
9247
class DEAPOptimisation(bluepyopt.optimisations.Optimisation):
9348

9449
"""DEAP Optimisation class"""
@@ -162,7 +117,6 @@ def setup_deap(self):
162117
IND_SIZE = len(self.evaluator.params)
163118

164119
# Bounds for the parameters
165-
166120
LOWER = []
167121
UPPER = []
168122

@@ -181,7 +135,7 @@ def setup_deap(self):
181135
self.toolbox.register(
182136
"Individual",
183137
deap.tools.initIterate,
184-
functools.partial(WSListIndividual, obj_size=OBJ_SIZE),
138+
functools.partial(utils.WSListIndividual, obj_size=OBJ_SIZE),
185139
self.toolbox.uniformparams)
186140

187141
# Register the population format. It is a list of individuals

bluepyopt/deapext/optimisationsCMA.py

Lines changed: 24 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -36,59 +36,13 @@
3636
logger = logging.getLogger('__main__')
3737

3838

39-
class ReduceFitness(deap.base.Fitness):
40-
"""Fitness that compares by weighted"""
41-
42-
def __init__(self, values=(), obj_size=None, reduce_fcn=numpy.sum):
43-
self.weights = [-1.0] * obj_size if obj_size is not None else [-1]
44-
self.reduce_fcn = reduce_fcn
45-
super(ReduceFitness, self).__init__(values)
46-
47-
@property
48-
def reduce(self):
49-
return self.reduce_fcn(self.values)
50-
51-
@property
52-
def reduce_weight(self):
53-
"""Weighted reduce of wvalues"""
54-
return self.reduce_fcn(self.wvalues)
55-
56-
def __le__(self, other):
57-
return self.reduce_weight <= other.reduce_weight
58-
59-
def __lt__(self, other):
60-
return self.reduce_weight < other.reduce_weight
61-
62-
def __deepcopy__(self, _):
63-
"""Override deepcopy"""
64-
65-
cls = self.__class__
66-
result = cls.__new__(cls)
67-
result.__dict__.update(self.__dict__)
68-
return result
69-
70-
71-
class ListIndividual(list):
72-
"""Individual consisting of list with weighted fitness field"""
73-
74-
def __init__(self, *args, **kwargs):
75-
"""Constructor"""
76-
self.fitness = ReduceFitness(obj_size=kwargs['obj_size'],
77-
reduce_fcn=kwargs['reduce_fcn'])
78-
del kwargs['obj_size']
79-
del kwargs['reduce_fcn']
80-
super(ListIndividual, self).__init__(*args, **kwargs)
81-
82-
# Used by CMA multi objective
83-
self._ps = "p", 0
84-
85-
8639
def _ind_convert_space(ind, convert_fcn):
8740
return [f(x) for f, x in zip(convert_fcn, ind)]
8841

8942

9043
class DEAPOptimisationCMA(bluepyopt.optimisations.Optimisation):
91-
"""CMA based optimisation class"""
44+
45+
"""Optimisation class for CMA-based evolution strategies"""
9246

9347
def __init__(self,
9448
evaluator=None,
@@ -105,10 +59,12 @@ def __init__(self,
10559
10660
Args:
10761
evaluator (Evaluator): Evaluator object
62+
seed (float): Random number generator seed
63+
offspring_size (int): Number of offspring individuals in each
64+
generation
10865
centroids (list): list of initial guesses used as the starting
10966
points of the CMA-ES
11067
sigma (float): initial standard deviation of the distribution
111-
seed (float): Random number generator seed
11268
map_function (function): Function used to map (parallelize) the
11369
evaluation function calls
11470
hof (hof): Hall of Fame object
@@ -124,11 +80,12 @@ def __init__(self,
12480
self.use_scoop = use_scoop
12581
self.seed = seed
12682
self.map_function = map_function
83+
12784
self.hof = hof
12885
if self.hof is None:
12986
self.hof = deap.tools.HallOfFame(10)
130-
self.fitness_reduce = fitness_reduce
13187

88+
self.fitness_reduce = fitness_reduce
13289
self.offspring_size = offspring_size
13390
self.centroids = centroids
13491
self.sigma = sigma
@@ -162,6 +119,7 @@ def __init__(self,
162119
self.lbounds = numpy.asarray(self.lbounds)
163120
bounds_radius = (self.ubounds - self.lbounds) / 2.
164121
bounds_mean = (self.ubounds + self.lbounds) / 2.
122+
165123
self.to_norm = []
166124
self.to_space = []
167125
for r, m in zip(bounds_radius, bounds_mean):
@@ -200,17 +158,17 @@ def setup_deap(self):
200158
# Register the individual format
201159
self.toolbox.register(
202160
"Individual",
203-
functools.partial(ListIndividual,
161+
functools.partial(utils.WSListIndividual,
204162
obj_size=self.ind_size,
205163
reduce_fcn=self.fitness_reduce)
206164
)
207165

208166
# A Random Indiviual is create by ListIndividual and parameters are
209167
# initially picked by 'uniform'
210168
self.toolbox.register(
211-
"RandomIndividual",
169+
"RandomInd",
212170
deap.tools.initIterate,
213-
functools.partial(ListIndividual,
171+
functools.partial(WSListIndividual,
214172
obj_size=self.ind_size,
215173
reduce_fcn=self.fitness_reduce),
216174
self.toolbox.uniformparams)
@@ -220,7 +178,7 @@ def setup_deap(self):
220178
"population",
221179
deap.tools.initRepeat,
222180
list,
223-
self.toolbox.RandomIndividual)
181+
self.toolbox.RandomInd)
224182

225183
# Register the evaluation function for the individuals
226184
self.toolbox.register("evaluate", self.evaluator.evaluate_with_lists)
@@ -251,13 +209,14 @@ def run(self,
251209
Args:
252210
max_ngen(int): Total number of generation to run
253211
cp_frequency(int): generations between checkpoints
254-
cp_filename(string): path to checkpoint filename
255212
continue_cp(bool): whether to continue
213+
cp_filename(string): path to checkpoint filename
256214
"""
257215

258216
stats = self.get_stats()
259217

260218
if continue_cp:
219+
261220
# A file name has been given, then load the data from the file
262221
cp = pickle.load(open(cp_filename, "br"))
263222
gen = cp["generation"]
@@ -270,17 +229,18 @@ def run(self,
270229
CMA_es.map_function = self.map_function
271230

272231
else:
232+
273233
history = deap.tools.History()
274234
logbook = deap.tools.Logbook()
275235
logbook.header = ["gen", "nevals"] + stats.fields
276236

277-
# Instantiate the CMA strategies centered on the centroids
237+
# Instantiate the CMA strategy centered on the centroids
278238
CMA_es = self.cma_creator(centroids=self.centroids,
279239
offspring_size=self.offspring_size,
280240
sigma=self.sigma,
281241
max_ngen=max_ngen,
282242
IndCreator=self.toolbox.Individual,
283-
RandIndCreator=self.toolbox.RandomIndividual,
243+
RandIndCreator=self.toolbox.RandomInd,
284244
map_function=self.map_function,
285245
use_scoop=self.use_scoop)
286246

@@ -299,8 +259,9 @@ def run(self,
299259
# Generate the new populations
300260
n_out = CMA_es.generate_new_pop(lbounds=self.lbounds,
301261
ubounds=self.ubounds)
302-
logger.info("Number of individuals outside of bounds: {} ({:.2f}%)"
303-
"".format(n_out, 100. * n_out / len(CMA_es.population)))
262+
logger.debug("Number of individuals outside of bounds: {} "
263+
"({:.2f}%)".format(n_out, 100. *
264+
n_out / len(CMA_es.population)))
304265

305266
# Get all the individuals in the original space for evaluation
306267
to_evaluate = CMA_es.get_population(self.to_space)
@@ -323,8 +284,11 @@ def run(self,
323284
CMA_es.check_termination(gen)
324285

325286
if cp_filename and cp_frequency and gen % cp_frequency == 0:
287+
288+
# Map function shouldn't be pickled
326289
temp_mf = CMA_es.map_function
327290
CMA_es.map_function = None
291+
328292
cp = dict(population=pop,
329293
generation=gen,
330294
halloffame=self.hof,
@@ -335,6 +299,7 @@ def run(self,
335299
CMA_es=CMA_es)
336300
pickle.dump(cp, open(cp_filename, "wb"))
337301
logger.debug('Wrote checkpoint to %s', cp_filename)
302+
338303
CMA_es.map_function = temp_mf
339304

340305
gen += 1

0 commit comments

Comments
 (0)