DEAP is a python genetic algorithm framework, here is its introduction. DEAP documentation
Today, I’ll sort out an overview of DEAP and get a general idea of its process. Initial study, not rigorous, only as their own memorandum learning notes.
The first thing to do is to think of the appropriate type for your problem.This is done with the creator module.
The first thing to do is to think about the appropriate type of problem you have (what kind of optimization problem, minimum? Maximum? Single objective? Multi-objective?). stay
creatorIt can be implemented in the module.
For example, the following creates a FitnessMin class for a minimization problem and an Individual class that is derived from a list with a fitness attribute set to the just created fitness.
For example, here’s how to create a minimization problem
FitnessMinClasses and individual classes, which come from the list of fitness attribute value sets just created.
from deap import base, creator creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) creator.create("Individual", list, fitness=creator.FitnessMin)
That’s it. More on creating types can be found in the Creating Types tutorial.
More questions about creating types can be viewed in Creating Types tutorial.
Once the types are created you need to fill them with sometimes random values, sometime guessed ones. Again, DEAP provides an easy mechanism to do just that.
Once these types are created, you need to fill them with random values, sometimes guesswork values. Similarly, DEAP greatly provides such a simple mechanism to do this.
The Toolbox is a container for tools of all sorts including initializers that can do what is needed of them. The following takes on the last lines of code to create the initializers for individuals containing random floating point numbers and for a population that contains them.
toolboxIt is a tool container that can be used to contain various “initializers” (to do what they need). Following is the code to create initialization with random floating-point numbers and the individual population with their last line. The last few lines of code below are used to create “initializers” for “individuals” that contain random values and populations that contain them.
import random from deap import tools IND_SIZE = 10 toolbox = base.Toolbox() toolbox.register("attribute", random.random) toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attribute, n=IND_SIZE) Toolbox. register ("population", tools. initRepeat, list, toolbox. individual) # Yeah, the individuality created is put into population.
This creates functions to initialize populations from individuals that are themselves initialized with random float numbers. The functions are registered in the toolbox with their default arguments under the given name.
This creates a function to initialize the population (from individuals initialized with random floating-point numbers). These functions are “registered” in toolbox under the default parameters of a given name.
registerFeel that the understanding of this word here can be seen as “creating” meaning, and then
toolbox.individual。 Specific understanding, but also see the following detailed introduction.
functionThe first parameter inside is the function name. Because in
AlgorithmIn this step, this usage occurs.
More initialization methods are found in the Creating Types tutorial and the various Examples.
More initialization methods can be viewed in Creating Types tutorial and Examples.
OperatorsIn the toolbox module, we need to select the appropriate algorithm for each operator. In Operator, the operator of each step can choose the appropriate algorithm.
In addition you must create your evaluation function. This is how it is done in DEAP.
It is this evaluation function that has to be written by oneself. In fact, it is also the fitness function.
Note also that fitness values must be iterable, that is why we return a tuple in the evaluate function.
It is important to note that the return value of the evaluation function must be iterative.
def evaluate(individual): return sum(individual), toolbox.register("mate", tools.cxTwoPoint) toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.1) toolbox.register("select", tools.selTournament, tournsize=3) toolbox.register("evaluate", evaluate)
Now that everything is ready, we can start to write our own algorithm. It is usually done in a main function. For the purpose of completeness we will develop the complete generational algorithm.
Now that everything is in place, we can start writing our own algorithms. It’s usually written in the main function. For the purpose of integrity, we will develop a complete generation algorithm.
def main(): pop = toolbox.population(n=50) CXPB, MUTPB, NGEN = 0.5, 0.2, 40 # Evaluate the entire population fitnesses = map(toolbox.evaluate, pop) for ind, fit in zip(pop, fitnesses): ind.fitness.values = fit for g in range(NGEN): # Select the next generation individuals offspring = toolbox.select(pop, len(pop)) # Clone the selected individuals offspring = map(toolbox.clone, offspring) # Apply crossover and mutation 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 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 = 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 return pop
Throughout the whole process, you can see that
DEAPThe idea in the process of GA implementation is generally clear.
creatorCreate and choose the type of problem solving
toolboxRegistered individuals, populations, etc.
OperatorOperator selection, crossover, mutation, selection, evolution and so on. Each operator has a different algorithm, you can choose!
AlgorithmsAlgorithms are specific functions registered above, ah, and so on, combined with the application, writing process.
# This file is part of DEAP. # # DEAP is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation, either version 3 of # the License, or (at your option) any later version. # # DEAP is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with DEAP. If not, see <http://www.gnu.org/licenses/>. # example which maximizes the sum of a list of integers # each of which can be 0 or 1 import random from deap import base from deap import creator from deap import tools Creator. create ("Fitness Max", base. Fitness, weights = (1.0,)# What is this base. Fitness here for??? Creator. create ("Individual", list, fitness = creator. Fitness Max) # Here, list, fitness is a parameter, why? Toolbox = base. Toolbox ()# base is a very basic class!!! It seems very important. # Attribute generator: define 'attr_bool' to be an attribute ('gene') # which corresponds to integers sampled uniformly # from the range [0,1] (i.e. 0 or 1 with equal # probability) Toolbox. register ("attr_bool", random. randint, 0, 1) contains random integers of 0, 1. Don't understand what's going on here??? # Structure initializers: define 'individual' to be an individual # consisting of 100 'attr_bool' elements ('genes') What is toolbox. register ("individual", tools. initRepeat, creator. Individual, tools. initRepeat??) toolbox.attr_bool, 100) # define the population to be a list of 'individual's toolbox.register("population", tools.initRepeat, list, toolbox.individual) # The goal ('fitness') function to be maximized attention!!! Here we define our fitness function!!! Because we have to solve the problem of seeking peace. # Just return a value to our fitness function! Use the Sum function! # This is called evalOne Max because the fitness function here is the basis for our later evaluation. def evalOneMax(individual): return sum(individual), #---------- # Operator registration #---------- # register the goal / fitness function # Here's the understanding of the toolbox register statement: registered a function evaluae is based on the evalOne Max after the rationalization!!! toolbox.register("evaluate", evalOneMax) # Look, the cross function here, Nima, crossover is not used. You have to use a mate. You think it's Huawei mate. You see, the functions used by the crossover operator here are also closed and optional. # register the crossover operator toolbox.register("mate", tools.cxTwoPoint) # register a mutation operator with a probability to # flip each attribute/gene of 0.05 toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) # operator for selecting individuals for breeding the next # generation: each individual of the current generation # is replaced by the 'fittest' (best) of three individuals # drawn randomly from the current generation. Toolbox. register ("select", tools. selTournament, tournsize = 3) # What does the tournsize chosen here mean? #---------- def main(): random.seed(64) # hash(64)is used # The function of random. seed method is to give a seed value to the random number object for generating random sequence. # For the input of the same seed value, the sequence of random numbers generated thereafter is the same. # Usually, the number of time seconds and other changes are regarded as seed values, and the random series produced by each operation is different. # create an initial population of 300 individuals (where # each individual is a list of integers) Pop = toolbox. population (n = 300) # defines the population of 300 individuals!!! # CXPB is the probability with which two individuals # are crossed # # MUTPB is the probability for mutating an individual # # NGEN is the number of generations for which the # Evolution runs evolutionary running algebra! Sure enough, after 40 generations of operation, the calculation stopped. CXPB, MUTPB, NGEN = 0.5, 0.2, 40 print("Start of evolution") # Evaluate the entire population fitnesses = list(map(toolbox.evaluate, pop)) for ind, fit in zip(pop, fitnesses): ind.fitness.values = fit Print ("Evaluated% I individuals"% len (pop)), at this time, the length of pop is still 300? # Begin the evolution began to evolve ha!!! Pay attention! It's a for loop! 40 times--algebra for g in range(NGEN): print("-- Generation %i --" % g) # Select the next generation individuals offspring = toolbox.select(pop, len(pop)) # Clone the selected individuals offspring = list(map(toolbox.clone, offspring)) # Apply crossover and mutation on the offspring for child1, child2 in zip(offspring[::2], offspring[1::2]): # cross two individuals with probability CXPB if random.random() < CXPB: toolbox.mate(child1, child2) # fitness values of the children # must be recalculated later del child1.fitness.values del child2.fitness.values for mutant in offspring: # mutate an individual with probability MUTPB 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 = map(toolbox.evaluate, invalid_ind) for ind, fit in zip(invalid_ind, fitnesses): ind.fitness.values = fit print(" Evaluated %i individuals" % len(invalid_ind)) # The population is entirely replaced by the offspring pop[:] = offspring # Gather all the fitnesses in one list and print the stats fits = [ind.fitness.values for ind in pop] length = len(pop) mean = sum(fits) / length sum2 = sum(x*x for x in fits) std = abs(sum2 / length - mean**2)**0.5 print(" Min %s" % min(fits)) print(" Max %s" % max(fits)) print(" Avg %s" % mean) print(" Std %s" % std) print("-- End of (successful) evolution --") best_ind = tools.selBest(pop, 1) print("Best individual is %s, %s" % (best_ind, best_ind.fitness.values)) if __name__ == "__main__": main()