Algorithmes Génétiques Marc-Olivier LaBarre Mai-Août 2002 Les algorithmes génétiques sont une méthode d’optimisation utile dans les cas non linéaires (évidemment, cette méthode fonctionne également pour les cas linéaires, mais dans ce cas, est inutilement lourde en temps et en calcul). Cette technique part du principe évolutif de la sélection naturelle de Darwin. Celle-ci énonçait que les individus les plus aptes à survivre (les « meilleurs ») se reproduiront plus souvent et auront plus de descendants. Ainsi, la qualité du pool génétique de la population sera augmentée, les gènes plus efficaces deviendront plus fréquent; la population s’améliore. Selon le même principe, un algorithme génétique part d’une population de solutions initiales, les fait se reproduire (les meilleures solutions ont plus de chances de se reproduire), créant ainsi la nouvelle génération de solutions. En répétant ce cycle plusieurs fois, on obtient une population composée de solutions meilleures. On utilise généralement les algorithmes génétiques pour trouver une solution, la meilleure solution après un certain nombre de générations. Voici le corps principal d’une itération d’un algorithme génétique : 1- Évaluer la qualité (fitness) des individus et leurs chances de survie 2- Sélectionner les individus pour la reproduction 3- Effectuer la reproduction 4- Remplacer l’ancienne population par la nouvelle Cette itération est répétée autant de fois que demandé. L’évaluation de la qualité (fitness) d’un individu permet d’illustrer avec une valeur numérique (et donc plus facile à manipuler) la qualité des gènes qui forment l’individu. Plus la qualité d’un individu est grande, plus ses chances d’être sélectionné pour la reproduction sont grandes. En général, on calcule les chances de reproduction d’un individu en regard de sa qualité en relation avec la qualité totale des individus de la population. La reproduction se fait en croisant deux individus. On applique sur les deux individus choisis des opérateurs génériques, habituellement l’enjambement (cross-over) et la mutation. La reproduction donne deux enfants (offspring), qui sont placés dans la nouvelle population. On répète la reproduction jusqu’à ce qu’on ait rempli la nouvelle population (la taille de la population devrait rester constante). On remplace alors l’ancienne population par la nouvelle, et on recommence le processus le nombre de générations voulu. Voici un algorithme plus détaillé d’un algorithme génétique : Algorithme génétique générique 1- Générer une population de individus de taille N : x1, x2, x3,…, xN. 2- Calculer les chances de survie (qualité ou encore fitness) de chaque individu. f(x1), f(x2), f(x3), …, f(xN). 3- Vérifier si le critère de terminaison est atteint. Si oui, terminer. 4- Choisir une paire d’individus pour la reproduction (selon les chances de survie de chaque individu). 5- Selon les probabilités associées à chaque opérateur génétique, appliquer ces opérateurs. 6789- Placer les individus produits dans la nouvelle population. Vérifier si la taille de la nouvelle population est correcte. Si non, retourner à l’étape 4. Remplacer l’ancienne population d’individus par la nouvelle. Retourner à l’étape 2. Notez que cet algorithme génétique générique est plutôt « vide ». Il s’agit d’un modèle très général. Nous verrons un exemple plus concret plus tard. EXPLICATIONS DES ÉLÉMENTS D’UN ALGORITHME GÉNÉTIQUE Individu : Les individus correspondent aux « solutions » du problème à optimiser. Ces solutions doivent être « codées » pour que le traitement puisse être effectué par l’algorithme génétique. Cette représentation codée d’une solution est appelée chromosome, et est composée de gènes. Chaque gène peut représenter une variable, un élément de la solution, ou encore une partie plus abstraite. La manière la plus utilisée de codage par algorithme génétique est le codage en vecteurs. Chaque solution est représentée par un vecteur. Ce vecteur peut être binaire ou encore de n’importe quel type discret dénombrable (entier, caractères, etc.). On pourrait également utiliser un type continu (ex : nombres réels), mais dans ce cas, il faut également revoir les opérations qui modifient le contenu des chromosomes (la fonction qui crée aléatoirement les chromosomes et les opérateurs génétiques). La simplicité veut que les chromosomes soient uniformes, c’est-à-dire que tous les gènes sont du même type. Cependant, si on tient compte encore une fois des opérations qui modifient le contenu des chromosomes, on peut assez aisément construire des vecteurs d’éléments de type différents. On demande habituellement que les chromosomes soient tous de même longueur, basés sur la même architecture, les gènes homologues étant au même endroit sur leur chromosome respectif. De fait, le codage par vecteur est si utilisé (très grande simplicité comparée aux autres méthodes de codage de chromosome) que les algorithmes sont souvent identifiés comme étant des méthodes de traitement vectoriel. Cette affirmation n’est pas tout a fait vraie car d’autres types de codage existent, bien que n’étant pas très fréquents. Par exemple, l’utilisation des algorithmes génétiques pour faire de la programmation génétique utilise un codage en arbre (ce qui permet entre autres d’avoir des chromosomes de longueurs différentes). Population : C’est l’ensemble des individus, ou encore l’ensemble des chromosomes d’une même génération. Habituellement, la taille de la population reste constante tout au long de l’algorithme génétique. Générer : Habituellement, au départ d’un algorithme génétique, il faut créer une population d’individus. Ces individus sont générés par une fonction simple. Cette fonction affecte à chaque individu qu’elle crée une valeur aléatoire pour chacun de ses gènes. L’algorithme génétique peut également utiliser comme population de départ une population déjà créée a priori. Qualité, fitness, d’un individu : Le calcul de la qualité d’un individu est essentiel aux algorithmes génétiques. Cette fonction donne, en valeur numérique (habituellement réelle), la qualité d’un individu. C’est selon cette valeur numérique qu’est calculée les chances de sélection de cet individu. La fonction de fitness doit avoir 0 comme plancher, pour ne pas fausser le calcul des pourcentages. Les algorithmes génétiques étant une technique d’optimisation, ils cherchent la qualité maximale, donc l’optimisation de la fonction de qualité. Si on cherche plutôt à minimiser une fonction, il faudra la modifier de sorte que la fonction de qualité se maximise. Il serait bien entendu possible de conserver un fonction de qualité qui fonctionne à l’envers et de modifie à la place le calcul des probabilités, mais ceci rendrait l’algorithme beaucoup plus difficile à décoder pour les utilisateurs externes. Sélection : Selon la qualité des individus, chacun se voit attribuer un pourcentage de chances d’être choisi pour la reproduction, qui correspond à l’importance relative de la qualité de l’individu par rapport à la qualité totale de la population. Reproduction : La reproduction s’effectue généralement en croisant deux individus, ce qui produit deux nouveaux individus à placer dans la nouvelle population. De la manière classique, la reproduction consiste à appliquer les opérateurs génétiques sur les deux chromosomes sélectionnés et mettre les deux chromosomes résultant dans la nouvelle population. Les deux opérateurs génétiques courants sont l’enjambement (cross-over) et la mutation. Le premier est la véritable reproduction. Chaque chromosome enfant reçoit environ la moitié des gènes de chacun de ses parents. La probabilité d’enjambement est presque toujours de 50% (effectue de cette manière un mélange plus efficace). Selon cette probabilité, on échange les gènes homologues des deux chromosomes. De cette façon, après l’enjambement, on obtient deux enfants qui sont complémentaires par rapport à leurs parents (si un enfant a un gène d’un tel parent, l’autre enfant tiendra ce même gène de l’autre parent). L’opérateur de mutation, bien qu’ayant une probabilité bien moindre (habituellement entre 0,5% et 5%) joue un rôle très important. Une reproduction utilisant uniquement l’enjambement est une méthode de hill-climbing, méthode qui est limitée par l’atteinte de maxima locaux. En effet, les gènes des enfants sont limités par les gènes des parents, et si un gène n’est pas présent dans la population initiale (ou s’il disparaît à cause des reproductions), il ne pourra jamais se développer chez les descendants. L’opérateur de mutation est là pour contourner ce problème. Chaque gène possède une faible probabilité de muter, c’est-à-dire d’être aléatoirement remplacé par une autre incarnation de ce gène. Cette précaution permet de conserver ce qu’on appelle la diversité génétique. Habituellement, la mutation crée des individus faibles, peu aptes à survivre. Cependant, un certaine mutation pourrait se révéler « géniale » et permet d’augmenter grandement l’évolution de la population. Ces opérateurs génétiques peuvent habituellement s’accommoder de la plupart des situations sans trop de modifications. Toutefois, afin de conserver la cohérence des individus, on doit parfois modifier grandement, voire changer totalement les opérateurs génétiques. Il n’y a pas de limite quant au nombre d’opérateurs génétiques. D’une manière générale, on considère comme opérateur génétique, n’importe quelle fonction qui modifie le contenu génétique d’un ou de plusieurs chromosomes. Il parle aussi quelques fois de l’opérateur génétique de clonage. Celui-ci existe (un individu est passé directement, sans modifications, à la génération suivante) et peut être incorporé dans un algorithme génétique. Cependant, le potentiel évolutif de cet opérateur est secondaire. On assiste également à un clonage lorsque les autres opérateurs génétiques n’ont pas d’effet (cas très rare). Validité et cohérence : Selon la méthode de codage et sa signification, on doit être toujours certain que les individus de notre population soient valides. En effet, que ferait-on d’une solution donnant une bonne note de qualité, mais n’ayant aucun sens pratique une fois interprété. Il faut donc s’assurer que la fonction de création des individus crée toujours des individus valides, et que les opérateurs génétiques conservent la validité des individus traités. Ceci vise à conserver la cohérence générale de l’algorithme. Critère de terminaison : Généralement, un algorithme génétique se termine après un certain nombre de générations, mais on peut également terminer l’exécution de l’algorithme lorsqu’un certaine condition soit atteinte, par exemple lorsque la qualité d’un individu dépasse un certain seuil. EXEMPLE SIMPLE1 D’ALGORITHME GÉNÉTIQUE Problématique : On veut trouver l’entier (de 0 à 16) qui maximise la fonction2 f x 1 4 15 x 2 x3 4 . Population : 6 chromosomes de 4 bits (codage), représentant sous forme binaire les entiers (individus) qu’ils représentent. Fonction de qualité : f x 1 4 15 x 2 x3 4 Opérateurs génétiques : enjambement : Il y a 50% de chance qu’un bit soit échangé avec son homologue sur l’autre chromosome. mutation : Chaque bit a 3% de chance de muter (passer de 1 à 0 ou de 0 à 1). Population initiale : Étiquette du Chaîne du Chromosome chromosome X1 X2 0100 0000 Entier décodé Qualité (fitness) 4 0 48 4 Chances de reproduction (%) 13,58 1,13 Ce cas est trop simple, mais il ne sert qu’à illustrer les processus de l’algorithme génétique. Résoudre ce problème peut évidemment se faire sans le trouble et le labeur que nécessite un algorithme génétique. Aussi, on ne note pas la présence de maxima locaux dans ce problème, ce qui fait que l’opérateur de mutation est plus un boulet qu’une aide. 1 2 X3 1110 14 X4 0001 1 X5 1000 8 X6 1011 11 Moyennes de la qualité (average fitness): 58,917. 53 7,5 116 125 14,99 2,12 32,81 35,36 Sélection et opérateurs génétiques: Chromosome enjambement mutation chromosomes finaux Couple 1 : X5 X3 1000 1110 1000 1110 1010 1100 1010 1100 Couple 2 : X5 X6 1000 1011 1000 1011 1011 1000 1011 1000 Couple 3 : X6 X1 1011 0100 1011 0100 1000 0111 1001 0111 Population pour la génération 2 : Étiquette du Chaîne du Chromosome chromosome Entier décodé X1’ 1010 10 X2’ 1100 12 X3’ 1011 11 X4’ 1000 8 X5’ 1001 9 X6’ 0111 7 Moyennes de la qualité (average fitness): 118,25. Qualité (fitness) 129 112 125 116 125,5 102 Chances de reproduction (%) 18,18 15,79 17,62 16,35 17,69 14,38 La population de la deuxième génération peut maintenant servir pour engendrer une troisième génération. Bien qu’ici, on ait trouvé la solution optimale (10) en une seule génération, on remarque quand même que les la moyenne des chances de survie a augmenté considérablement. De cette façon, on peut conclure que l’algorithme génétique encourage le « perfectionnement de la race ». STRATÉGIES D’ÉVOLUTION Les stratégies d’évolution sont une variante des algorithmes génétiques. La stratégie d’évolution la plus simple se nomme stratégie d’évolution-(1+1) ( (1+1)-evolution strategy). Au lieu de faire se reproduire des individus d’une population, on n’utilise qu’un seul individu, auquel on applique de mutations « normales ». En effet, chaque paramètre du problème est une expression numérique continue3 (nombres réels) et on Il n’est pas vraiment nécessaire que ces expressions numériques soient continues, quoique cela donne une meilleure réalisation de la stratégie d’évolution. 3 applique sur chacun d’entre eux une mutation « normale » basée sur des écarts-types choisis à l’avance. De cette façons, les petites mutations sont plus fréquentes que les grandes, ce qui reflète encore une propriété de l’évolution darwinienne. Ensuite, si l’individu ainsi créé est meilleur que sont parent, on remplace celui-ci par sont enfant, puis on recommence le processus. Voici un algorithme générique d’un stratégie d’évolution : Algorithme d’une stratégie d’évolution-(1+1) 1- Choisir un nombre de paramètre N pour représenter le problème, et déterminer l’intervalle de possibilité (feasible range) pour chaque paramètre : x1min , x1max ,x2min , x2max ,...,xN min , xN max , Définir une variance pour chaque paramètre et la fonction à être optimisée. 2- Mettre une valeur initiale à chaque paramètre dans leur intervalle de possibilité respectif. Cet ensemble de valeurs constitue la population initiale de paramètres « parents ». x1 , x2 ,..., xN 3- Calculer la solution associée avec les paramètres « parents ». X f x1 , x2 ,..., xN 4- Créer un descendant en additionnant une variable normalement distribuée a de moyenne zéro et de variance choisie (à l’étape 1) δ, pour chaque paramètre « parent ». xi xi a 0, , i 1, 2,..., N Les mutations distribuées normalement de moyenne zéro reflètent le processus naturel de l’évolution où les changements plus petits arrivent plus fréquemment que les grands changements. 5- Calculer la solution associée avec les paramètres du « descendant ». X f x1, x2 ,..., xN 6- Comparer la solution « descendant » avec la solution « parent ». Si la solution du « descendant » est meilleure que celle du « parent », remplacer la population de paramètres « parents » par la population de paramètres « descendant ». Sinon, garder la population de paramètres « parent ». 7- Retourne à l’étape 4 et répéter le processus jusqu’à ce qu’une solution satisfaisante soit obtenue, ou qu’un certain nombre de générations soit atteint. Cette stratégie d’évolution n’utilise qu’un seul individu. Il serait possible d’en utiliser plus qu’un, mais des expériences ont montré que le modèle avec un seul individu fonctionnait mieux. La technique de modifier tous les gènes d’un individu en même temps est encore un fois pour se libérer des maxima locaux. Les stratégies d’évolution diffèrent des algorithmes génétiques par le fait qu’elles ne nécessitent aucun codage, mais d’un autre côté, n’utilisent que des paramètres numériques. PROGRAMMATION GÉNÉTIQUE La programmation génétique est un usage spécifique des algorithmes génétiques. Premièrement, la programmation génétique utilise un codage en arbre. Aussi, les « solutions » que cherche la programmation génétique sont en fait des programmes. Ces programmes sont représentés par des arbres où les nœuds sont des opérateurs simples (par exemple, +, -, *, /, ) et où les feuilles terminales sont les variables du programme (a, b, c, etc.) ou encore des constantes. La fonction qui calcule la qualité d’un programme utilise, tout comme les réseaux de neurones, une fonction qui cherche à minimiser la somme des erreurs carrées obtenues avec des exemples de test. Les opérateurs génétiques sont les mêmes que les opérateurs de base, c’est-à-dire l’enjambement et la mutation. L’enjambement s’effectue en intervertissant des nœuds (et tout ce qui en découle, les nœuds et feuilles qui leurs sont rattachées par le bas) entre deux arbres-programmes. La mutation s’effectue en mutant un élément de l’arbre avec un élément du même type (variable avec variable, opérateur avec opérateur). Attention cependant, si on prend les opérateurs vus précédemment, on pourra muter un + en un /, mais on ne pourra muter , car il ne prend qu’un seul paramètre. On peut également définir une mutation comme la mutation, non seulement d’un nœud, mais également du sous-arbre que ce nœud soutient. Par exemple, si on veut découvrir un programme qui donne les réponses suivantes : Variable a Variable b Réponse Variable a Variable b Réponse 3 5 5.830952 12 10 15.620499 8 14 16.214515 21 6 21.840330 18 2 18.110770 7 4 8.062258 32 11 33.937849 16 24 28.844410 4 3 5.0000000 2 9 9.219545 avec les opérations +, *, / et , ainsi que les paramètres a et b. D’abord, on compose une génération de programmes, on les fait exécuter avec les paramètres a et b des exemples. On compare les réponses obtenues avec les réponses voulues et on calcule la somme des erreurs carrées. On effectue ensuite une sélection des parents pour la reproduction, puis on applique les opérateurs génétiques tels que décrit cihaut. Dans le cas présent, la solution est la théorème de Pythagore et l’algorithme devrait être capable de trouver la formule X a2 b2 , ou, sous forme d’arbre : + * a * a b b La méthode illustrée ici n’est évidemment qu’un exemple très simple de la programmation génétique. Des techniques beaucoup plus élaborées sont habituellement utilisées. Par exemple, une modification courante est de spécifier une certaine taille maximum, ou encore exiger la présence d’un certain nœud. AUTRES CHAMPS DES ALGORITHMES ÉVOLUTIFS Les algorithmes évolutifs, tout comme la programmation génétique et les stratégies d’évolutions ont partie du domaine des algorithmes évolutifs. Deux autres champs importants peuvent également être cités ici : la programmation évolutive et les systèmes de classificateurs. Ces deux méthodes partagent avec les autres présentées ci-haut les caractéristiques principales des algorithmes évolutifs, c’est-à-dire l’évolution de « solutions » pour fin d’optimisation. D’autres domaines connexes sont les automates cellulaires et la vie artificielle. Ces deux domaines utilisent des processus similaires aux algorithmes génétiques, mais sont toutefois plus complexes. BIBLIOGRAPHIE 1. 2. Livres LUGER, George F., Atrificial Intelligence : Structures & Strategies for complex problem solving, 4ème édition, Addison-Wesley, 2002, 856p. NEGNEVITSKY, Michael, Artificial Intelligence : A guide to Intelligent Systems. Addison-Wesley, 2002, 394p. Sites Internet FRASER, Adam et Adil QURESHI (Salford University). Genetic Programming http://www-dept.cs.ucl.ac.uk/research/genprog/index.html GECCO, Genetic and Evolutionary Computation Conference 2001 http://wwwilligal.ge.uiuc.edu:8080/GECCO-2001/ Genetic-Programming.org http://www.genetic-programming.org/ ISGEC, International Society for Genetic and Evolutionary Computation http://www-illigal.ge.uiuc.edu:8080/ KANTROVITZ, Mark, Hitch-Hiker's Guide to Evolutionary Computation. http://www-2.cs.cmu.edu/Groups/AI/html/faqs/ai/genetic/top.html OBITKO, Marek, Introduction to Genetic Algorithms with Java Applets, http://cs.felk.cvut.cz/~xobitko/ga/ OPTIWATER GA-Search - The Genetic Algorithms Search Engine http://www.optiwater.com/GAsearch/ POHLHEIM, Hartmut, Genetic and Evolutionary Algorithms: Principles, Methods and Algorithms. http://www.geatbx.com/docu/algindex.html RENNARD, Jean-Philippe, Introduction aux algorithmes génétiques. http://www.rennard.org/alife/french/gavintr.html SIPPER, Moshe. A Brief Introduction To Genetic Algorithms. http://lslwww.epfl.ch/~moshes/ga_main.html WALL, Matthew, MIT, Matthew’s Genetic Algorithm Library http://lancet.mit.edu/ga/