Python genetic algorithm (GA) DEAP-Overview learning abstract

Time:2019-9-11

DEAP-Overview

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.

I. Types

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?). staycreatorIt 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 problemFitnessMinClasses 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.

II. Initialization

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 thentoolboxThat’s it.toolbox.individual。 Specific understanding, but also see the following detailed introduction.
toolboxApparent sumfunctionThe first parameter inside is the function name. Because inAlgorithmIn this step, this usage occurs.toolbox.population()
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.

III. Operator

toolbox.register("mate", tools.cxTwoPoint)

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)

IV. Algorithms

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 thatDEAPThe idea in the process of GA implementation is generally clear.

  1. Sure?TypescreatorCreate and choose the type of problem solving

  2. InitializationInitializationtoolboxRegistered individuals, populations, etc.

  3. OperatorOperator selection, crossover, mutation, selection, evolution and so on. Each operator has a different algorithm, you can choose!

  4. AlgorithmsAlgorithms are specific functions registered above, ah, and so on, combined with the application, writing process.

Example

#    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[0] 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)[0]
    print("Best individual is %s, %s" % (best_ind, best_ind.fitness.values))

if __name__ == "__main__":
    main()