Les algorithmes génétiques démystifiés 6
La dernière fois on était resté sur un algorithme parfois bloqué par l’extremum local. Aujourd’hui on arrange cela grâce à la mutation génétique.
Tout d’abord un petit mot sur la mutation génétique. Vous voyez peut-être cela comme de sombres expériences de laboratoire, ou bien vous pensez à Peter Parker mordu par une araignée radioactive et devenant Spiderman… En fait, la mutation génétique est un phénomène tout à fait naturel, et à l’origine de l’évolution des espèces. Pour ce qui nous intéresse ici, on imaginera que, de temps en temps, un gène est mal recopié, ce qui va se traduire par une inversion d’un bit dans un chromosome.
Voici la méthode qui est chargée de muter un chromosome:
On sélectionne au hasard un bit parmi les 48 que comporte le chromosome, puis on l’inverse. Enfin on retourne le nouveau chromosome. Pour voir ce code à l’oeuvre, on peut écrire ceci:
On peut voir qu’un bit a été inversé:
[~/genetic]⇒ ruby test.rb
[nil, "101000101001011110110000011000010000110011011110"]
[nil, "101000101001011110110000011000010000110010011110"]
Reste à savoir quand muter ? On considère généralement que le bon taux de mutation se trouve entre 1/1000 et 1/100000. Ce qui nous donne la méthode suivante:
Un individu sur 1000 va recevoir une mutation, ce qui va permettre d’apporter du nouveau matériel génétique et, en théorie, d’éviter de tomber dans un extremum local. Pour voir ce que ça donne, il faut modifier le code du dernier article pour appliquer la mutation:
Vous noterez au passage que je suis passé de 50 générations à 10000. Les algorithmes génétiques n’ont vraiment de sens que sur un grand nombre de générations. Voyons le résultat:
[~/genetic]⇒ ruby test.rb
Generation: 0 Best: 39
Generation: 1 Best: 100
Generation: 2 Best: 34
Generation: 3 Best: 88
Generation: 4 Best: 44
Generation: 5 Best: 19
Generation: 6 Best: 105
Generation: 7 Best: 47
Generation: 8 Best: 13
Generation: 9 Best: 13
Generation: 10 Best: 13
Generation: 11 Best: 2
Generation: 12 Best: 1
Generation: 13 Best: 3
Generation: 14 Best: 33
Generation: 15 Best: 19
Generation: 16 Best: 7
Generation: 17 Best: 9
Generation: 18 Best: 1
...
Generation: 465 Best: 1
Generation: 466 Best: 0
Formula: 88-1%3+900
Ça fonctionne ! Sauf que parfois…
Parfois on atteint la 10.000ème génération sans avoir la solution. Je l’ai déjà dit et je le répète : un algorithme génétique ne peut pas garantir que l’on trouvera la meilleure solution. Le problème avec notre algorithme (dont je donne le code complet à la fin de l’article) tient sûrement dans sa méthode de sélection ainsi que dans la manière dont on produit une nouvelle génération. Il serait intéressant de voir ce qu’il se passe en introduisant du sang frais, c’est à dire quelques individus produits au hasard. Peut-être le sujet d’un prochain article ?
Le code source entier
À demain.