遗传算法是计算数学中用于解决最优化的搜索算法,是进化算法的一种。进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择以及杂交等。其本质是一种高效、并行、全局搜索的方法,能在搜索过程中自动获取和积累有关搜索空间的知识,并自适应地控制搜索过程以求得最佳解。
相关术语 (了解)
概念 | 意思 |
---|---|
基因型(genotype) | 性状染色体的内部表现 |
表现型(phenotype) | 染色体决定的性状的外部表现 |
进化(evolution) | 种群逐渐适应生存环境,品质不断得到改良 |
适应度(fitness) | 度量某个物种对于生存环境的适应程度 |
选择(selection) | 以一定的概率从种群中选择若干个个体 |
复制(reproduction) | 细胞分裂时,DNA通过复制而转移到新产生的细胞中,新细胞就继承了旧细胞的基因 |
交叉(crossover) | 两个染色体的某一相同位置处DNA被切断,前后两串分别交叉组合形成两个新的染色体 |
变异(mutation) | 复制时可能(很小的概率)产生某些复制差错,变异产生新的染色体,表现出新的性状 |
编码(coding) | DNA中遗传信息在一个长链上按一定的模式排列(表现型到基因型的映射) |
解码(decoding) | 基因型到表现型的映射 |
个体(individual) | 染色体带有特征的实体 |
种群(population) | 个体的集合,该集合内个体数称为种群的大小 |
遗传算法的流程
- 随机生成一组可行解,也就是第一代染色体
- 采用适应度函数分别计算每一条染色体的适应程度,并根据适应程度计算每一条染色体在下一次进化中被选中的概率
- 通过“交叉”,生成 N-M 条染色体
- 对交叉后生成的 N-M 条染色体进行“变异”操作
- 使用“复制”的方式生成 M 条染色体
- 分别计算N条染色体的适应度和下次被选中的概率,紧接着进行新一轮的进化
选择进化次数
理论上进化次数越多越好,每次都会进一步优化,但是在实际应用中需要考虑时间和结果的精确度,因此需要对进化次数进行约束。
限定次数
如果实验表明不管输入的数据如何变化,算法在进化 N 次之后就能够得到最优解,那么可以将进化的次数设成 N
限定范围
如果算法要达到全局最优解可能要进行很多次的进化,这极大影响系统的性能。那么可以在算法的精确度和系统效率之间寻找一个平衡点。我们可以事先设定一个可以接收的结果范围,当算法进行 N 次进化后,一旦发现结果已经在误差范围之内了,那么就终止算法
两个方法中,前者在实际情况下难以达到要求,不同的输入会导致得到最优解时的迭代次数相差较大;后者的缺点则是有些情况下可能稍微进化几次就进入了误差允许范围,算法的执行效率不可控。因此需要根据情况进行合理地选择
案例解读
找出已知函数在特定区间的最大值:
函数曲线如图:
范例使用 MatLab
主函数
function genmain()
tic;
clear
clf
popsize = 50; %群体大小
chromlength = 10; %字符串长度(个体长度)
pc = 0.6; %交叉概率
pm = 0.001; %变异概率
pop = initpop(popsize, chromlength); %随机产生初始群体
for i = 1:20 %20为迭代次数
objvalue = calobjvalue(pop); %计算目标函数
fitvalue = calfitvalue(objvalue); %计算群体中每个个体的适应度
newpop = selection(pop, fitvalue); %复制
newpop = crossover(pop, pc); %交叉
newpop = mutation(pop, pm); %变异
[bestindividual, bestfit] = best(pop, fitvalue); %求出群体中适应值最大的个体及其适应值
y(i) = max(bestfit);
n(i) = i;
pop5 = bestindividual;
x(i) = decodechrom(pop5, 1, chromlength) * 10 / 1023;
pop = newpop;
end
%画出图形
fplot('10*sin(5*x)+7*cos(4*x)', [0 10])
hold on
plot(x, y, 'r*')
hold off
可以看到上面代码中,每一步都是按照遗传算法的流程来进行的
结果如图:
出现的各个函数下面再具体解释:
初始化函数
function pop = initpop(popsize, chromlength)
pop = round(rand(popsize, chromlength));
% rand产生行数为popsize,列数为chromlength的矩阵,其中每个数随机取 0 或 1
% round对矩阵的每个单元进行圆整
popsize
表示群体的大小,chromlength
表示染色体的长度 (二值数的长度),长度大小取决于变量的二进制编码的长度 (在本例中取10位)
因为在进行交叉、变异等操作时,需要使用二进制数的形式进行
比如:1010110101 和 1101001010 进行交叉
结果可以是:1010101010,此处把前 5 位用前者的数,后 5 位用后者的数,实际操作时随机进行
但是当我们代值运算时,使用的是十进制数,因此需要进行进制转换。10 位二进制数的转为十进制数的范围是 [0, 1023],采用 的式子来转换,其中 b 为 [0,1023] 中的一个二值数
进制转换
function pop2 = decodebinary(pop)
[px, py] = size(pop); %求pop行和列数
for i = 1:py
pop1(:, i) = 2.^(py-i).*pop(:, i);
end
pop2 = sum(pop1,2); %求pop1的每行之和
function pop2 = decodechrom(pop, spoint, length)
pop1 = pop(:,spoint:spoint+length-1);
pop2 = decodebinary(pop1);
上面两个都是将二进制转换为十进制的函数,面对不同情况,都会用到
计算目标函数值
function [objvalue] = calobjvalue(pop)
temp1 = decodechrom(pop, 1, 10); %将pop每行转化成十进制数
x = temp1*10/1023; %将二值域 中的数转化为变量域 的数
objvalue = 10*sin(5*x)+7*cos(4*x); %计算目标函数值
此处就是把 x 值代入函数中计算得出 y 值
计算个体的适应度
function fitvalue = calfitvalue(objvalue)
global Cmin;
Cmin = 0;
[px, py] = size(objvalue);
for i = 1:px
if objvalue(i)+Cmin > 0
temp = Cmin+objvalue(i);
else
temp = 0.0;
end
fitvalue(i) = temp;
end
fitvalue = fitvalue';
求出适应度是为了选择适合的个体,上述函数中只有大于 0 的值的适应度才大于 0,值越大适应度越大
之后单个个体被选择的概率为:个体适应度 / 适应度之和,只有大于 0 的个体才可能被选中,值越大被选中的概率越大
选择复制
function [newpop] = selection(pop, fitvalue)
totalfit = sum(fitvalue); %求适应值之和
fitvalue = fitvalue/totalfit; %单个个体被选择的概率
fitvalue = cumsum(fitvalue); %如 fitvalue=[1 2 3 4],则 cumsum(fitvalue)=[1 3 6 10]
[px,py] = size(pop);
ms = sort(rand(px,1)); %从小到大排列
fitin = 1;
newin = 1;
while newin <= px %随机选择优良个体(所需个体)复制到下一代
if(ms(newin)) < fitvalue(fitin)
newpop(newin) = pop(fitin);
newin = newin+1;
else
fitin = fitin+1;
end
end
上诉程序中采用赌轮盘选择法选择。假如有5条染色体,他们的适应度分别为5、8、3、7、2,那么总的适应度为:F = 5 + 8 + 3 + 7 + 2 = 25;那么各个个体的被选中的概率为:那么各个个体的被选中的概率为:20%、32%、12%、28%、8%
得到如下转盘:
当指针在这个转盘上转动,停止下来时指向的个体就被选择到,适应度越高的个体被选中的概率越大
交叉
function [newpop] = crossover(pop,pc)
[px,py] = size(pop);
newpop = ones(size(pop));
for i = 1:2:px-1
if(rand<pc)
cpoint = round(rand*py);
newpop(i, :) = [pop(i, 1:cpoint), pop(i+1, cpoint+1:py)];
newpop(i+1, :) = [pop(i+1, 1:cpoint), pop(i, cpoint+1:py)];
else
newpop(i, :) = pop(i);
newpop(i+1, :) = pop(i+1);
end
end
交叉(crossover),群体中的每个个体之间都以一定的概率 pc 交叉,即两个个体从各自字符串的某一位置(一般是随机确定)开始互相交换,这类似生物进化过程中的基因分裂与重组。
例如:假设2个父代个体x1,x2为:x1=0100110、x2=1010001
从每个个体的第3位开始交叉,交又后得到2个新的子代个体y1,y2分别为:y1=0100001、y2=1010110
这样2个子代个体就分别具有了2个父代个体的某些特征。利用交又我们有可能由父代个体在子代组合成具有更高适合度的个体,事实上交又是遗传算法区别于其它传统优化方法的主要特点之一
变异
function [newpop] = mutation(pop, pm)
[px, py] = size(pop);
newpop = ones(size(pop));
for i = 1:px
if(rand < pm)
mpoint = round(rand*py);
if mpoint <= 0
mpoint = 1;
end
newpop(i) = pop(i);
if any(newpop(i, mpoint)) == 0
newpop(i, mpoint) = 1;
else
newpop(i, mpoint) = 0;
end
else
newpop(i) = pop(i);
end
end
变异(mutation),基因的突变普遍存在于生物的进化过程中。变异是指父代中的每个个体的每一位都以概率 pm 翻转,即由“1”变为“0”,或由“0”变为“1”。遗传算法的变异特性可以使求解过程随机地搜索到解可能存在的整个空间,因此可以在一定程度上求得全局最优解
求出群体中最大得适应值及其个体
function [bestindividual,bestfit]=best(pop,fitvalue)
[px,py]=size(pop);
bestindividual=pop(1,:);
bestfit=fitvalue(1);
for i=2:px
if fitvalue(i)>bestfit
bestindividual=pop(i,:);
bestfit=fitvalue(i);
end
end
转载:https://blog.csdn.net/weixin_44613063/article/details/104139960