源代码

  完整代码如下所示,评价函数使用的是经典的ZDT3测试函数。

import numpy as np
from deap import base, tools, creator, algorithms
import random
import matplotlib.pyplot as plt
#定义问题
creator.create('MultiObjMin',base.Fitness,weights=(-1.0,-1.0))#两个目标,都求最小值
creator.create('Individual',list,fitness = creator.MultiObjMin)#创建individual类def genInd(low,up):return [random.uniform(low[0],up[0]),random.uniform(low[1],up[1])]#实数编码,一个个体里两个基因toolbox  = base.Toolbox()
Ndim = 2#两个变量
low = [0,0]#两个变量的下界
up = [1,1]#两个变量的上界toolbox.register('genInd',genInd,low,up)
toolbox.register('individual',tools.initIterate,creator.Individual,toolbox.genInd)#注册个体生成工具
#print(toolbox.individual())#打印一个个体检查def ZDT3(ind):#测试函数,注意这里与单目标比最明显的区别是有两个返回值(两个目标)n = len(ind)f1 = ind[0]g = 1 + 9 * np.sum(ind[1:])/(n-1)f2 = g * (1 - np.sqrt(ind[0]/g) - ind[0]/g * np.sin(10*np.pi*ind[0]))return f1,f2#返回在两个函数上的值
toolbox.register('evaluate',ZDT3)#注册评价函数N_POP = 200#种群内个体数量,参数过小,搜索速度过慢
toolbox.register('population',tools.initRepeat,list,toolbox.individual)#注册种群生成工具
pop = toolbox.population(n=N_POP)#建立种群pop
#for ind in pop:#打印一个种群检查
#   print(ind)toolbox.register('selectGen1', tools.selTournament, tournsize=2)
toolbox.register('select', tools.emo.selTournamentDCD) # 该函数是binary tournament,不需要tournsize
toolbox.register('mate', tools.cxSimulatedBinaryBounded, eta=20.0, low=low, up=up)#交叉与变异方式选取较为讲究,随意换成其他方式效果不佳
toolbox.register('mutate', tools.mutPolynomialBounded, eta=20.0, low=low, up=up, indpb=1.0/Ndim)NGEN = 200#迭代步数,参数过小,在收敛之前就结束搜索
CXPB = 0.8#交叉概率,参数过小,族群不能有效更新
MUTPB = 0.2#突变概率,参数过小,容易陷入局部最优#开始迭代
#第一代与第二代之后的代数操作不同
fitnesses = toolbox.map(toolbox.evaluate,pop)#为初始种群进行评价,得到适应度
for ind,fitness in zip(pop,fitnesses):ind.fitness.values = fitness#这里先有一个适应度才能进行快速非支配排序fronts = tools.emo.sortNondominated(pop,k=N_POP,first_front_only=False)#快速非支配排序,得到不同前沿的pareto层集合fronts
#print(fronts)#打印一个pareto层集合fronts检查,每层前沿都是一个列表for idx,front in enumerate(fronts):#使用枚举循环得到各层的标号与pareto解#print(idx,front)#打印检查前沿标号与每层的pareto解for ind in front:ind.fitness.values = (idx+1),#将个体的适应度设定为pareto解的前沿次序offspring = toolbox.selectGen1(pop,N_POP)#进行选择
offspring = algorithms.varAnd(offspring,toolbox,CXPB,MUTPB)#只做一次交叉与变异操作#从第二代开始循环
for gen in range(1,NGEN):combinedPop = pop + offspring#将子代与父代结合成一个大种群fitnesses = toolbox.map(toolbox.evaluate,combinedPop)#对该大种群进行适应度计算for ind,fitness in zip(combinedPop,fitnesses):ind.fitness.values = fitnessfronts = tools.emo.sortNondominated(combinedPop,k=N_POP,first_front_only=False)#对该大种群进行快速非支配排序for front in fronts:tools.emo.assignCrowdingDist(front)#计算拥挤距离pop = []for front in fronts:pop += frontpop = toolbox.clone(pop)pop = tools.selNSGA2(pop,k=N_POP,nd='standard')#基于拥挤度实现精英保存策略offspring = toolbox.select(pop,N_POP)#选择offspring = toolbox.clone(offspring)offspring = algorithms.varAnd(offspring,toolbox,CXPB,MUTPB)#交叉变异bestInd = tools.selBest(pop,1)[0]#选择出种群中最优个体
bestFit = bestInd.fitness.values
print('best solution:',bestInd)
print('best fitness:',bestFit)front = tools.emo.sortNondominated(pop,len(pop))[0]#返回的不同前沿的pareto层集合fronts中第一个front为当前最优解集
#图形化显示
for ind in front:plt.plot(ind.fitness.values[0],ind.fitness.values[1],'r.',ms=2)
plt.xlabel('f1')
plt.ylabel('f2')
plt.tight_layout()
plt.show()

