当前位置:文档之家› 遗传算法的并行实现

遗传算法的并行实现

遗传算法(基于遗传算法求函数最大值)指导老师:刘建丽学号:S201007156姓名:杨平班级:研10级1班遗传算法一、 遗传算法的基本描述遗传算法(Genetic Algorithm ,GA )是通过模拟自然界生物进化过程来求解优化问题的一类自组织、自适应的人工智能技术。

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

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

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

为反映适者生存的思想,算法中设计一个选择机制,使得:适应度好的个体有更多的机会生存。

在种群的进化过程中,主要存在两种类型的遗传算子:杂交和变异。

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

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

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

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

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

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

因时间有些紧张,做如TSP 等复杂问题怕时间不够,做不出来,请老师原谅),考虑的具有问题是:对给定的正整数n 、n 元函数f ,以及定义域D ,求函数f 在D 内的最大值。

二、 串行遗传算法1. 染色体与适应度函数对函数优化问题,一个潜在的解就是定义域D 中的一个点011(,,...,)n x x x -,因此,我们只需用一个长度为n 的实数数组来表示一个个体的染色体。

由于问题中要求求函数f 的最大值,我们可以以个体所代表点011(,,...,)n x x x -在f 函数下的值来判断该个体的好坏。

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

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

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

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

我们定义P 为当前种群内所有个体的集合,(0)(1)(1),,...,n x x x -为P 中所有个体的一个固定排列。

若xP ∈为某一个体,()f x 表示该个体的适应度,则种群P 的适应度定义为:1()0()()n i i s P f x -==∑ 对任意个体x P ∈,x 的相对适应度定义为()()/()r x f x s P =。

相对适应度()r x 反映了个体()i x 的适应度在整个适应度总和中所占的比例。

个体适应度越高,被选中的概率越高。

累积适应度定义为:进行选择之前,先产生一个0到1之间的随机实数t ,若满足1()()k k r x t r x +≤<,则第k+1个个体被选中。

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

具体实现见如下函数:void pop_select(void ) { int mem, i, j, k; double sum = 0; double p; /* 计算种群适应度之和 */for (mem = 0; mem < POPSIZE; mem++) {/* 按照累积适应度概率选取母体种群 */ for (i = 0; i < POPSIZE; i++) { p = rand()%1000/1000.0; if (p < population[0].cfitness) newpopulation[i] = population[0]; else { for (j = 0; j < POPSIZE;j++) if (p >= population[j].cfitness && p < population[j+1].cfitness) newpopulation[i] = population[j+1]; }} /*计算种群的总适应度*/ for (i = 0; i < POPSIZE; i++) population[i] = newpopulation[i];} sum += (population[mem].fitness - lower_fitness); }/* 计算相对适应度 */for (mem = 0; mem < POPSIZE; mem++) { population[mem].rfitness = (population[mem].fitness - lower_fitness)/sum; } population[0].cfitness = population[0].rfitness;/* 计算累积适应度 */for (mem = 1; mem < POPSIZE; mem++) { population[mem].cfitness = population[mem-1].cfitness + population[mem].rfitness; ()()0()()k k i i c x r x ==∑}3.杂交算子杂交算子的流程一般如下:(1)按杂交概率选择一对参与进化的个体;(2)随机确定一个截断点;(3)将两个个体的染色体从截断点处截断,并交换,从而得到新的染色体。

具体算法见如下函数:void crossover(void){int i, j, k, m, point;int first = 0;double x;for (k = 0; k < POPSIZE; k++) {x = rand()%1000/1000.0; //产生随机交叉概率if(x < PXOVER) /*如果随机交叉概率小于交叉概率,则进行交叉*/{first++;if (first % 2 == 0) {if (NVARS == 2) point = 1; //得到一个交叉点else point = (rand() % (NVARS - 1)) + 1;for (j = 0; j < point; j++)//交叉运算,两个个体的交叉点前的基因进行交换swap(&population[m].gene[j], &population[k].gene[j]);}else m = k;}}}4.变异算子在遗传算法中使用变异算子有两个目的:改善遗传算法的局部搜索能力。

维持群体的多样性,防止出现早熟现象。

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

其执行过程是:(1)对个体的每一个基因组,依变异概率Pm指定为变异点。

(2)对每一个指定的变异点,对其基因取非或者用其他等位基因值来代替,从而产生一个新的个体。

实现代码如下:void mutate(void){int i, j;double lbound, hbound;double p; //定义p为随机变异概率for (i = 0; i < POPSIZE; i++)for (j = 0; j < NVARS; j++) {p = rand()%1000/1000.0;if (p < PMUTATION) {population[i].gene[j] = randval(lower[j], upper[j]);}}}串行遗传算法的主要流程如图1所示。

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

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

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

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

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

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

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

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

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

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

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

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

对每一个待交流的个体,具体策略如下:(1)随机地从本地的待进化母体种群内抽取与之进行交流的母体;(2)比较本地个体与传送过来的待交流个体,选取适应度高者作为最终母体。

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

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

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

图2 并行遗传算法基本流程四、算法实现该算法实现的最关键部分为选择中的种群交流,该功能有如下函数实现void pop_select(void){MPI_Status status;MPI_Request handle;int mem, i, j, k;double sum = 0;double p;static struct genotype ex_member[EX_NUM];/* 计算子种群的总适应度 */for (mem = 0; mem < TASK_NUM(pid); mem++) {sum += (population[mem].fitness - lower_fitness);}/* 计算各个体相应适应度 */for (mem = 0; mem < TASK_NUM(pid); mem++) {population[mem].rfitness =(population[mem].fitness - lower_fitness)/sum;}population[0].cfitness = population[0].rfitness;/* 计算各个体累积适应度 */for (mem = 1; mem < TASK_NUM(pid); 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 < population[0].cfitness) {MPI_Isend(&population[0], sizeof(struct genotype)/sizeof(char),MPI_CHAR, (pid+i*generation)%pnum, 0, MPI_COMM_WORLD, &handle);}else {for (j = 0; j < TASK_NUM(pid);j++)if(p >= population[j].cfitness && p < population[j+1].cfitness){ 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(struct genotype)/sizeof(char), MPI_CHAR, (pid+(pnum-i)*generation)%pnum, 0, MPI_COMM_WORLD, &status);}/* 按照累积适应度概率选取母体种群 */for (i = 0; i < TASK_NUM(pid); i++){p = rand()%1000/1000.0;if (p < population[0].cfitness)newpopulation[i] = population[0];else {for (j = 0; j < TASK_NUM(pid); j++)if (p >= population[j].cfitness &&p < population[j+1].cfitness)newpopulation[i] = population[j+1];}}for (i = 0; i < TASK_NUM(pid); i++)population[i] = newpopulation[i];/* 按优胜劣汰的原则完成种群交流 */for (i = 0; i < EX_NUM; i++) {j = rand()%TASK_NUM(pid);if (population[j].fitness < ex_member[i].fitness) {for (k = 0; k < NVARS; 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 );其中,具体的归约操作由如下函数实现:void gene_max(double *in, double *inout, int *len, MPI_Datatype *dptr) { int i; if (inout[0] < in[0]) { /* 比较适应度 */ for (i=0; i < *len; ++i) { inout[i] = in[i]; /* 复制适应度较高的个体 */ } } }五、 算法分析与实验结果下面的实验结果是在192.169.129.47上利用结点vC0—168-129-48(slaver )和vC0—168-129-49(slaver )和vC0—168-129-46(slaver )获得的。

相关主题