end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

pythonによる GA(Genetic Algorithm、遺伝的アルゴリズム)

遺伝的アルゴリズムを上記urlから写経します。

 \large{ y = x^2 (0≦x≦1) }

の最大値を探索しています。

突然変異は実装していますが、交差は実装していません

import random
import copy
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# GA:Genetic Algorithm 遺伝的アルゴリズム による
# y = x^2 (0<x<1) の最大値探索
# cf. https://github.com/igenki/youtube_python/blob/main/SimpleGA.ipynb

chromosome_size = 10    # 染色体の個体数
epochs_size     = 100   # 進化する世代数
genes_size      = 8     # 遺伝子数
mutation_rate   = 0.05  # 突然変異率

def main():
    ga = SimpleGeneticAlgorithm()
    ga.evolve()
    ga.output_animation()

class SimpleGeneticAlgorithm():

    def __init__(self):
        self.chromosomes = [Chromosome() for i in range(chromosome_size)]

        # 出力する画像のsizeはinch指定
        self.fig = plt.figure(figsize=(5, 5))
        # アニメ出力する各コマ
        self.ims = []
    
    def evolve(self):
        for epoch in range(epochs_size+1):
            
            self.tournament()

            # 突然変異
            for chromosome in self.chromosomes:
                chromosome.mutate()

            # 進化経過のアニメ出力
            self.snapshot(epoch)

            # 進化経過のtext出力
            if epoch % 10 == 0:
                print("epoch:",epoch)
                for chro in self.chromosomes:
                    print("\t", chro.getFittness() )
                    
    # トーナメント選択
    def tournament(self):
        chro_next = []
        while len(chro_next) < chromosome_size:
            chro_tmp_1 = copy.deepcopy(
                self.chromosomes[random.randrange(chromosome_size)])
            chro_tmp_2 = copy.deepcopy(
                self.chromosomes[random.randrange(chromosome_size)])
            
            if chro_tmp_1.getFittness() > chro_tmp_2.getFittness():
                chro_next.append(chro_tmp_1)
            else:
                chro_next.append(chro_tmp_2)
                
        self.chromosomes = chro_next

    def snapshot(self, t):
        # linspace():等差数列作成
        im=plt.plot(np.linspace(0,1,100),
                    [n*n for n in np.linspace(0,1,100)],
                    color='black',
                    linestyle='solid')
        im += [plt.text(0,0.8,'epoch: {}'.format(t))]
        im += [plt.scatter(
            [chro.getVal() for chro in self.chromosomes],
            [chro.getFittness() for chro in self.chromosomes],c='r')]
        self.ims.append(im)

    def output_animation(self):
        ani = animation.ArtistAnimation(self.fig, self.ims)
        ani.save('./GeneticAlgorithm.gif', writer="pillow")
        # ani.save('./GeneticAlgorithm.mp4', writer="ffmpeg")

#染色体
class Chromosome:
    def __init__(self):
        self.gene = [random.randint(0,1) for i in range(genes_size)]
        
    # 突然変異
    def mutate(self):
        for i in range(genes_size):
            if random.random() < mutation_rate:
                self.gene[i] = 1 - self.gene[i]
                
    # 遺伝子型から表現型への発現
    #  -遺伝子型の例 0110001011     ( 2進数)
    #  -表現型の例   395/(1024-1)   (10 〃 )
    def getVal(self):
        value = 0.
        for g in self.gene:
            value *= 2
            value += g
        value = value / (2 ** genes_size - 1.0)
        return value
    
    # 適応度評価
    def getFittness(self):
        result = self.getVal()
        return result * result

if __name__ == '__main__':
    main()

↑こう書くと、↓こう表示されます