问题定义

  测试函数为ZTD3,取n=2,也就是有两个目标。两个目标都取最小值,因此代码中目标参数要写成weights=(-1.0,-1.0)

creator.create('MultiObjMin',base.Fitness,weights=(-1.0,-1.0))#两个目标,都求最小值
creator.create('Individual',list,fitness = creator.MultiObjMin)#创建individual类

个体编码与生成

  测试函数ZTD3要求自变量的取值范围是[0,1],我们有两个变量,说明一个个体中含有两个基因。考虑到基因为复数并且对精度没有特殊需求,因此使用实数编码法生成个体。
  以下函数的编写是常见的实数编码法应用,在一个列表中生成两个均匀随机分布的实数。

def genInd(low,up):return [random.uniform(low[0],up[0]),random.uniform(low[1],up[1])]

  编码完毕之后设定变量的上界与下界,再注册到工具箱中即可。

def genInd(low,up):return [random.uniform(low[0],up[0]),random.uniform(low[1],up[1])]#实数编码,一个个体里两个基因toolbox  = base.Toolbox()
Ndim = 2#两个变量
low = [0,0]#两个变量的下界
up = [1,1]#两个变量的上界toolbox.register('genInd',genInd,low,up)
toolbox.register('individual',tools.initIterate,creator.Individual,toolbox.genInd)#注册个体生成工具
#print(toolbox.individual())#打印一个个体检查

评价函数(ZTD3)

  ZTD3是一个常用来测试代码性能的函数,ZTD3的内容如下图所示:

  
  这里取m=2(无视上图中的m=30,那样目标太多难以使用图像直观观察)。从函数中可以看到,双目标的求解其实是计算出一组解,令其在f1,f2上求得最小值。

def ZDT3(ind):#测试函数,注意这里与单目标比最明显的区别是有两个返回值(两个目标)n = len(ind)f1 = ind[0]g = 1 + 9 * np.sum(ind[1:])/(n-1)f2 = g * (1 - np.sqrt(ind[0]/g) - ind[0]/g * np.sin(10*np.pi*ind[0]))return f1,f2#返回在两个函数上的值
toolbox.register('evaluate',ZDT3)#注册评价函数

  此外,和单目标程序最明显的区别为,评价函数返回了两个值。这样的表现也可以理解为该程序有两个评价函数,分别用于评价两个目标上的适应度。

生成种群

  种群的生成方法与单目标程序无异:

N_POP = 200#种群内个体数量,参数过小,搜索速度过慢
toolbox.register('population',tools.initRepeat,list,toolbox.individual)#注册种群生成工具
pop = toolbox.population(n=N_POP)#建立种群pop
#for ind in pop:#打印一个种群检查
#   print(ind)

注册工具与超参数设置

  注册工具中注册了两个选择函数,一个是selectGen1,一个是selectselectGen1函数是第一次进行选择时使用的,而第二代之后的选择就需要考虑到拥挤度比较了,因此需要另一个选择函数tools.emo.selTournamentDCD
  此外,在测试了其他的交叉,变异函数后发现运行结果并不理想,说明该多目标算法对交叉,变异的手段有特定的需求,这一点将在今后继续研究。
  填坑,后续的项目测试证明,个体采用实数编码,有取值范围的情况,变异与交叉应当采用含边界方式的变异与交叉方法

toolbox.register('selectGen1', tools.selTournament, tournsize=2)
toolbox.register('select', tools.emo.selTournamentDCD) # 该函数是binary tournament,不需要tournsize
toolbox.register('mate', tools.cxSimulatedBinaryBounded, eta=20.0, low=low, up=up)#交叉与变异方式选取较为讲究,随意换成其他方式效果不佳
toolbox.register('mutate', tools.mutPolynomialBounded, eta=20.0, low=low, up=up, indpb=1.0/Ndim)NGEN = 200#迭代步数,参数过小,在收敛之前就结束搜索
CXPB = 0.8#交叉概率,参数过小,族群不能有效更新
MUTPB = 0.2#突变概率,参数过小,容易陷入局部最优

