📜  遗传算法

📅  最后修改于: 2021-10-19 08:11:16             🧑  作者: Mango

遗传算法(GA)是自适应启发式搜索算法,属于进化算法的较大部分。遗传算法基于自然选择和遗传学的思想。这些是对随机搜索的智能利用,提供历史数据,以将搜索引导到解决方案空间中性能更好的区域。它们通常用于为优化问题和搜索问题生成高质量的解决方案。

遗传算法模拟自然选择的过程,这意味着那些能够适应环境变化的物种能够生存和繁殖并传给下一代。简单来说,它们模拟了连续世代个体之间的“适者生存”来解决问题。每一代都由一群个体组成,每个个体代表搜索空间中的一个点和可能的解决方案。每个个体都表示为字符串字符/integer/float/bits。这个字符串类似于染色体。

遗传算法基础

遗传算法基于与种群染色体的遗传结构和行为的类比。以下是基于此类比的 GA 的基础 –

  1. 种群中的个体争夺资源和配偶
  2. 那些成功(最适者)的人然后交配比其他人创造更多的后代
  3. 来自“最适”父母的基因会在整个世代中传播,即有时父母会创造比父母任何一方都更好的后代。
  4. 因此,每一代都更适合他们的环境。

搜索空间

个体种群保持在搜索空间内。每个人代表搜索空间中给定问题的一个解决方案。每个个体都被编码为组件的有限长度向量(类似于染色体)。这些可变成分类似于基因。因此,一条染色体(个体)由几个基因(可变成分)组成。

体能得分

每个人都有一个健身分数,它显示了一个人“竞争”的能力。寻找具有最佳适应度得分(或接近最佳)的个体。

GA 维护 n 个个体(染色体/溶液)的种群以及它们的适应度分数。具有更好适应度分数的个体比其他个体有更多的繁殖机会。通过结合父母的染色体,选择具有更好适应度分数的个体来交配并产生更好的后代。人口规模是静态的,因此必须为新来者创造房间。因此,当旧种群的所有交配机会耗尽时,一些个体死亡并被新来的人取代,最终创造出新的一代。希望在连续几代人中会出现更好的解决方案,而最不适合的方法会消失。

平均而言,每一代都比前几代的个体(解决方案)拥有更多的“更好的基因”。因此,每一代都比前几代拥有更好的“部分解决方案” 。一旦产生的后代与先前种群产生的后代没有显着差异,种群就会收敛。据说该算法收敛到问题的一组解决方案。

遗传算法的算子

创建初始代后,该算法会使用以下运算符来进化代 –
1)选择算子:这个想法是优先考虑具有良好适应度分数的个体,并允许他们将基因传递给后代。
2)交叉算子:这代表个体之间的交配。使用选择运算符选择两个个体,随机选择交叉站点。然后交换这些交叉位点的基因,从而创造一个全新的个体(后代)。例如 –

3)突变算子:关键思想是在后代中插入随机基因,以保持种群的多样性,避免早熟收敛。例如 –

整个算法可以概括为——

1) Randomly initialize populations p
2) Determine fitness of population
3) Untill convergence repeat:
      a) Select parents from population
      b) Crossover and generate new population
      c) Perform mutation on new population
      d) Calculate fitness for new population

使用遗传算法的示例问题和解决方案

给定一个目标字符串,目标是从相同长度的随机字符串开始生成目标字符串。在下面的实现中,进行了以下类比——

  • 字符AZ、az、0-9等特殊符号被视为基因
  • 由这些字符生成的字符串被认为是染色体/解决方案/个体

适应度分数是在特定索引处与目标字符串中的字符不同的字符数。因此,具有较低适应度值的个体被给予更多的偏好。

C++
// C++ program to create target string, starting from
// random string using Genetic Algorithm
  
#include 
using namespace std;
  
// Number of individuals in each generation
#define POPULATION_SIZE 100
  
// Valid Genes
const string GENES = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP"\
"QRSTUVWXYZ 1234567890, .-;:_!\"#%&/()=?@${[]}";
  
// Target string to be generated
const string TARGET = "I love GeeksforGeeks";
  
// Function to generate random numbers in given range 
int random_num(int start, int end)
{
    int range = (end-start)+1;
    int random_int = start+(rand()%range);
    return random_int;
}
  
// Create random genes for mutation
char mutated_genes()
{
    int len = GENES.size();
    int r = random_num(0, len-1);
    return GENES[r];
}
  
