遗传算法入门

2 遗传算法

2.1 理论引入

2.1.1 基因和染色体

1) 概述

​ 遗传算法中每一条染色体,对应着遗传算法的一个解决方案,一般我们用适应性函数(fitness function)来衡量这个解决方案的优劣。所以从一个基因组到其解的适应度形成一个映射。可以把遗传算法的过程看作是一个在多元函数里面求最优解的过程。 可以这样想象,这个多维曲面里面有数不清的“山峰”,而这些山峰所对应的就是局部最优解。而其中也会有一个“山峰”的海拔最高的,那么这个就是全局最优解。而遗传算法的任务就是尽量爬到最高峰,而不是陷落在一些小山峰。(另外,值得注意的是遗传算法不一定要找“最高的山峰”,如果问题的适应度评价越小越好的话,那么全局最优解就是函数的最小值,对应的,遗传算法所要找的就是“最深的谷底”)
在这里插入图片描述


2) 相关问题

​ 我们可以看下述这样的简单问题, 对于一元函数 f ( x ) = x sin ⁡ ( 10 π x ) + 2      x ∈ [ − 1 , 2 ] f(x)=x\sin(10\pi x)+2 \ \ \ \ x \in [-1,2] f(x)=xsin(10πx)+2    x[1,2] 要求在给定的区间找到函数最大值:
在这里插入图片描述
​ 这样的问题就是遗传算法所需解决的问题, 我们随机生成种群然后根据种群适应度进行选择、交叉、变异、复制等操作, 得到最切合函数曲线的最大值。 值的注意的是, 算法得到的最大值并不一定是全局最优的, 由于某些参数或数据集大小的限制, 我们会很容易陷入局部最优的状态。



2.1.2 袋鼠跳问题

既然我们把函数曲线理解成一个一个山峰和山谷组成的山脉。那么我们可以设想所得到的每一个解就是一只袋鼠,我们希望它们不断的向着更高处跳去,直到跳到最高的山峰(尽管袋鼠本身不见得愿意那么做)。所以求最大值的过程就转化成一个“袋鼠跳”的过程。作为对比下面简单介绍“袋鼠跳”的几种方式:

1) 爬山法(最速上升爬山法)

​ 从搜索空间中随机产生邻近的点,从中选择对应解最优的个体,替换原来的个体,不断重复上述过程。因为爬山法只对“邻近”的点作比较,所以目光比较“短浅”,常常只能收敛到离开初始位置比较近的局部最优解上面。对于存在很多局部最优点的问题,通过一个简单的迭代找出全局最优解的机会非常渺茫。(在爬山法中,袋鼠最有希望到达最靠近它出发点的山顶,但不能保证该山顶是珠穆朗玛峰,或者是一个非常高的山峰。因为一路上它只顾上坡,没有下坡。)


2) 模拟退火

​这个方法来自金属热加工过程的启发。在金属热加工过程中,当金属的温度超过它的熔点(Melting Point)时,原子就会激烈地随机运动。与所有的其它的物理系统相类似,原子的这种运动趋向于寻找其能量的极小状态。在这个能量的变迁过程中,开始时,温度非常高, 使得原子具有很高的能量。随着温度不断降低,金属逐渐冷却,金属中的原子的能量就越来越小,最后达到所有可能的最低点。利用模拟退火的时候,让算法从较大的跳跃开始,使到它有足够的“能量”逃离可能“路过”的局部最优解而不至于限制在其中,当它停在全局最优解附近的时候,逐渐的减小跳跃量,以便使其“落脚 ”到全局最优解上。(在模拟退火中,袋鼠喝醉了,而且随机地大跳跃了很长时间。运气好的话,它从一个山峰跳过山谷,到了另外一个更高的山峰上。但最后,它渐渐清醒了并朝着它所在的峰顶跳去。)


3) 遗传算法:

