遗传算法导论总论.docx
《遗传算法导论总论.docx》由会员分享,可在线阅读,更多相关《遗传算法导论总论.docx(22页珍藏版)》请在冰豆网上搜索。
遗传算法导论总论
遗传算法导论
IntroductiontoGeneticAlgorithms
I简介
前言
遗传算法是进化计算技术的一部分,而进化计算技术在人工智能领域得到飞速的发展。
你或许已经在想:
遗传算法是不是受到了达尔文进化论的启发?
简单地说,用遗传算法求解问题时,问题的解是在不断进化中得到的。
历史
二十世纪六十年代,I.Rechenberg在他的《演化战略》中第一次引入了进化算法的思想(起初称之为Evolutionsstragegie)。
他的这一思想逐渐被其他一些研究者发展。
遗传算法(GeneticAlgorithms)是JohnHolland发明的,后来他和他的学生及他的同事又不断发展了它。
终于,在1975年JohnHolland出版了专著《自然系统和人工系统中的自适应》(AdaptionInNaturalandArtificialSystems)。
1992年,JohnKoza曾经使用遗传算法编出新的程序去做一些具体的工作。
他称他的这种方法为“进化规划”(GeneticProgramming,简称GP)。
其中使用了LISP规划方法,这是因为这种语言中的程序被表示为“分析树”(ParseTree),而这种遗传算法就是以这些分析树为对象的。
II生物学背景
基因
所有的生物都是由细胞组成的。
在每一个细胞中都有想同序列的染色体。
染色体是一串DNA的片断,它为整个有机体提供了一种复制模式。
染色体是由基因组成的,或者说染色体就是一块块的基因。
每一个基因为一个特定的蛋白质编码。
或者更简单的说,每一个基因为生物体的某一特定特征编码,比如说眼睛的颜色。
所有可能的某一特定特征的属性(比如,蓝色,桔黄色等)被称之为等位基因。
每一个基因在染色体上都有其特定的位置,这个位置一般被称作位点(Locus)。
全部序列的基因物质(或者全部的染色体)称之为基因组(或染色体组)(Genome)。
基因组上特定序列的基因被称作基因型(Genotype)。
基因型和后天的表现型两者是有机体的显性、生理和心理特征比如说眼睛的颜色、智力的基础。
复制(Repeoduction)
在复制中,首先发生的是交叉(Crossover)。
来自于父代的基因按照一定的方式组成了新的基因。
新的子代还可能发生变异(Mutation)。
变异的意思是DNA上的某一些成分发生了一点点的变化。
这些改变可能是由于在由父代到子代的基因复制中出现的误差。
生物体的适应度由生物体自身是否能生存来度量的。
III搜索空间
搜索空间(SearchSpace)
在很多情况下,我们解决一个问题就是从一大堆的数据中寻找一个解,而通常这个解都是混杂在数据中的。
所有可行解(FeasibleSolution可行解就是满足了一定约束条件的解)组成的空间称之为搜索空间(也可以称之为状态空间)。
搜索空间中的每一个点都是一个可行解。
每一个可行解都可以被它的函数值或者它的适应度所标记。
记住:
问题的解就是搜索空间中的一个点,于是我们就是要从搜索空间中找到这个点。
这样,求解问题就可以转化为在搜索空间中寻找极值点(最大值或者最小值点)。
搜索空间在求解问题时可能是完全已知的,但一般来说我们只知道一些孤立的点,然后我们逐渐地生成其它点。
问题是,这个搜索过程可能很复杂,我们甚至不知道该去哪里搜索或者该从是么地方开始搜索。
事实上,有很多寻找合适解(注意:
不一定是最优解)的方法,比如说爬山法(HillClimbing)禁止接近法(TabuSearch),模拟退火算法(SimulatedAnnealing)以及遗传算法等等.用遗传算法求解出来的解一般被认为是一个比较好的解,因为我们没有办法证明它是最优解.
NP难题(NP-hard)
举一个比较难的NP问题,这个问题无法用传统的方法解决。
我们知道很多问题有快速的算法(多项式算法).但是,也有很多问题是无法用算法解决的。
事实上,已经证明很多问题不可能在多项式时间内解决出来。
但是,有很多很重要的问题他们的解虽然很难求解出来,但是他们的值却是很容易求可以算出来的。
这种事实导致了NP完全问题。
NP表示非确定的多项式(NondeterministicPolynomial),意思是这个问题的解可以用非确定性的算法“猜”出来。
如果我们有一个可以猜想的机器,我们就可以在合理的时间内找到一个比较好的解。
NP-完全问题学习的简单与否,取决于问题的难易程度。
因为有很多问题,它们的输出极其复杂,比如说人们早就提出的一类被称作NP-难题的问题。
这类问题不像NP-完全问题那样时间有限的。
因为NP-问题由上述那些特征,所以很容易想到一些简单的算法――把全部的可行解算一遍。
但是这种算法太慢了(通常时间复杂度为O(2^n))在很多情况下是不可行的.
现在,没有知道有没有那种精确的算法存在。
证明存在或者不存在那种精确的算法这个沉重的担子就留给了新的研究者了,或许你就是。
现在很多人认为那种精确的算法是不存在的,所以他们试图寻找一种替代的算法――比如说这里的遗传算法。
这里的NP-问题的例子,旅行商问题(TravellingSalesmanProblem)或背包问题(knapsackproblem),都是满意性问题。
NP问题的简述你可以在这里看到。
IV遗传算法
基本思想
遗传算法受到达尔文进化论的影响很大。
在遗传算法中,问题的解是逐渐进化得到的!
遗传算法的计算从一组可能解开始,这组解被称作种群(Population),在算法中被表示成基因。
我们又把种群中的解拿出来去构成新的一个种群,这是因为我们期望新的种群要比旧的种群要好!
当然,新的种群中的解要有这样的性质,就必须按照它的适应度去选择,适应度越高,它参与构造新的种群的机会就越大。
这个过程一次又一次的重复,一直到我们所给的约束条件满足为止,比如说种群中解得个数或者种群的良好程度。
遗传算法的基本结构
1[开始]按照问题的特点随机产生一个拥有N个染色体的种群;
2[适应度计算]用适应度函数f(x)计算种群每一个基因的适应度;
3[产生新的种群]重复以下步骤,一直到新的母体群建立起来为止;
1.[选择]按照种群中的各个基因的适应度从中选择两个父代基因(适应度越大,机会越大);
2.[交叉]以一定的交叉概率交叉两个父代的基因以产生子代。
交叉完成之后,子代完完全全是父代的复制;
3.[变异(Mutation)]以一定的概率对子代基因的的每一个位点(Locus)进行变异;
4.[接受]把这个子代放到新的种群中去;
4[替换]对新产生的种群进行更深入的算法运算;
5[测验]如果终止条件满足,则停止;并且把当前母体群中最好的解输出;
6[循环]如果5不满足,则转到2;继续进行
一些说明
你可以发现这个遗传算法的基本结构是很一般的。
在具体的问题中,我们还要做很多工作以实现算法。
首先的问题是怎样创建一个基因?
怎样对它们编码?
这些问题都是和对基因的操作(交叉、变异)密切联系的。
编码、交叉和变异我们将在下一章介绍。
下一个问题是怎样从父代种群中选择用来交叉的父代。
方法有很多,但是最基本的思想是:
选择好的父代(因为我们认为好的父代可以产生好的子代)。
你或许在想:
仅仅从产生的子代中选择基因去构造新的种群可能会丢失掉上一代种群中的很多信息。
这确实是事实,我们可以使用精英主义(Elitism)方法。
也就是说,种群中最好的那个基因我们将毫无改变的复制到新的种群中。
显然,任何时刻产生的一个最优解的解都可以存活到算法结束。
还有很多问题我们都将在后面的章节中陆续讨论。
你可能在想,为什么遗传算法能够得到我们需要的结果呢?
这个问题部分地可以被Holland的模式定理(SchemaTheorem)解决。
可是,这个模式定理现在被很多人批评,因为很多人认为它是有问题的。
如果你有兴趣的话,你可以在这里找到更多的资料!
V遗传算法中的算子
概述
在前面的遗传算法的基本结构中我们注意到交叉和变异是遗传算法中最重要的部分。
算法的结果受交叉和变异的影响最大。
当然,在我们讨论交叉和变异之前我们先要介绍一些基因的信息。
基因的编码
基因在一定能够意义上包含了它所代表的问题的解在里面。
最常用的编码方式是二进制串(BinaryString)。
于是基因可以表示为:
1号基因
1101100100110110
2号基因
1101111000011110
每一个基因用一个二进制串表示,这个二进制串的每一位表示解的某些特征。
或者,整个二进制串表示一个数,比如说在基本的遗传算法的Applet中就是如此。
当然,编码的方法有很多。
选用什么方法编码主要取决于所要解决的问题本身。
比如说,有的问题直接用整数或者实数来编码可能更好!
交叉
当我们决定了用什么方法来编码后,我们既可以考虑下一步了――交叉。
交叉的本质就是从种群中选择父代以生成新的母体群。
最简单的方法就是随机的选择一个交叉点,在交叉点之前的部分来自父代1号基因,交叉点之后的部分来自来父代的2号基因。
用图可以表示为上述过程如下:
(|表示交叉点)
1号基因
11011|00100110110
2号基因
11011|11000011110
子代1
11011|11000011110
子代2
11011|00100110110
当然,交叉的方式也很多。
比如说一个直接的对这个方法的改良就是多选择几个交叉点。
交叉可能很复杂,这有可能是基因编码方法的原因!
对特定的问题我们要选择特定的交叉方法以使得遗传算法的结果比较好!
变异
一旦交叉完成,变异就要开始了。
变异的目的是防止种群中的解跑到局部极值去。
变异是对子代的随机的改变。
对二进制串编码方式来说,我们可以随机地改变子代中的某个位点的数字(1变为0,或者0变为1)。
于是,变异可以用表表示如下:
变异前的子代1
1101111000011110
变异前的子代2
1101100100110110
变异后的子代1
1100111000011110
变异后的子代2
1101100101110110
显然,变异取决于编码方式和交叉方法。
比如说变异可以是交叉两个基因。
VI遗传算法的一个例子
求函数最小值
问题
在搜索空间那一章中我们已经提到:
我们遇到的很多问题都可以转化为求解一个函数的极值。
下面这个例子就是恰好是这种问题。
给定一些函数,然后用遗传算法求这些函数在给定空间中的最小值。
对于其他一些问题,通过定义搜索空间和适应度函数,我们通常可以转化为这种问题。
VII遗传算法中的一些参数
交叉和变异的概率
遗传算法中有两个基本参数:
交叉的概率和变异的概率。
交叉的概率是说交叉行为发生的几率大小,如果几率为0,那么子代就完完全全和父代一样。
只要存在交叉,子代的基因是由几个父代的基因的中的片段组合而成的,所以就不完全和父代一样。
如果交叉100%的发生,那么所有的子代都是由交叉产生的。
如果交叉的概率为0%,那么子代就是父代的完全复制。
(注意:
但是,这并不意味着子代就和父代完全一样)
交叉过程的目的就是希望新的基因是由旧的基因中好的部分组合而成的,从而新的基因比原先的基因要好。
当然把旧的种群中的一部分基因完全保留到下一代中去也是很有意义的。
变异的概率说的是基因的某些部分发生变异的概率。
如果没有变异的话,子代就和交叉过的父代没有任何区别。
只要存在变异,子代的基因就会发生改变。
如果变异的概率为100%,那么所有的子代都会改变。
如果交叉的概率为0%,那么子代就不会改变。
变异的目的是为了防止遗传算法的解跑到局部极值点,所以,变异应该发生。
但是变异不能发生的太频繁,否则的话就变成了随机搜索了。
其他一些参数
遗传算法中还有一些其它参数,比如说种群的大小就是一个很重要的参数。
种群的大小是说每一代种群中所含基因的多少。
如果其中的基因太少,则遗传算法中进行交叉操作的机会就越少,所以导致我们的算法只是考察了搜索空间的一部分。
另一方面,如果基因太多,则遗传算法的速度就会变慢。
进一步的研究表明,在一定的条件下(这些条件主要由问题本身和编码方法决定)增大种群的大小是没有意义的,因为它不会加快遗传算法的计算速度。
VIII函数的极值点
问题
这里又是一个求函数极值的问题,但是在这个例子中我们的函数是一个二元函数。
例子(此处是JAVA程序,略)
IX选择算子
简介
正如我们在遗传算法基本结构中已经知道的那样,用来交叉的基因是从从父代种群中选择出来.那么怎样选择这些基因呢?
根据达尔文的进化论,适应环境的(好的)基因将生存下来并且交叉产生新的一代。
选择好的基因的方法有很多,比如轮盘赌选择方法(RouletteWheelSelection)、(BoltmanSelection)、锦标赛选择方法(TournamentSelection)、分级选择方法(RankSelection)、稳定状态选择方法(SteadyStateSelection)等等。
在本章中我们将选择部分做深入一点的说明。
轮盘赌选择方法(RouletteWheelSelection)
父代的选择是根据他们的适应度做出的。
基因越是适应环境,那么它被选择到的机会就越大。
想像一个轮盘赌的机器上放置了种群中所有的基因。
每一个基因所占的地方的大小和它的适应度成正比。
如下图所示:
然后开始扔弹子,扔到那个地方就把对应的基因拿出来。
显然,适应度越大的基因被选到的机会就越大。
这个过程可以被下面的这个算法来模拟:
1.[求和]计算所有种群的适应度的和S;
2.[选择]在区间(0,S)上随机的产生一个数r;
3.[循环]从某个基因开始,逐一取出基因来,把它的适应度加到s上去(s开始为0),如果s大于r,则停止循环并返回当前基因;
当然,第一步在计算中只需要执行一次。
分级选择方法(RankSelection)
前面这中选择方法很简单,但是当适应度变化比较大时就会有问题。
比如说,当前种群中最好的基因(适应度最大)的适应度占S的90%的时候,那么其它基因就很少有机会被选择到。
分级选择方法首先把种群分几个等级。
然后,每一个基因收到各自等级中的适应度。
我们定义最差的等级的适应度为1;次差的为2等等,最好的那个级适应度定义为N(N就是种群中基因的个数)。
通过下面这两个图,你可以看看在分级前后有什么改变。
这样,所有的基因都有机会被选择到。
但是这样又会导致算法的收敛速度变慢,因为最好的基因与其它基因的差别被缩小了。
稳定状态选择方法(SteadyStateSelection)
其实,这并不是选择父代的特殊方法。
这种方法的主要思想是有很多的基因要保留到下一代中!
于是遗传算法将按照如下的方式进行:
在每一代中选择一少部分基因(与适应度相符合)来构造子代。
接着,父代中一部分基因(与适应度不符合的)被新产生的子代所代替,父代中其它的人基因被保留到新的一代中。
精英主义
精英主义思想我们已经在前面介绍过了。
这种思想是说当利用交叉和变异产生新的一代时,我们有很大的可能把在某个中间步骤中得到的最优解丢失。
精英主义正如它的语义所蕴含的那样,在每一次产生新的一代时,我们首先把当前最优解原封不动的复制到新的一代中。
然后按照我们前面所说的那样做就行。
精英主义方法可以大幅提高运算速度,因为它可以防止丢失掉找到的最好的解!
X编码(Encoding)
简介
当你开始用遗传算法求解问题时,基因的编码是一个很重要的问题。
编码方法是依赖于问题本身的。
在这一章中我们将介绍几种在实际中已经取得成功的方法。
二进制编码
二进制编码是最常见的一个编码方法,这主要是因为用遗传算法编的第一个程序就是用二进制编码的。
在使用二进制编码时,每一个基因就是一个由0或者1组成的字符串。
基因A
101100101100101011100101
基因B
111111100000110000011111
二进制编码的基因
使用二进制编码时,即使等位基因的数量不大,我们也可以得到很多种可能的基因。
另一方面,这种方法对于很多问题来都很不自然,所以有时候在交叉和变异结束后还要做一些调整。
―――――――――――――――――
一个问题:
背包问题(KnapsackProblem)
问题:
这里有一些给定价值和大小的东西。
背包的容积是给定的。
请你在不超过背包容积的情况下往背包中装东西,以使得背包中东西的价值达到最大。
编码方法:
二进制的每一位代表对应的东西是否在背包中。
―――――――――――――――――
互换编码(PermutationEncoding)
互换编码可以用来解决排序问题,比如说旅行商问题(TravellingSalesmanProblem)和任务排序问题(TaskOrderingProblems)。
基因A
153264798
基因B
856723149
互换编码的例子
互换编码只是对排序问题有用。
即使是排序问题中的某些问题采用互换编码,在交叉和变异后还必须作出一些调整以使得基因保持一致(比如,有可能产生实数)。
―――――――――――――――――
一个问题:
旅行商问题(TravellingSalesmanProblem)――TSP
问题:
给定一些城市和这些城市间的距离。
旅行商要到所有这些城市中去,但是它不能花太多时间。
寻找一个到所有这些城市的顺序以使得旅行路程最短。
编码方法:
基因表示的是访问各个城市的顺序。
―――――――――――――――――
值编码(ValueEncoding)
在很多问题中我们还可以采用直接的值编码,也就是说用一些比较复杂的数来编码,比如说实数。
因为二进制编码在这类问题中不好用。
在值编码中,每个基因就是一串取值。
这些取值可以是与问题有关任何值:
整数,实数,字符或者其他一些更复杂的东西。
基因A
1.23245.32430.45562.32932.4545
基因B
ABDJEIFJDHDIERJFDLDF
基因C
(back),(back),(right),(forward),(left)
值编码的例子
值编码对于一些特殊的问题是很有效的。
但是,对于这种编码方法它的交叉和变异算子就要按照问题和编码方法具体的去设计。
―――――――――――――――――
一个问题:
为神经网络寻找权重(FindingWeightsForNeuralNetworks)
问题:
这里有一些给定了结构的神经网络算法。
求要输入的神经元的权重以使得网络有我们想要的输出。
编码方法:
用一个实数表示对应的输入的权重。
―――――――――――――――――
树形编码(TreeEncoding)
树形编码主要用于遗传规划中的演化编程或者表示。
在树形编码中,每个基因都是由数字或符号组成的树形结构。
这些符号可以是函数,也可以是规划中使用的一些命令。
基因A
基因B
(+x(/ 5 y))
(do_untilstepwall)
数形编码的一个例子
数形编码对演化规划这类问题很适合.规划语言LISP经常在其中使用,因为规划中使用的很多程序可以用数形结构很容易的表示出来,从而交叉算子和变异算子相对也简单.
―――――――――――――――――
一个问题:
为给定的自变量和函数值选择一个函数(FindingAFunctionFromGivenValues)
问题:
给定了很多组输入和输出。
请你为这些输入输出选择一个函数,使得这个函数把每个输入尽可能近地映射为输出。
编码方法:
基因就是树形结构中的一些函数。
―――――――――――――――――
XI交叉和变异
简介
交叉和变异是遗传算法中的两个最基本的算子。
遗传算法的好坏由他们决定。
这两个算子的类型和实现是由问题本身和编码方法决定的。
交叉和变异的方式有很多。
这一章我们我们介绍几种例子,通过这些例子你可以去体会交叉算子和变异算子的构造方法。
二进制编码
1. 交叉算子
◆ 单交叉点交叉算子(SinglePointCrossover):
选择一个交叉点,子代在交叉点前面的基因从一个父代基因那里得到,后面的部分从另外一个父代基因那里得到;
11001011+11011111=11001111
◆ 双交叉点交叉算子(TwoPointCrossover):
选择两个交叉点,子代基因在两个交叉点间部分来自一个父代基因,其余部分来自于另外一个父代基因.
11001011+11011111=11011111
◆ 均匀交叉算子(UniformCrossover):
子代基因的每一个位点是随机地来自于两个父代基因中的一个的;
11001011+11011101=11011111
◆ 算术交叉算子(ArithmeticCrossover):
对父代基因做一个代数运算从而产生一个新的基因。
下面就是使用和运算(AND)实现的:
11001011+11011111=11001001(AND)
2. 变异算子
◆ 位点转换算子(BitInversion):
选择一些位点然后将这些地方的0,1互换;
11001001=>10001001
互换编码
1. 交叉算子
◆ 单交叉点交叉算子(SinglePointCrossover):
选择一个交叉点,子代的从初始位置出发的部分从一个基因复制,然后在另一个基因中扫描,如果某个位点在子代中没有,就把它添加进去?
注意:
这个算法交叉点后面的部分可以有很多中具体的方法;
(123456789)+(453689721)=(123456897)
2. 变异算子
◆ 变序算子(OrderChanging):
从子代基因中选择两个数,交换它们的位置;
(123456897)=>(183456297)
值编码
1. 交叉算子
上面二进制编码中所由交叉算子都适用。
2. 变异算子
◆ 填值算子(AddingCrossover):
对于实数编码的算法,可以给选定的一些数添加一个小的实数(扰动):
(1.295.682.864.115.55)=>(1.295.682.734.225.55)
树形编码
1. 交叉算子
◆ 树交叉算子(TreeCrossover):
在两个父代基因上选一个交叉点(位置),然后把他们在交叉点下面的部分交换就行;
2.变异算子
◆ 改变交叉算子(ChangingOperator):
选择一些节点,然后把他们换掉;
XII旅行商问题(TSP)
(