Travailler avec différentes représentations d'algorithmes génétiques en Python
En fonction de la nature du problème à optimiser, l'algorithme génétique (AG) prend en charge deux représentations de gènes différentes : binaire et décimale. L'AG binaire n'a que deux valeurs pour ses gènes, qui sont 0 et 1. Cela est plus facile à gérer car ses valeurs de gènes sont limitées par rapport à l'AG décimale, pour laquelle nous pouvons utiliser différents formats comme flottant ou entier, et des plages limitées ou illimitées.
Ce tutoriel explique comment la bibliothèque PyGAD prend en charge les deux représentations GA, binaire et décimale. Le plan de ce tutoriel est le suivant :
- Commencer avec PyGAD
- Contrôler la portée du gène dans la population initiale
- Type de gène (
intoufloat) - Éviter de dépasser la plage initiale
- Plages génétiques continues et discrètes
- Valeurs personnalisées pour chaque gène
- Personnaliser certains gènes tout en randomisant d'autres
- L'algorithme génétique binaire
- Population initiale définie par l'utilisateur
Introduction
PyGAD est une bibliothèque Python pour implémenter l'algorithme génétique. Pour l'installer et commencer, consultez le tutoriel 5 Applications de l'algorithme génétique utilisant PyGAD. Comme son nom l'indique, nous allons vous montrer comment développer cinq applications différentes en utilisant la bibliothèque.
Dans la création d'un agent de jeu pour CoinTex en utilisant l'algorithme génétique, PyGAD a été utilisé pour construire un agent qui joue à un jeu appelé CoinTex.
PyGAD est également documenté sur Read the Docs.
Avant de commencer ce tutoriel, assurez-vous d'avoir installé au moins la version 2.6.0 de PyGad.
pip install pygad>=2.6.0
La section suivante explique comment utiliser PyGAD pour personnaliser la plage de valeurs pour les gènes.
Contrôlez la portée des gènes dans la population initiale
Comme nous en avons discuté, l'AG a deux représentations pour ses gènes :
- Binaire
- décimale
Pour le GA binaire, chaque gène n'a que deux valeurs : 0 ou 1. En revanche, la représentation décimale peut utiliser n'importe quelle valeur décimale pour le gène. Cette section discute de la façon de limiter la plage des valeurs des gènes.
Dans certains problèmes, il peut être utile pour un utilisateur de limiter la plage de valeurs de gènes valides. Par exemple, disons que chaque valeur de gène doit être comprise entre 5 et 15 sans aucune exception. Comment pouvons-nous faire cela ?
PyGAD prend en charge deux paramètres pour gérer ce scénario : init_range_low et init_range_high. Le paramètre init_range_low spécifie la limite inférieure de la plage à partir de laquelle la population initiale est créée, tandis que init_range_high spécifie la limite supérieure. Notez que init_range_high est exclusive. Ainsi, si init_range_low=5 et init_range_high=15, alors les valeurs des gènes possibles vont de 5 jusqu'à, mais sans inclure, 15. Cet exemple est montré dans l'extrait de code ci-dessous.
En plus de ces arguments, nous devons également spécifier notre fonction de fitness, fitness_func, et le nombre de générations, num_generations.
Bien qu'ils soient optionnels, les trois paramètres suivants doivent être spécifiés lorsque la population initiale est créée aléatoirement :
num_parents_mating: Nombre de parents à accoupler.sol_par_pop: Défini sur 3, ce qui signifie que la population a 3 solutions.num_genes: Chaque solution a 4 gènes.
import pygad
def fitness_function(solution, solution_idx):
return sum(solution)
ga_instance = pygad.GA(num_generations=1,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=5,
init_range_high=15)
Une fois l'instance créée, la population initiale aléatoire est préparée dans l'attribut initial_population. La ligne ci-dessous l'imprime. Comme la population a 3 solutions, où chaque solution a 4 gènes, la forme de la population est (3, 4). Notez que chaque gène a une valeur comprise entre 5 et 15. Par défaut, le type des gènes est un float.
print(ga_instance.initial_population)
print(ga_instance.initial_population.shape)
[[14.02138539 10.13561641 13.77733116 5]
[13.28398269 14.13789428 12.6097329 7.51336248]
[ 9.42208693 6.97035939 14.54414418 6.54276097]]
(3, 4)
Le code suivant définit init_range_low à 1 et init_range_high à 3, pour voir comment la plage de gènes change.
ga_instance = pygad.GA(num_generations=1,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=1,
init_range_high=3)
print(ga_instance.initial_population)
Comme indiqué ci-dessous, la population créée au hasard a tous les gènes entre 1 et 3. Notez qu'il est possible d'avoir un gène avec une valeur de 1 mais qu'il est impossible d'avoir une valeur de 3.
[[1.00631559 2.91140666 1.30055502 2.10605866]
[2.23160212 2.32108812 1.90731624 1]
[2.23293791 1.9496456 1.25106388 2.46866602]]
Notez que les paramètres init_range_low et init_range_high limitent simplement la plage des gènes dans la population initiale. Que se passerait-il si les solutions évoluaient au fil de plusieurs générations ? Cela pourrait faire en sorte que les gènes dépassent la plage initiale.
Pour réaliser une expérience, le paramètre num_generations est fixé à 10 et la méthode run() est appelée pour faire évoluer les solutions à travers les 10 générations.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=1,
init_range_high=3)
ga_instance.run()
Après que la méthode run() soit terminée, le code suivant imprime ce qui suit :
- La population initiale utilisant l'attribut
initial_population. - La population finale utilisant l'attribut
population.
print(ga_instance.initial_population)
print(ga_instance.population)
[[1.08808272 1.16951518 1.30742402 1.40566555]
[2.88777068 2.49699173 2.47277427 2.36010308]
[1.94598736 2.10177613 1.57860387 1.45981019]]
[[3.7134492 1.9735615 3.39366783 2.21956642]
[3.7134492 2.49699173 2.47277427 2.36010308]
[2.94450144 1.9735615 3.39366783 2.36010308]]
Pour la population initiale, tous les gènes sont compris entre 1 et 3. Pour la population finale, certains gènes ont dépassé cette plage, comme le premier et le troisième gène dans la première solution. Comment forcer les gènes dans une population à rester dans cette plage ? Cela est discuté dans la section Éviter de Dépasser la Plage.
Une autre chose à noter est que le type du gène est à virgule flottante. Certains problèmes peuvent ne fonctionner qu'avec des valeurs entières. La section suivante traite de la façon de spécifier le type de gènes en utilisant le paramètre gene_type.
Type de gène (int ou float)
Par défaut, PyGAD attribue des valeurs décimales aléatoires à la population initiale. Dans le cas où l'utilisateur souhaite que les valeurs soient des entiers, le paramètre gene_type est disponible à cet effet. Il est supporté dans PyGAD 2.6.0 et versions supérieures.
Il prend en charge 2 valeurs :
float: C'est la valeur par défaut. Cela signifie que les gènes sont des nombres à virgule flottante.- Les gènes sont convertis de nombres à virgule flottante en entiers.
Le code suivant définit le paramètre gene_type sur int pour forcer la population initiale aléatoire à avoir des gènes entiers.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=1,
init_range_high=3,
gene_type=int)
print(ga_instance.initial_population)
La population initiale aléatoire est imprimée ci-dessous. Notez que la plage des gènes est de 1 à 3 exclus. Cela signifie que 1 et 2 sont les seuls entiers. Ainsi, la population n'a que des valeurs 1 et 2.
[[1 1 2 1]
[1 2 2 1]
[1 2 1 2]]
Lorsque l'intervalle change pour être de 5 à 10, alors les valeurs génétiques possibles sont 5, 6, 7, 8 et 9.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=5,
init_range_high=10,
gene_type=int)
print(ga_instance.initial_population)
[[5 9 7 8]
[5 7 9 8]
[5 5 6 7]]
Notez que le réglage du paramètre gene_type à int ou float n'empêche pas les gènes de dépasser la plage spécifiée à l'aide des paramètres init_range_low et init_range_high. Cela est discuté dans la section suivante.
Évitez de dépasser la plage initiale
La population initiale créée aléatoirement a ses gènes dans la plage spécifiée par les 2 paramètres init_range_low et init_range_high. Mais cela ne garantit pas que ses gènes restent toujours dans cette plage. La raison est que les valeurs des gènes changent en raison de l'opération de mutation.
Par défaut, l'opération de mutation de type random est appliquée à tous les gènes. Cela entraîne des changements aléatoires dans les gènes, ce qui fait que leurs valeurs dépassent la plage initiale. En fonction du type de problème à résoudre, le dépassement de cette plage peut être un problème ou non.
Si le problème doit avoir ses gènes dans une plage, alors il existe différentes options pour contraindre tous les gènes de toutes les générations à être dans cette plage. Ces options sont résumées comme suit :
- Ne pas utiliser de mutation
random. - Désactivez l'opération de mutation.
- Utilisez le paramètre
mutation_by_replacement. C'est l'option la plus pratique.
Discutons de chacune de ces options.
Ne pas utiliser la mutation random
Le type de l'opération de mutation utilisée est spécifié à l'aide du paramètre mutation_type. Les types pris en charge sont :
- Aléatoire :
mutation_type=random - Échange :
mutation_type=swap - Inversion :
mutation_type=inversion - Brouiller :
type_de_mutation=brouiller
Parmi ces 4 types, seule la mutation aléatoire peut modifier les valeurs des gènes en dehors de la plage initiale. Ainsi, une façon de forcer les gènes à rester dans la plage initiale est d'utiliser un autre type de mutation que la mutation aléatoire.
Le code suivant utilise la mutation swap. Même après l'exécution de la méthode run(), les valeurs des gènes se trouvent toujours à l'intérieur de la plage initiale.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=5,
init_range_high=10,
mutation_type="swap",
gene_type=int)
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[6 9 8 7]
[5 5 8 8]
[9 8 5 6]]
[[8 9 6 9]
[8 9 6 9]
[8 9 6 9]]
Cette option peut ne pas être réalisable dans de nombreuses situations car les autres types conservent les valeurs génétiques originales tout en ne changeant que leur ordre. Aucune modification n'est apportée aux gènes.
Désactiver l'opération de mutation
PyGAD peut désactiver l'opération de mutation en définissant le paramètre mutation_type sur None. Même cela préserve les valeurs des gènes dans la plage initiale, mais cela désactive l'une des options principales pour faire évoluer les solutions.
Le code suivant désactive l'opération de mutation. Après 10 générations, les gènes sont toujours dans la plage spécifiée.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=5,
init_range_high=10,
mutation_type=None,
gene_type=int)
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[7 9 5 9]
[5 6 6 8]
[8 5 6 6]]
[[7 9 5 9]
[7 9 6 6]
[7 9 5 6]]
Utilisez le paramètre mutation_by_replacement
Les deux options précédentes scarifient soit par la mutation aléatoire, soit par la mutation elle-même pour maintenir le gène dans la plage initiale. L'option la plus réalisable qui permet d'utiliser la mutation aléatoire tout en gardant les gènes dans la plage spécifiée est le paramètre booléen mutation_par_remplacement.
Normalement, la mutation aléatoire génère une valeur aléatoire. Cette valeur est ensuite ajoutée à la valeur actuelle du gène. Supposons qu'il y ait un gène avec une valeur de 2,5 et que la plage spécifiée soit de 1 à 3, exclu. Si la valeur aléatoire est de 0,7, alors l'ajouter à la valeur actuelle du gène donne 2,5+0,7=3,2 ce qui est hors de la plage.
Lorsque le paramètre mutation_by_replacement est Vrai, il remplace (et n'ajoute pas) la valeur du gène par la valeur aléatoire. Donc, lorsque la valeur aléatoire est 0,7, la nouvelle valeur du gène sera 0,7. Si le gene_type est défini sur int, le résultat sera 1,0.
L'utilisateur peut contrôler la plage à partir de laquelle la valeur aléatoire est générée en utilisant les 2 paramètres random_mutation_min_val et random_mutation_max_val qui spécifient respectivement les limites inférieure et supérieure.
Pour garder les gènes dans la plage, chacun de ces paramètres doit satisfaire la condition suivante :
init_range_low <= param <= init_range_high
Pour la meilleure expérience, définissez random_mutation_min_val=init_range_low et random_mutation_max_val=init_range_high.
Le code suivant donne un exemple d'utilisation des 3 paramètres discutés dans cette sous-section (mutation_by_replacement, random_mutation_min_val, et random_mutation_max_val).
ga_instance = pygad.GA(num_generations=1000,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=5,
init_range_high=10,
random_mutation_min_val=5,
random_mutation_max_val=10,
mutation_by_replacement=True,
gene_type=int)
ga_instance.run()
Pour un nombre quelconque de générations, les gènes ne dépasseront pas la plage. Le code suivant imprime les populations initiale et finale. Les gènes de la population finale ne dépassent pas la plage.
print(ga_instance.initial_population)
print(ga_instance.population)
[[5 8 8 5]
[9 8 8 9]
[5 9 8 9]]
[[9 9 9 9]
[9 9 9 9]
[9 9 8 9]]
En utilisant les 3 paramètres mutation_by_replacement, il est possible de faire en sorte que l'AG fonctionne uniquement avec des gènes binaires (c'est-à-dire des gènes avec des valeurs 0 et 1). Cela se fait en procédant comme suit :
- Définissez
init_range_low=random_mutation_min_val=0. - Définir
init_range_high=random_mutation_max_val=2. - Définissez
mutation_by_replacement=True. - Définir
gene_type=int.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=0,
init_range_high=2,
random_mutation_min_val=0,
random_mutation_max_val=2,
mutation_by_replacement=True,
gene_type=int)
ga_instance.run()
Voici les populations initiales et finales où tous les gènes sont soit 0 soit 1.
print(ga_instance.initial_population)
print(ga_instance.population)
[[1 1 0 1]
[0 1 0 0]
[0 1 1 1]]
[[0 1 0 1]
[0 1 0 0]
[0 1 1 0]]
Veuillez noter que ce n'est pas la seule façon de supporter GA binaire. En utilisant le paramètre gene_space, il est également possible de soutenir le GA binaire. Ce paramètre est introduit dans la section suivante.
Gammes de gènes continues et discrètes
La discussion précédente suppose que l'intervalle à partir duquel les gènes sont échantillonnés est continu. Donc, si l'intervalle commence de 1 à 5, alors toutes les valeurs dans cet intervalle (1, 2, 3 et 4) sont acceptables. Que se passe-t-il si certaines valeurs dans un intervalle ne sont pas autorisées ou si les valeurs ne suivent pas un intervalle continu (par exemple -2, 18, 43 et 78) ? À cet effet, PyGAD prend en charge un paramètre nommé gene_space pour spécifier l'espace des valeurs des gènes.
Le paramètre gene_space permet à l'utilisateur de lister toutes les valeurs de gènes possibles. Il accepte une liste ou un tuple dans lequel toutes les valeurs de gènes possibles sont énumérées.
Le code suivant utilise le paramètre gene_space pour énumérer les valeurs possibles pour tous les gènes. En conséquence, tous les gènes sont échantillonnés à partir des 4 valeurs énumérées.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
gene_space=[-2, 18, 43, 78])
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[78 43 78 -2]
[18 -2 78 78]
[43 43 18 -2]]
[[-2 -2 18 78]
[18 -2 78 78]
[-2 -2 18 78]]
Notez que tous les gènes sont échantillonnés à partir des mêmes valeurs. En d'autres termes, les valeurs dans le paramètre gene_space sont globales à tous les gènes. Que se passe-t-il si chaque gène a des valeurs distinctes ? La section suivante discute de la manière de spécifier des valeurs personnalisées pour chaque gène.
Valeurs personnalisées pour chaque gène
Lorsque le paramètre gene_space accepte une liste/tuple non imbriquée, les valeurs de cette liste/tuple sont utilisées pour échantillonner les valeurs de tous les gènes. Il peut arriver que certains gènes aient leurs propres valeurs distinctes. Le paramètre gene_space accepte les valeurs de chaque gène séparément. Cela se fait en créant une liste/tuple imbriqué où chaque élément contient les valeurs possibles pour son gène correspondant.
Supposons qu'il y ait 4 gènes et que chaque gène ait son propre espace de valeurs. Une liste des valeurs possibles pour chaque gène est préparée comme indiqué ci-dessous. Notez qu'aucun gène n'a ses valeurs suivant une séquence. Chaque gène peut avoir un nombre différent de valeurs.
- Gène 1 : [-4, 2]
- Gène 2 : [0, 5, 7, 22, 84]
- Gène 3 : [-8, -3, 0, 4]
- Gène 4 : [1, 6, 16, 18]
Les 4 listes sont toutes ajoutées en tant qu'éléments dans le paramètre gene_space comme indiqué ci-dessous.
gene_space = [[-4, 2],
[0, 5, 7, 22, 84],
[-8, -3, 0, 4],
[1, 6, 16, 18] ]
Le code suivant crée une instance de la classe pygad.GA qui utilise l'attribut gene_space. La population initiale et finale imprimée montre comment chaque gène est échantillonné de son propre espace. Par exemple, les valeurs du premier gène pour toutes les solutions sont -4 et 2.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
gene_space=[[-4, 2],
[0, 5, 7, 22, 84],
[-8, -3, 0, 4],
[1, 6, 16, 18] ])
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[-4. 84. 0. 18.]
[ 2. 7. 4. 1.]
[ 2. 0. -8. 6.]]
[[-4. 7. 4. 1.]
[ 2. 7. 4. 1.]
[-4. 7. 4. 6.]]
Les valeurs des 4 gènes précédents ne suivaient pas une séquence. Il se peut que les valeurs de certains gènes suivent une séquence. Les valeurs des 4 gènes sont énumérées ci-dessous. Les valeurs du premier gène vont de 0 à 5 (exclusif) et les valeurs du deuxième gène vont de 16 à 27 (exclusif). Les valeurs des troisième et quatrième gènes restent les mêmes que précédemment.
- Gène 1 : [0, 1, 2, 3, 4]
- Gène 2 : [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]
- Gène 3 : [-8, -3, 0, 4]
- Gène 4 : [1, 6, 16, 18]
La nouvelle valeur du paramètre gene_space est donnée ci-dessous.
gene_space = [ [0, 1, 2, 3, 4],
[16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26],
[-8, -3, 0, 4],
[1, 6, 16, 18] ]
Que se passe-t-il si un gène a une séquence de, par exemple, 1 000 valeurs. Devons-nous lister ses éléments individuels ? Heureusement, PyGAD permet de spécifier l'espace d'un seul gène en utilisant la fonction range(). Si l'espace de valeur du premier gène commence à 0 et n'inclut pas 5, alors il peut être modélisé en utilisant range(0, 5). Pour le deuxième gène qui commence à 16 et n'inclut pas 26, alors son espace de valeur est représenté en utilisant range(16, 27).
Après avoir utilisé la fonction range(), la nouvelle valeur du paramètre gene_space est donnée ci-dessous.
gene_space = [ range(5), range(16, 27), [-8, -3, 0, 4], [1, 6, 16, 18] ]
Voici le code qui utilise le gene_space mis à jour.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
gene_space=[range(5),
range(16, 27),
[-8, -3, 0, 4],
[1, 6, 16, 18] ])
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[ 0. 19. -8. 18.]
[ 2. 26. 4. 6.]
[ 3. 18. -3. 1.]]
[[ 3. 25. 0. 6.]
[ 0. 26. 4. 18.]
[ 3. 22. 0. 6.]]
Il est possible de fixer un gène à une seule valeur. Cela se fait en attribuant son élément dans le paramètre gene_space à cette valeur unique. Voici un exemple où le premier gène est fixé à 4 et le troisième gène à 5. Ces 2 gènes ne verront jamais leurs valeurs changer.
gene_space = [4,
range(16, 27),
5,
[1, 6, 16, 18] ]
Voici le code qui utilise la dernière valeur de gene_space. Dans la population initiale et finale, le premier et le troisième gène ne changent jamais.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
gene_space=[4,
range(16, 27),
5,
[1, 6, 16, 18] ])
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[ 4. 21. 5. 16.]
[ 4. 18. 5. 16.]
[ 4. 24. 5. 16.]]
[[ 4. 18. 5. 1.]
[ 4. 18. 5. 16.]
[ 4. 18. 5. 18.]]
Personnaliser certains gènes tout en randomisant d'autres
Selon la discussion précédente sur le paramètre gene_space, chaque gène a son propre espace génétique spécifié soit en codant en dur les valeurs individuelles, soit en utilisant la fonction range().
Dans certains cas, l'utilisateur pourrait devoir forcer certains gènes à être restreints à certaines valeurs, mais d'autres gènes pourraient être aléatoires. Par exemple, si le chromosome a un gène qui doit être soit -1 soit 1, mais que les autres gènes peuvent avoir n'importe quelle valeur aléatoire. Comment faire cela ?
Pour que le gène soit aléatoire, assignez son élément dans le paramètre gene_space à None. Cela signifie que la valeur pour ce gène sera aléatoire. La ligne suivante assigne la liste [-1, 1] au premier gène et None aux 3 gènes restants. Les 3 derniers gènes auront des valeurs aléatoires.
gene_space = [[-1, 1], None, None, None]
Le code suivant utilise la dernière valeur de gene_space. Notez que le premier gène est échantillonné à partir de la liste [-1, 1], tandis que les autres gènes ont des valeurs aléatoires.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
gene_space=[[-1, 1], None, None, None])
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[ 1. 0.28682682 1.39230915 1.12768838]
[-1. -1.05781089 1.71296713 2.56994039]
[ 1. 3.78611876 -3.80634854 2.15975074]]
[[-1. -1.05781089 1.88097581 2.56994039]
[-1. -1.05781089 1.71296713 2.56994039]
[-1. -1.05781089 1.3061504 2.56994039]]
Notez que les gènes aléatoires sont initialisés aléatoirement à partir de valeurs dans la plage spécifiée par les 2 paramètres init_range_low et init_range_high. Si le type de mutation est aléatoire, alors la valeur aléatoire ajoutée au gène est échantillonnée à partir de la plage spécifiée par les 2 paramètres random_mutation_min_val et random_mutation_max_val. De plus, le type de la valeur aléatoire est déterminé en fonction du paramètre gene_type. Enfin, si le mutation_by_replacement est défini sur True, alors la valeur aléatoire ne sera pas ajoutée mais remplacera le gène. Notez que ces paramètres n'affectent que les gènes dont l'espace est défini sur None.
Le code suivant force la valeur initiale du gène à être comprise entre 10 et 20, exclusive. La plage de mutation aléatoire est de 30 à 40, exclusive. Le type_de_gène est défini sur int.
ga_instance = pygad.GA(num_generations=1000,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
init_range_low=10,
init_range_high=20,
random_mutation_min_val=30,
random_mutation_max_val=40,
gene_space=[[-1, 1], None, None, None],
gene_type=int)
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[ 1. 16. 14. 10.]
[-1. 12. 16. 14.]
[-1. 17. 19. 13.]]
[[-1. 12. 16. 48.]
[-1. 15. 26. 14.]
[-1. 12. 16. 14.]]
Algorithme génétique binaire
Dans la section Utiliser le paramètre mutation_by_replacement, PyGAD a pris en charge l'algorithme génétique binaire en utilisant les paramètres suivants.
init_range_low=random_mutation_min_val=0.init_range_high=random_mutation_max_val=2.mutation_par_remplacement=True.type_gène=int.
Il est également possible de soutenir le GA binaire en utilisant le paramètre gene_space. Cela se fait en définissant ce paramètre à l'espace global [0, 1]. Cela signifie que tous les gènes ont leurs valeurs soit 0 soit 1.
Le code suivant définit le paramètre gene_space à [0, 1]. Cela force les valeurs de tous les gènes à être soit 0, soit 1.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
sol_per_pop=3,
num_genes=4,
fitness_func=fitness_function,
gene_space=[0, 1])
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[1 1 1 0]
[0 1 0 0]
[1 1 1 0]]
[[0 1 1 0]
[0 1 0 1]
[0 1 0 0]]
Population initiale définie par l'utilisateur
Parfois, l'utilisateur peut vouloir commencer avec une population initiale personnalisée sans aucune randomisation. PyGAD prend en charge un paramètre nommé initial_population qui permet à l'utilisateur de spécifier une population initiale personnalisée.
Le code suivant prépare une liste imbriquée assignée au paramètre initial_population dans laquelle il y a 3 solutions, chacune ayant 4 gènes. Dans ce cas, les paramètres num_genes et sol_per_pop ne sont pas nécessaires car ils seront déduits de la valeur assignée au paramètre initial_population.
ga_instance = pygad.GA(num_generations=10,
num_parents_mating=2,
fitness_func=fitness_function,
initial_population=[[34, 32, 24, -2],
[3, 7, 2, 7],
[-2, -4, -6, 1]])
ga_instance.run()
print(ga_instance.initial_population)
print(ga_instance.population)
[[34 32 24 -2]
[ 3 7 2 7]
[-2 -4 -6 1]]
[[3 7 2 6]
[3 7 2 7]
[3 7 2 7]]
Conclusion
Ce tutoriel a utilisé la bibliothèque PyGAD pour travailler avec les représentations binaire et décimale de l'algorithme génétique. Le tutoriel a discuté des différents paramètres de PyGAD permettant à l'utilisateur de contrôler la création de la population initiale ainsi que de contrôler l'opération de mutation.
En utilisant le paramètre gene_type, les valeurs des gènes peuvent être soit des nombres à virgule flottante soit des entiers. Le paramètre mutation_by_replacement est utilisé pour maintenir les gènes dans leur plage initiale. Le paramètre initial_population accepte une population initiale définie par l'utilisateur.
Le paramètre gene_space est utile dans le cas où les valeurs des gènes ne suivent pas une séquence. Dans ce cas, les valeurs discrètes des gènes sont fournies sous forme de liste. Ce paramètre accepte un espace de valeur personnalisé pour chaque gène. De plus, il permet à certains gènes d'être tirés d'un espace défini et à d'autres d'être sélectionnés au hasard.

