I am new using DEAP. My task is to optimize a technical system, which needs parameters as int and float values in a specific range.
As a first step I wrote a small script based on the DEAP documentation.
import random
from deap import base
from deap import creator
from deap import tools
CXPB, MUTPB = 0.2, 0.2
IND_SIZE = 1
POP_SIZE = 10
GEN_SIZE = 50
MIN_1, MAX_1 = 7.5, 8.5
MIN_2, MAX_2 = 20, 60
creator.create("FitnessMin", base.Fitness, weights=(-1.0, -1.0))
creator.create("Individual", list, fitness=creator.FitnessMin)
toolbox = base.Toolbox()
toolbox.register("attr_float", random.uniform, MIN_1, MAX_1)
toolbox.register("attr_int" , random.randint, MIN_2, MAX_2)
toolbox.register("individual", tools.initCycle, creator.Individual,(toolbox.attr_int,toolbox.attr_float), IND_SIZE)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)
def evaluate(individual):
print ('evaluate:',individual)
a = sum(individual)
b = len(individual)
return a, 1. / b
toolbox.register("evaluate", evaluate)
pop = toolbox.population(n=POP_SIZE)
for g in range(GEN_SIZE):
print ('generation',g)
# Select the next generation individuals
offspring = toolbox.select(pop, len(pop))
# Clone the selected individuals
offspring = map(toolbox.clone, offspring)
# Apply crossover on the offspring
for child1, child2 in zip(offspring[::2], offspring[1::2]):
if random.random() < CXPB:
toolbox.mate(child1, child2)
del child1.fitness.values
del child2.fitness.values
# Apply mutation on the offspring
for mutant in offspring:
if random.random() < MUTPB:
toolbox.mutate(mutant)
del mutant.fitness.values
# Evaluate the individuals with an invalid fitness
invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
for ind, fit in zip(invalid_ind, fitnesses):
ind.fitness.values = fit
# The population is entirely replaced by the offspring
pop[:] = offspring
During running this script I found, that the values of attr_float and attr_int are violating the bounds given with MIN_1, MIN_2, MAX_1 and MAX_2 during the generations. Also the type of attr_int is changing after some generations
('generation', 0)
('evaluate:', [20, 8.307457724269371])
('evaluate:', [40, 8.035611879681108])
('evaluate:', [31, 8.331020742869226])
('evaluate:', [50, 8.370955173904012])
('evaluate:', [29, 8.427249762963857])
('evaluate:', [31, 8.331020742869226])
('evaluate:', [21, 7.6194437005665065])
('evaluate:', [24, 8.465103759419549])
('evaluate:', [21, 7.6194437005665065])
('evaluate:', [58, 8.367292359534245])
('generation', 1)
('evaluate:', [21, 7.6194437005665065])
('evaluate:', [29, 8.427249762963857])
('evaluate:', [29, 8.427249762963857])
('evaluate:', [21, 8.465103759419549])
('evaluate:', [24, 7.6194437005665065])
('generation', 2)
('evaluate:', [20, 8.396172876010239])
('evaluate:', [21, 8.465103759419549])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [21, 9.858264850764389])
('generation', 3)
('evaluate:', [21, 8.465103759419549])
('generation', 4)
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('generation', 5)
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('generation', 6)
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20.078343870132688, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('generation', 7)
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.402212748253602])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('generation', 8)
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 8.307457724269371])
('evaluate:', [20, 7.615346845706964])
('generation', 9)
('evaluate:', [20, 8.307457724269371])
('evaluate:', [18.96281744779058, 7.615346845706964])
[...]
('generation', 49)
('evaluate:', [17.61774546537507, 2.7252396993750345])
('evaluate:', [17.61774546537507, 2.7252396993750345])
('evaluate:', [17.70293390305071, 2.7252396993750345])
('evaluate:', [17.42737560814011, 0.3317893475658673])
As far as I understand these bounds are only used for creating the initial population. How can I preserve the bounds and the type of the parameter?
I found the reason.
I run the code in spyder and in the ipython enviroment holds values of earlier runs, even if they are not used in the current run.
I had to click on "remove all variables" in the ipython console to get rid of this effect.
I now added
in the first two lines of my code, which hopefully helps