第一次迭代

  在NSGA2代码中,第一次迭代与后续的迭代操作不同,主要区别有:
  (1)第一次迭代不计算拥挤距离。
  (2)第一次迭代中选择的依据——适应度,用的是个体对应的pareto解的前沿次序。
  如果熟悉之前deap程序的话,可以看到多了些陌生但在NSGA2程序中常见的变量:frontsfront
  首先解释一下frontsfronts是一个列表,列表内记录了一个种群中个体按照非支配排序后形成的不同层的前沿pareto解。由下图所示,完整的整个列表就是fronts。红框处框选了一个列表,该列表正是第一层pareto解,也就是pareto最优解,其中又包含了两个小列表,每个小列表显然是一个解。
  也就是说,该fronts里面的第一层pareto解里面有两个解,同理可以看出,第二层里有4个解,第三层里有4个解。
  

  
  front的概念就更好理解了,front就是fronts中某一层pareto解的集合,以上图举例,红框框选的那个列表就是一个front,该front里面有两个个体(ind)。
  在程序中按照枚举循环的方式打印fronts可以看到内容如下图所示(这里换了一个种群):
  
  
  前方箭头指向的数字0~5就是pareto解的层数,该种群中总共有6层pareto解。数字之后的列表就是每个front的内容,可以看到,第一层front有3个解(个体),第二层front有5个解(个体)等等……

#开始迭代
#第一代与第二代之后的代数操作不同
fitnesses = toolbox.map(toolbox.evaluate,pop)#为初始种群进行评价,得到适应度
for ind,fitness in zip(pop,fitnesses):ind.fitness.values = fitness#这里先有一个适应度才能进行快速非支配排序fronts = tools.emo.sortNondominated(pop,k=N_POP,first_front_only=False)#快速非支配排序,得到不同前沿的pareto层集合fronts
#print(fronts)#打印一个pareto层集合fronts检查,每层前沿都是一个列表for idx,front in enumerate(fronts):#使用枚举循环得到各层的标号与pareto解#print(idx,front)#打印检查前沿标号与每层的pareto解for ind in front:ind.fitness.values = (idx+1),#将个体的适应度设定为pareto解的前沿次序offspring = toolbox.selectGen1(pop,N_POP)#进行选择
offspring = algorithms.varAnd(offspring,toolbox,CXPB,MUTPB)#只做一次交叉与变异操作

第二次及之后的迭代

  在NSGA2代码中,后续的迭代与第一次迭代操作不同,主要区别有:
  (1)引入了父代子代合并后选择的精英选择机制。
  (2)计算拥挤距离,利用拥挤距离进行种群内选择。
  

#从第二代开始循环
for gen in range(1,NGEN):combinedPop = pop + offspring#将子代与父代结合成一个大种群fitnesses = toolbox.map(toolbox.evaluate,combinedPop)#对该大种群进行适应度计算for ind,fitness in zip(combinedPop,fitnesses):ind.fitness.values = fitnessfronts = tools.emo.sortNondominated(combinedPop,k=N_POP,first_front_only=False)#对该大种群进行快速非支配排序for front in fronts:tools.emo.assignCrowdingDist(front)#计算拥挤距离pop = []for front in fronts:pop += frontpop = toolbox.clone(pop)pop = tools.selNSGA2(pop,k=N_POP,nd='standard')#基于拥挤度实现精英保存策略offspring = toolbox.select(pop,N_POP)#选择offspring = toolbox.clone(offspring)offspring = algorithms.varAnd(offspring,toolbox,CXPB,MUTPB)#交叉变异

图形化显示

front = tools.emo.sortNondominated(pop,len(pop))[0]#返回的不同前沿的pareto层集合fronts中第一个front为当前最优解集
#图形化显示
for ind in front:plt.plot(ind.fitness.values[0],ind.fitness.values[1],'r.',ms=2)
plt.xlabel('f1')
plt.ylabel('f2')
plt.tight_layout()
plt.show()

  可以看到pareto最优解集将ztd3函数的部分轮廓较为完整地勾勒出来。
  
  

后记

  最近项目中可用的优化影响因素较少,因此暂时使用单目标优化的程序,更多的约束打算放在惩罚函数中处理,多目标优化的学习要暂时耽搁。
  

