关于遗传算法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于遗传算法相关的知识,希望对你有一定的参考价值。
参考技术A遗传算法(Genetic Algorithm,简称GA)是美国 Michigan大学的 John Golland提出的一种建立在自然选择和群体遗传学机理基础上的随机、迭代、进化、具有广泛适用性的搜索方法。现在已被广泛用于学习、优化、自适应等问题中。图4-1 给出了 GA搜索过程的直观描述。图中曲线对应一个具有复杂搜索空间(多峰空间)的问题。纵坐标表示适应度函数(目标函数),其值越大相应的解越优。横坐标表示搜索点。显然,用解析方法求解该目标函数是困难的。采用 GA时,首先随机挑选若干个搜索点,然后分别从这些搜索点开始并行搜索。在搜索过程中,仅靠适应度来反复指导和执行 GA 搜索。在经过若干代的进化后,搜索点后都具有较高的适应度并接近最优解。
一个简单GA由复制、杂交和变异三个遗传算子组成:
图4-1 GA处理过程
复制算子(Pr)是把当前群体中的个体,按与适应值成比值的概率复制到新的群体中。它的作用只是提高群体的平均适应值。由于没有新的个体产生,群体中最好个体的适应值不会得到改进。在复制算子中,由于低适应值个体趋向于被淘汰,高适应值个体趋向于被复制,所以群体的这些改进虽具有代表性,但这是以损失群体的多样性为代价的。
杂交算子(Pc)能够产生新的个体,检测空间中新的点。复制算子每次仅作用在一个个体上,而杂交算子每次作用在随机抽取的两个个体上,按一定概率部分交换相对应的两个串,例如,设两个串
储层特征研究与预测
为配对串,杂交点选在4(冒号所示),则杂交算子的作用结果为:
储层特征研究与预测
一点杂交有时会造成子代与父代相同的情况,这时杂交算子就失去了作用。例如:
储层特征研究与预测
为避免这样情况的发生,实际应用中大多采用两点杂交或多点杂交。杂交算子的应用频率由杂交率C来控制,每代新个体中,有C·N(群体)个串实行杂交,杂交率越高,群体中串的更新就越快,串的性能也就破坏得越快;杂交率过低,搜索会由于太小的探查而停滞不前。排除变异仅有杂交的GA可看做是可吸收的马尔可夫过程。C一般取0.5~0.9。
变异算子(Pm)能够以很小的概率随机地改变染色体中的某些位,从而在恢复由于复制操作而使群体中损失的多样性方面具有潜在的作用。对于二进制串,就是把相应的位从“1”变为“0”,从“0”变为“1”。排除杂交仅有变异GA相当于并行模拟退火。变异率M通常取0.01~0.1。GA的搜索能力主要是由复制和杂交赋予的,变异算子则保证了算法能搜索到问题解空间的每一点,从而使算法具有全局最优,它进一步增强了GA的搜索能力。
GA惟一用到的信息就是适应值,每个串都与一个确定的适应值相对应,表明该串所表示的参数组合对给的性能评价标准的适应程度。在遗传算法中,适应值用来区分群体中个体(问题的解)的好坏,适应值越大的个体越好,反之,适应值越小的个体越差。遗传算法正是基于适应值对个体进行选择,以保证适应性好的个体有机会在下一代中产生更多的子个体。然而在许多问题中,求解目标更自然地被表示成某个代价函数f(x)的极小化,而不是某个利益函数g(x)的极大化;即使问题被表示成极大化形式,仅仅这一点并不能确保利益函数g(x)对所有的x都是非负的。作为这些问题的结果,常常需要通过一次或多次变换把目标函数转化到适应函数F(x)。经常要用到的从目标函数到适应函数的变换为:
储层特征研究与预测
其中参数Cmax的选取有多种方法,可以取为输入参数、到目前为止所得到的f的最大值和在当前群体中或者最近W代中f的最大值。当目标函数是利益函数时,可以直接得到适应函数。
如果出现了负利益函数g(x)值的情形,可以利用下面的变换来克服:
储层特征研究与预测
其中Cmin可以取为输入参数、当前代中或最近W代中g的最小值的绝对值。
GA的主要计算步骤如下:
首先在解空间中取一群点,作为遗传开始的第一代。每个点(基因)用一个二进制的数字串表示,其优先程度用一目标函数来衡量。目标函数值大,表明那个点(基因)好,容易在遗传中生存下去。
在向下一代遗传演变中,首先当前一代中的每个数字串根据由其目标函数值决定的概率被复制到配对池中。好的数字串以高的概率被复制下来,劣的数字串被淘汰掉。然后将配对池中的数字串任意配对,并对每一对数字串进行交叉操作,产生新的子孙(数字串)。最后对新的数字串的某些位进行变异。这就产生了新的一代。按照同样的方法,经过数代的遗传演变后,在最后一代中得到全局最优解或近似最优解。
GA的基本框图如图4-2所示,其中变量GEN为当前代数:GA是一种借鉴自然选择和自然遗传机制的高度并行的、随机的自适应搜索算法。隐含并行性和对全局信息的有效利用能力是GA的两大显著特点,前者使GA只须检测少量的结构就能反映搜索空间的大量区域,后者使GA具有稳健性。与传统的搜索方法相比,GA具有以下不同:
(1)GA不是直接作用在参变量集上,而且利用参变量集的某种编码。
(2)GA不是从单个点开始搜索,而是从一个点所在的群体开始搜索,因而能快速全局收敛。
(3)GA利用适应值信息对算法产生的每个染色体进行评估,并基于适应值来选择染色体,使适应性好的染色体比适应性差的染色体有更多的繁殖机会。它不受搜索空间的限制性假设的约束,不必要求诸如连续性、导数存在和单峰等假设,因而具有广泛的适应性。
(4)GA利用权率转移规则,即非确定性规则。通过变异算子的作用,GA在恢复群体失去的多样性等方面具有潜在的作用,因此能搜索离散的、有噪声的、多峰值复杂空间。
(5)GA在解空间内充分的搜索,但并不是盲目的穷举或瞎碰(适应值为选择提供了依据),因此其搜索时耗用效率往往优于其他优化算法。
图4-2 常规遗传算法流程图
- 官方服务
- 官方网站
遗传算法详解与MATLAB实现
1算法讲解
1.1遗传算法流程描述
- 我们先随机生成几个个体(数值),
- 计算这几个个体是否适合当前环境(带入某个评价函数后结果大不大)
- 记录一下最好的一个个体(记录一下局部最优解)
- 依据适应度选入、淘汰一些个体(结果越好的数值有越大的概率不被扔掉,但是怕局部最优解所以还有有一定概率要被扔)
- 交叉互换的方式进行变异(转换为十进制语言来说,例如我有两个数值13和15都还可以,新的两个数值我要在11-17区间内选俩)
- 基因突变的方式进行变异(在范围内变异固然好,但是怕陷入局部最优解我还是要偶尔搞点大变异,哪怕是坏的变异)
- 进入下一轮循环,重新计算对当前环境适应程度继续前面的一系列步骤
- 好多好多带后(迭代次数大于我们的设定)后,输出记录的每一轮最优解里面最好的一个。
1.2关于为什么要用二进制码表示个体信息
可控变异:
假如我们有个二进制序列1111,转换为十进制就是15
若是我们将其变为1110,十进制变为14
若是我们将其变为1101,十进制变为13
变为1011,十进制变为11
变为0111,十进制变为7
也就是说,我们可以在大部分位置数据信息不变的情况下,各种幅度的改变我们的二进制序列代表的十进制信息。
1.3目标函数值与适应值区别
适应值=目标函数值-f(x)下限
为了方便求概率才多了个这么个操作,
举几个例子
1.假设f(x)范围是[0,3]
那么三个个体函数值为[1,2,3],那么每个个体被取到的概率很自然我们就想到设置为[1,2,3]/(1+2+3)=[1/6,1/3,1/2],数值越大取到概率越大很正常
2.假设f(x)范围为[10,10.1]
三个个体函数值为[10.01,10.05,10.03],算出其概率为[0.3327,0.3340,0.3333]非常的接近,这是因为0.几的数对比与10太小了,因而减去10非常有必要。
3.假设f(x)范围为[-1,1]
万一有个体数值为负数总不能搞个负数概率叭,所以-(-1)也是很有必要的
综上我们看出Fmin的设置也需要有一定讲究,不能使适应值出现负数,也最好能使数据具有区分度,当然如果有更加合适的映射来代替线性映射也是极好(例如机器学习就常用sigmod函数来映射)。
1.4关于如何将二进制码转化为为变量数值
假设我们有一个长度为4的二进制码,则其取值范围为0000至1111即[0,15];同时我们知道最优解范围是[2,3],我们只需要将二进制码转化为十进制,并且映射到最优解取值范围就好啦,
例如1011转换为十进制为11,从区间[0,15]映射到[2,3]即为,
(11-0)/(15-0)*(3-2)+2=2.7333,
从这个转换方式我们可以看出:
- 二进制码越长,其可取值也就越多也就能把最优解区间划分的越细,也就能使结果越精确,(当然我们可以依据我们想要的精确度大体设置二进制码长度)
- 最优解区间范围一定要有!!而且一个好的最优解区间能够让我们在取较短的二进制码时依旧可以得到较为精确的结果。
1.4关于代码改进
很多很多老版代码各种循环,这里能用向量运算就用向量运算,增加量程序的整洁度和速度
2各部分代码及使用
2.1代码使用
实例描述:
f
(
x
)
=
x
+
10
s
i
n
(
5
x
)
+
7
c
o
s
(
4
x
)
,
0
≤
x
≤
9
f(x)=x+10sin(5x)+7cos(4x),0\\leq x\\leq9
f(x)=x+10sin(5x)+7cos(4x),0≤x≤9
求
x
0
=
a
r
g
m
a
x
(
f
(
x
)
)
x_0=argmax(f(x))
x0=argmax(f(x))即使
f
(
x
)
f(x)
f(x)最大的
x
x
x值
使用代码:
[Count,Result,BestMember]=Genetic1(24,6,str2sym('x+10*sin(5*x)+7*cos(4*x)'),0,9,15,0.9,200);
参数:
- 24,二进制码长度为24
- 6,个体数目为6
- str2sym(‘x+10sin(5x)+7cos(4x)’),评价函数
- 0,x取值下限
- 9,x取值上限
- 15,f(x)下限,低于这个的我们认为这个个体完全不适合在该环境下生存
- 0.9,突变概率为了防止陷入局部最优这里数值设的其实有点大,大家用的时候设置小点就好
- 200,迭代代数
关于各个参数更详细的说明往后看
计算结果:
Count =200
Result =
7.8401,7.8048,7.8443,7.8403,7.8574,8.9649
24.8050,24.3683 ,24.8271,24.8066,11.1532,14.5649
BestMember =
7.8574
24.8553
即
x
=
7.8574
x=7.8574
x=7.8574时
f
(
x
)
f(x)
f(x)取最大值
24.8553
24.8553
24.8553
画个图看确实如此:
注:
遗传算法毕竟是智能算法,算出的值并不一定是最优解,因而可以调整迭代次数的大小,变异概率,二进制串长度,个体数量等一系列数据来调整,正因为各个变量比较难以说明为何这样设置,所以各种建模比赛还是尽量少用这样的智能算法。
2.2–Genetic1–主函数
function [Count,Result,BestMember]=Genetic1(MumberLength,MemberNumber,FunctionFitness,MinX,MaxX,Fmin,MutationProbability,Gen)
% 参数解释:
% 参数名 参数类型 参数含义
% =========================================================================
% MumberLength | 数值 | 表示一个染色体位串的二进制长度
% MemberNumber | 数值 | 表示群体中染色体个数
% FunctionFitness | 字符串 | 表示目标函数
% MinX | 数值 | 变量区间的下限
% MaxX | 数值 | 变量区间的上限
% Fmin | 数值 | 适应函数过程中给出目标函数可能最小值
% MutationProbability| 数值 | 变异概率
% Gen | 数值 | 遗传代数
% -------------------------------------------------------------------------
% Count | 数值 | 遗传代数
% Result | 数值 | 计算结果
% BestMember | 数值 | 最优个体及其适应值
global Count;Count=1;% 在之后的版本中可能会不支持函数输出作为全局变量(建议在改进工作中修改)
global CurrentBest; % 声明全局变量Count(代数)和CurrentBest(当前代数下的最优染色体)
% 随机地产生一个初始群体。
Population=PopulationInitialize(MumberLength,MemberNumber); PopulationCode=Population;
% 计算群体中每一个染色体的目标函数值,适应函数值,入选概率
PopulationFitness=Fitness(PopulationCode,FunctionFitness,MinX,MaxX,MumberLength);
PopulationFitnessF=FitnessF(PopulationFitness,Fmin);
PopulationProbability=Probability(PopulationFitnessF);
% 依据入选概率保留个体并记录最优个体
[Population,CurrentBest,EachGenMaxFitness]=Elitist(PopulationCode,PopulationFitness,MumberLength);
EachMaxFitness(Count)=EachGenMaxFitness;
MaxFitness(Count)=CurrentBest(MumberLength+1);
while Count<Gen
% 通过入选概率将入选概率大的个体选入种群,淘汰概率小的个体形成新群体
NewPopulation=Select(Population,PopulationProbability,MemberNumber);
Population=NewPopulation;
% 通过交叉互换形成新群体;
NewPopulation=Crossing(Population);
Population=NewPopulation;
% 通过变异形成新群体
NewPopulation=Mutation(Population,MutationProbability);
Population=NewPopulation;
% 计算新群体中每一染色体的目标函数值并借此计算出适应值与入选概率
PopulationFitness=Fitness(Population,FunctionFitness,MinX,MaxX,MumberLength);
PopulationFitnessF=FitnessF(PopulationFitness,Fmin);
PopulationProbability=Probability(PopulationFitnessF);
Count=Count+1;
% 替换当前最优个体并将最劣个体用最优个体替换
[NewPopulation,CurrentBest,EachGenMaxFitness]=Elitist(Population,PopulationFitness,MumberLength);
% EachMaxFitness,记录了第Count代中最优个体所对应的目标函数值;
% MaxFitness,前Count代中最优个体所对应的目标函数值;
EachMaxFitness(Count)=EachGenMaxFitness;
MaxFitness(Count)=CurrentBest(MumberLength+1);
Population=NewPopulation;
end
% 数据整理
Dim=size(Population);
Result=ones(2,Dim(1));
for ii=1:Dim(1)
Result(1,ii)=Translate(Population(ii,:),MinX,MaxX,MumberLength);
end
Result(2,:)=Fitness(Population,FunctionFitness,MinX,MaxX,MumberLength);
BestMember(1,1)=Translate(CurrentBest(1:MumberLength),MinX,MaxX,MumberLength);
BestMember(2,1)=CurrentBest(MumberLength+1);
% 绘图
close all
subplot(2,1,1)
plot(EachMaxFitness);
subplot(2,1,2)
plot(MaxFitness);
end
2.3–PI(PopulationInitialize)–产生初始种群
功能: 随机地产生一个初始群体。
输入变量:
- MemberNumber代表染色体个数
- MumberLength代表每个染色体上含有MumberLength个基因(即编码长度)
输出变量: Poplation表示第一代群体
原理: 生成MemberNumber个长度为MumberLength的0-1向量
function Population=PopulationInitialize(MumberLength,MemberNumber)
Temporary=rand(MemberNumber,MumberLength);
Population=Temporary>=0.5;
% Population是一个逻辑矩阵(0-1矩阵,这么写为了方便),
% 在此函数中表示第一代群体,Population的每一行表示一个染色体
end
2.4–Fitness–计算目标函数值
功能: 计算群体中每一个染色体的目标函数值。
输入参数:
- PopulationCode表示用二进制代码表示的群体;
- FunctionFitness表示目标函数;
- MinX,MaxX分别表示变量区间的下限和上限;
- MumberLength代表一个染色体位串的二进制长度;
输出变量:
PopulationFitness表示每一染色体对应的目标函数值
原理:
这部分就是把各个二进制码转换为十进制数(区间范围内),然后再带入到目标函数中算出数值。
说明: 由于懒,这里把网上大部分代码中的Translate函数和Transfer函数也合了进去,没必要为了两行运算多开俩函数吧。。。
function PopulationFitness=Fitness(PopulationCode,FunctionFitness,MinX,MaxX,MumberLength)
Dim=size(PopulationCode);
PopulationFitness=zeros(1,Dim(1));
FunctionFitness=matlabFunction(str2sym(FunctionFitness));
for i=1:Dim(1)
% 转换为10进制
PopulationData=sum(PopulationCode(i,:).*(2.^(MumberLength-1:-1:0)));
% 映射到x取值范围
PopulationData=MinX+PopulationData*(MaxX-MinX)/(2^Dim(2)-1);
% 计算对应f(x)数值
PopulationFitness(i)=FunctionFitness(PopulationData);
end
end
2.5–FitnessF–计算适应值
功能: 计算每个染色体的适应函数值
输入参数:
PopulationFitness表示目标函数值;
Fmin表示目标函数的可能的最小值;
输出参数: PopulationFitnessF表示每一染色体的适应函数值
function PopulationFitnessF=FitnessF(PopulationFitness,Fmin)
% 若某一染色体的目标函数值大于Fmin,则置其适应函数值为其目标函数值-Fmin
% 若某一染色体的目标函数值小于Fmin,则置其适应函数值为0
PopulationFitnessF=PopulationFitness-Fmin;
PopulationFitnessF(PopulationFitnessF<0)=0;
end
2.6–Translate–将二进制码转换
这部分代码已经包含在Fitness函数内了,再写一遍是专门用来服务于最后的结果输出的。
function PopulationData=Translate(PopulationCode,MinX,MaxX,MumberLength)
Dim=size(PopulationCode);
PopulationData=sum(PopulationCode.*(2.^(MumberLength-1:-1:0)));
PopulationData=MinX+PopulationData*(MaxX-MinX)/(2^Dim(2)-1);
end
2.7–Probability–染色体入选概率
就是将适应值转换为概率,其方法就是除以所有适应值的和
function PopulationProbability=Probability(PopulationFitnessF)
PopulationProbability=PopulationFitnessF./sum(PopulationFitnessF);
end
2.8–Select–个体选择
根据入选概率在群体中按比例选择部分染色体组成种群
function NewPopulation=Select(Population,PopulationProbability,MemberNumber)
% 概率密度转换为概率分布
CProbability=PopulationProbability(1);
for i=2:MemberNumber
CProbability(i)=CProbability(i-1)+PopulationProbability(i);
end
% 摇随机数并依据随机数和概率选择个体
pmat=rand([MemberNumber,1]);
index=sum((pmat>=CProbability),2)+1;
NewPopulation=Population(index,:);
end
2.9–Crossing–交叉互换
群体中的交叉并产生新群体,原理描述如下:
我们每次都是两个相邻的进行交叉,这样如果个体数为奇数,则最后一个个体则一直无法参与互换,因此我们每次都将倒数第一和倒数第二个体换位置,这样倒数第一位和倒数第二位就能够轮流参与交叉互换。(当然其实直接整体全部交换顺序也可以)
function NewPopulation=Crossing(Population)
Dim=size(Population);
if Dim(1)>=3
Population([Dim(1),Dim(1)-1],:)=Population([Dim(1)-1,Dim(1)],:);
% 若群体中个体数大于等于3,则将最后一个个体与倒数第二个个体基因型互换;
% 目的是防止有个体从始至终未参与交叉。
end
for i=1:2:Dim(1)-1
% 相邻的俩个体交叉互换
Site=randi(Dim(2));
Population([i,i+1],1:Site)=Population([i+1,i],1:Site);
end
NewPopulation=Population;
end
想改成全部互换则可写做:
function NewPopulation=Crossing(Population)
Dim=size(Population);
Population(1:Dim,:)=Population(randperm(Dim(1)),:);
for i=1:2:Dim(1)-1
Site=randi(Dim(2));
Population([i,i遗传算法详解与MATLAB实现