8

一、遗传算法进化论背景知识

作为遗传算法生物背景的介绍,下面内容了解即可:

  • 种群(Population):生物的进化以群体的形式进行,这样的一个群体称为种群。

  • 个体:组成种群的单个生物。

  • 基因 ( Gene ) :一个遗传因子。

  • 染色体 ( Chromosome ) :包含一组的基因。

  • 生存竞争,适者生存:对环境适应度高的、牛B的个体参与繁殖的机会比较多,后代就会越来越多。适应度低的个体参与繁殖的机会比较少,后代就会越来越少。

  • 遗传与变异:新个体会遗传父母双方各一部分的基因,同时有一定的概率发生基因变异。

简单说来就是:繁殖过程,会发生基因交叉( Crossover ) ,基因突变 ( Mutation ) ,适应度( Fitness )低的个体会被逐步淘汰,而适应度高的个体会越来越多。那么经过N代的自然选择后,保存下来的个体都是适应度很高的,其中很可能包含史上产生的适应度最高的那个个体。

二、遗传算法思想

GA的组成:

  • 编码(产生初始种群)

  • 适应度函数

  • 遗传算子(选择、交叉、变异)

  • 运行参数

借鉴生物进化论,遗传算法将要解决的问题模拟成一个生物进化的过程,通过复制、交叉、突变等操作产生下一代的解,并逐步淘汰掉适应度函数值低的解,增加适应度函数值高的解。这样进化N代后就很有可能会进化出适应度函数值很高的个体。

举个例子,使用遗传算法解决“0-1背包问题”的思路:0-1背包的解可以编码为一串0-1字符串(0:不取,1:取) ;首先,随机产生M个0-1字符串,然后评价这些0-1字符串作为0-1背包问题的解的优劣;然后,随机选择一些字符串通过交叉、突变等操作产生下一代的M个字符串,而且较优的解被选中的概率要比较高。这样经过G代的进化后就可能会产生出0-1背包问题的一个“近似最优解”。

2.1 编码

需要将问题的解编码成字符串的形式才能使用遗传算法。最简单的一种编码方式是二进制编码,即将问题的解编码成二进制位数组的形式。例如,问题的解是整数,那么可以将其编码成二进制位数组的形式。将0-1字符串作为0-1背包问题的解就属于二进制编码。

基因在一定能够意义上包含了它所代表的问题的解。基因的编码方式有很多,这也取决于要解决的问题本身。常见的编码方式有:

  1. 二进制编码,基因用0或1表示(常用于解决01背包问题) 如:基因A:00100011010 (代表一个个体的染色体)

  2. 互换编码(用于解决排序问题,如旅行商问题和调度问题) 如旅行商问题中,一串基因编码用来表示遍历的城市顺序,如:234517986,表示九个城市中,先经过城市2,再经过城市3,依此类推。

  3. 树形编码(用于遗传规划中的演化编程或者表示)

如,问题:给定了很多组输入和输出。请你为这些输入输出选择一个函数,使得这个函数把每个输入尽可能近地映射为输出。 编码方法:基因就是树形结构中的一些函数。

  1. 值编码 (二进制编码不好用时,解决复杂的数值问题)

在值编码中,每个基因就是一串取值。这些取值可以是与问题有关任何值:整数,实数,字符或者其他一些更复杂的东西。

2.2 适应度函数

适应度函数 ( Fitness Function ):用于评价某个染色体的适应度,用f(x)表示。有时需要区分染色体的适应度函数与问题的目标函数。例如:0-1背包问题的目标函数是所取得物品价值,但将物品价值作为染色体的适应度函数可能并不一定适合。适应度函数与目标函数是正相关的,可对目标函数作一些变形来得到适应度函数。

遗传算子:遗传算法有3个最基本的操作:选择,交叉,变异。

2.3 选择

选择一些染色体来产生下一代。一种常用的选择策略是 “比例选择”,也就是个体被选中的概率与其适应度函数值成正比。假设群体的个体总数是M,那么那么一个体Xi被选中的概率为f(Xi)/( f(X1) + f(X2) + …….. + f(Xn) ) 。比例选择实现算法就是所谓的“轮盘赌算法”( Roulette Wheel Selection )。



轮盘赌算法

/*

* 按设定的概率,随机选中一个个体

* P[i]表示第i个个体被选中的概率

*/

int RWS()

