对于下述知识可先学习:Geatpy库学习流程_要努力呦的博客-CSDN博客
有了以上的经验后,对于如何使用 Geatpy 面向对象进化算法框架求解新的问题就 会得心应手。下面看一个带约束的多目标优化问题:
编写问题类如下:
# -*- coding: utf-8 -*-
"""MyProblem.py"""
import numpy as np
import geatpy as ea
class MyProblem(ea.Problem): # 继承Problem父类
def __init__(self):
name = 'BNH' # 初始化name(函数名称,可以随意设置)
M = 2 # 初始化M(目标维数)
maxormins = [1] * M # 初始化maxormins
Dim = 2 # 初始化Dim(决策变量维数)
varTypes = [0] * Dim #
# 初始化varTypes(决策变量的类型,0:实数;1:整数)
lb = [0] * Dim # 决策变量下界
ub = [5, 3] # 决策变量上界
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 # 得到决策变量矩阵
x1 = Vars[:, [0]] # 注意这样得到的x1是一个列向量,表示所有个体的x1
x2 = Vars[:, [1]]
f1 = 4*x1**2 + 4*x2**2
f2 = (x1 - 5)**2 + (x2 - 5)**2
# 采用可行性法则处理约束
pop.CV = np.hstack([(x1 - 5)**2 + x2**2 - 25,
-(x1 - 8)**2 - (x2 - 3)**2 + 7.7])
# 把求得的目标函数值赋值给种群pop的ObjV
pop.ObjV = np.hstack([f1, f2])
def calReferObjV(self): # 计算全局最优解
N = 10000 # 欲得到10000个真实前沿点
x1 = np.linspace(0, 5, N)
x2 = x1.copy()
x2[x1 >= 3] = 3
return np.vstack((4 * x1**2 + 4 * x2**2,
(x1 - 5)**2 + (x2 - 5)**2)).T
Geatpy 的问题类有三大函数:构造函数(又称“构造方法”)__init()__()、目标 函数 aimFunc() 以及计算理论参考解的目标函数参考值(常常是理论最优解)的函数 calReferObjV()。如果实际问题并不知道模型的理论最优解的目标函数参考值,那么 calReferObjV() 函数的定义可以被省略。在多目标优化中,“真实帕累托前沿”可在 calReferObjV() 中进行计算或读取文件得到。
完成了问题类的定义后,对“2.2.1”中的执行脚本“main.py”略加修改便可以用于当前问题的求解:
# -*- coding: utf-8 -*-
"""main.py"""
import geatpy as ea # import geatpy
from MyProblem import MyProblem # 导入自定义问题接口
"""=========================实例化问题对象==========================="""
problem = MyProblem() # 实例化问题对象
"""===========================种群设置=============================="""
Encoding = 'RI' # 编码方式
NIND = 100 # 种群规模
Field = ea.crtfld(Encoding, problem.varTypes, problem.ranges,
problem.borders) # 创建区域描述器
population = ea.Population(Encoding, Field, NIND) #
# 实例化种群对象(此时种群还没被真正初始化,仅仅是生成一个种群对象)
"""=========================算法参数设置============================"""
myAlgorithm = ea.moea_NSGA2_templet(problem, population) #
实例化一个算法模板对象
myAlgorithm.MAXGEN = 200 # 最大遗传代数
myAlgorithm.drawing = 1 # 设置绘图方式
"""===================调用算法模板进行种群进化=======================
调用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 = problem.getReferObjV() # 获取真实前沿
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: %f'%GD)
print('IGD: %f'%IGD)
print('HV: %f'%HV)
print('Spacing: %f'%Spacing)
"""=====================进化过程指标追踪分析========================"""
if PF is not None:
metricName = [['IGD'], ['HV']]
[NDSet_trace, Metrics] =ea.indicator.moea_tracking(myAlgorithm.pop_trace, PF,
metricName, problem.maxormins)
# 绘制指标追踪分析图
ea.trcplot(Metrics, labels = metricName, titles = metricName)
上述执行脚本调用了多目标优化的“moea_NSGA2_templet”算法模板,它实现的是多目标优化 NSGA-II 算法,详见“moea_NSGA2_templet.py”源码。
在调用完算法模板后,通过 problem 对象的“getReferObjV()”方法获取真实前沿。这 里也许会产生疑问:前面“MyProblem.py”中不是定义了“calReferObjV()”方法来计算 问题的真实前沿吗?并没有定义“getReferObjV()”函数。实际上,“getReferObjV()”函数 是自定义的“MyProblem”类的父类:“Problem”中定义的一个函数(详见“Problem.py”), 它将先尝试读取本地的特定格式的全局最优解参考值的记录文件,如果没有找到,它将 调用自定义的“calReferObjV()”函数来计算全局最优解的参考值(这里即真实前沿), 计算完成后,它把结果按照特定格式保存到“Real_Best”文件夹下面的.csv 文件中。
上述执行脚本还展示了如何使用 Geatpy 提供的多目标优化进化过程指标追踪分析功能。调用工具箱的“indicator.moea_tracking()”函数即可完成指标追踪分析,为此需 要一个保存着历代种群对象的列表“pop_trace”,该列表在进化算法模板的父类中有定 义(详见“Algorithm.py”中的“MoeaAlgorithm 类”——多目标进化优化算法模板父类, Geatpy 中所有的多目标进化优化算法模板都继承了这个父类)。