​模拟物竞天择的生物进化过程,通过维护一个潜在解的群体执行了多方向的搜索,并支持这些方向上的信息构成和交换。是以面为单位的搜索,比以点为单位的搜索,更能发现全局最优解。(在遗传算法中,有很多袋鼠,它们降落到喜玛拉雅山脉的任意地方。这些袋鼠并不知道它们的任务是寻找珠穆朗玛峰。但每过几年,就在一些海拔高度较低的地方射杀一些袋鼠,并希望存活下来的袋鼠是多产的,在它们所处的地方生儿育女。)(或者换个说法。从前,有一大群袋鼠,它们被莫名其妙的零散地遗弃于喜马拉雅山脉。于是只好在那里艰苦的生活。海拔低的地方弥漫着一种无色无味的毒气,海拔越高毒气越稀薄。可是可怜的袋鼠们对此全然不觉,还是习惯于活蹦乱跳。于是,不断有袋鼠死于海拔较低的地方,而越是在海拔高的袋鼠越是能活得更久,也越有机会生儿育女。就这样经过许多年,这些袋鼠们竟然都不自觉地聚拢到了一个个的山峰上,可是在所有的袋鼠中,只有聚拢到珠穆朗玛峰的袋鼠被带回了美丽的澳洲。)



2.1.3 遗传算法概述

1) 概述

​遗传算法的实现过程实际上就像自然界的进化过程那样。首先寻找一种对问题潜在解进行“数字化”编码的方案。(建立表现型和基因型的映射关系)然后用随机数初始化一个种群(那么第一批袋鼠就被随意地分散在山脉上),种群里面的个体就是这些数字化的编码。接下来,通过适当的解码过程之后(得到袋鼠的位置坐标),用适应性函数对每一个基因个体作一次适应度评估(袋鼠爬得越高,越是受我们的喜爱,所以适应度相应越高)。用选择函数按照某种规定择优选择(我们要每隔一段时间,在山上射杀一些所在海拔较低的袋鼠,以保证袋鼠总体数目持平。)。让个体基因变异(让袋鼠随机地跳一跳)。然后产生子代(希望存活下来的袋鼠是多产的,并在那里生儿育女)。遗传算法并不保证你能获得问题的最优解,但是使用遗传算法的最大优点在于你不必去了解和操心如何去“找”最优解。(你不必去指导袋鼠向那边跳,跳多远。)而只要简单的“否定”一些表现不好的个体就行了。(把那些总是爱走下坡路的袋鼠射杀,这就是遗传算法的精粹!)


2) 一般步骤
start while loss <= x:			//开始循环直至找到满意的解
1.评估每条染色体所对应个体的适应度。
2.遵照适应度越高,选择概率越大的原则,从种群中选择两个个体作为父方和母方。
3.抽取父母双方的染色体,进行交叉,产生子代。
4.对子代的染色体进行变异。
5.重复234步骤,直到新种群的产生。
end while;						//结束循环


2.2 算法细节

2.2.1 基因编码

1) 二进制编码

受到人类染色体结构的启发,我们可以设想一下,假设目前只有 0/1 两种碱基,我们也用一条链条把他们有序的串连在一起,因为每一个单位都能表现出 1 比特 的信息量,所以一条足够长的染色体就能为我们勾勒出一个个体的所有特征。这就是二进制编码法,染色体大致如下:
010010011011011110111110 010010011011011110111110 010010011011011110111110


2) 浮点数编码

相对来说, 二进制编码具有简单、直观的特点, 但显然在个体特征比较复杂的时候,需要大量的编码才能精确地描述,相应的解码过程(类似于生物学中的DNA翻译过程,就是把基因型映射到表现型的过程)将过分繁琐,为改善遗传算法的计算复杂性、提高运算效率,提出了浮点数编码。染色体大致如下:

1.2    3.3    2.0    5.4    2.7    4.3 1.2 \ \ 3.3 \ \ 2.0 \ \ 5.4 \ \ 2.7 \ \ 4.3 1.2  3.3  2.0  5.4  2.7  4.3


3) 模型抽取

​如果我们一时无法准确的判断哪些“个体特征”是必要的,哪些是非必要的,我们常常可以用到这样一种思维方式:比如你认为袋鼠的爱吃什么东西非常必要,那么你就想一想,有两只袋鼠,它们其它的个体特征完全同等的情况下,一只长得黑,另外一只长得不是那么黑。你会马上发现,这不会对它们的命运有丝毫的影响,它们应该有同等的概率被射杀!只因它们处于同一个地方。(值得一提的是,如果你的基因编码设计中包含了袋鼠黑不黑的信息,这其实不会影响到袋鼠的进化的过程,而那只攀到珠穆朗玛峰的袋鼠黑与白什么的也完全是随机的,但是它所在的位置却是非常确定的。)