// create chromosome or string of genes
string create_gnome()
{
    int len = TARGET.size();
    string gnome = "";
    for(int i = 0;ichromosome = chromosome;
    fitness = cal_fitness(); 
};
  
// Perform mating and produce new offspring
Individual Individual::mate(Individual par2)
{
    // chromosome for offspring
    string child_chromosome = "";
  
    int len = chromosome.size();
    for(int i = 0;i population;
    bool found = false;
  
    // create initial population
    for(int i = 0;i new_generation;
  
        // Perform Elitism, that mean 10% of fittest population
        // goes to the next generation
        int s = (10*POPULATION_SIZE)/100;
        for(int i = 0;i


Python
# Python3 program to create target string, starting from
# random string using Genetic Algorithm
  
import random
  
# Number of individuals in each generation
POPULATION_SIZE = 100
  
# Valid genes
GENES = '''abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP
QRSTUVWXYZ 1234567890, .-;:_!"#%&/()=?@${[]}'''
  
# Target string to be generated
TARGET = "I love GeeksforGeeks"
  
class Individual(object):
    '''
    Class representing individual in population
    '''
    def __init__(self, chromosome):
        self.chromosome = chromosome 
        self.fitness = self.cal_fitness()
  
    @classmethod
    def mutated_genes(self):
        '''
        create random genes for mutation
        '''
        global GENES
        gene = random.choice(GENES)
        return gene
  
    @classmethod
    def create_gnome(self):
        '''
        create chromosome or string of genes
        '''
        global TARGET
        gnome_len = len(TARGET)
        return [self.mutated_genes() for _ in range(gnome_len)]
  
    def mate(self, par2):
        '''
        Perform mating and produce new offspring
        '''
  
        # chromosome for offspring
        child_chromosome = []
        for gp1, gp2 in zip(self.chromosome, par2.chromosome):    
  
            # random probability  
            prob = random.random()
  
            # if prob is less than 0.45, insert gene
            # from parent 1 
            if prob < 0.45:
                child_chromosome.append(gp1)
  
            # if prob is between 0.45 and 0.90, insert
            # gene from parent 2
            elif prob < 0.90:
                child_chromosome.append(gp2)
  
            # otherwise insert random gene(mutate), 
            # for maintaining diversity
            else:
                child_chromosome.append(self.mutated_genes())
  
        # create new Individual(offspring) using 
        # generated chromosome for offspring
        return Individual(child_chromosome)
  
    def cal_fitness(self):
        '''
        Calculate fittness score, it is the number of
        characters in string which differ from target
        string.
        '''
        global TARGET
        fitness = 0
        for gs, gt in zip(self.chromosome, TARGET):
            if gs != gt: fitness+= 1
        return fitness
  
# Driver code
def main():
    global POPULATION_SIZE
  
    #current generation
    generation = 1
  
    found = False
    population = []
  
    # create initial population
    for _ in range(POPULATION_SIZE):
                gnome = Individual.create_gnome()
                population.append(Individual(gnome))
  
    while not found:
  
        # sort the population in increasing order of fitness score
        population = sorted(population, key = lambda x:x.fitness)
  
        # if the individual having lowest fitness score ie. 
        # 0 then we know that we have reached to the target
        # and break the loop
        if population[0].fitness <= 0:
            found = True
            break
  
        # Otherwise generate new offsprings for new generation
        new_generation = []
  
        # Perform Elitism, that mean 10% of fittest population
        # goes to the next generation
        s = int((10*POPULATION_SIZE)/100)
        new_generation.extend(population[:s])
  
        # From 50% of fittest population, Individuals 
        # will mate to produce offspring
        s = int((90*POPULATION_SIZE)/100)
        for _ in range(s):
            parent1 = random.choice(population[:50])
            parent2 = random.choice(population[:50])
            child = parent1.mate(parent2)
            new_generation.append(child)
  
        population = new_generation
  
        print("Generation: {}\tString: {}\tFitness: {}".\
              format(generation,
              "".join(population[0].chromosome),
              population[0].fitness))
  
        generation += 1
  
      
    print("Generation: {}\tString: {}\tFitness: {}".\
          format(generation,
          "".join(population[0].chromosome),
          population[0].fitness))
  
if __name__ == '__main__':
    main()


输出:

Generation: 1    String: tO{"-?=jH[k8=B4]Oe@}    Fitness: 18
Generation: 2    String: tO{"-?=jH[k8=B4]Oe@}    Fitness: 18
Generation: 3    String: .#lRWf9k_Ifslw #O$k_    Fitness: 17
Generation: 4    String: .-1Rq?9mHqk3Wo]3rek_    Fitness: 16
Generation: 5    String: .-1Rq?9mHqk3Wo]3rek_    Fitness: 16
Generation: 6    String: A#ldW) #lIkslw cVek)    Fitness: 14
Generation: 7    String: A#ldW) #lIkslw cVek)    Fitness: 14
Generation: 8    String: (, o x _x%Rs=, 6Peek3   Fitness: 13
                           . 
                           . 
                           . 
Generation: 29    String: I lope Geeks#o, Geeks   Fitness: 3
Generation: 30    String: I loMe GeeksfoBGeeks    Fitness: 2
Generation: 31    String: I love Geeksfo0Geeks    Fitness: 1
Generation: 32    String: I love Geeksfo0Geeks    Fitness: 1
Generation: 33    String: I love Geeksfo0Geeks    Fitness: 1
Generation: 34    String: I love GeeksforGeeks    Fitness: 0

注意:每次算法都以随机字符串开头,因此输出可能会有所不同

正如我们从输出中看到的,我们的算法有时会停留在局部最优解,这可以通过更新适应度分数计算算法或通过调整变异和交叉运算符来进一步改进。

为什么要使用遗传算法

  • 他们是健壮的
  • 提供大空间状态的优化。
  • 与传统 AI 不同,它们不会因输入的微小变化或噪声的存在而中断

遗传算法的应用

遗传算法有很多应用,其中一些是——

  • 循环神经网络
  • 突变测试
  • 密码破解
  • 滤波和信号处理
  • 学习模糊规则库等

参考
https://en.wikipedia.org/wiki/List_of_genetic_algorithm_applications
https://en.wikipedia.org/wiki/Genetic_algorithm
https://www.doc.ic.ac.uk/~nd/surprise_96/journal/vol1/hmw/article1.html