{

m =0;

r =Random(0,1); //r为0至1的随机数

for(i=1;i<=N; i++)

{

/* 产生的随机数在m~m+P[i]间则认为选中了i

* 因此i被选中的概率是P[i]

*/

m = m + P[i];

if(r<=m) return i;

2.4 交叉

所谓交叉运算,是指对两个相互配对的染色体依据交叉概率按某种方式相互交换其部分基因,从而形成两个新的个体。交叉运算在GA中起关键作用,是产生新个体的主要方法。

2.4.1 2条染色体交换部分基因,来构造下一代的2条新的染色体。例如:

交叉前:

00000|011100000000|10000

11100|000001111110|00101

交叉后:

00000|000001111110|10000

11100|011100000000|00101

染色体交叉是以一定的概率发生的,这个概率记为Pc 。

2.4.2 双交叉点法 (用于二进制编码)

选择两个交叉点,子代基因在两个交叉点间部分来自一个父代基因,其余部分来自于另外一个父代基因. 如:

交叉前:

01 |0010| 11

11 |0111| 01

交叉后:

11 |0010| 01

01 |0111| 11

2.4.3. 基于“ 与/或 ”交叉法 (用于二进制编码)

对父代按位"与”逻辑运算产生一子代A;按位”或”逻辑运算产生另一子代B。该交叉策略在解背包问题中效果较好 . 如:

交叉前:

01001011

11011101

交叉后:

01001001

11011111

还有其他交叉方法,参考遗传算法学习心得

2.5 变异

变异是指依据变异概率将个体编码串中的某些基因值用其它基因值来替换,从而形成一个新的个体。GA中的变异运算是产生新个体的辅助方法,它决定了GA的局部搜索能力,同时保持种群的多样性。交叉运算和变异运算的相互配合,共同完成对搜索空间的全局搜索和局部搜索。

注:变异概率Pm不能太小,这样降低全局搜索能力;也不能太大,Pm > 0.5,这时GA退化为随机搜索。

在繁殖过程,新产生的染色体中的基因会以一定的概率出错,称为变异。变异发生的概率记为Pm 。

2.5.1. 基本位变异算子 (用于二进制编码)

基本位变异算子是指对个体编码串随机指定的某一位或某几位基因作变异运算。对于基本遗传算法中用二进制编码符号串所表示的个体,若需要进行变异操作的某一基因座上的原有基因值为0,则变异操作将其变为1;反之,若原有基因值为1,则变异操作将其变为0。

变异前:

000001110000000010000

变异后:

000001110000100010000

2.5.2. 逆转变异算子(用于互换编码)

在个体中随机挑选两个逆转点,再将两个逆转点间的基因交换。 如:

变异前: 1346798205

变异后: 1246798305

2.6 运行参数

GA运行时选择的参数应该视解决的具体问题而定,到目前为止,还没有一个适用于GA所有应用领域的关于算法参数的理论。下面是一般情况下使用GA时推荐的参数:

2.6.1 交叉率

交叉率一般来说应该比较大,推荐使用80%-95%。

2.6.2 变异率

变异率一般来说应该比较小,一般使用0.5%-1%最好。

2.6.3 种群的规模

种群规模指的是群体中个体的个数。实验发现,比较大的种群的规模并不能优化遗传算法的结果。种群的大小推荐使用20-30,一些研究表明,种群规模 的大小取决于编码的方法,具体的说就是编码串(Encoded String)的大小。也就是说,如果说采用32位为基因编码的时候种群的规模大小最好为32的话,那么当采用16位为基因编码时种群的规模相应应变为原 来的两倍。

2.6.4 遗传运算的终止进化代数

个人的想法是,设定一个计数器,如果连续N代出现的最优个体的适应度都一样时,(严格的说应该是,连续N代子代种群的最优个体适应度都<=父代最优个性的适应度)可以终止运算。

三、SGA(基本遗传算法)的伪代码

SGA(基本遗传算法)中采用轮盘赌选择方法

3.1算法流程图

GA流程图


基本遗传算法伪代码



/*

* Pc:交叉发生的概率

* Pm:变异发生的概率

* M:种群规模

* G:终止进化的代数

* Tf:进化产生的任何一个个体的适应度函数超过Tf,则可以终止进化过程

*/

初始化Pm,Pc,M,G,Tf等参数。随机产生第一代种群Pop



do

{ 

  计算种群Pop中每一个体的适应度F(i)。

  初始化空种群newPop

  do

  {

    根据适应度以比例选择算法从种群Pop中选出2个个体

    if ( random ( 0 , 1 ) < Pc )

    {

      对2个个体按交叉概率Pc执行交叉操作

    }

    if ( random ( 0 , 1 ) < Pm )

    {

      对2个个体按变异概率Pm执行变异操作

    }

将2个新个体加入种群newPop中

} until ( M个子代被创建 )

用newPop取代Pop

}until ( 任何染色体得分超过Tf, 或繁殖代数超过G )

四、基本遗传算法的优化

下面的方法可优化遗传算法的性能。

4.1 灾变

遗传算法的局部搜索能力较强,但是很容易陷入局部极值。引用网上的一段原话: “那么如何解决遗传算法容易陷入局部极值的问题呢?让我们来看看大自然提供的方案。

六千五百万年以前,恐龙和灵长类动物并存,恐龙在地球上占绝对统 治地位,如果恐龙没有灭绝灵长类动物是绝没有可能统治地球的。正是恐龙的灭绝才使灵长类动物有了充分进化的余地,事实上地球至少经历了5次物种大灭绝,每 次物种灭绝都给更加高级的生物提供了充分进化的余地。所以要跳出局部极值就必须杀死当前所有的优秀个体,从而让远离当前极值的点有充分的进化余地。这就是灾变的思想。”

灾变就是杀掉最优秀的个体,这样才可能产生更优秀的物种。那何时进行灾变,灾变次数又如何设定?

何时进行灾变,可以采用灾变倒计数的方式。如果n代还没有出现比之前更优秀的个体时,可以发生灾变。灾变次数可以这样来确定,如果若干次灾变后产生的个体的适应度与没灾变前的一样,可停止灾变。

4.2 精英主义(Elitist Strategy)选择:

当利用交叉和变异产生新的一代时,我们有很大的可能把在某个中间步骤中得到的最优解丢失。

精英主义的思想是,在每一次产生新的一代时,首先把当前最优解原封不动的复制到新的一代中。然后按照前面所说的那样做就行。精英主义方法可以大幅提高运算速度,因为它可以防止丢失掉找到的最好的解。

精英主义是基本遗传算法的一种优化。为了防止进化过程中产生的最优解被交叉和变异所破坏,可以将每一代中的最优解原封不动的复制到下一代中。

4.3 矛盾

由上面看来,灾变与精英主义之间似乎存在着矛盾.前者是将产生的最优个体杀掉,而后者是将最优秀个体基因直接保存到下一代.

应该辩证地看待它们之间的矛盾,两者其实是可以共存的.我们在每一代进行交叉运算时,均直接把最优秀的个体复制到下一代;但当连续N代,都没有更优 秀的个体出现时,便可以猜想可能陷入局部最优解了,这样可以采用灾变的手段.可以说,精英主义是伴随的每一代的,但灾变却不需要经常发生,否则算法可能下 降为随机搜索了.

当然,每个算法中不一定要用精英主义和灾变的手段,应该根据具体的问题而定

4.4 插入操作:

可在3个基本操作的基础上增加一个插入操作。插入操作将染色体中的某个随机的片段移位到另一个随机的位置。

五、GA算法特点

5.1 遗传算法的优点:

  • 群体搜索,易于并行化处理;

  • 不是盲目穷举,而是启发式搜索;

  • 适应度函数不受连续、可微等条件的约束,适用范围很广。

  • 容易实现。一旦有了一个遗传算法的程序,如果想解决一个新的问题,只需针对新的问题重新进行基因编码就行;如果编码方法也相同,那只需要改变一下适应度函数就可以了。

5.2 遗传算法的缺点:

  • 全局搜索能力不强,很容易陷入局部最优解跳不出来;(可结合SA进行改进,因为SA在理率上是100%得到全局最优的,但搜索代价高)

将遗传算法用于解决各种实际问题后,人们发现遣传算法也会由于各种原因过早向目标函数的局部最优解收敛,从而很难找到全局最优解。其中有些是由于目标函数的特性造成的,例如函数具有欺骗性,不满足构造模块假说等等;另外一些则是由于算法设计不当。为此,不断有人对遗传算法提出各种各样的改进方案。例如:针对原先的定长二进制编码方案;提出了动态编码、实数编码等改进方案;针对按比例的选择机制,提出了竞争选择、按续挑选等改进方案;针对原先的一点交算子,提出了两点交、多点交、均匀交等算子;针对原先遗传算法各控制参数在进化过程中不变的情况,提出了退化遗传算法、自适应遗传算法等。另外,针对不同问题还出现了分布式遗传算法、并行遗传算法等等。

六、遗传算法的实例

参考:

参考文献都是干货!!!参考文献都是干货!!!参考文献都是干货!!!

  1. 遗传算法入门-博客园-苍梧
    本文主要参考,推荐!感谢作者~

  2. 经典算法研究系列:七、深入浅出遗传算法
    July大神写的,通俗易懂,推荐!!!

  3. HELLO,遗传算法!
    博主语言轻松,用python描述了遗传算法求解一个函数最大值的例子。

  4. 遗传算法理论基础与简单应用实例
    博主总结整理的内容,挺不错的,文中的链接有实例应用。

  5. 遗传算法入门到掌握(一) CSDN-GA代码下载
    袋鼠跳的例子来描述了GA算法,帮助理解GA。

  6. 非常好的理解遗传算法的例子
    求下述二元函数的最大值的例子

  7. 遗传算法学习心得


欢迎来我的博客看看~
Michael翔的小窝-GA总结


Michael翔
2.4k 声望219 粉丝