前言
在上一篇中,我们已经介绍了如何在DEAP中实现进化算法的基本操作,这一篇中我们试图将各个操作组装起来,用进化算法解决一个简单的一元函数寻优问题
一.问题描述与分析
给定一个函数,求解其最大值
该函数的图像为:
该函数的最大值应该出现在28.309042309042308处,值为1657.4235763265594。
可以看到该函数有很多局部极值作为干扰项,如果进化算法过早收敛,很容易陷入某个局部最优。
二.问题的编码与解码
对于该问题,可以选取很多不同的编码方式。本文计划采用二进制编码,精确度要求到6位,那么首先应当确定编码的长度与解码方式。由于有:
所以我们需要的二进制编码长度为26
三.利用DEAP自带算法求解
1.DEAP自带的进化算法介绍
DEAP自带的算法都比较基础,通常可以用来测试问题描述、编码方式和交叉突变操作组合的有效性。需要比较复杂的进化算法时,可以通过在已有的算子上进行扩充
简单进化算法
deap.algorithms.eaSimple
DEAP中预置的简单进化算法流程描述如下:
1.根据工具箱中注册的toolbox.evaluate评价族群
2.根据工具箱中注册的toolbox.select选择与父代相同个数的育种个体
3.在族群中进行第一次循环,用工具箱中注册的toolbox.mate进行配种,并用生成的两个子代替换对应父代
4.在族群中进行第二次循环,用工具箱中注册的toolbox.mutate进行变异,用变异后的子代替换对应父代
5.从1开始重复循环,直到达到设定的迭代次数
需要注意的是在这个过程中,生成子代有四种情况:受到配种影响;受到变异影响;既受到配种也受到变异影响;既不受配种影响也不受变异影响
对应的伪代码可以表述为:
evaluate(population)
for g in range(ngen):
population = select(population, len(population))
offspring = varAnd(population, toolbox, cxpb, mutpb)
evaluate(offspring)
population = offspring
(μ + λ)进化算法
deap.algorithms.eaMuPlusLambda
该算法的流程如下:
1.根据工具箱中注册的toolbox.evaluate评价族群
2.在族群中进行循环,在每次循环中,随机选择crossover,mutation和reproduction三者之一:
如果选择到crossover,那么随机选择2个个体,用工具箱中注册的toolbox.mate进行配种,<将生成的第一个子代加入到后代列表中,第二个子代丢弃;
如果选择到mutation,用工具箱中注册的toolbox.mutate进行变异,将变异后的子代加入到后代列表中;
如果选择到reproduction,随机选择一个个体,将其复制加入到后代列表中
3.根据工具箱中注册的toolbox.select,在父代+子代中选择给定数量的个体作为子代
4.从1开始重复循环,直到达到设定的迭代次数
注意在这个子代生成的过程中,子代不会同时受到变异和配种影响。
对应的伪代码可以表述为:
evaluate(population)
for g in range(ngen):
offspring = varOr(population, toolbox, lambda_, cxpb, mutpb)
evaluate(offspring)
population = select(population + offspring, mu)
(μ,λ)进化算法
deap.algorithms.eaMuCommaLambda
与(μ + λ)进化算法基本相同,唯一的区别在于生成子代族群时,只在产生的子代中选择,而丢弃所有父代。
对应伪代码可以表述为
evaluate(population)
for g in range(ngen):
offspring = varOr(population, toolbox, lambda_, cxpb, mutpb)
evaluate(offspring)
population = select(offspring, mu)
2.调用DEAP自带的进化算法
在调用DEAP自带的算法时需要注意的是,由于内置算法调用的alias已经提前给定,因此我们在register的时候,需要按照给定名称注册。
例如toolbox.register('crossover', tools.cxUniform)就不能被内置算法识别,而应当按照
要求,命名为mate,并且显示给出交叉概率:
toolbox.register('mate', tools.cxUniform, indpb = 0.5)
按照要求,使用预置的算法需要注册的工具有:
toolbox.evaluate:评价函数
toolbox.select:育种选择
toolbox.mate:交叉操作
toolbox.mutate:突变操作
from deap import algorithms, creator, tools, base
from scipy.stats import bernoulli
import numpy as np
import random
random.seed(42) # 保证结果可以复现
# 定义问题
creator.create('FitnessMax', base.Fitness, weights=(1.0,)) # 单目标优化,最大值问题
creator.create('Individual', list, fitness=creator.FitnessMax)
# 生成个体
gene_size = 26 # 26位编码
toolbox = base.Toolbox()
toolbox.register('Binary', bernoulli.rvs, 0.5)
toolbox.register('Individual', tools.initRepeat, creator.Individual, toolbox.Binary, n=gene_size)
# 解码 - 二进制转换为十进制
def decode(individual):
# 解码到10进制
num = int(''.join([str(_) for _ in individual]), 2)
# 映射到-30到30区间
x = -30 + num * 60 / (2 ** 26 - 1)
return x
# 评价函数-适应度
def eval(individual):
# 转化到区间内实数
x = decode(individual)
return ((np.square(x) + x) * np.cos(