bounds violated in genetic algorithm using DEAP

257 views Asked by At

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?

1

There are 1 answers

0
AudioBubble On BEST ANSWER

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

from IPython import get_ipython
get_ipython().magic('reset -sf')

in the first two lines of my code, which hopefully helps