遗传算法是一类借鉴达尔文自然选择原理和孟德尔遗传机理而创制的仿生算法,通过模拟生物的代际进化,解决优化问题。
自然选择与遗传机制
在介绍遗传算法之前,我们需要知道一些基本的生物学概念、理论:
基因:基因也叫遗传因子。从承载生命信息的角度来说,基因承载着与生物体的生长、发育、疾病、死亡相关的一切“信息”,可以说所有生命现象都与基因有关;生命活动也无不由基因调控。从物质角度来说,承载着遗传信息的脱氧核糖核酸(DNA)片段为基因。
性状:可遗传的发育个体和全面发育个体可以观察到的特征,包括形态特征、生理特征、行为特征等。生物体的性状是由基因控制的。
遗传:指亲代的性状通过无性繁殖或有性繁殖遗传给子代,使子代继承亲代的特性。在有性生殖中,亲代各提供一部分基因融合为子代的基因,因此子代有可能具有亲代双方的特征。
变异:这里仅指发生在遗传过程中且可遗传的变异,即基因发生歧变(如DNA片段的缺失、重复、倒位等)导致遗传信息发生变化。变异可能会影响形状;从根本上来说,变异是生物进化的根源。
达尔文进化论:自然环境中资源有限,生物具有过度繁殖的倾向,会争夺各类生存资源;因此种群内部存在竞争。由于遗传和变异,生物性状具有多样性(本质上基因具有多样性),而环境倾向于使具有某类性状的生物获取资源、生存繁衍的机会;而因为性状不适应环境的个体因为在竞争中失败,会丧失生命,逐渐被淘汰。这样的过程就是自然选择;生物因自然选择而进化。
核心关系:①基因决定性状,性状很大程度决定生物是否适应环境;基因不是一成不变的,通过遗传和变异让子代产生新的性状。
②自然选择淘汰了不适应环境的个体,但也让适应环境的个体存活下来,得以繁衍。生物对环境的适应性来源于基因,因此“适应环境的基因”也得以遗传。
③将种群(彼此可交配繁殖的个体集合)中的全部基因看做一个整体,“基因池”;随着自然选择的进行,基因池中的基因在整体分布上发生着深刻的变化,这就是生物的进化。
理论的迁移
众所周知,自然选择学说与遗传理论在科学史上具有中心性的地位,且对人类思想史有着深刻的影响,其理论、概念被迁移、应用到了社会学、人类学、哲学等领域。而今天我们要谈的遗传算法,就是融合了该理论的一种启发式算法。
我们可以思考以下的问题:为什么自然选择学说和遗传理论可以被迁移到解决优化问题上来?或者说,解优化问题和生物进化有何相似性:
如果将优化问题的解看做生物个体,同时也看做生物的基因;优化问题的目标函数看做“自然选择”的标准。那么对每个解而言,它们的目标函数值不同,正如每个生物个体在自然选择前的“适应度”不同。目标函数值更符合期待的解如更适应自然选择的个体,而不符合期待的解如不适应自然选择的个体;
通过某种规则,让两个解生成一个能反映双方特征的新解,且通过引入随机变动让解“变异”,增加解的多样性,就能丰富解的范围,正如产生具有基因多样性的种群;
最后,基于适应度(目标函数决定的“自然选择”)淘汰适应度低的解(个体),保留适应度高的解(个体)。适应度高的解可能具有某种“好”的特征,在后续两两作用产生新解的过程中,有可能产生更“好”(适应度更高的个体)的解,这正如生物的优良特性代际累积,从而进化。每轮进化生物体的适应度都在变高,这等同于问题的解朝最优解靠近,因而通过模拟进化过程,有可能得到优化问题的最优解。
对应关系:解--个体 基于目标函数给出的适应度--对自然的适应度
两个解按规则产生新解--繁殖 解随机变动--变异 适应度低的淘汰--自然选择
总体上“解”变好--进化
以上即为遗传算法的思想,实际上遗传算法是可行的,而且在解决某些复杂优化问题上效果奇佳。关于遗传算法另有许多相关理论,在此不再赘述。
遗传算法步骤
以上谈到的均为思想。实际操作中,遗传算法的流程可以表述为:
①对解进行编码;
②根据优化问题目标定义适应度函数;
③确定遗传策略,包括种群大小,选择、交叉、变异方式;明确对应的概率参数。
④随机产生初始种群。
⑤计算当前种群各个体的适应度;
⑥按照遗传策略进行选择、交叉、变异,生成下一代种群;
⑦如果种群适应度达到预定指标或者迭代次数达最大迭代次数,则停止,输出当前种群最优的个体;否则转⑥。
对步骤的细化解释
①对解的编码
编码即用数值的形式表示优化问题的可行解。编码的不同形式有:二进制编码、整数编码、浮点数编码,等。
二进制编码:用二进制数序列表示解。比如对于某组合问题,二进制数可以表示n个不同的选择(0或1)的组合。这种方式解码、交叉、变异方便,但无法处理连续优化问题。
整数编码:用整数序列表示解。比如某问题的解可以表示为一个整数排序(如TSP)。
浮点数编码:,为浮点数。该编码方式适合于大范围、高精度搜索、有复杂约束的情况;交叉、变异需要限定范围。
对解的编码需要分析问题后进行。比如求解无约束优化,采用浮点数编码:.个体为一个二维向量,种群为的一个子空间。
②定义适应度函数
适应度函数需要能反映解的优劣性。比如中,可令为适应度函数,解越优越小,适应度越大。或者直接令为适应度,适应度越小解越优(说法问题)。
③遗传策略
选择、交叉、变异都可以一定概率进行,保证随机性。交叉概率常取0.4-0.99,变异概率常取0.001-0.2,具体取值分析问题而定。交叉概率取大可保证充分交叉,但时间消耗大;变异概率太小则收敛慢,太大则算法趋于随机,不稳定。
其余参数的取值:可取初始种群数量200-2000,进化代数20-1000。
选择、交叉、变异方式是遗传算法的核心。方法很多,例如:
选择:
锦标赛选择:从总体中选择若干个个体,选择适应度最大(假定适应度最大就是好,下同)的个体进入下一代;
随机竞争选择:每次选定一对个体,选择适应度大的那个进入下一代;
轮盘赌选择:所有个体以一定概率进入下一代,进入下一代的概率跟个体的适应度成正比。
交叉:
单点交叉:编码序列中选择一个位点将两个个体的基因片段切开,将二者切开的片段重新组合形成新的个体;
双点交叉:编码序列取两个位点切开,交换位点之间的基因片段。(还可定义多点交叉)
重组:打碎重组。
变异:
位变异:某个点位的基因变异。
子串变异:某个基因子串替换为新的。
插入/删除变异:插入/删除一些基因片段的变异。
④随机产生初始种群
即随机产生一些初始解。中如果已经知道最优解在区间[-1,1]上,将初始解限制在[-1,1]上即可。
⑤计算适应度
⑥执行遗传、进化策略
比如计算一代种群的适应度后,单点交叉、单位点变异产生新个体,原个体+新个体中选择适应度最高的种群规模个个体,形成下一代种群。
⑦迭代与终止
遗传算法达到终止条件:比如解的函数值达到某精度,或者完成任务,则终止;或者达到最大迭代次数则终止。遗传算法有收敛过早的可能性,即一定代数后目标值下降趋于0,意味着算法后期的一些迭代是徒劳的。
程序实现
以下是用Matlab实现的函数寻优式的遗传算法代码。关于其他优化问题(主要是TSP)的遗传算法解决,后续会写文章阐述。
function [bestone,bestf]=GA(f,dim,n,pcross,pvari,area,maxiter)
%遗传算法GA(函数优化)
%引用的函数f
%函数的维数dim
%种群数量n
%交叉概率pcross
%变异概率pvari
%寻优范围area
%最大迭代次数maxiter
%1.产生初始种群
iter=0;
ppl=2*area*(rand(dim,n)-0.5);
allbestf=[];
while(iter<maxiter)
%2.交叉互换(单点交叉)
[~,numppl]=size(ppl);
for i=1:numppl
r=rand(1);
if(r<pcross)%以交叉概率交叉
x1=ppl(:,i);%选中种群中每一个个体,使之有机会交叉
x2=ppl(:,randi(numppl));%随机选中一个个体与x1交叉
%随机选择一个2-末尾的位点,交叉互换2-末尾的基因片段
if(dim>=2)
cut=randi(dim-1)+1;
end
if(dim==1)
cut=1;
end
replace=x1(cut:dim,1);
x1=[x1(1:cut-1,1);x2(cut:dim,1)];
x2(cut:dim,1)=replace;
ppl=[ppl,x1,x2];%交换产生的两个子代纳入种群中
end
end
[~,numppl]=size(ppl);%更新种群数量
%3.变异(单基因突变)
for j=1:numppl
r=rand(1);
if(r<pvari)
x=ppl(:,j);
replace=area*(rand(1)-0.5);
x(randi(dim),1)=replace;
ppl=[ppl,x];
end
end
%4.筛选
[~,index]=sort(f(ppl));%按适应度升序给个体排序
ppl=ppl(:,index(1,1:n));%这些个体进入下一代,其余淘汰
bestone=ppl(:,1);
bestf=f(bestone);
iter=iter+1;
allbestf=[allbestf,bestf];
end
disp('函数值下降曲线:')
plot(1:iter,allbestf)
end
输入:要传入的目标函数f,函数的变量数dim,种群数量n,交叉概率pcross,变异概率pvari,寻优范围area,最大迭代次数maxiter.
寻优范围area是一个正常数,选定后n维函数在[-area,area]*[-area,area]*...*[-area,area](n个)这一n维正方体内寻优。限定范围减少了搜索成本,算是我代码的独创之处吧。
该程序的参数需要手动输入而非默认,主要是为了方便观察遗传算法的收敛情况并且方便灵活调整。如果你对遗传算法不熟悉,可以取n=200,pcross=0.8,pvari=0.2,area=10,maxiter=100,有问题再调整。
程序会绘制遗传算法最优值随迭代次数的下降图。
优势
遗传算法可以找到函数最值点而不陷入局部最优。
Schaffer函数:
Schaffer函数
函数在上有无穷多局部极小值点,极小值-0.99027;全局最小值点为(0,0),最小值-1。
同时运用遗传算法和Matlab自带的优化问题求解器求函数最值:
[x,minf]=GA(@f,2,1000,0.8,0.99,10,300)
[x2,minf2]=fmincon(@f,[1,1]')
function y=f(x)
y=((sin((x(1,:).^2+x(2,:).^2).^0.5)).^2-0.5)./(((x(1,:).^2+x(2,:).^2)*0.001+1).^2)-0.5;
end
发现Matlab自带的求解器陷入了局部最优,而遗传算法很好地找到了全局最小值点,而且是在搜索范围较大的情况下。收敛也十分快。
技术细节
如果缩减搜索范围area:
[x,minf]=GA(@f,2,1000,0.8,0.99,10^-1,300)
[x2,minf2]=fmincon(@f,[1,1]')
function y=f(x)
y=((sin((x(1,:).^2+x(2,:).^2).^0.5)).^2-0.5)./(((x(1,:).^2+x(2,:).^2)*0.001+1).^2)-0.5;
end
会发现遗传算法解的精度提升了。这提示我们如果能预先确定最优解的大致范围可以提高解的精度。且精度提高的机理可以想象:趋近于最优解是相当于x,y趋于0,(总体意义上而非局部最优),则优秀的个体=x,y绝对值都很小的个体。个体的优良特性=x或y的绝对值很小,在遗传中保留;随机数产生x,y更小的变异(需要限定范围)--->产生更优个体,进化。可以看到代际优势得到了保留,这也可以从最优值是逐代下降的看出来。