遗传算法是一种能够模拟生物进化论的自然选择和遗传学机制的生物进化过程的计算模型,是一种通过模拟自然进化的方法来搜索最优解的一种方法。主要特点是直接对结构对象进行操作,不存在梯度求导机制和函数连续性的限定,主要是采用概率的方法来实现寻优的方法,自适应调整搜索的方向。
遗传算法主要有三大模块构成,即编码、个体适应度估计和遗传运算三大模块构成,遗传运算又包括染色体复制、交叉、变异、倒位等等。改良的遗传算法都是由SAG(Simple genetic algorithm)的变异形式。在遗传算法中,定义种群或者群体为所有编码后的染色体的集合,表征每个个体的都是其相应的染色体。
遗传算法中包括有二进制编码和浮点数编码形式。
二进制编码: 这种形式是用0和1代码串的形式形成一条链的染色体。一个位能够表示出2中状态的信息量,故而足够长二进制染色体便能够表现出所有的特征。假设某一个参数的取值范围为 ( L , U ) (L,U) (L,U) ,使用长度为k的二进制编码的形式表示该参数的大小,则它一共有 2 k 2^{k} 2k种不同的编码:
0000000000000000=0 ==> L
0000000000000001=1 ==> L + delta
0000000000000010=2 ==> L + 2*delta
...
1111111111111111=2^k-1 ==> U
所以我们能够得到:
δ = U − L 2 k − 1 \delta=\frac{U-L}{2^{k}-1} δ=2k−1U−L
解码 的目的是为了将不直观的二进制数据串还原成为十进制。假设一个个体的二进制染色体编码为:
b k b k − 1 . . . b 2 b 1 ‾ \overline{b_{k}b_{k-1}...b_{2}b_{1}} bkbk−1...b2b1
则对应的二进制解码公式为:
x = L + ( ∑ i = 1 k b i ⋅ 2 i − 1 ) U − L 2 k − 1 x=L+(\sum\limits_{i=1}^{k}b_{i}\cdot{2^{i-1}})\frac{U-L}{2^{k}-1} x=L+(i=1∑kbi⋅2i−1)2k−1U−L
二进制编码适用于一些离散化的数据形式,具有这些优点:
1.编码和解码操作简单,容易进行;
2.交叉、变异等遗传操作便于实现;
3.符合最小字符集编码的原则;
同样也会有一些缺点:对于一些连续函数的优化问题,由于随机的性质使得其局部搜索能力较差,长度较长的时候虽然能够解决高精度的要求,但是解码难度增加,使得遗传算法的搜索空间呈指数形式增加。
浮点数编码: 浮点是编码指的是用某一个范围内的浮点数来表示。在浮点数编码的方法中,必须保证基因值在给定的区间限制范围内,遗传算法中所使用到的交叉、变异等遗传算子也必须保证其运算结果所产生的新的个体基因值也在这个区间限制的范围内。在后面的内容会介绍如何用浮点数进行交叉、变异。
在二进制编码或者是其他序列编码中,交配值得是使用单点交配或者是多点进行交叉的算子。首先,用随机数生成一个或者是多个交配点的位置,然后两个个体在交配点的位置互换部分基因编码,从而形成两个不同的个体。例如:
A = 0001010111001011 # 个体A的编码序列
B = 0110110010111011 # 个体B的编码序列
# 进行第2~8位进行交叉,并产生两个新的个体A',B'
A' = 0110110011001011
B' = 0001010110111011
浮点数的交叉是用交叉常数进行求解:
x A t + 1 = α x B t + ( 1 − α ) x A t x B t + 1 = α x A t + ( 1 − α ) x B t x_{A}^{t+1}=\alpha x_{B}^{t}+(1-\alpha)x_{A}^{t}\\ x_{B}^{t+1}=\alpha x_{A}^{t}+(1-\alpha)x_{B}^{t} xAt+1=αxBt+(1−α)xAtxBt+1=αxAt+(1−α)xBt
其中, α \alpha α是交叉常数, x m i n ≤ x A 1 , x B 1 ≤ x m a x x_{min}\leq x_{A}^{1},x_{B}^{1}\leq x_{max} xmin≤xA1,xB1≤xmax。可以通过归纳法证明出 x m i n ≤ x A t , x B t ≤ x m a x x_{min}\leq x_{A}^{t},x_{B}^{t}\leq x_{max} xmin≤xAt,xBt≤xmax
突变运算是用基本位进行基因突变。为避免在算法迭代后期出现种群过早收敛的可能,使用突变运算将某些个体进行突变。对于二进制编码的算子来说,种群中的个体实行基因编码的小概率翻转。其他序列编码可以根据具体问题具体分析。浮点数突变的运算可以由以下的运算规则进行运算:
x A t + 1 = { x A t + k ⋅ ( x m a x − x A t ) ⋅ r , r a n d ( ) % 2 = = 1 x A t − k ⋅ ( x A t − x m i n ) ⋅ r , r a n d ( ) % 2 = = 0 x_{A}^{t+1}=\begin{cases} x_{A}^{t}+k\cdot(x_{max}-x_{A}^{t})\cdot{r}&,rand()\%2==1\\ x_{A}^{t}-k\cdot(x_{A}^{t}-x_{min})\cdot{r}&,rand()\%2==0 \end{cases} xAt+1={xAt+k⋅(xmax−xAt)⋅rxAt−k⋅(xAt−xmin)⋅r,rand()%2==1,rand()%2==0
倒位运算是对序列编码来说的。倒位指的是一个染色体某段正常排列顺序发生180°的颠倒,造成染色体DNA序列重新排列的一种运算方式,包括臂内倒位和臂间倒位。倒位的个体并不影响个体的生活力,只是改变了染色体上相邻基因的位置顺序。举个例子:
A = 010100100111010011 #原序列
# 现在对5-11位进行倒位运算,A'为倒位之后的结果
A' = 010111001001010011
自然界中能够适应环境的生物有更大的机会存活下来,个体适应度大的个体更容易存活下来,被遗传到下一个子代当中。通常,求目标函数最大值的问题可以直接把目标函数作为检测个体适应度大小的函数。
复制运算是根据个体适应度大小决定其下一代遗传的可能性。若设个体总数为 N N N,个体 k k k的适应度为 f k f_{k} fk,则个体 k k k被选中的概率为:
P k = f k ∑ j = 1 N f j P_{k}=\frac{f_{k}}{\sum\limits_{j=1}^{N}f_{j}} Pk=j=1∑Nfjfk
当个体复制几率决定之后,再产生 [ 0 , 1 ] [0,1] [0,1]内的随机数来决定哪些个个体参加复制。如果个体的适应度 f k f_{k} fk比较大,则被选中的概率 P k P_{k} Pk的概率就大,则可能被多次选择,它的遗传基因就会在种群中扩散;若复制几率小,则会被逐渐淘汰。
首先我们举一个最简单的例子,即函数的极值求解。编码我们采用浮点数编码的方法,更新的规则是选取交配之后的四个算子当中最好的两个。设我们所求的函数为:
f ( x ) = x + 10 sin ( 5 x ) + 7 cos ( 4 x ) f(x)=x+10\sin(5x)+7\cos(4x) f(x)=x+10sin(5x)+7cos(4x)
设种群的个数为20个,初始时候的位置为:
经过遗传算法计算之后,求解的极值点的位置如下所示:
详细代码可以参见笔者的github。
TSP问题就不再过多叙述了,详细见笔者的博文群体智能算法之模拟退火算法。
在TSP问题中,个体编码用 N N N个城市的排列顺序表示: X k = ( w 1 , w 2 , . . . , w N ) X_{k}=(w_{1},w_{2},...,w_{N}) Xk=(w1,w2,...,wN),其适应度函数表示为:
f k = 1 ∑ j = 1 N d ( w j , w j + 1 ) f_{k}=\frac{1}{\sum\limits_{j=1}^{N}d(w_{j},w_{j+1})} fk=j=1∑Nd(wj,wj+1)1
一般地说,选择将使得适应度较大的优良个体有较大的存在机会,而适应度较小的个体继续存在的机会也就会小。这里我们使用轮盘赌的方法进行选择个体。这里重点来说明以下个体之间的交叉运算方法。
基于路径表示的编码方法,要求个体的染色体编码不允许有重复的基因编码,即要满足任意一个城市必须而且只能访问一次的约束。所以说基于遗传算法的交叉操作并不能满足这个约束条件。这里我们使用到部分匹配交叉的方法,即任意选取两个交叉点,以便于确定一个匹配段,根据两个父个体中两个交叉点之间中间段给出的映射关系生成两个子体。
部分匹配交叉: 先随机生成两个交叉点,定义这两个点之间的区域为匹配区域,并交换两个父代的匹配区域。举个例子,对于十个城市来说:
#两个父代个体
父代A:872|130|9546
父代B:983|567|1420
#交换之后的变化为
tempA:872|567|9546
tempB:983|130|1420
#建立区域内位置匹配关系
1 <==>5,3<==>6,7<==>0
#最后子代的个体为
子代A:802|567|9143
子代B:986|130|5427
数据集我们选取TSP数据集中的eil51.tsp问题。经过算法求解之后,得到的结果为
在迭代过程中,每一次迭代过程中平均路径长度为:
由图中可以看出,遗传算法是收敛的,但是由于后期群体中基因型近似相同,得到的群体个体表现型近乎相同,群体出现过早收敛性,所以迭代过程中变得缓慢。具体代码可以参见笔者的github
另外一种改进的方法可以是种群变化的遗传算法。这种算法中如果没有环境阻力的影响,那么种群的变化呈现指数形式增长。加入环境阻力之后,群体变化呈现出逻辑斯蒂增长模型。这种情况下可以引入捕食者模型,即与被捕食者适应度有关的一个种群递减阻力因素。所以最终可以通过PSO算法结合遗传算法来求解这一个过程,具体就不再描述了。
种群的规模: 种群规模要根据问题的规模设定种群的大小。当种群规模太小的时候,非常容易出现近亲交配,很容易出现病态的基因,而且造成有效等位基因先天缺乏,即便使用较大概率的变异,但是生成具有高竞争能力的个体可能性比较小,而且对现有的种群容易产生破坏;种群规模太大会使得难以收敛并且很浪费计算资源,并不可取,一般选取0-500左右。
变异概率: 变异概率太小时候,种群的多样性下降太快,容易导致有效基因丢失迅速并且不容易修补;变异概率太大,则虽然种群多样性很多,但是很容易破坏种群。建议选取0.001~0.2左右。
交配概率: 它和变异的概率类似,它是更新新种群的重要手段,太大则会破坏种群,太小则不能有效更新种群。
本小结中详细介绍了遗传算法的原理和一些具体的应用。需要注意的是遗传算法中一些参数的设置方法和模型的灵活应用。
[1] https://www.jianshu.com/p/ae5157c26af9
[2] https://blog.csdn.net/xyisv/article/details/86741983