github: 智能算法的课件和参考资料以及实验代码
- 遗传算法(Genetic Algorithm)
模拟达尔文生物进化论的自然选择和遗传学机理的生物进化过程的计算模型,是一种通过模拟自然进化过程搜索最优解的方法。遗传算法是从代表问题可能潜在的解集的一个种群(population)开始的,而一个种群则由经过基因(gene)编码的一定数目的个体(individual)组成。每个个体实际上是染色体(chromosome)带有特征的实体。由于仿照基因编码的工作很复杂,我们往往进行简化,如二进制编码,初代种群产生之后,按照适者生存和优胜劣汰的原理,逐代(generation)演化产生出越来越好的近似解,在每一代,根据问题域中个体的适应度(fitness)大小选择(selection)个体,并借助于自然遗传学的遗传算子(genetic operators)进行组合交叉(crossover)和变异(mutation),产生出代表新的解集的种群。这个过程将导致种群像自然进化一样的后生代种群比前代更加适应于环境,末代种群中的最优个体经过解码(decoding),可以作为问题近似最优解。
原理:
遗传算法是一类随机优化算法,通过对染色体的评价和对染色体中基因的遗传操作,有效地指导搜索有希望改善优化质量的状态。标准遗传算法主要步骤可描述如下:
1、随机产生一组初始个体构成初始种群。
2、计算每一个体的适配值(fitness value,也称为适应度)。适应度值是对染色体(个体)进行评价的一种指标,是遗传算法进行优化所用的主要信息,它与个体的目标值存在一种对应关系。
3、判断算法收敛准则是否满足,若满足,则输出搜索结果;否则执行以下步骤。
4、根据适应度值大小以一定方式(例如赌轮法)执行选择操作。
5、按交叉概率pc执行交叉操作。
6、按变异概率pm执行变异操作。
7、返回步骤②。
下面是一元函数和二元函数优化示例代码:
f1.m
function y = f(x)
% 测试函数为一元函数 x∈[-2, 1]
y = x * sin(10 * pi * x) + 2.0;
mainGA1.m
clear all
tic
% N: 初始种群数量
% pc: 交叉概率
% pm: 变异概率
% per: 要求精度10^4 * (b-a)
N=10;pc=0.95;pm=0.1;
per=4;
a=-2;b=1; % x范围在[-2, 1]
L=ceil(log2((b-a)*10^per)); % L为编码长度
% 四种取整函数用法:
% fix(x): 截尾取整
% floor(x): 向下取整
% ceil(x): 向上取整
% round(x): 四舍五入取整
s=round(rand(N,L)); % N行L列矩阵,表示N个个体
maxf=0;
% 由于y在循环中是动态扩容数组,解释器提示会影响性能,因此提前分配
y = zeros(1, N);
s2 = s;
max_f = y;
mean_f = y;
% 遍历种群找适应度最大个体对应的maxf和适应度向量y
for i=1:N
% num2str()函数将第i行所有列拼接成字符串
% x为第i个个体binary string转换成的整数
x=a+bin2dec(num2str(s(i,:)))*(b-a)/(2^L-1);
y(i)=f1(x); % 计算适应度 y向量表示每个个体适应度
if y(i)>maxf
maxf=y(i);
opmx=x; % f(x)取最大适应度的x值
end
end
T=1000; % T迭代次数.
for t=1:T
%select 选择
% 选择方法: 赌轮选择法
p=y/sum(y); % p向量表示每个染色体选择的概率
q=cumsum(p); % q向量表示每个染色体的累积概率
% for循环从新生成N个个体
for i=1:N
temp=rand(1);
Ind=find(q>=temp); % Ind(1)为q向量中累计概率第一个大于temp的染色体
s2(i,:)=s(Ind(1),:);
end
% 选择方法: 随机普遍采样法
% p = y/sum(y);
% q=cumsum(p);
% temp=rand(1)/N;
% i=1;
% j=1;
% for i=1:N
% while(temp<q(i))
% s2(j,:)=s(i,:);
% j=j+1;
% temp=temp+1/N;
% end
% end
% crossover 交叉
% 单点交叉
for i=1:N
if rand(1)<pc
I=1+fix((N-1)*rand(1));
J=1+fix((N-1)*rand(1));
if I~=J
k=round((L-1)*rand(1)); % k范围[0, L-1]
temp1=s2(I,k+1:end);
temp2=s2(J,k+1:end);
s2(I,k+1:end)= temp2;
s2(J,k+1:end)= temp1;
end
end
end
% 两点交叉
% for i=1:N
% if rand(1)<pc
% I=1+fix((N-1)*rand(1));
% J=1+fix((N-1)*rand(1));
% if I~=J
% k=round((L-1)*rand(1)); % k范围[0,L-1]
% l=round((L-1)*rand(1)); % L范围[0,L-1]
% if k<=L
% temp1=s2(I,k+1:l+1);
% temp2=s2(J,k+1:l+1);
% s2(I,k+1:l+1)= temp2;
% s2(J,k+1:l+1)= temp1;
% else
% temp1=s2(I,l+1:k+1);
% temp2=s2(J,l+1:k+1);
% s2(I,l+1:k+1)= temp2;
% s2(J,l+1:k+1)= temp1;
% end
% end
% end
% end
% 均匀交叉
% px = 0.5; % 均匀交叉位交换概率
% for i=1:N
% if rand(1)<pc
% I=1+fix((N-1)*rand(1));
% J=1+fix((N-1)*rand(1));
% if I~=J
% for j=1:L
% if rand(1)<=px
% temp1=s2(I,j);
% temp2=s2(J,j);
% s2(I,j)= temp2;
% s2(J,j)= temp1;
% end
% end
% end
% end
% end
%mututation 变异
for i=1:N
if rand(1)<pm
I=1+fix((N-1)*rand(1));
k=1+fix((L-1)*rand(1));
s2(I,k)=1-s2(I,k); % 单点变异位置k取反
end
end
s=s2;
% 计算每个个体适应度值,记录最大maxf适应度以及对应x的值
for i=1:N
x=a+bin2dec(num2str(s(i,:)))*(b-a)/(2^L-1);
y(i)=f1(x);
if y(i)>maxf
maxf=y(i);
opmx=x;
end
end
max_f(t)=maxf; % max_f最终是100列的向量,记录每次迭代最大适应度
mean_f(t)=mean(y); % 种群平均适应度
end
plot(1:T,max_f,'r',1:T,mean_f,'g');
hold on;
legend("pc=" + num2str(pc), "pm=" + num2str(pm));
xlabel('种群代数');
ylabel('适应度');
title("GA一元函数实验: " + "种群数量: " + num2str(N) + " 代数:" + num2str(T) + " 时间:" + num2str(toc) + " seconds");
maxf
opmx
f2.m
funcion y = f2(x1, x2)
% 测试函数为二元函数 x1∈ [-3.0, 12.1], x2 ∈ [4.1, 5.8]
y = 21.5 + x1 * sin(4 * pi * x1) + x2 * sin(20 * pi * x2);
mainGA2.m
clear all
tic
% N: 初始种群数量
% pc: 交叉概率
% pm: 变异概率
% per: 要求精度10^4 * (b-a)
N=10;pc=0.95;pm=0.1;
per=4;
% x1∈[-3, 12.1] 编码长度L1
a1=-3;b1=12.1;
L1=ceil(log2((b1-a1)*10^per));
a2=4.1;b2=5.8;
% x2∈[4.1, 5.8] 编码长度L2
L2=ceil(log2((b2-a2)*10^per));
% L为二进制串基因总编码长度
L=L1+L2;
s=round(rand(N,L)); % 初始种群
maxf=0;
% 由于y在循环中是动态扩容数组,解释器提示会影响性能,因此提前分配
y = zeros(1, N);
s2 = s;
max_f = y;
mean_f = y;
for i=1:N
x1=a1+bin2dec(num2str(s(i,1:L1)))*(b1-a1)/(2^L1-1);
x2=a2+bin2dec(num2str(s(i,L1+1:L1+L2)))*(b2-a2)/(2^L2-1);
y(i)=f2(x1,x2);
if y(i)>maxf
maxf=y(i);
opmx=[x1,x2]; % f(x1, x2)取最大适应度x1,x2组成的行向量
end
end
T=1000; % 种群代数(iteration count constants)
for t=1:T
%select 选择
p=y/sum(y);
q=cumsum(p);
for i=1:N
temp=rand(1);
Ind=find(q>=temp);
s2(i,:)=s(Ind(1),:);
end
%crossover 交叉
for i=1:N
if rand(1)<pc
I=1+fix((N-1)*rand(1));
J=1+fix((N-1)*rand(1));
if I~=J
k=round((L-1)*rand(1));
temp1=s2(I,k+1:end);
temp2=s2(J,k+1:end);
s2(I,k+1:end)= temp2;
s2(J,k+1:end)= temp1;
end
end
end
%mututation 变异
for i=1:N
if rand(1)<pm
I=1+fix((N-1)*rand(1));
k=1+fix((L-1)*rand(1));
s2(I,k)=1-s2(I,k);
end
end
s=s2;
for i=1:N
x1=a1+bin2dec(num2str(s(i,1:L1)))*(b1-a1)/(2^L1-1);
x2=a2+bin2dec(num2str(s(i,L1+1:L1+L2)))*(b2-a2)/(2^L2-1);
y(i)=f2(x1,x2);
if y(i)>maxf
maxf=y(i);
opmx=[x1,x2];
end
end
max_f(t)=maxf;
mean_f(t)=mean(y);
end
plot(1:T,max_f,'b',1:T,mean_f,'g')
hold on;
legend("pc=" + num2str(pc), "pm=" + num2str(pm));
xlabel('种群代数');
ylabel('适应度');
title("GA二元函数实验: " + "种群数量: " + num2str(N) + " 代数:" + num2str(T) + " 时间:" + num2str(toc) + " seconds");
maxf
opmx
GA算法可以应用到背包问题、旅行商问题、以及工业流程等优化问题,在机器学习中也有一些应用。