为了能随时了解Matlab主要操作及思想。
故本文贴上NSGA-Ⅱ算法Matlab实现(测试函数为ZDT1)。
感谢郭伟学长提供的代码。
代码所有权归郭伟学长。
在看Matlab实现之前,请先看一下NSGA-II算法概述
NSGA-Ⅱ就是在第一代非支配排序遗传算法的基础上改进而来,其改进主要是针对如上所述的三个方面:
①提出了快速非支配排序算法,一方面降低了计算的复杂度,另一方面它将父代种群跟子代种群进行合并,使得下一代的种群从双倍的空间中进行选取,从而保留了最为优秀的所有个体;
②引进精英策略,保证某些优良的种群个体在进化过程中不会被丢弃,从而提高了优化结果的精度;
③采用拥挤度和拥挤度比较算子,不但克服了NSGA中需要人为指定共享参数的缺陷,而且将其作为种群中个体间的比较标准,使得准Pareto域中的个体能均匀地扩展到整个Pareto域,保证了种群的多样性。
Matlab实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
function NSGAII() clc;format compact;tic;hold on %---初始化/参数设定 generations=100; %迭代次数 popnum=100; %种群大小(须为偶数) poplength=30; %个体长度 minvalue=repmat(zeros(1,poplength),popnum,1); %个体最小值 maxvalue=repmat(ones(1,poplength),popnum,1); %个体最大值 population=rand(popnum,poplength).*(maxvalue-minvalue)+minvalue; %产生新的初始种群 %---开始迭代进化 for gene=1:generations %开始迭代 %-------交叉 newpopulation=zeros(popnum,poplength); %子代种群 for i=1:popnum/2 %交叉产生子代 k=randperm(popnum); %从种群中随机选出两个父母,不采用二进制联赛方法 beta=(-1).^round(rand(1,poplength)).*abs(randn(1,poplength))*1.481; %采用正态分布交叉产生两个子代 newpopulation(i*2-1,:)=(population(k(1),:)+population(k(2),:))/2+beta.*(population(k(1),:)-population(k(2),:))./2; %产生第一个子代 newpopulation(i*2,:)=(population(k(1),:)+population(k(2),:))/2-beta.*(population(k(1),:)-population(k(2),:))./2; %产生第二个子代 end %-------变异 k=rand(size(newpopulation)); %随机选定要变异的基因位 miu=rand(size(newpopulation)); %采用多项式变异 temp=k<1/poplength & miu<0.5; %要变异的基因位 newpopulation(temp)=newpopulation(temp)+(maxvalue(temp)-minvalue(temp)).*((2.*miu(temp)+(1-2.*miu(temp)).*(1-(newpopulation(temp)-minvalue(temp))./(maxvalue(temp)-minvalue(temp))).^21).^(1/21)-1); %变异情况一 newpopulation(temp)=newpopulation(temp)+(maxvalue(temp)-minvalue(temp)).*(1-(2.*(1-miu(temp))+2.*(miu(temp)-0.5).*(1-(maxvalue(temp)-newpopulation(temp))./(maxvalue(temp)-minvalue(temp))).^21).^(1/21)); %变异情况二 %-------越界处理/种群合并 newpopulation(newpopulation>maxvalue)=maxvalue(newpopulation>maxvalue); %子代越上界处理 newpopulation(newpopulation<minvalue)=minvalue(newpopulation<minvalue); %子代越下界处理 newpopulation=[population;newpopulation]; %合并父子种群 %-------计算目标函数值 functionvalue=zeros(size(newpopulation,1),2); %合并后种群的各目标函数值,这里的问题是ZDT1 functionvalue(:,1)=newpopulation(:,1); %计算第一维目标函数值 g=1+9*sum(newpopulation(:,2:poplength),2)./(poplength-1); functionvalue(:,2)=g.*(1-(newpopulation(:,1)./g).^0.5); %计算第二维目标函数值 %-------非支配排序 fnum=0; %当前分配的前沿面编号 cz=false(1,size(functionvalue,1)); %记录个体是否已被分配编号 frontvalue=zeros(size(cz)); %每个个体的前沿面编号 [functionvalue_sorted,newsite]=sortrows(functionvalue); %对种群按第一维目标值大小进行排序 while ~all(cz) %开始迭代判断每个个体的前沿面,采用改进的deductive sort fnum=fnum+1; d=cz; for i=1:size(functionvalue,1) if ~d(i) for j=i+1:size(functionvalue,1) if ~d(j) k=1; for m=2:size(functionvalue,2) if functionvalue_sorted(i,m)>functionvalue_sorted(j,m) k=0; break end end if k d(j)=true; end end end frontvalue(newsite(i))=fnum; cz(i)=true; end end end %-------计算拥挤距离/选出下一代个体 fnum=0; %当前前沿面 while numel(frontvalue,frontvalue<=fnum+1)<=popnum %判断前多少个面的个体能完全放入下一代种群 fnum=fnum+1; end newnum=numel(frontvalue,frontvalue<=fnum); %前fnum个面的个体数 population(1:newnum,:)=newpopulation(frontvalue<=fnum,:); %将前fnum个面的个体复制入下一代 popu=find(frontvalue==fnum+1); %popu记录第fnum+1个面上的个体编号 distancevalue=zeros(size(popu)); %popu各个体的拥挤距离 fmax=max(functionvalue(popu,:),[],1); %popu每维上的最大值 fmin=min(functionvalue(popu,:),[],1); %popu每维上的最小值 for i=1:size(functionvalue,2) %分目标计算每个目标上popu各个体的拥挤距离 [~,newsite]=sortrows(functionvalue(popu,i)); distancevalue(newsite(1))=inf; distancevalue(newsite(end))=inf; for j=2:length(popu)-1 distancevalue(newsite(j))=distancevalue(newsite(j))+(functionvalue(popu(newsite(j+1)),i)-functionvalue(popu(newsite(j-1)),i))/(fmax(i)-fmin(i)); end end popu=-sortrows(-[distancevalue;popu]')'; %按拥挤距离降序排序第fnum+1个面上的个体 population(newnum+1:popnum,:)=newpopulation(popu(2,1:popnum-newnum),:); %将第fnum+1个面上拥挤距离较大的前popnum-newnum个个体复制入下一代 end %---程序输出 fprintf('已完成,耗时%4s秒\n',num2str(toc)); %程序最终耗时 output=sortrows(functionvalue(frontvalue==1,:)); %最终结果:种群中非支配解的函数值 plot(output(:,1),output(:,2),'*b'); %作图 axis([0,1,0,1]);xlabel('F_1');ylabel('F_2');title('ZDT1') end |
这个有约束条件的话,怎么加呢?
请问问题解决了吗,QQ978438391
博主,我用ZDT3测试并不能得到间段的结果,这是为什么?
博主您好,目标函数要写在哪里呢?就是我自己根据实际例子编写的目标函数,比如列车速度最小、耗能最小这钟?
请问你懂了吗?我也想问一下如何加上自己的目标函数
请问问题解决了吗,QQ978438391
想问一下博主,不知道你有没有NSGA-3的像这样子的代码,有的话可以给我发一份吗,感谢感谢!
我的邮箱是2215421217@qq.com
可以使用PlatEMO
哪里找这个平台
https://github.com/BIMK/PlatEMO
楼主你好,感谢你的分享。我在学习过程中不太明白交叉系数beta 1.481是什么意思是,以及产生第一、第二个子代的交叉公式 newpopulation(i*2-1,:) 的依据,不知能否解答?十分感谢
第一个系数是实验中选择的最好的结果,交叉方式有很多,可以调研一下遗传算法的交叉。
嗯嗯,谢谢!
我想问下你的这个代码为什么没有交叉变异概率呀?
有的
temp=k<1/poplength & miu<0.5; %要变异的基因位
这个我知道,但是那个交叉概率呢?正态分布交叉和多项式变异,您那边有数学公式吗?感谢🙏
您好,请问我用matlab中的dace工具得到的优化函数是个结构体,这种情况该怎么处理,谢谢。
请问在代码的哪一行呢?
您好,我想把测试函数改成ZDT4,但是遇到了一些问题,请问计算目标函数值的地方我改的 g=1+10.*(poplength-1)+sum((newpopulation(:,2:poplength),2).^2-10.*cos(4.*pi.*(newpopulation(:,2:poplength),2)));哪里不太对_(:з」∠)_
请问你懂了吗?我想请问一下应该在代码哪个位置加上自己的目标函数?
同问,请问您解决了嘛?
您好,有问题想请教,目标函数不会处理呀,我的目标函数比较复杂,涉及到的优化参量也比较多,我能加下您的QQ吗,想要学习下。我的qq562808145
这样啊,我也只会个框架而已,我觉得目标函数可以和nsga2分开来独立出来,不一定会你的,你加我QQ吧:644327005
你好,我想咨询一下关于有约束的多目标优化函数您这边解决了吗 可以看一下程序吗
同需要解决类似的问题,可以交流一下吗
我也需要解决这类问题,可以一起交流嘛?
我也是
我也需要解决这类问题,请问您解决了嘛?