Skip to content

Commit

Permalink
Stop reinserting parents into offspring. Fixed island indexes for that
Browse files Browse the repository at this point in the history
  • Loading branch information
gAldeia committed Nov 2, 2023
1 parent 7c1d83f commit f341896
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 16 deletions.
6 changes: 2 additions & 4 deletions src/brush/deap_api/nsga2.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def calculate_statistics(ind):
# offspring = tools.selTournamentDCD(pop, len(pop))
parents = toolbox.select(pop, len(pop))
# offspring = [toolbox.clone(ind) for ind in offspring]
offspring, successfull = [], 0
offspring = []
for ind1, ind2 in zip(parents[::2], parents[1::2]):
off1, off2 = None, None
if rnd_flt() < CXPB: # either mutation or crossover
Expand All @@ -77,15 +77,13 @@ def calculate_statistics(ind):
off2 = toolbox.mutate(ind2)

if off1 is not None: # Mutation worked. first we fit, then add to offspring
successfull = successfull + 1
# Evaluate (instead of evaluateValidation) to fit the weights of the offspring
off1.fitness.values = toolbox.evaluate(off1)
if use_batch: # Adjust fitness to the same data as parents
off1.fitness.values = toolbox.evaluateValidation(off1, data=batch)
offspring.extend([off1])

if off2 is not None:
successfull = successfull + 1
off2.fitness.values = toolbox.evaluate(off2)
if use_batch:
off2.fitness.values = toolbox.evaluateValidation(off2, data=batch)
Expand All @@ -98,7 +96,7 @@ def calculate_statistics(ind):
pop.sort(key=lambda x: x.fitness, reverse=True)

record = stats.compile(pop)
logbook.record(gen=gen, evals=successfull+(len(pop) if use_batch else 0), **record)
logbook.record(gen=gen, evals=len(offspring)+(len(pop) if use_batch else 0), **record)

if verbosity > 0:
print(logbook.stream)
Expand Down
43 changes: 31 additions & 12 deletions src/brush/deap_api/nsga2island.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ def calculate_statistics(ind):
stats.register("max", np.max, axis=0)

logbook = tools.Logbook()
logbook.header = "gen", "evals", "avg (O1 train, O2 train, O1 val, O2 val)", \
"med (O1 train, O2 train, O1 val, O2 val)", \
"std (O1 train, O2 train, O1 val, O2 val)", \
"min (O1 train, O2 train, O1 val, O2 val)", \
"max (O1 train, O2 train, O1 val, O2 val)"
logbook.header = ['gen', 'evals'] + \
[f"{stat} {partition} O{objective}"
for stat in ['avg', 'med', 'std', 'min', 'max']
for partition in ['train', 'val']
for objective in toolbox.get_objectives()]

# Tuples with start and end indexes for each island. Number of individuals
# in each island can slightly differ if N_ISLANDS is not a divisor of MU
Expand Down Expand Up @@ -81,7 +81,9 @@ def calculate_statistics(ind):
parents.extend(island_parents)

offspring = [] # Will have the same size as pop
island_failed_variations = []
for (idx_start, idx_end) in island_indexes:
failed_variations = 0
for ind1, ind2 in zip(parents[idx_start:idx_end:2],
parents[idx_start+1:idx_end:2]
):
Expand All @@ -92,9 +94,21 @@ def calculate_statistics(ind):
off1 = toolbox.mutate(ind1)
off2 = toolbox.mutate(ind2)

# Inserting parent if mutation failed
offspring.extend([off1 if off1 is not None else toolbox.Clone(ind1)])
offspring.extend([off2 if off2 is not None else toolbox.Clone(ind2)])
if off1 is not None:
off1.fitness.values = toolbox.evaluate(off1)
if use_batch:
off1.fitness.values = toolbox.evaluateValidation(off1, data=batch)
offspring.extend([off1])
else:
failed_variations += 1

if off2 is not None:
off2.fitness.values = toolbox.evaluate(off2)
if use_batch:
off2.fitness.values = toolbox.evaluateValidation(off2, data=batch)
offspring.extend([off2])
else:
failed_variations += 1

# Evaluate (instead of evaluateValidation) to fit the weights of the offspring
fitnesses = toolbox.map(functools.partial(toolbox.evaluate), offspring)
Expand All @@ -107,10 +121,15 @@ def calculate_statistics(ind):

# Select the next generation population
new_pop = []
for (idx_start, idx_end) in island_indexes:
island_new_pop = toolbox.survive(pop[idx_start:idx_end] \
+offspring[idx_start:idx_end],
idx_end-idx_start)
for i, (idx_start, idx_end) in enumerate(island_indexes):
# original population combined with offspring, taking into account that variations can fail
island_new_pop = toolbox.survive(
pop[idx_start:idx_end] \
+ offspring[
idx_start-sum(island_failed_variations[:i]):idx_end+island_failed_variations[i]
],
idx_end-idx_start # number of selected individuals should still the same
)
new_pop.extend(island_new_pop)

# Migration to fill up the islands for the next generation
Expand Down

0 comments on commit f341896

Please sign in to comment.