遗传算法的并行实现.docx

上传人:b****6 文档编号:7140290 上传时间:2023-01-21 格式:DOCX 页数:24 大小:172.89KB
下载 相关 举报
遗传算法的并行实现.docx_第1页
第1页 / 共24页
遗传算法的并行实现.docx_第2页
第2页 / 共24页
遗传算法的并行实现.docx_第3页
第3页 / 共24页
遗传算法的并行实现.docx_第4页
第4页 / 共24页
遗传算法的并行实现.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

遗传算法的并行实现.docx

《遗传算法的并行实现.docx》由会员分享,可在线阅读,更多相关《遗传算法的并行实现.docx(24页珍藏版)》请在冰豆网上搜索。

遗传算法的并行实现.docx

遗传算法的并行实现

遗传算法的并行实现

章衡2007310437

一、问题描述

遗传算法是通过模拟自然界生物进化过程来求解优化问题的一类自组织、自适应的人工智能技术。

它主要基于达尔文的自然进化论和孟德尔的遗传变异理论。

多数遗传算法的应用是处理一个由许多个体组成的群体,其中每个个体表示问题的一个潜在解。

对个体存在一个评估函数来评判其对环境的适应度。

为反映适者生存的思想,算法中设计一个选择机制,使得:

适应度好的个体有更多的机会生存。

在种群的进化过程中,主要存在两种类型的遗传算子:

杂交和变异。

这些算子作用于个体对应的染色体,产生新的染色体,从而构成下一代种群中的个体。

该过程不断进行,直到找到满足精度要求的解,或者达到设定的进化代数。

显然,这样的思想适合于现实世界中的一大类问题,因而具有广泛的应用价值。

遗传算法的每一次进化过程中的,各个体之间的操作大多可以并列进行,因此,一个非常自然的想法就是将遗传算法并行化,以提高计算速度。

本报告中试图得到一个并行遗传算法的框架,并考察并行化之后的一些特性。

为简单起见(本来应该考虑更复杂的问题,如TSP。

因时间有些紧张,请老师原谅),考虑的具有问题是:

对给定的正整数n、n元函数f,以及定义域D,求函数f在D内的最大值。

二、串行遗传算法

1.染色体与适应度函数

对函数优化问题,一个潜在的解就是定义域D中的一个点

,因此,我们只需用一个长度为n的实数数组来表示一个个体的染色体。

由于问题中要求求函数f的最大值,我们可以以个体所代表点

在f函数下的值来判断该个体的好坏。

因此,我们直接用函数f作为个体的适应度函数。

2.选择机制

选择是遗传算法中最主要的机制,也是影响遗传算法性能最主要的因素。

若选择过程中适应度好的个体生存的概率过大,会造成几个较好的可行解迅速占据种群,从而收敛于局部最优解;反之,若适应度对生存概率的影响过小,则会使算法呈现出纯粹的随机徘徊行为,算法无法收敛。

下面我们介绍在实验中所使用的选择机制。

我们定义

为当前种群内所有个体的集合,

中所有个体的一个固定排列。

为某一个体,

表示该个体的适应度,则种群

的适应度定义为:

对任意个体

的相对适应度定义为

累积适应度定义为

进行选择之前,先产生一个0到1之间的随机实数

,若满足

,则第k+1个个体被选中。

循环以上过程,即得到生成下一代种群的母体。

具体实现见如下函数:

voidpop_select(void)

