Python遗传和进化算法框架(⼀)Geatpy快速⼊门
Geatpy是⼀个⾼性能实⽤型的Python遗传算法⼯具箱,提供⼀个⾯向对象的进化算法框架,经过全⾯改版后,新版Geatpy2⽬前由华南农业⼤学、暨南⼤学、华南理⼯等本硕博学⽣联合团队开发及维护。
Website (including documentation):
Demo :
Pypi page :
Contact us:
Bug reports:
Notice:
FAQ:
Geatpy提供了许多已实现的遗传和进化算法相关算⼦的库函数,如初始化种、选择、交叉、变异、重插⼊、多⽬标优化⾮⽀配排序等,并且提供诸多已实现的进化算法模板来实现多样化的进化算法。其
执⾏效率⾼于Matlab、Java和Python编写的⼀些知名⼯具箱、平台或框架等,学习成本低、模块⾼度脱耦、扩展性⾼。
Geatpy⽀持⼆进制/格雷码编码种、实数值种、整数值种、排列编码种。⽀持赌选择、随机抽样选择、锦标赛选择。提供单点交叉、两点交叉、洗牌交叉、部分匹配交叉(PMX)、顺序交叉(OX)、线性重组、离散重组、中间重组等重组算⼦。提供简单离散变异、实数值变异、整数值变异、互换变异等变异算⼦。⽀持随机重插⼊、精英重插⼊。⽀持awGA、rwGA、nsga2、快速⾮⽀配排序等多⽬标优化的库函数、提供进化算法框架下的常⽤进化算法模板等。
关于遗传算法、进化算法的学习资料,在官⽹中有详细讲解以及相关的学术论⽂链接。同时⽹上也有很多资料。
闲话少说……下⾯讲⼀下怎么安装和使⽤:
先说⼀下安装⽅法:
⾸先是要windows系统,Python要是3.5,3.6或3.7版本,并且安装了pip。只需在控制台执⾏
pip install geatpy
即可安装成功。或者到github上下载源码进⾏编译安装:。推荐是直接⽤pip的⽅式安装。因为这样⽅便后续的更新。我为了⽅便运⾏demo代码以及查看源码和官⽅教程⽂档,因此另外在github上也下载了(但仍⽤pip⽅式安装)。
有些初学Python的读者反映还是不知道怎么安装,或者安装之后不知道怎么写代码。这⾥推荐安装Anaconda,它集成了Python的许多常⽤的运⾏库,⽐如Numpy、Scipy等。其内置的Spyder开发软件的风格跟Matlab类似,给⼈熟悉的感觉,更容易上⼿。
再说⼀下更新⽅法:
Geatpy在持续更新。可以通过以下命令使电脑上的版本与官⽅最新版保持⼀致:
pip install --upgrade geatpy
若在更新过程中遇到"--user"错误的问题,是windows下⽤pip进⾏安装时遇到的常见问题之⼀。意味着需要以管理员⽅式运⾏:
pip install --user --upgrade geatpy
Geatpy提供2种⽅式来使⽤进化算法求解问题。先来讲⼀下第⼀种最基本的实现⽅式:编写编程脚本。
1. 编写脚本实现遗传算法:
以⼀个⾮常简单的单⽬标优化问题为例:求f(x)=x*sin(10*pi*x)+2.0 在 x∈[-1,2] 上的最⼤值。
直接编写脚本如下:
"""demo.py"""
import numpy as np
import geatpy as ea # 导⼊geatpy库
import matplotlib.pyplot as plt
import time
"""============================⽬标函数============================"""
def aim(x): # 传⼊种染⾊体矩阵解码后的基因表现型矩阵
return x * np.sin(10 * np.pi * x) + 2.0
x = np.linspace(-1, 2, 200)
plt.plot(x, aim(x)) # 绘制⽬标函数图像
"""============================变量设置============================"""
x1 = [-1, 2] # ⾃变量范围
b1 = [1, 1] # ⾃变量边界
varTypes = np.array([0]) # ⾃变量的类型,0表⽰连续,1表⽰离散
Encoding = 'BG'# 'BG'表⽰采⽤⼆进制/格雷编码
微服务网关有哪些codes = [1] # 变量的编码⽅式,2个变量均使⽤格雷编码
precisions =[4] # 变量的编码精度
scales = [0] # 采⽤算术刻度
ranges=np.vstack([x1]).T # ⽣成⾃变量的范围矩阵
borders=np.vstack([b1]).T # ⽣成⾃变量的边界矩阵
"""=========================遗传算法参数设置========================="""
NIND = 40; # 种个体数⽬
MAXGEN = 25; # 最⼤遗传代数
FieldD = ea.crtfld(Encoding,varTypes,ranges,borders,precisions,codes,scales) # 调⽤函数创建区域描述器
Lind = int(np.sum(FieldD[0, :])) # 计算编码后的染⾊体长度
obj_trace = np.zeros((MAXGEN, 2)) # 定义⽬标函数值记录器
var_trace = np.zeros((MAXGEN, Lind)) # 定义染⾊体记录器,记录每⼀代最优个体的染⾊体
"""=========================开始遗传算法进化========================"""
start_time = time.time() # 开始计时
Chrom = ea.crtbp(NIND, Lind) # ⽣成种染⾊体矩阵
variable = ea.bs2real(Chrom, FieldD) # 对初始种进⾏解码
ObjV = aim(variable) # 计算初始种个体的⽬标函数值
best_ind = np.argmax(ObjV) # 计算当代最优个体的序号
# 开始进化
for gen in range(MAXGEN):
FitnV = ea.ranking(-ObjV) # 根据⽬标函数⼤⼩分配适应度值(由于遵循⽬标最⼩化约定,因此最⼤化问题要对⽬标函数值乘上-1)
SelCh=Chrom[ea.selecting('rws', FitnV, NIND-1), :] # 选择,采⽤'rws'赌选择
bin('xovsp', SelCh, 0.7) # 重组(采⽤两点交叉⽅式,交叉概率为0.7)
SelCh=ea.mutbin(Encoding, SelCh) # ⼆进制种变异
# 把⽗代精英个体与⼦代合并
Chrom = np.vstack([Chrom[best_ind, :], SelCh])
variable = ea.bs2real(Chrom, FieldD) # 对育种种进⾏解码(⼆进制转⼗进制)
ObjV = aim(variable) # 求育种个体的⽬标函数值
# 记录
best_ind = np.argmax(ObjV) # 计算当代最优个体的序号
obj_trace[gen, 0] = np.sum(ObjV) / NIND # 记录当代种的⽬标函数均值
obj_trace[gen, 1] = ObjV[best_ind] # 记录当代种最优个体⽬标函数值
var_trace[gen, :] = Chrom[best_ind, :] # 记录当代种最优个体的变量值
# 进化完成
end_time = time.time() # 结束计时
"""============================输出结果及绘图================================"""
best_gen = np.argmax(obj_trace[:, [1]])
print('⽬标函数最⼤值:', obj_trace[best_gen, 1]) # 输出⽬标函数最⼤值
variable = ea.bs2real(var_trace[[best_gen], :], FieldD) # 解码得到表现型
print('对应的决策变量值为:')
print(variable[0][0]) # 因为此处variable是⼀个矩阵,因此⽤[0][0]来取出⾥⾯的元素
print('⽤时:', end_time - start_time)
plt.plot(variable, aim(variable),'bo')
运⾏结果如下:
⽬标函数最⼤值: 3.850270731049811
手机网页制作运用技术对应的决策变量值为:
1.8504898220770896
⽤时: 0.015621423721313477
仔细查看上述代码,我们会发现Geatpy的书写风格与Matlab⼤同⼩异,有Matlab相关编程经验的基本上可以⽆缝转移到Python上利⽤
Geatpy进⾏遗传算法程序开发。
Geatpy提供了详尽的API⽂档,⽐如要查看上⾯代码中的"ranking"函数是⼲什么的,可以在python中执⾏
import geatpy as ga
help(ga.ranking)
即可看到"ranking"函数的相关使⽤⽅法。
另外官⽹上也有更多详尽的Geatpy教程:
2. 利⽤框架实现遗传算法。
Geatpy提供开放的⾯向对象进化算法框架。即“问题类”+“进化算法模板类+种类”。对于⼀些复杂的进化算法,如多⽬标进化优化、改进的遗传算法等,按照上⾯所说的编写脚本代码是⾮常⿇烦的,⽽⽤框架的⽅法可以极⼤提⾼编程效率。
这⾥给出⼀个利⽤框架实现NSGA-II算法求多⽬标优化函数ZDT-1的帕累托前沿⾯的例⼦:
第⼀步:⾸先编写ZDT1的问题类,写在“MyProblem.py”⽂件中:
# -*- coding: utf-8 -*-
"""MyProblem.py"""
import numpy as np
import geatpy as ea
class MyProblem(ea.Problem): # 继承Problem⽗类
def__init__(self):
name = 'ZDT1'# 初始化name(函数名称,可以随意设置)
M = 2 # 初始化M(⽬标维数)
maxormins = [1] * M # 初始化maxormins(⽬标最⼩最⼤化标记列表,1:最⼩化该⽬标;-1:最⼤化该⽬标)
Dim = 30 # 初始化Dim(决策变量维数)
varTypes = [0] * Dim # 初始化varTypes(决策变量的类型,0:实数;1:整数)
lb = [0] * Dim # 决策变量下界
ub = [1] * Dim # 决策变量上界
lbin = [1] * Dim # 决策变量下边界
ubin = [1] * Dim # 决策变量上边界
# 调⽤⽗类构造⽅法完成实例化
ea.Problem.__init__(self, name, M, maxormins, Dim, varTypes, lb, ub, lbin, ubin)
def aimFunc(self, pop): # ⽬标函数
Vars = pop.Phen # 得到决策变量矩阵
ObjV1 = Vars[:, 0]
python入门教程 非常详细 pdf
gx = 1 + 9 * np.sum(Vars[:, 1:30], 1)
hx = 1 - np.sqrt(ObjV1 / gx)
ObjV2 = gx * hx
pop.ObjV = np.array([ObjV1, ObjV2]).T # 把结果赋值给ObjV
def calBest(self): # 计算全局最优解
N = 10000 # ⽣成10000个参考点
ObjV1 = np.linspace(0, 1, N)
ObjV2 = 1 - np.sqrt(ObjV1)
globalBestObjV = np.array([ObjV1, ObjV2]).T
return globalBestObjV
上⾯代码中,问题类的构造函数__init__()是⽤于定义与ZDT1测试问题相关的⼀些参数,如决策变量
范围、类型、边界等等。aimFunc()是待优化的⽬标函数。calBest()可以⽤来计算理论的全局最优解,这个理论最优解可以是通过计算得到的,也可以是通过导⼊外部⽂件的数据得到的,如果待求解的问题没有或尚不知道理论最优解是多少,则这个calBest()函数可以省略不写。
第⼆步:在同⼀个⽂件夹下编写执⾏脚本,实例化上述问题类的对象,然后调⽤Geatpy提供的nsga2算法的进化算法模板
(moea_NSGA2_templet),最后结合理论全局最优解PF(即俗称的“真实前沿点”)通过计算GD、IGD、HV等指标来分析优化效果:
# -*- coding: utf-8 -*-
import geatpy as ea # import geatpy
from MyProblem import MyProblem
"""================================实例化问题对象============================="""
problem = MyProblem() # ⽣成问题对象
"""==================================种设置================================"""
Encoding = 'RI'# 编码⽅式
NIND = 50 # 种规模
Field = ea.crtfld(Encoding, problem.varTypes, problem.ranges, problem.borders) # 创建区域描述器
population = ea.Population(Encoding, Field, NIND) # 实例化种对象(此时种还没被初始化,仅仅是完成种对象的实例化)
"""================================算法参数设置==============================="""
button1myAlgorithm = ea.moea_NSGA2_templet(problem, population) # 实例化⼀个算法模板对象`
myAlgorithm.MAXGEN = 200 # 最⼤进化代数
myAlgorithm.drawing = 1 # 设置绘图⽅式(0:不绘图;1:绘制结果图;2:绘制过程动画)
"""===========================调⽤算法模板进⾏种进化===========================
调⽤run执⾏算法模板,得到帕累托最优解集NDSet。NDSet是⼀个种类Population的对象。
NDSet.ObjV为最优解个体的⽬标函数值;NDSet.Phen为对应的决策变量值。
详见Population.py中关于种类的定义。
"""
NDSet = myAlgorithm.run() # 执⾏算法模板,得到⾮⽀配种
NDSet.save() # 把结果保存到⽂件中
# 输出
print('⽤时:%f 秒'%(myAlgorithm.passTime))
print('评价次数:%d 次'%(myAlgorithm.evalsNum))
print('⾮⽀配个体数:%d 个'%(NDSet.sizes))
print('单位时间到帕累托前沿点个数:%d 个'%(int(NDSet.sizes // myAlgorithm.passTime)))
# 计算指标
PF = Best() # 获取真实前沿,详见Problem.py中关于Problem类的定义
if PF is not None and NDSet.sizes != 0:
GD = ea.indicator.GD(NDSet.ObjV, PF) # 计算GD指标
IGD = ea.indicator.IGD(NDSet.ObjV, PF) # 计算IGD指标
HV = ea.indicator.HV(NDSet.ObjV, PF) # 计算HV指标
Spacing = ea.indicator.Spacing(NDSet.ObjV) # 计算Spacing指标
print('GD',GD)
print('IGD',IGD)
print('HV', HV)
print('Spacing', Spacing)
"""=============================进化过程指标追踪分析============================"""
if PF is not None:
metricName = [['IGD'], ['HV']]
[NDSet_trace, Metrics] = a_tracking(myAlgorithm.pop_trace, PF, metricName, problem.maxormins) # 绘制指标追踪分析图
运⾏结果如下:
种信息导出完毕。
easyui的使用⽤时:0.503653 秒
linux主要有哪三个部分组成评价次数:10000 次
⾮⽀配个体数:50 个
单位时间到帕累托前沿点个数:99 个
GD 0.0011025023611967554
IGD 0.15098973339777405
HV 0.624906599521637
Spacing 0.009326105831814594
正在进⾏进化追踪指标分析,请稍后......
指标追踪分析结束,进化记录器中有效进化代数为: 200
上述代码中已经对各个流程进⾏了详细的注释。其中进化算法的核⼼逻辑是写在进化算法模板内部的,
可前往查看对应的源代码。此外,我们还可以参考Geatpy进化算法模板的源代码来⾃定义算法模板,以实现丰富多样的进化算法,如各种各样的改进的进化算法等:
最后值得注意的是:⽬标函数aimFunc()那⼀块地⽅最容易写错。aimFunc()的输⼊参数pop是⼀个种对象(有关种对象可以查看⼯具箱中的Population.py类源码,或者查看)。pop.Phen是种的表现型矩阵,意思是种染⾊体解码后得到的表现型矩阵,它对应的即为问题类中的决策变量。Phen是⼀个矩阵,每⼀⾏对应种中的⼀个个体的表现型。在计算⽬标函数时,可以把这个Phen拆成⼀⾏⼀⾏,即逐个逐个个体地计算⽬标函数值,然后再拼成⼀个矩阵赋值给pop对象的ObjV属性。也可以利⽤Numpy的矩阵化计算来“⼀⼝⽓”把种所有个体的⽬标函数值计算出来。⽆论采⽤的是哪种计算⽅法,最后得到的⽬标函数值是要保存在pop对象的ObjV属性中的,这个ObjV是“种
⽬标函数值矩阵”,每⼀⾏对应⼀个个体的所有⽬标函数值,每⼀列对应⼀个⽬标。⽐如:
它表⽰有种3个个体,待优化⽬标有2个。
后⾯的博客将深⼊理解Geatpy的数据结构、进化算法框架的⽤法与扩展,以及探讨框架的核⼼——进化算法模板的实现。还会讲⼀些使
⽤Geatpy解决问题的案例。欢迎继续跟进~感谢!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论