​以上是遗传算法编码过程中必须经历的思维过程。把具体问题抽象成数学模型,突出主要矛盾,舍弃次要矛盾, 只有这样才能简洁而有效的解决问题。

​既然确定了袋鼠的位置作为个体特征,具体来说位置就是横坐标。那么接下来,我们就要建立表现型到基因型的映射关系。就是说如何用编码来表现出袋鼠所在的横坐标。由于横坐标是一个实数,所以说透了我们就是要对这个实数编码。回顾我们上面所介绍的两种编码方式,最先想到的应该就是,对于二进制编码方式来说,编码会比较复杂,而对于浮点数编码方式来说,则会比较简洁。恩,正如你所想的,用浮点数编码,仅仅需要一个浮点数而已。而下面则介绍如何建立二进制编码到一个实数的映射。



2.1.2 适应度评分与选择 物竞天择

1) 物竞 - 适应度函数(fitness function)

自然界生物竞争过程往往包含两个方面:生物相互间的搏斗与及生物与客观环境的搏斗过程。但在我们这个实例里面,你可以想象到,袋鼠相互之间是非常友好的,它们并不需要互相搏斗以争取生存的权利。它们的生死存亡更多是取决于你的判断。因为你要衡量哪只袋鼠该杀,哪只袋鼠不该杀,所以你必须制定一个衡量的标准。而对于这个问题,这个衡量的标准比较容易制定:袋鼠所在的海拔高度。(因为你单纯地希望袋鼠爬得越高越好。)所以我们直接用袋鼠的海拔高度作为它们的适应性评分。即适应度函数直接返回函数值就行了。


2) 天择 - 选择函数(selection)

选择函数的意义在于从庞大的种群中选择出适应度最高的群体, 当然这里的选择并不等价于排序并截取的过程, 它的选择是概率性的选择, 也即适应度越高的群体被选择到的几率越大。 自然界中,越适应的个体就越有可能繁殖后代。但是也不能说适应度越高的就肯定后代越多,只能是从概率上来说更多。(毕竟有些所处海拔高度较低的袋鼠很幸运,逃过了你的眼睛)那么我们怎么来建立这种概率关系呢?下面我们介绍一种常用的选择方法。


轮盘赌(Roulette Wheel Selection)选择法

​ 假如我们有五条染色体, 每条染色体的适应度评分分别为: 5, 10 ,20 ,20, 45

​ 那么其累计适应度为: 5 + 10 + 20 + 20 + 45 = 100

​ 因此每条染色体被选择到的概率为:
x 1 = 5 100 = 5 % x 2 = 10 100 = 10 % x 3 = 20 100 = 20 % x 4 = 20 100 = 20 % x 5 = 45 100 = 45 % x_1 = \frac {5}{100} = 5\% \\ x_2 = \frac {10}{100} = 10\% \\ x_3 = \frac {20}{100} = 20\% \\ x_4 = \frac {20}{100} = 20\% \\ x_5 = \frac {45}{100} = 45\% \\ x1=1005=5%x2=10010=10%x3=10020=20%x4=10020=20%x5=10045=45%
​ 根据不同的概率我们可以得出如下的扇形图, 也可以看做 轮盘

在这里插入图片描述
​因此我们可以想象, 我们取一个指针随后对轮盘进行转动, 指针指向的位置就是我们选中的染色体。 这样凸显了我们之前所说的适应度越大的个体越容易被选中的特点。


锦标赛选择算法

在这里插入图片描述
​ 遗传算法中的锦标赛选择策略每次从种群中取出一定数量个体(放回抽样),然后选择其中最好的一个进入子代种群。重复该操作,直到新的种群规模达到原来的种群规模。几元锦标赛就是一次性在总体中取出几个个体,然后在这些个体中取出最优的个体放入保留到下一代种群的集合中。具体的操作步骤如下:
​① 确定每次选择的个体数量N。(二元锦标赛选择即选择2个个体)
​② 从种群中随机选择N个个体(每个个体被选择的概率相同) ,根据每个个体的适应度值,选择其中适应度值最好的个体进入下一代种群。
​③ 重复步骤②多次(重复次数为种群的大小),直到新的种群规模达到原来的种群规模。



2.1.3 基因重组/交叉(recombination/crossover)

​ 遗传算法每一次迭代都会生成N条染色体,在遗传算法中,这每一次迭代就被称为一次“进化”。那么,每次进化新生成的染色体是如何而来的呢?——答案就是“交叉”,你可以把它理解为交配。

