zoukankan      html  css  js  c++  java
  • 遗传算法--句子匹配

    Source of original code

    Author: Morvan
    Visualize Genetic Algorithm to match the target phrase.
    Visit tutorial website for more: https://morvanzhou.github.io/tutorials/

    The result

    Absolutely, it's satisfying.
    With only 24 generations(Maybe a little more or less, randomly.), the sentence matches perfectly.

    Algorithm & Code interpretation

    the code component

    The whole code is consists of three parts.
    Some const variables , the class GA and the main function.

    some const variables

    TARGET_PHRASE = 'I love you!'       # target DNA
    POP_SIZE = 300                      # population size
    CROSS_RATE = 0.4                    # mating probability (DNA crossover)
    MUTATION_RATE = 0.01                # mutation probability
    N_GENERATIONS = 1000                # max generation
    DNA_SIZE = len(TARGET_PHRASE)       # the size of DNA
    
     # target ASCII indices of the target string, convert string to number
    TARGET_ASCII = np.fromstring(TARGET_PHRASE, dtype=np.uint8) 
    ASCII_BOUND = [32, 126]             # the bounds of the ASCII charactors
    

    main function

    Firstly, we constuct a GA object ,named ga with the const variables above.

    ga = GA(DNA_size=DNA_SIZE, DNA_bound=ASCII_BOUND, cross_rate=CROSS_RATE,
        mutation_rate=MUTATION_RATE, pop_size=POP_SIZE)
    

    Then, execute a for loop in the max generation

    for generation in range(N_GENERATIONS):
        fitness = ga.get_fitness()                      # get the fitness of the current population
        best_DNA = ga.pop[np.argmax(fitness)]           # best matching DNA
        best_phrase = ga.translateDNA(best_DNA)         # translate the DNA to string we can read
        print('Gen', generation, ': ', best_phrase)     # print the string
        if best_phrase == TARGET_PHRASE:                # as if the string matches perfectly, break the loop
            break
        ga.evolve()                                     # if not, evolve to the next generation
    

    GA class

    function init()

    def __init__(self, DNA_size, DNA_bound, cross_rate, mutation_rate, pop_size):
        self.DNA_size = DNA_size        # the size of DNA
        DNA_bound[1] += 1
        self.DNA_bound = DNA_bound      # ASCII Bound
        self.cross_rate = cross_rate
        self.mutate_rate = mutation_rate   
        self.pop_size = pop_size    # population
        # define the population of first generation
        self.pop = np.random.randint(*DNA_bound, size=(pop_size, DNA_size)).astype(np.int8)  # int8 for convert to ASCII
    

    To initialize the class with const variables above

    function translateDNA()

    def translateDNA(self, DNA):                 
        # convert to readable string
        return DNA.tostring().decode('ascii')
    

    Such as translate
    [126, 34, 45, 125, 46, 101, 32, 119, 38, 126, 33] to '~"-}.e w&~!'

    function get_fitness()

    def get_fitness(self):                      # count how many character matches
        match_count = (self.pop == TARGET_ASCII).sum(axis=1)
        return match_count
    

    To calculate the fitness of every DNA in current generation.
    List of array convert to list of int , int means match numbers

    function select()

    def select(self):
        fitness = self.get_fitness() + 1e-4     # add a small amount to avoid all zero fitness
        idx = np.random.choice(np.arange(self.pop_size), size=self.pop_size, replace=True, p=fitness/fitness.sum())
        return self.pop[idx]
    

    To select better fit DNA
    Every new array element depends on the probabilities of old array elements
    (probability = element.fitness/fitness.sum())
    The probability is higher, the more it will appear in the new array

    function crossover()

    def crossover(self, parent, pop):
        if np.random.rand() < self.cross_rate:
            i_ = np.random.randint(0, self.pop_size, size=1)                        # select another individual from pop
            cross_points = np.random.randint(0, 2, self.DNA_size).astype(np.bool)   # choose crossover points
            parent[cross_points] = pop[i_, cross_points]                            # mating and produce one child
        return parent
    

    To cross this parent with another random parent in current generation

    function mutate()

    def mutate(self, child):
        for point in range(self.DNA_size):
            if np.random.rand() < self.mutate_rate:
                child[point] = np.random.randint(*self.DNA_bound)  # choose a random ASCII index
        return child
    

    Traverse all the elements in a DNA
    Randomly convert a element to a random ASCII charactor index

    function evolve()

    def evolve(self):
        pop = self.select()
        pop_copy = pop.copy()
        for parent in pop:  # for every parent
            child = self.crossover(parent, pop_copy)
            child = self.mutate(child)
            parent[:] = child
        self.pop = pop
    

    To evolve into the next generation.
    Firstly, select the better fitting ones
    Then, creat a copy of current generation
    Then, traverse everyone in current generation,
    cross it with another random one in current generation
    mutate randomly.
    Finally, upgrade to the next generation

    Complete code

    import numpy as np
    
    TARGET_PHRASE = 'I love you!'       # target DNA
    POP_SIZE = 300                                # population size
    CROSS_RATE = 0.4                          # mating probability (DNA crossover)
    MUTATION_RATE = 0.01                   # mutation probability
    N_GENERATIONS = 1000
    
    DNA_SIZE = len(TARGET_PHRASE)
    TARGET_ASCII = np.fromstring(TARGET_PHRASE, dtype=np.uint8)  # convert string to number
    ASCII_BOUND = [32, 126]
    
    
    class GA(object):
        def __init__(self, DNA_size, DNA_bound, cross_rate, mutation_rate, pop_size):
            self.DNA_size = DNA_size
            DNA_bound[1] += 1
            self.DNA_bound = DNA_bound
            self.cross_rate = cross_rate
            self.mutate_rate = mutation_rate
            self.pop_size = pop_size
    
            self.pop = np.random.randint(*DNA_bound, size=(pop_size, DNA_size)).astype(np.int8)  # int8 for convert to ASCII
    
        def translateDNA(self, DNA):                 # convert to readable string
            return DNA.tostring().decode('ascii')
    
        def get_fitness(self):                      # count how many character matches
            match_count = (self.pop == TARGET_ASCII).sum(axis=1)
            return match_count
    
        def select(self):
            fitness = self.get_fitness() + 1e-4     # add a small amount to avoid all zero fitness
            idx = np.random.choice(np.arange(self.pop_size), size=self.pop_size, replace=True, p=fitness/fitness.sum())
            return self.pop[idx]
    
        def crossover(self, parent, pop):
            if np.random.rand() < self.cross_rate:
                i_ = np.random.randint(0, self.pop_size, size=1)                        # select another individual from pop
                cross_points = np.random.randint(0, 2, self.DNA_size).astype(np.bool)   # choose crossover points
                parent[cross_points] = pop[i_, cross_points]                            # mating and produce one child
            return parent
    
        def mutate(self, child):
            for point in range(self.DNA_size):
                if np.random.rand() < self.mutate_rate:
                    child[point] = np.random.randint(*self.DNA_bound)  # choose a random ASCII index
            return child
    
        def evolve(self):
            pop = self.select()
            pop_copy = pop.copy()
            for parent in pop:  # for every parent
                child = self.crossover(parent, pop_copy)
                child = self.mutate(child)
                parent[:] = child
            self.pop = pop
    
    if __name__ == '__main__':
        ga = GA(DNA_size=DNA_SIZE, DNA_bound=ASCII_BOUND, cross_rate=CROSS_RATE,
                mutation_rate=MUTATION_RATE, pop_size=POP_SIZE)
    
        for generation in range(N_GENERATIONS):
            fitness = ga.get_fitness()
            best_DNA = ga.pop[np.argmax(fitness)]
            best_phrase = ga.translateDNA(best_DNA)
            print('Gen', generation, ': ', best_phrase)
            if best_phrase == TARGET_PHRASE:
                break
            ga.evolve()
  • 相关阅读:
    要改变静态文本框的值,必须设置静态文本框控件的样式中(Notify通知)勾选
    MFC对话框中的编辑控件的7种操作方式
    孙鑫C++视频教程 rmvb格式 全20CD完整版
    Windows server2008 下 PowerShell对.NET3.5静默安装
    MFC关机函数
    PDI-KETTLE-2:KETTLE安装,环境变量配置,开发准备
    KETTLE常见问题记录第一篇【安装,资源库,数据库】
    日常问题解决记录一:远程桌面进程如果关闭了怎么呼出?
    KETTLE调度第二篇:把Jenkins调度Web启动设置为后台执行
    PDI-KETTLE-1:使用KETTLE如何设计一个作业-以数据库迁移为例
  • 原文地址:https://www.cnblogs.com/liyuquan/p/7617128.html
Copyright © 2011-2022 走看看