遗传算法,(英文全称是genetic algorithm,GA)是一种非常经典的优化算法,是上个世纪60年代提出的,经过这么长时间的不断地改进,现在已经成为一个体系。原理就是模仿生物界中的进化方法,“物竞天择,适者生存”就是这个算法最好的概述。
遗传算法,简单来说就是,把一个非常具体的问题用数学言语(也就是数学公式)来描述清楚,比如找出对应问题合适的适应度函数和对应的目标状态集合;
再把问题的参数(x,y,z,i,h,l 这样的参数)进行编码,也就是把这些参数二进制化(比如 X=8,就是表示成1000),这些由0和1组成的组合串就被称为染色体(也可以说成个体),这种组合成染色体的1和0 就是基因。这每一个染色体也可以理解为这个问题的一个解,只不过不一定是最优解,遗传算法就是通过一些接下来的操作来找出问题的最优解。
由一定数量的个体,就组成了群体,这个群体就叫:种群,这个群体内部的个体数量就叫:种群大小,也可以叫成:种群规模。
这个群体在算法刚开始进行的时候就是随机从问题参数中进行选取出来的,先计算每个个体对应的适应度函数值,之后就是根据这个计算值,进行排序。
按照排序的高低,一般视适应度函数和目标状态而定,如果需要适应度函数值最小,那么就是计算值越小越好,反之也是同样的道理。
算法进行到这里,就是整个遗传算法的最重要的地方了。整个遗传算法的精髓可以说是:复制、交叉、变异。
把排名最好的那几个计算值挑出来,他们对应的个体,也就是染色体不要变,原样的ctrl + C,ctrl+V到下一代的种群中。
排名靠前但是不是前几名的计算值也挑出来,他们个体的二进制数的对应的位数,进行交叉的操作,其实就是把我的数给你,你的数再给我,就是相互交换,这样就会产生新的个体,这样也进入下一代新的种群中去。
剩下的就是排名最差的计算值,他们所对应的个体就需要进行变异的操作,所谓的变异,就是把这些个体的二进制数的对应位数上的0和1,进行变换,比如说原来第2位上是0,现在就要变成1,这样操作过后,也会产生新的个体进入到下一代新的种群去。
就是经过了:复制、交叉、变异,这三个核心操作之后,一个新的种群诞生了,就可以开始新的一轮上述的操作了。这就是迭代的过程。
最经典的遗传算法,是在算法最开始的地方设置:最大迭代数,每一次迭代,迭代计数器就会自动加一,再判断是否达到最大迭代数,达到之后,整个算法就会退出循环,按照最后一代的种群的计算值的最优解,将其视为整个问题的最优解。
我之前也上传过遗传算法的讲解视频。链接如下:知乎视频www.zhihu.com
下面,通过一个非常简单的小栗子来从代码的角度说明以上思路。
问题:简单的一元函数优化,利用遗传算法来寻找一下函数的最小值
首先是利用matlab代码来进行解释说明。运行本代码需要事先安装谢非尔得大学的matlab遗传算法工具箱
clc
clear all
close all
%% 画出函数图
figure(1);
hold on;
lb=1;ub=2; %函数自变量范围【1,2】
ezplot('sin(10*pi*X)/X',[lb,ub]); %画出函数曲线
xlabel('自变量/X')
ylabel('函数值/Y')
%% 定义遗传算法参数
NIND=40; %个体数目
MAXGEN=20; %最大遗传代数
PRECI=20; %变量的二进制位数
GGAP=0.95; %代沟
px=0.7; %交叉概率
pm=0.01; %变异概率
trace=zeros(2,MAXGEN); %寻优结果的初始值
FieldD=[PRECI;lb;ub;1;0;1;1]; %区域描述器
Chrom=crtbp(NIND,PRECI); %初始种群
%% 优化
gen=0; %代计数器
X=bs2rv(Chrom,FieldD); %计算初始种群的十进制转换
ObjV=sin(10*pi*X)./X; %计算目标函数值
while gen
FitnV=ranking(ObjV); %分配适应度值
SelCh=select('sus',Chrom,FitnV,GGAP); %选择
SelCh=recombin('xovsp',SelCh,px); %重组
SelCh=mut(SelCh,pm); %变异
X=bs2rv(SelCh,FieldD); %子代个体的十进制转换
ObjVSel=sin(10*pi*X)./X; %计算子代的目标函数值
[Chrom,ObjV]=reins(Chrom,SelCh,1,1,ObjV,ObjVSel); %重插入子代到父代,得到新种群
X=bs2rv(Chrom,FieldD); %计算种群的十进制转换
gen=gen+1; %代计数器增加
[Y,I]=min(ObjV); %获取每代的最优解及其序号,Y为最优解,I为个体的序号
trace(1,gen)=X(I); %记下每代的最优值
trace(2,gen)=Y; %记下每代的最优值
end
plot(trace(1,:),trace(2,:),'bo'); %画出每代的最优点
grid on;
plot(X,ObjV,'b*'); %画出最后一代的种群
hold off
%% 画进化图
figure(2);
plot(1:MAXGEN,trace(2,:));
grid on
xlabel('遗传代数')
ylabel('解的变化')
title('进化过程')
bestY=trace(2,end);
bestX=trace(1,end);
fprintf(['最优解:\nX=',num2str(bestX),'\nY=',num2str(bestY),'\n'])
这篇文章是我第一次尝试用大白话来讲讲这个遗传算法,可能其中会有一些不太严谨或者我理解错误的地方,希望读者有思考和收获,若发现错误,可以指出,也欢迎讨论交流。