​ 交叉的过程需要从上一代的染色体中寻找两条染色体,一条是爸爸,一条是妈妈。然后将这两条染色体的某一个位置切断,并拼接在一起,从而生成一条新的染色体。这条新染色体上即包含了一定数量的爸爸的基因,也包含了一定数量的妈妈的基因。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ZKfJCnn-1634202237858)(img/image-20211012221350435.png)]

那么,如何从上一代染色体中选出爸爸和妈妈的基因呢?这不是随机选择的,一般是通过轮盘赌算法完成。

在每完成一次进化后,都要计算每一条染色体的适应度,然后采用如下公式计算每一条染色体的适应度概率。那么在进行交叉过程时,就需要根据这个概率来选择父母染色体。适应度比较大的染色体被选中的概率就越高。这也就是为什么遗传算法能保留优良基因的原因。

染色体i被选择的概率 = 染色体i的适应度 / 所有染色体的适应度之和



2.1.4 基因突变/变异(Mutation)

​ 交叉能保证每次进化留下优良的基因,但它仅仅是对原有的结果集进行选择,基因还是那么几个,只不过交换了他们的组合顺序。这只能保证经过N次进化后,计算结果更接近于局部最优解,而永远没办法达到全局最优解,为了解决这一个问题,我们需要引入变异。

​ 变异很好理解。当我们通过交叉生成了一条新的染色体后,需要在新染色体上随机选择若干个基因,然后随机修改基因的值,从而给现有的染色体引入了新的基因,突破了当前搜索的限制,更有利于算法寻找到全局最优解。

​ 比如一个简单的二进制基因串可以通过变异得到与之前不同的序列结果
101101001011001      突 变 前 001101011011001      突 变 后 101101001011001 \ \ \ \ 突变前 \\\\ 001101011011001 \ \ \ \ 突变后 101101001011001    001101011011001    



2.1.5 复制

每次进化中,为了保留上一代优良的染色体,需要将上一代中适应度最高的几条染色体直接原封不动地复制给下一代。

假设每次进化都需生成N条染色体,那么每次进化中,通过交叉方式需要生成N-M条染色体,剩余的M条染色体通过复制上一代适应度最高的M条染色体而来。



2.1.6 算法流程

  • 引用

    通过上述概念,相信遗传算法的大致原理你已经了解,下面我们将这些概念串联起来,介绍遗传算法的执行流程。

    • 在算法初始阶段,它会随机生成一组可行解,也就是第一代染色体。
    • 然后采用适应度函数分别计算每一条染色体的适应程度,并根据适应程度计算每一条染色体在下一次进化中被选中的概率(这个上面已经介绍,这里不再赘述)。

    上面都是准备过程,下面正式进入“进化”过程。

    • 通过“交叉”,生成N-M条染色体;
    • 再对交叉后生成的N-M条染色体进行“变异”操作;
    • 然后使用“复制”的方式生成M条染色体;

    到此为止,N条染色体生成完毕!紧接着分别计算N条染色体的适应度和下次被选中的概率。

    这就是一次进化的过程,紧接着进行新一轮的进化。


  • 百度百科

    遗传算法的基本运算过程如下:

    ① 初始化:设置进化代数计数器t=0,设置最大进化代数T,随机生成M个个体作为初始群体P(0)。

    ② 个体评价:计算群体P(t)中各个个体的适应度。

    ③ 选择运算:将选择算子作用于群体。选择的目的是把优化的个体直接遗传到下一代或通过配对交叉产生新的个体再遗传到下一代。选择操作是建立在群体中④ 个体的适应度评估基础上的。

    ⑤ 交叉运算:将交叉算子作用于群体。遗传算法中起核心作用的就是交叉算子。

    ⑥ 变异运算:将变异算子作用于群体。即对群体中的个体串的某些基因座上的基因值作变动。群体P(t)经过选择、交叉、变异运算之后得到下一代群体P(t+1)

    终止条件判断:若t=T,则以进化过程中所得到的具有最大适应度个体作为最优解输出,终止计算。

    遗传操作包括以下三个基本遗传算子(genetic operator):选择(selection);交叉(crossover);变异(mutation)。


tips: 以上笔记是根据两篇 blog 再加上自己的理解和归纳总结而来的, 附上引用链接,供大家参考。

引自: blog1 blog2

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值