[PYTHON] Note d'utilisation deap (OneMax)

introduction

Ceci est un mémo sur l'utilisation de deap. Ici, le mémo est décrit en utilisant deap \ examples \ onemax_numpy.py comme exemple.

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

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

OneMax? C'est un problème de maximiser la somme d'une séquence de nombres composée de 0,1 comme [1, 1, 1, 1, 0, 0, 0, 1, 1, 0]. ⇒ La solution à obtenir est [1, 1, 1, 1, 1, 1, 1, 1, 1, 1].

Dans le code ci-dessous, le problème est une chaîne de longueur 100.

Code et résultats d'exécution

Collez le code avec des notes.

<détails>

Code avec notes </ summary>

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            #Nombre de gènes par individu
n_individuals = 300     #Nombre d'individus par génération
n_generations = 1000    #Nombre de générations

p_cxpb = 0.5            #Taux de croisement (nombre d'individus traversant)
p_mutpb = 0.2           #Taux de mutation (nombre d'individus à muter)
p_mutate = 0.05         #Probabilité de mutation (taux de mutation génique)

n_tournsize = 3         #Taille du tournoi

def evalOneMax(individual):
    """Fonction d'évaluation onemax"""
    return sum(individual),

def init_creator():
    """Définir la direction de la fonction objectif"""
    #Une fonction objective pour évaluer, maximiser l'adaptabilité individuelle
    creator.create("FitnessMax", base.Fitness, weights=(1.0,))
    # numpy.Hériter de la classe ndarray
    # fitness=creator.Créer une classe individuelle avec une variable membre appelée FitnessMax
    creator.create("Individual", numpy.ndarray, fitness=creator.FitnessMax)
    return creator

def my_gene_generator(min, max):
    """Fonction de génération de gène"""
    return random.randint(min, max)

def init_generator(creator):
    """Définition des méthodes de génération de gènes, d'individus et de générations"""
    toolbox = base.Toolbox()
    #Définition de la fonction qui produit le gène
    toolbox.register("attr_bool", my_gene_generator, 0, 1)
    #Définition de la fonction pour générer un individu
    toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, n_gene)
    #Définition de la fonction qui génère la génération
    toolbox.register("population", tools.initRepeat, list, toolbox.individual)
    return toolbox

def operator_registration(toolbox):
    """Fonction d'évaluation / définition de la stratégie"""
    toolbox.register("evaluate", evalOneMax)                                # evaluate =Fonction d'évaluation
    toolbox.register("mate", tools.cxTwoPoint)                              # mate =Traversée en deux points
    toolbox.register("mutate", tools.mutFlipBit, indpb=p_mutate)            # mutate =inversion de bits
    toolbox.register("select", tools.selTournament, tournsize=n_tournsize)  # select = tournament(3)

def stats_register():
    """Paramètres de définition d'état"""
    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):
    """Réglage 2 points pour croisement à 2 points"""
    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):
    """Crossover à 2 points pour 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()

    #Génération de la première génération
    pop = toolbox.population(n=n_individuals)

    #élite pour numpy=1 stratégie
    hof = tools.HallOfFame(1, similar=numpy.array_equal)

    #définition des statistiques
    stats = stats_register()

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

    #Affichage des meilleurs individus
    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__":
    #Définir la direction de la fonction objectif
    creator = init_creator()

    #Définition des méthodes de génération de gènes, d'individus et de générations
    toolbox = init_generator(creator)

    #Réglage de la méthode d'évolution
    operator_registration(toolbox)

    #Routine principale
    main(toolbox)

Résultat d'exécution

<détails>

Résultat de l'exécution </ summary>

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]

Où rester coincé

① Je ne sais pas comment déterminer la direction (maximisation / minimisation) de la fonction d'évaluation. -Un poids négatif est donné lors de la minimisation de l'adaptabilité, et un poids positif est donné lors de sa maximisation (toute valeur est acceptable). ・ Le poids doit être tapple

creator.py


#Une fonction objective pour évaluer, maximiser l'adaptabilité individuelle
creator.create("FitnessMax", base.Fitness, weights=(1.0,))
#Il y a deux fonctions objectives à évaluer, la première est de minimiser l'adaptabilité et la seconde est de maximiser.
creator.create("FitnessMulti", base.Fitness, weights=(-1.0, 1.0))

② Comment générez-vous et évaluez-vous les gènes? -Enregistrer la fonction générée dans la boîte à outils Ici, une fonction appelée my_gene_generator qui génère au hasard 0 ou 1 est utilisée. Inscrivez-vous avec le nom "attr_bool" dans la boîte à outils

gene_generator.py


def my_gene_generator(min, max):
    """Fonction de génération de gène"""
    return random.randint(min, max)

def init_generator(creator):
    """Définition des méthodes de génération de gènes, d'individus et de générations"""
    toolbox = base.Toolbox()
    #Définition de la fonction qui produit le gène
    toolbox.register("attr_bool", my_gene_generator, 0, 1)

・ Enregistrez la fonction d'évaluation dans la boîte à outils Ici, une fonction appelée evalOneMax Inscrivez-vous avec le nom «évaluer» dans la boîte à outils

gene_eval.py


def evalOneMax(individual):
    """Fonction d'évaluation onemax"""
    return sum(individual),

def operator_registration(toolbox):
    """Fonction d'évaluation / définition de la stratégie"""
    toolbox.register("evaluate", evalOneMax) # evaluate =Fonction d'évaluation

③ Où est la boucle principale? · Ici

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

Recommended Posts