[PYTHON] deap usage memo (OneMax)

Introduction

This is a memo on how to use deap. Here, the memo is described using deap \ examples \ onemax_numpy.py as an example.

deap https://deap.readthedocs.io/en/master/

deap github https://github.com/DEAP/deap

OneMax? This is a problem that maximizes the sum of a sequence of 0s and 1s, such as [1, 1, 1, 1, 0, 0, 0, 1, 1, 0]. ⇒ The solution to be obtained is [1, 1, 1, 1, 1, 1, 1, 1, 1, 1].

In the code below, the problem is a sequence of length 100.

Code and execution results

Paste the code with notes.

Code with notes

my_onemax_numpy.py


import random
import numpy
from deap import algorithms
from deap import base
from deap import creator
from deap import tools

# parameter
n_gene = 100            #Number of genes per individual
n_individuals = 300     #Number of individuals per generation
n_generations = 1000    #Number of generations

p_cxpb = 0.5            #Crossover rate (number of crossing individuals)
p_mutpb = 0.2           #Mutation rate (number of individuals to mutate)
p_mutate = 0.05         #Mutation probability (gene mutation rate)

n_tournsize = 3         #Tournament size

def evalOneMax(individual):
    """Evaluation function onemax"""
    return sum(individual),

def init_creator():
    """Set the direction of the objective function"""
    #One objective function to evaluate, maximizing individual fitness
    creator.create("FitnessMax", base.Fitness, weights=(1.0,))
    # numpy.Inherit the ndarray class
    # fitness=creator.Create an Individual class with a member variable called FitnessMax
    creator.create("Individual", numpy.ndarray, fitness=creator.FitnessMax)
    return creator

def my_gene_generator(min, max):
    """Gene generation function"""
    return random.randint(min, max)

def init_generator(creator):
    """Setting of gene, individual, and generation generation methods"""
    toolbox = base.Toolbox()
    #Definition of the function that produces the gene
    toolbox.register("attr_bool", my_gene_generator, 0, 1)
    #Definition of a function to generate an individual
    toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, n_gene)
    #Definition of the function that generates the generation
    toolbox.register("population", tools.initRepeat, list, toolbox.individual)
    return toolbox

def operator_registration(toolbox):
    """Evaluation function / strategy setting"""
    toolbox.register("evaluate", evalOneMax)                                # evaluate =Evaluation function
    toolbox.register("mate", tools.cxTwoPoint)                              # mate =Two-point crossing
    toolbox.register("mutate", tools.mutFlipBit, indpb=p_mutate)            # mutate =bit inversion
    toolbox.register("select", tools.selTournament, tournsize=n_tournsize)  # select = tournament(3)

def stats_register():
    """State definition settings"""
    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("avg", numpy.mean)
    stats.register("std", numpy.std)
    stats.register("min", numpy.min)
    stats.register("max", numpy.max)
    return stats

def get_cxpoint(size):
    """2 point setting for 2 point crossing"""
    cxpoint1 = random.randint(1, size)
    cxpoint2 = random.randint(1, size - 1)
    if cxpoint2 >= cxpoint1:
        cxpoint2 += 1
    else: # Swap the two cx points
        cxpoint1, cxpoint2 = cxpoint2, cxpoint1
    return cxpoint1, cxpoint2

def cxTwoPointCopy(ind1, ind2):
    """2-point crossover for numpy"""
    size = min(len(ind1), len(ind2))
    cxpoint1, cxpoint2 = get_cxpoint(size)
    
    ind1[cxpoint1:cxpoint2], ind2[cxpoint1:cxpoint2] \
        = ind2[cxpoint1:cxpoint2].copy(), ind1[cxpoint1:cxpoint2].copy()
        
    return ind1, ind2

def set_seed(seed=42):
    random.seed(seed)

def main(toolbox):
    set_seed()

    #Generation of early generation
    pop = toolbox.population(n=n_individuals)

    #elite for numpy=1 Strategy
    hof = tools.HallOfFame(1, similar=numpy.array_equal)

    #stats definition
    stats = stats_register()

    # main loop
    algorithms.eaSimple(pop, toolbox, cxpb=p_cxpb, mutpb=p_mutpb, ngen=n_generations, stats=stats,
                        halloffame=hof)

    #Display of best individuals
    best_ind = tools.selBest(pop, 1)[0]
    print("Best individual is \n Eval:\n  %s, \n Gene:\n  %s" % (best_ind.fitness.values, best_ind))

    return pop, stats, hof


if __name__ == "__main__":
    #Set the direction of the objective function
    creator = init_creator()

    #Setting of gene, individual, and generation generation methods
    toolbox = init_generator(creator)

    #Evolution method setting
    operator_registration(toolbox)

    #Main routine
    main(toolbox)

Execution result

Execution result
gen     nevals  avg     std     min     max
0       300     49.88   4.82344 36      64
1       172     54.27   3.60792 45      68
2       181     57.24   3.32    47      68 
・ ・ ・
987     183     98.9767 2.3642  89      100
988     171     99.1467 2.02941 89      100
989     192     99.0567 2.26424 90      100
990     176     99.1167 2.12047 88      100
991     183     99.2733 1.94901 90      100
992     164     98.97   2.30704 90      100
993     178     99.03   2.0581  90      100
994     188     98.9767 2.24264 89      100
995     174     98.95   2.3211  86      100
996     177     98.83   2.33833 90      100
997     186     99.0367 2.15453 89      100
998     177     98.9833 2.16095 91      100
999     175     98.9933 2.25683 90      100
1000    181     98.8967 2.23443 89      100
Best individual is
 Eval:
  (100.0,),
 Gene:
  [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]

Where to get stuck

① I don't know how to determine the direction (maximization / minimization) of the evaluation function. -A negative weight is given when minimizing fitness, and a positive weight is given when maximizing fitness (any value is acceptable). ・ Weight must be tuple

creator.py


#One objective function to evaluate, maximizing individual fitness
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
#There are two objective functions to evaluate, the first is to minimize fitness and the second is to maximize.
creator.create("FitnessMulti", base.Fitness, weights=(-1.0, 1.0))

② How do you generate and evaluate genes? -Register the generated function in the toolbox Here, a function called my_gene_generator that randomly generates 0 or 1 is used. Register with the name "attr_bool" in the toolbox

gene_generator.py


def my_gene_generator(min, max):
    """Gene generation function"""
    return random.randint(min, max)

def init_generator(creator):
    """Setting of gene, individual, and generation generation methods"""
    toolbox = base.Toolbox()
    #Definition of the function that produces the gene
    toolbox.register("attr_bool", my_gene_generator, 0, 1)

・ Register the evaluation function in the toolbox Here, a function called evalOneMax Register with the name "evaluate" in the toolbox

gene_eval.py


def evalOneMax(individual):
    """Evaluation function onemax"""
    return sum(individual),

def operator_registration(toolbox):
    """Evaluation function / strategy setting"""
    toolbox.register("evaluate", evalOneMax) # evaluate =Evaluation function

③ Where is the main loop? ・ Here

algorithms.eaSimple(pop, toolbox, cxpb=p_cxpb, mutpb=p_mutpb, ngen=n_generations, stats=stats, halloffame=hof)

Recommended Posts

deap usage memo (OneMax)
RDKit usage memo
virtualenv Basic command usage memo
Easy usage memo of Anaconda (conda)
BESS Development Memo # 01: BESS Installation and Basic Usage