基于DEAP库的NSGA2代码详解相关推荐

  1. mysql relay bin 主库_MySQL主库binlog(master-log)与从库relay-log关系代码详解

    主库binlog: # at 2420 #170809 17:16:20 server id 1882073306 end_log_pos 2451 CRC32 0x58f2db87 Xid = 32 ...

  2. mysql 从库relay_MySQL主库binlog(master-log)与从库relay-log关系代码详解

    主库binlog: # at 2420 #170809 17:16:20 server id 1882073306 end_log_pos 2451 CRC32 0x58f2db87 Xid = 32 ...

  3. 基于U-Net的的图像分割代码详解及应用实现

    摘要 U-Net是基于卷积神经网络(CNN)体系结构设计而成的,由Olaf Ronneberger,Phillip Fischer和Thomas Brox于2015年首次提出应用于计算机视觉领域完成语 ...

  4. 基于python的随机森林回归实现_PYTHON | 随机森林实战(代码+详解)

    大家好,我是菜鸟君,之前跟大家聊过R语言的随机森林建模,指路 R语言 | 随机森林建模实战(代码+详解),作为刚过完1024节日的码农算法工程师来说,怎么可能只会用一种语言呢?今天就来说说Python ...

  5. 基于C语言的JPEG编码代码详解

    一.基于C语言的JPEG编码代码详解 #include <stdio.h> #include <stdlib.h> #include <string.h>#prag ...

  6. 基于神经网络的依存句法分析总结及代码详解

    上一篇文章CS224n之句法分析总结,介绍了句法分析以及具体的依存分析中的arc-standard算法.arc-standard系统是transition systems中最流行的一个系统之一.而本文 ...

  7. 基于YOLOv5的目标检测系统详解(附MATLAB GUI版代码)

    摘要:本文重点介绍了基于YOLOv5目标检测系统的MATLAB实现,用于智能检测物体种类并记录和保存结果,对各种物体检测结果可视化,提高目标识别的便捷性和准确性.本文详细阐述了目标检测系统的原理,并给 ...

  8. 基于RK3399ESP8285自动售货柜项目—MP08开发板端代码详解

    基于RK3399&ESP8285自动售货柜项目-②MP08开发板端代码详解 本系列文章将详细讲解该基于RK3399及ESP8285自动售货柜的完整实现方法,从硬件连接到网络通信再到软件实现,本 ...

  9. 基于模糊C均值聚类(FCM)的图像分割原理+python代码详解

    一.模糊 "模糊":一个元素可以不同程度的属于某几个子集,也就是说元素对于集合的隶属度可以在[0,1]上取连续值. 二.步骤 2.1步骤 翻译一下: S1:初始化参数:加权指数m, ...

  10. 基于spring security实现vue2前后端分离的双token刷新机制(完整代码详解,含金量拉满!)

    目录 一.前言: 核心功能概要: 通过加密算法创建一个用户: 二.后端 代码详解: 1.代码整体结构: 2.所需依赖: 3.UserDetailServiceImpl拦截用户登陆: 4.所需工具类 4 ...

最新文章

  1. opencv 最大内接矩形笔记
  2. linux cfs,朴素的UNIX之-Linux CFS一个注释
  3. Visual Studio 2015和2017里面应该创建哪种 Class Library
  4. [JavaScript] 正则表达式
  5. java 反射用法_Java 反射的概念与使用
  6. PHP学习总结(9)——PHP入门篇之WAMPServer服务控制面板介绍
  7. evb测试板_DVT测试方案
  8. android+mms发送流程,mms发送流程代码版droid.docx
  9. 常用的实现Javaweb页面跳转的方式
  10. 英国交通分析指南(Transport analysis guidance)解读及启示
  11. python怎么创建桌面快捷方式_Python3创建RIDE桌面快捷方式的另一种方法
  12. Thinkphp3.2如何where查询条件如何同时添加字符串条件和数组条件
  13. 【css】巧用border制作三角形
  14. 机器学习- MACHINE LEARNING
  15. ASP.NET动态网站开发培训-23.论文管理系统(三、制作论文内容页面)
  16. 波澜不惊 波澜不惊 波澜不惊
  17. ARM汇编指令MRS和MSR
  18. kibana 更新 索引模式_Kibana探索数据(Discover)详解
  19. Ubuntu16.04安装搜狗输入法,以及解决不能输入中文的办法
  20. pomelo源码解析--新建项目(cli工具: pomelo)

热门文章

  1. 谭浩强《c语言程序设计》第四版--重点难点总结
  2. java 判定1个IP地址是否是合法IP
  3. 关于 HenCoder
  4. Javascript json转对象(互转)
  5. 唐宇迪学习笔记2:Python数据分析处理库——pandas
  6. 学以致用——使用莱斯利矩阵模型预测蠵龟种群数量的演变(Demographics of the Loggerhead Sea Turtle using Leslie population model)
  7. Chrome浏览器插件之---AdBlock和Adblock Plus
  8. Lambert 投影转换相关代码
  9. Ubuntu 18.04下QFIL刷机
  10. 《算法笔记》和《算法笔记上机训练指南》学习笔记汇总