{

intmem,i,j,k;

doublesum=0;

doublep;

/*计算种群适应度之和*/

for(mem=0;mem

sum+=(population[mem].fitness-lower_fitness);

}

/*计算相应适应度*/

for(mem=0;mem

population[mem].rfitness=(population[mem].fitness-lower_fitness)/sum;

}

population[0].cfitness=population[0].rfitness;

/*计算累积适应度*/

for(mem=1;mem

population[mem].cfitness=population[mem-1].cfitness+

population[mem].rfitness;

}

/*按照累积适应度概率选取母体种群*/

for(i=0;i

p=rand()%1000/1000.0;

if(p

newpopulation[i]=population[0];

else{

for(j=0;j

if(p>=population[j].cfitness&&

p

newpopulation[i]=population[j+1];

}

}

for(i=0;i

population[i]=newpopulation[i];

}

3.杂交算子

杂交算子的流程一般如下:

(1)按杂交概率选择一对参与进化的个体;

(2)随机确定一个截断点;

(3)将两个个体的染色体从截断点处截断,并交换,从而得到新的染色体。

具体算法见如下函数:

voidcrossover(void)

{

inti,j,k,m,point;

intfirst=0;

doublex;

for(k=0;k

x=rand()%1000/1000.0;

if(x

{

first++;

if(first%2==0){

if(NVARS==2)point=1;

elsepoint=(rand()%(NVARS-1))+1;

for(j=0;j

swap(&population[m].gene[j],&population[k].gene[j]);

}

elsem=k;

}

}

}

4.变异

变异操作的实现相当简单,只需遍历各染色体的各个单元,按某一变异概率将该单元变成一个随机的合法值。

具体操作如下函数所示:

voidmutate(void)

{

inti,j;

doublelbound,hbound;

doublex;

for(i=0;i

for(j=0;j

x=rand()%1000/1000.0;

if(x

population[i].gene[j]=randval(lower[j],upper[j]);

}

}

}

串行遗传算法的主要流程如图1所示。

在每一次进化过程中,总是找出种群中的最优解与最差解,并将最优解保存,将本次最差解用上次保存的最优解替换,这样保证了各次进化的最优解的适应度不会降低,从而增快收敛的速度。

图1串行遗传算法基本流程

三、算法设计

分析图1中的串行算法,容易看出,在选择函数中,计算相对适应度需要用到全局种群的适应度之和,计算个体xk+1的累积适应度依赖于xk的累积适应度,如果在并行算法中要原封不动地模拟串行算法的运算,这些数据依赖关系都将产生通讯。

更为不幸的是,选择后的个体需在各进程中作大量数据迁移。

杂交算子中,一次杂交需要用到母体中的两个个体,若在这两个个体分配在不同进程,则需要进行一次通讯。

此后的变异和评估都可以非常容易的实现并行,并且完全不需要任何通讯。

但最后一步求最优个体和最差个体需要对各进程进行归约。

由这些分析可以看出,完全地模拟串行情形将使算法变得相当低效。

幸运地是,遗传算法本身是一个概率算法,我们完全可以对串行算法作些必要的改变。

如图2所示,我们将整个种群分成p个子种群,每一子种群由一个单一的进程负责。

各进程独立地完成串行遗传算法的整个过程,唯一不同的是选择函数。

各进程作选择操作时,首先计算各子种群内的局部累积适应度,然后根据局部累积适应度选择若干(本算法实现中使用的时常数3,也可以设为子种群大小的一个函数)个体按一固定规则轮流发送到其他进程;同时,按照该规则相应地从其他进程获取若干用来进行交流的个体。

获取到个体后,先将其暂存;然后按串行算法中的选择机制从原子种群中选择进行进化的母体;最后再用之前暂存的个体完成进程间的种群交流。

对每一个待交流的个体,具体策略如下:

(1)随机地从本地的待进化母体种群内抽取与之进行交流的母体;

(2)比较本地个体与传送过来的待交流个体,选取适应度高者作为最终母体。

各进程在每一次进化过程中,均分别保留各自的局部最优解,用来在下一次进化中替换局部最差的个体。

各进程均完成所预定的进化迭代后,最后对各进程的局部最优解进行归约,从而得到整个算法的全局最优解。

算法的主要流程详见图2。

图2并行遗传算法基本流程

四、算法实现

该算法实现的最关键部分为选择中的种群交流,该功能有如下函数实现

voidpop_select(void)

{

MPI_Statusstatus;

MPI_Requesthandle;

intmem,i,j,k;

doublesum=0;

doublep;

staticstructgenotypeex_member[EX_NUM];

/*计算子种群的总适应度*/

for(mem=0;mem

sum+=(population[mem].fitness-lower_fitness);

}

/*计算各个体相应适应度*/

for(mem=0;mem

population[mem].rfitness=(population[mem].fitness-lower_fitness)/sum;

}

population[0].cfitness=population[0].rfitness;

/*计算各个体累积适应度*/

for(mem=1;mem

population[mem].cfitness=population[mem-1].cfitness+population[mem].rfitness;

}

/*按照累积适应度概率选取种群交流个体,并发送和接收*/

for(i=1;i<=EX_NUM;i++){

p=rand()%1000/1000.0;

if(p

MPI_Isend(&population[0],sizeof(structgenotype)/sizeof(char),

MPI_CHAR,(pid+i*generation)%pnum,0,MPI_COMM_WORLD,&handle);

}

else{

for(j=0;j

if(p>=population[j].cfitness&&p

MPI_Isend(&population[j+1],sizeof(structgenotype)/sizeof(char),

MPI_CHAR,(pid+i*generation)%pnum,0,MPI_COMM_WORLD,&handle);

break;

}

}

MPI_Recv(&ex_member[i-1],sizeof(structgenotype)/sizeof(char),MPI_CHAR,

(pid+(pnum-i)*generation)%pnum,0,MPI_COMM_WORLD,&status);

}

/*按照累积适应度概率选取母体种群*/

for(i=0;i

{

p=rand()%1000/1000.0;

if(p

newpopulation[i]=population[0];

else{

for(j=0;j

if(p>=population[j].cfitness&&

p

newpopulation[i]=population[j+1];

}

}

for(i=0;i

population[i]=newpopulation[i];

/*按优胜劣汰的原则完成种群交流*/

for(i=0;i

j=rand()%TASK_NUM(pid);

if(population[j].fitness

for(k=0;k

population[j].gene[k]=ex_member[i].gene[k];

}

population[j].rfitness=0;

population[j].cfitness=0;

population[j].fitness=ex_member[i].fitness;

}

}

}

另外,全局最优解的归约由如下代码实现:

MPI_Op_create((MPI_User_function*)gene_max,1,&my_op);

MPI_Reduce(local_best_individual,best_individual,NVARS+1,

MPI_DOUBLE,my_op,pnum-1,MPI_COMM_WORLD);

其中,具体的归约操作由如下函数实现:

voidgene_max(double*in,double*inout,int*len,MPI_Datatype*dptr)

{

inti;

if(inout[0]

for(i=0;i<*len;++i){

inout[i]=in[i];/*复制适应度较高的个体*/

}

}

}

五、算法分析与实验结果

下面的实验结果是在166.111.143.24上利用结点cn115和cn116获得的。

用来计算最大值的函数为

其定义域如文件ga_data.txt中所示,总种群大小为500,最大进化次数为2000。

进程个数

1

2

3

4

5

6

7

运算时间

32.308594

9.132812

4.335938

2.777344

3.699219

2.949219

2.621094

加速比

1

3.537639

7.451351

11.632910

8.733896

10.954966

12.326377

x1

22.455050

22.455050

22.455050

22.455050

22.455050

22.455050

22.455050

x2

7.205500

7.279000

7.289500

7.237000

7.289500

7.289500

7.289500

x3

19.269500

19.239000

19.269500

19.269500

19.269500

19.269500

19.269500

x4

4.944000

4.992000

4.072000

4.984000

4.888000

4.984000

4.968000

x5

-1.193000

-1.196500

-1.200000

-1.200000

-1.200000

-1.196500

-1.200000

x6

-9.120000

-9.113180

-9.072260

-9.120000

-9.120000

-9.120000

-9.120000

f

157521400.960884

157373629.694664

157325373.684378

157701606.886265

157673921.515628

157623544.425141

157702393.783168

进程个数

8

9

10

11

12

13

14

运算时间

2.226562

2.574219

2.449219

2.617188

2.289062

2.664062

2.597656

加速比

14.510530

12.550833

13.191386

12.344774

14.114338

12.127568

12.437595

x1

22.455050

22.455050

22.455050

22.455050

22.455050

22.455050

22.455050

x2

7.289500

7.289500

7.279000

7.289500

7.289500

7.289500

7.279000

x3

19.269500

19.269500

19.269500

19.269500

19.269500

19.269500

19.269500

x4

4.920000

4.976000

4.992000

4.984000

4.992000

4.968000

4.992000

x5

-1.200000

-1.200000

-1.200000

-1.200000

-1.200000

-1.196500

-1.200000

x6

-9.120000

-9.120000

-9.120000

-9.120000

-9.120000

-9.120000

-9.120000

f

157689427.608764

157704566.391334

157624693.663186

157706742.306205

157708921.527178

157619195.230127

157707891.211178

表1实验结果

表1中最为有趣的现象是,当进程数小于5时,该算法的加速比似乎与进程数p存在一个平方关系,也就是说,存在一个超线性加速的关系。

进程数大于等于5时,这种超线性加速实际也应该存在,只是由于节点数的限制,被进程管理的开销所限制。

下面我们通过估计时间复杂性来分析造成这种超线性加速的原因。

如果将对染色体中每一变元上的一个计算看作一个基本计算,并设变元数为k,总种群中个体数为n,进程数则对每一进程,分析容易得到:

pop_select函数最坏情形的时间复杂性为O((kn/p)2),crossover函数最坏情形的时间复杂性为O(kn/p),mutate函数最坏情形的时间复杂性为O(kn/p),评估函数最坏情形的时间复杂性为O(kn/p),elitist函数最坏情形的时间复杂性为O(n/p+k)。

此外,按照算法的设计,在选择过程中的通讯所耗费的时间为O(kn/p)。

综合可知,一次进化的时间复杂性为O((kn/p)2)。

因此,所有进程总的计算时间醉最坏情形的渐近上界为O((kn)2/p)。

而串行遗传算法一次进化的时间复杂性为O((kn)2),这就解释了为什么p小于5的情形会具有超线性加速。

当然,这并不能说明并行计算真能产生超线性加速比,因为我们可以非常有效地用一个进程来模拟p个进程的计算,也就是说在串行的情形下也能达到这样的加速。

真正值得研究的问题是分析上述建立并行遗传算法的收敛速度与串行遗传算法的收敛速度之间的关系。

不过从表1可以看出,进程增加时,解得质量并没有任何降低。

因为时间的限制,不能在这里进行进一步的理论分析,请老师谅解。

六、源程序清单

#include"mpi.h"

#include

#include

#include

#definePOPSIZE500

#defineNVARS6

#defineMAXGENS2000

#definePXOVER0.8/*杂交概率*/

#definePMUTATION0.15/*变异概率*/

#defineTASK_NUM(i)((POPSIZE+pnum-1)/pnum)

#defineEX_NUM3

structgenotype

{

doublegene[NVARS];

doublefitness;/*适应度*/

doublerfitness;/*相对适应度*/

doublecfitness;/*累积适应度*/

}*population,*newpopulation;

doubleupperbound[NVARS];

doublelocal_best_individual[NVARS+1];/*局部最优解*/

doublebest_individual[NVARS+1];/*全局最优解*/

intgeneration;

doublelower_fitness;

FILE*galog;

intpid,pnum;

doublerandval(doublelow,doublehigh)

{

doubleval;

val=((double)(rand()%1000)/1000.0)*(high-low)+low;

returnval;

}

voidinitialize(void)

{

FILE*infile;

inti,j,r;

doublelbound,ubound;

MPI_Statusstatus;

population=malloc(sizeof(structgenotype)*(TASK_NUM(pid)+1));

newpopulation=malloc(sizeof(structgenotype)*(TASK_NUM(pid)+1));

if(pid==pnum-1){

if((infile=fopen("ga_data.txt","r"))==NULL)

{

fprintf(galog,"\nCannotopeninputfile!

\n");

exit

(1);

}

srand(time(0));

for(i=0;i

r=rand();

MPI_Send(&r,1,MPI_INT,i,1,MPI_COMM_WORLD);

}

fo

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 院校资料

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1