AI中的几种搜索算法---基因算法
2016-12-06 16:25
309 查看
引言
进化计算(Evolutionary Computation)这个涵盖的范围比较广,其中包括基因算法(Genetic Algorithm)、进化式策略(Evolutionary Strategy)、基因程序(Genetic Programming)等等。这篇是进化计算的开篇,我会从基因算法入手,进而介绍进化计算中的一些基本思想。
每一次操作,从群体中挑选两个优秀的个体,取出这两个个体的基因,进行拆分重组,从而得到新方案,放入新一代的群体中去。
其中利用到了生物学中的重组(Recombination)、选择(Selection)和突变(Mutation)。所以在学习这一算法的时候,不妨和生物学中一些概念进行类比,这样能够更好地理解基因算法的工作原理。
基因算法,在挑选的过程中,随机地挑选了两个优秀个体;在对两个个体的基因重组的时候,也引用了突变这一个不确定因素,整个过程貌似都笼罩在“随机”阴影下。确实在某种意义上,基因算法是一种随机搜索的算法。但必须指出的是基因算法在搜索能力上大大优于普通的随机搜索。
一般来说,包括这三个操作:交叉(Crossover)、突变Mutation和倒置(Inversion)。
接下来我解释这三个操作:
ParentA(1111111111111111) ParentB(0000000000000000)
ChildA(1111111100000000) ChildB(0000000011111111)
就像上面,将ParentA切成两段,同时也将ParentB的基因链也切成两段。
先将ParentB的一半基因链接在ParentA的一半基因链后面,从而产生ChildA;同理可得ChildB,只是交换了ParentA和ParentB的顺序。
这里ChildA从ParentA中得到了全部的基因,但是可以发现,其中ChildA中有一位是0,而0显然不是ParentA的基因,所以这便是突变。
同理可得ChildB。
这个操作的结果有点类似突变。其实这个的操作过程是这样的:去ParentA的一个片段,对这个片段中每一个基因进行取反,从而得到了ChildA。
首先便是创建群体,不断随机创建个体。
从当前群体中挑选两个优秀个体,对其基因进行重组,生成两个新个体,这两个新个体便组成了新一代的群体。
利用步骤2,创建一个与当前群体容量相当的新一代群体,便将新一代群体设定为当前群体。
判断是否得到了我们所需要的个体,如果得到就停止算法。
判断群体是否不再符合要求(失去了多样性),如果不符合就停止算法;如果符合就继续步骤3。
伪代码:
这里我们会用基因算法,再次求解这个问题。虽然已经介绍过TSP问题,这里为了阅读的方便,我就直接拷贝了《AI中的几种搜索算法---SA搜索算法》的部分内容。
TSP问题即旅行商问题:一个旅行商A被分配到一个任务,公司要求A去几个城市进行公司业务拓展,所以A就会拿出地图制定一个合理的路线。其中路线的要求便是消耗最小,并且能够从某一个城市出发,并且最后返回该城市时,已经访问过了所有城市。
对于这个公式,我稍作解释:Fitness就是我们一直提到的适应能力(适应值),Length(solution)计算路线solution的路程长度。
杂交算子
这里我们介绍一个新的基因重组算法。较之于之前介绍的“交叉”、“突变”和“倒置”,这个算法会复杂一点。
杂交算子,算法来于《构建“基因库”求解TSP问题的混合遗传算法》
接下来开始介绍:
首先从当前群体中,随机选取两个优秀的个体作为父辈:ParentA和ParentB。
随机选取两个基因位置(即处于基因链中第几个位置):PosA1和PosA2。
找到ParentA基因链,PosA1和PosA2位置处的基因:G1和G2。
找到ParentB基因链中基因G1和G2所处的位置:PosB1和PosB2。
将ParentB基因链中,与处于ParentA基因链PosA1和PosA2之间相同的基因去掉。
然后如果PosB1 < PosB2,将处于ParentA基因链PosA1和PosA2之间的基因片段,在ParentB基因链的PosB1位置开始顺序插入;
如果PosB1 >= PosB2,将将处于ParentA基因链PosA1和PosA2之间的基因片段,在ParentB基因链的PosB2位置开始逆序插入。
经过步骤6之后,得到新个体Child,如果Child并没有比父辈优秀,则再回到步骤1,继续相同操作;如果新个体优于父辈,则将新个体放入新一代群体中,再继续产生下一个个体。
下面举一个具体的例子
代码
如果想要详细了解可以去基因算法解决TSP问题处下载
下面是整个基因算法的流程代码:
效果图
其中我在实现这个算法的时候,在尝试基因链重组算法的时候,一直没有找到一个能够保证优秀基因遗传下去的好方法,所在在网上搜了一下关于TSP和基因算法,找到了一篇论文《构建“基因库”求解TSP问题的混合遗传算法》,有兴趣的读者可以去看一下这篇文章。
如果有兴趣的可以留言,一起交流一下算法学习的心得。
进化计算(Evolutionary Computation)这个涵盖的范围比较广,其中包括基因算法(Genetic Algorithm)、进化式策略(Evolutionary Strategy)、基因程序(Genetic Programming)等等。这篇是进化计算的开篇,我会从基因算法入手,进而介绍进化计算中的一些基本思想。
一、基因算法的基本介绍
1.核心思想
基因算法与A*、Tabu、BFS等一些启发式算法,最大的不同便是:从针对个体,转变到针对由个体组成的“群体”(Population)。根据适应值(Fitness)来决定个体的优秀程度。每一次操作,从群体中挑选两个优秀的个体,取出这两个个体的基因,进行拆分重组,从而得到新方案,放入新一代的群体中去。
其中利用到了生物学中的重组(Recombination)、选择(Selection)和突变(Mutation)。所以在学习这一算法的时候,不妨和生物学中一些概念进行类比,这样能够更好地理解基因算法的工作原理。
基因算法,在挑选的过程中,随机地挑选了两个优秀个体;在对两个个体的基因重组的时候,也引用了突变这一个不确定因素,整个过程貌似都笼罩在“随机”阴影下。确实在某种意义上,基因算法是一种随机搜索的算法。但必须指出的是基因算法在搜索能力上大大优于普通的随机搜索。
2.基因拆分重组
接下来介绍一些常用的基因重组算法。一般来说,包括这三个操作:交叉(Crossover)、突变Mutation和倒置(Inversion)。
接下来我解释这三个操作:
交叉
ParentA(1111111111111111) ParentB(0000000000000000)
Crossover
ChildA(1111111100000000) ChildB(0000000011111111)
就像上面,将ParentA切成两段,同时也将ParentB的基因链也切成两段。
先将ParentB的一半基因链接在ParentA的一半基因链后面,从而产生ChildA;同理可得ChildB,只是交换了ParentA和ParentB的顺序。
突变
ParentA(1111111111111111) ParentB(0000000000000000) Mutation ChildA(1111111101111111) ChildB(0000000000100000)
这里ChildA从ParentA中得到了全部的基因,但是可以发现,其中ChildA中有一位是0,而0显然不是ParentA的基因,所以这便是突变。
同理可得ChildB。
倒置
ParentA(1111111111111111) ParentB(0000000000000000) Inversion ChildA(1111111100011111) ChildB(0000000111100000)
这个操作的结果有点类似突变。其实这个的操作过程是这样的:去ParentA的一个片段,对这个片段中每一个基因进行取反,从而得到了ChildA。
3.基本流程
基因算法的流程也是简单易懂的,接下来就大致描述一下这个流程:首先便是创建群体,不断随机创建个体。
从当前群体中挑选两个优秀个体,对其基因进行重组,生成两个新个体,这两个新个体便组成了新一代的群体。
利用步骤2,创建一个与当前群体容量相当的新一代群体,便将新一代群体设定为当前群体。
判断是否得到了我们所需要的个体,如果得到就停止算法。
判断群体是否不再符合要求(失去了多样性),如果不符合就停止算法;如果符合就继续步骤3。
伪代码:
Population[2][NUM]; //随机获得NUM个个体,并放入群体Population[0]中去 Rand(Population[0]); curGeneration = 0; While(TRUE) { newGeneration = curGeneration == 1 ? 0 : 1; For(i = 0 ; i < NUM ; ++i) { //select : 从当前群体Population中挑选优秀的个体作为此次操作的父辈 ParantA = Select(Population[curGeneration]); ParentB = Select(Population[curGeneration]); //Recombination: 重组ParentA和ParentB的基因链,获得新个体Child Child = Recombination(ParentA,ParentB); //计算新一代个体的适应值 CalculateFitness(Child); //如果获得Child并不比父辈的优秀,重新重组 If(Child.Fitness< ParentA.Fitness || Child.Fitness < ParentB.Fitness) { --i; Continue; } //将新个体加入新一代的群体中 Population[newGeneration][i]= Child; } //当群体之间的个体差异很小的时候,考虑退出算法 If(avgfitness / maxfitness > 0.99999) Break; curGeneration = newGeneration; }
二、TSP问题
1.TSP问题介绍
这里举TSP问题,TSP问题在另一篇文章《AI中的几种搜索算法---SA搜索算法》有提到过,那个时候主要用的是SA算法对这个问题进行了求解。这里我们会用基因算法,再次求解这个问题。虽然已经介绍过TSP问题,这里为了阅读的方便,我就直接拷贝了《AI中的几种搜索算法---SA搜索算法》的部分内容。
TSP问题即旅行商问题:一个旅行商A被分配到一个任务,公司要求A去几个城市进行公司业务拓展,所以A就会拿出地图制定一个合理的路线。其中路线的要求便是消耗最小,并且能够从某一个城市出发,并且最后返回该城市时,已经访问过了所有城市。
2.TSP问题分析
这里我们可以计算出整个路线的路程。而这个路程和我们之前提到过的Fitness成反比,路程越长,表示这个路线越差。对于这个公式,我稍作解释:Fitness就是我们一直提到的适应能力(适应值),Length(solution)计算路线solution的路程长度。
杂交算子
这里我们介绍一个新的基因重组算法。较之于之前介绍的“交叉”、“突变”和“倒置”,这个算法会复杂一点。
杂交算子,算法来于《构建“基因库”求解TSP问题的混合遗传算法》
接下来开始介绍:
首先从当前群体中,随机选取两个优秀的个体作为父辈:ParentA和ParentB。
随机选取两个基因位置(即处于基因链中第几个位置):PosA1和PosA2。
找到ParentA基因链,PosA1和PosA2位置处的基因:G1和G2。
找到ParentB基因链中基因G1和G2所处的位置:PosB1和PosB2。
将ParentB基因链中,与处于ParentA基因链PosA1和PosA2之间相同的基因去掉。
然后如果PosB1 < PosB2,将处于ParentA基因链PosA1和PosA2之间的基因片段,在ParentB基因链的PosB1位置开始顺序插入;
如果PosB1 >= PosB2,将将处于ParentA基因链PosA1和PosA2之间的基因片段,在ParentB基因链的PosB2位置开始逆序插入。
经过步骤6之后,得到新个体Child,如果Child并没有比父辈优秀,则再回到步骤1,继续相同操作;如果新个体优于父辈,则将新个体放入新一代群体中,再继续产生下一个个体。
下面举一个具体的例子
随机取PosA1 = 3 , PosA2 = 6 , 得到基因G1 = 3 , G2 = 6 在ParentB基因链的位置PosB1 = 8 , PosB2 = 5 ParentA : 1 2 3 4 5 6 7 8 9 ParentB: 2 4 7 8 6 5 1 3 9 将ParentB基因链,去除基因 3,4,5,6 得到: ParentB: 2 x 7 8 x x 1 x 9 因为PosB1 > PosB2,所以在PosB2处开始逆序插入(3,4,5,6) 得到: Child: 2 7 8 6 5 4 3 1 9
代码
如果想要详细了解可以去基因算法解决TSP问题处下载
下面是整个基因算法的流程代码:
int tsp_ga(City * cities,intnCities,int ** path) { srand(time(NULL));// *path = new int[nCities]; floatsumCurFitness ; //初始化群体,随机得到一群个体 InitPopulation(cities,nCities,sumCurFitness); intcurGeneration = 0,generation = 0; int iBest =0; for(;1 ;++generation)//循环 { int newGeneration = curGeneration == 0 ? 1 : 0; float sumFitness = 0.0 , maxFitness = 0.0; //开始获得新个体 for (int i = 0 ; i< NUMPOPULATION ; ++i) { //选取优秀个体作为父辈 int parenta =SelectParent(curGeneration,sumCurFitness); int parentb =SelectParent(curGeneration,sumCurFitness); //开始重组父辈的基因链,获得新个体 //这里使用上面介绍的杂交算法 Recombination(population[curGeneration][parenta],population[curGeneration][parentb], population[newGeneration][i],nCities); //计算新个体的fitness CaculateFitness(cities,nCities,population[newGeneration][i]); float fitness= population[newGeneration][i].fitness; //如果新个体并没有比父辈优秀,重新产生新个体 if(fitness< population[curGeneration][parenta].fitness || fitness <population[curGeneration][parentb].fitness) { --i; continue; } if(fitness> maxFitness) { maxFitness = fitness; iBest = i; } sumFitness += fitness; } sumCurFitness = sumFitness; curGeneration = newGeneration; float result = sumFitness / (maxFitness*NUMPOPULATION ); if( result > 0.99999)//如果群体中个体差异很小,停止算法 break; } for (int i = 0 ; i < nCities ; ++i) { (*path)[i] =population[curGeneration][iBest].path[i]; } //清理资源 for (int i = 0; i < NUMPOPULATION ; ++i) { delete[]population[0][i].path; delete[]population[1][i].path; } returngeneration; } //下面就是基因链重组算法的实现代码
void Recombination(constIndividual & parenta,const Individual &parentb,Individual & child,int n) { int posa1 =rand()%(n-1); int posa2 =rand()%n; while(posa2<= posa1) posa2 = rand()%n; // int lseg =posa2 - posa1 + 1; int * genseg= new int[lseg]; for(int i = posa1 ; i <= posa2 ; ++i) genseg[i-posa1] = parenta.path[i]; //// int posb1 =-1,posb2 = -1; int iChild =0 , iStartInsert = 0; for(int i = 0 ; i < n ; ++i) { int gb =parentb.path[i]; int j =0; for(; j< lseg; ++j) { intg = genseg[j]; if(gb== g) { if(0== j) { posb1 = i; iStartInsert = iChild; iChild += lseg; } elseif(j == (lseg-1)) posb2 = i; break; } } // if(lseg== j) { child.path[iChild++] = gb; } } if(posb1< posb2) for(int i = 0 ; i < lseg ; ++i) child.path[i + iStartInsert] =genseg[i]; else for(int i = 0 ; i < lseg ; ++i) child.path[i + iStartInsert] =genseg[lseg - i -1]; delete[]genseg; }
效果图
三、总结
基因算法总的来说体现了一个“优胜劣汰”的法则,优秀的基因存活下来。而且基因算法从针对于个体转到了群体,有别于A*这些普通的启发式算法。其中我在实现这个算法的时候,在尝试基因链重组算法的时候,一直没有找到一个能够保证优秀基因遗传下去的好方法,所在在网上搜了一下关于TSP和基因算法,找到了一篇论文《构建“基因库”求解TSP问题的混合遗传算法》,有兴趣的读者可以去看一下这篇文章。
如果有兴趣的可以留言,一起交流一下算法学习的心得。
相关文章推荐
- AI中的几种搜索算法---基因算法
- AI中的几种搜索算法---基因算法
- AI中的几种搜索算法---基因算法
- AI中的几种搜索算法---A*搜索算法
- AI中的几种搜索算法---SA搜索算法
- AI中的几种搜索算法---SA搜索算法
- AI中的几种搜索算法---A*搜索算法
- AI中的几种搜索算法---Tabu搜索算法
- AI中的几种搜索算法---Tabu搜索算法
- 五子棋AI算法第二篇-极大极小值搜索算法
- 不能滥用穷举暴力:关于几种不同图搜索算法的详细分析与思考
- Ubuntu 16.04安装OpenAI Gym的几种方法
- python在线调用AI平台API的几种方法
- 当前 Java 软件开发中几种认识误区
- 几种计算机语言的评价
- c#调用c++ dll的几种类型转换
- Spring定时任务的几种实现
- Android之Activity的几种跳转方式
- PHP中判断变量为空的几种方法
- jira插件带ui界面和几种方式