☰
用 DEAP 的 algorithms 模块一行跑通遗传算法:One Max 短版示例精解
2026/10/7 9:27:32 网站建设 项目流程
  • 机器学习
  • 人工智能

【免费下载链接】deap

Distributed Evolutionary Algorithms in Python

项目地址:https://gitcode.com/gh_mirrors/de/deap
点击查看免费下载

导读

本文围绕 DEAP 官方示例 examples/ga/onemax_short.py 展开,讲解如何借助deap.algorithms模块内置的eaSimple函数,把完整手写的遗传算法主循环压缩成一次函数调用。你会学到:如何复用deap.tools中的评估、交叉、变异、选择算子并注册进Toolbox,如何用HallOfFame保住历史最优个体、用Statistics+Logbook自动记录每一代的统计数据,以及verbose参数如何控制演化过程的可视化输出。读完本文,你可以把同样的套路直接迁移到 DEAP 的其他进化算法示例中。

本示例是 DEAP 文档中完整版 One Max 教程(doc/examples/ga_onemax.rst)的“短版”,核心差异只有一个:不再手写选择—交叉—变异—评估—替换的主循环,而是把工具箱交给eaSimple代为执行。

One Max 短版与完整版的本质区别

完整版示例 examples/ga/onemax.py 用while max(fits) < 100 and g < 1000手写了每一代的循环:选择、克隆、按CXPB/MUTPB概率交叉与变异、失效个体重评估、整代替换、手工计算 min/max/avg/std。而短版示例把这一切交给deap.algorithms模块中实现的基础进化算法,代码量大幅缩减,逻辑也更不易出错。

两者在个体表示、适应度、工具箱注册上几乎完全一致,唯一的差别集中在两个地方:

  1. 导入:短版额外引入了algorithms模块和numpy(用于统计函数);
  2. 演化驱动:短版不再自己写循环,而是调用algorithms.eaSimple(...)。

文档 doc/examples/ga_onemax_short.rst 明确指出:短版示例与完整版非常相似,唯一区别就是使用了deap.algorithms模块中实现的一些基础进化算法。

额外的导入与初始化

短版示例在导入阶段引入了完整版没有的依赖(对应 examples/ga/onemax_short.py):

import array import random import numpy from deap import algorithms from deap import base from deap import creator from deap import tools
  • deap.algorithms:提供eaSimple等现成的进化算法骨架;
  • numpy:作为统计函数(numpy.mean、numpy.std等)的提供者;
  • array:个体容器类型,这里用typecode='b'表示有符号字节数组,比 Python 内置list更省内存。

随后的个体与适应度定义也和完整版一脉相承(examples/ga/onemax_short.py):

creator.create("FitnessMax", base.Fitness, weights=(1.0,)) creator.create("Individual", array.array, typecode='b', fitness=creator.FitnessMax) toolbox = base.Toolbox() # Attribute generator toolbox.register("attr_bool", random.randint, 0, 1) # Structure initializers toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, 100) toolbox.register("population", tools.initRepeat, list, toolbox.individual)
  • weights=(1.0,):单目标最大化;
  • attr_bool:从{0, 1}中均匀采样,作为基因;
  • individual:通过tools.initRepeat生成包含 100 个 0/1 基因的个体;
  • population:个体列表构成种群,n参数在使用时再传入。

注册算法需要的四个算子

要用deap.algorithms里的进化函数,必须在工具箱中注册四个关键别名(examples/ga/onemax_short.py):

def evalOneMax(individual): return sum(individual), toolbox.register("evaluate", evalOneMax) toolbox.register("mate", tools.cxTwoPoint) toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) toolbox.register("select", tools.selTournament, tournsize=3)

evaluate:目标函数

evalOneMax统计个体中 1 的个数并返回元组。DEAP 要求评估结果是与权重数量等长的可迭代对象,返回sum(individual),末尾的逗号保证了这一点。理论上当个体全为 1 时适应度为 100,即该问题的全局最优。

mate:两点交叉

tools.cxTwoPoint在两个个体上随机选择两个切点,交换中间片段,并原地修改两个个体(deap/tools/crossover.py)。从源码看,它先随机生成cxpoint1、cxpoint2两个切点,再执行ind1[cxpoint1:cxpoint2], ind2[cxpoint1:cxpoint2] = ind2[cxpoint1:cxpoint2], ind1[cxpoint1:cxpoint2]完成片段交换,两个个体长度保持不变。

mutate:位翻转变异

tools.mutFlipBit以indpb为每个基因独立的翻转概率,把 0 变成 1、1 变成 0(deap/tools/mutation.py)。源码中的实现是:

for i in range(len(individual)): if random.random() < indpb: individual[i] = type(individual[i])(not individual[i])

这里indpb=0.05意味着每个基因平均有 5% 的概率被翻转。由于示例个体是array.array(字节数组),type(individual[i])(not individual[i])会借助原类型构造出翻转后的字节值。

select:锦标赛选择

tools.selTournament进行k次独立锦标赛,每次从种群中随机抽出tournsize个候选者,取其中适应度最优者入选(deap/tools/selection.py)。tournsize=3即“三选一”。eaSimple的伪代码要求选择过程是随机化的——因为每一代都是整代替换,selTournament允许同一个体被多次选中,这正符合要求;而确定性选择函数(如selBest)在 1:1 替换下会导致完全没有选择压力。

用 HallOfFame 与 Statistics 记录演化过程

在main()中,短版示例用两个 DEAP 工具对象来观察演化(examples/ga/onemax_short.py):

def main(): random.seed(64) pop = toolbox.population(n=300) hof = tools.HallOfFame(1) stats = tools.Statistics(lambda ind: ind.fitness.values) stats.register("avg", numpy.mean) stats.register("std", numpy.std) stats.register("min", numpy.min) stats.register("max", numpy.max) pop, log = algorithms.eaSimple(pop, toolbox, cxpb=0.5, mutpb=0.2, ngen=40, stats=stats, halloffame=hof, verbose=True) return pop, log, hof

HallOfFame:保存历史最优个体

tools.HallOfFame(1)只保留演化史上出现过的最优个体(deap/tools/support.py)。文档特别强调:它即使在最优个体灭绝的情况下也能继续保留它。从源码看,HallOfFame.update(population)会把种群中优于当前最差成员的个体插入,并在容量满时淘汰最差者;插入时用deepcopy复制个体,保证名人堂中的个体与种群中的对象相互独立。maxsize=1时,hof[0]就是整个演化过程中的全局最优解。

Statistics:每代统计量

tools.Statistics(lambda ind: ind.fitness.values)指定了统计数据的提取键,即每个个体的适应度值;随后通过stats.register注册四个聚合函数(avg、std、min、max)。从 deap/tools/support.py 的源码实现可以看到,compile(data)会先对种群应用 key 提取数据,再对每个注册函数计算并打包成字典。由于注册的是numpy函数,它们天然支持对适应度元组这类多维数据的计算。

Logbook:演化日志

eaSimple会内部创建tools.Logbook(同样定义在 deap/tools/support.py),其表头为['gen', 'nevals'] + stats.fields,即每一代包含:代数编号、本代评估的个体数、以及你注册的全部统计量。最终eaSimple返回(population, logbook),你可以用log.select("gen", "avg", "max")提取演化曲线数据用于绘图或存档。

eaSimple 内部到底做了什么

deap.algorithms模块的文档注释(deap/algorithms.py)说明:该模块旨在提供一些常见的进化算法以便直接执行,方法更多是“便利性”而非“参考实现”,因为进化算法的实现方式千差万别,且绝大多数算法都使用注册在工具箱中的算子。其通用的关键字约定为:mate交叉、mutate变异、select选择、evaluate评估。

eaSimple的核心流程在 deap/algorithms.py 中,伪代码为:

evaluate(population) for g in range(ngen): population = select(population, len(population)) offspring = varAnd(population, toolbox, cxpb, mutpb) evaluate(offspring) population = offspring

对应的实际调用链是:

  1. 评估种群中所有适应度无效的个体,并把它们记入第 0 代日志;
  2. 若传入了halloffame,先对其更新一次;
  3. 进入ngen代循环:先用toolbox.select(population, len(population))整代选择,再调用varAnd完成变异阶段;
  4. 重新评估变异后适应度失效的个体(仅评估not ind.fitness.valid的子集,节省计算量);
  5. 更新名人堂,用population[:] = offspring原地整代替换;
  6. 每代将统计结果写入Logbook,若verbose为真则打印当前行的日志。

varAnd:变异阶段的实现

varAnd(deap/algorithms.py)负责“交叉和变异”这一阶段,其命名即来源于此。它的执行细节:

  • 先用toolbox.clone克隆整个亲代种群,保证返回的子代与输入种群互不依赖;
  • 第一轮循环对相邻个体对按概率cxpb执行toolbox.mate,交叉后立刻del掉两个子代的适应度使其失效;
  • 第二轮循环对每个个体按概率mutpb执行toolbox.mutate,同样失效其适应度。

因此一个子代可能来自:仅交叉、仅变异、交叉加变异、或原样繁殖,具体取决于随机数与概率的比较。两个概率都应落在[0, 1]区间内。

参数速查表

eaSimple(population, toolbox, cxpb, mutpb, ngen, stats=None, halloffame=None, verbose=__debug__)的完整参数含义如下:

参数示例值含义
populationpop初始种群,list或支持[:]赋值的容器
toolboxtoolbox注册了mate/mutate/select/evaluate的 deap/base.py 工具箱
cxpb0.5两个个体发生交叉的概率
mutpb0.2个体发生变异的概率
ngen40演化代数
statsstatstools.Statistics对象,逐代更新(可选)
halloffamehoftools.HallOfFame对象,保存历史最优(可选)
verboseTrue是否逐代打印日志,默认等价于__debug__(即 Python 非优化模式为真)

需要特别说明的是,verbose默认值是__debug__:当以python onemax_short.py正常运行时为True,而以python -O优化模式运行时会自动变为False,相当于“调试模式下默认打印”。这与 deap/algorithms.py 中的函数签名一致。

运行方式与输出解读

在仓库根目录执行:

python examples/ga/onemax_short.py

由于main()设置了random.seed(64),每次运行结果可复现。程序会打印类似下面的逐代日志(verbose=True):

gen nevals avg std min max 0 300 49.673 5.09617 34 66 1 181 55.94 6.17816 40 74 ... 40 105 97.73 1.36588 94 100
  • gen:代数,从 0 开始;
  • nevals:本代实际评估的个体数。第 0 代为 300(整个初始种群),之后每代只评估交叉/变异后适应度失效的个体,因此远小于 300;
  • avg/std/min/max:由stats中注册的四个 numpy 函数算出。

最终max达到 100,说明种群中出现了全 1 的最优个体,One Max 问题得到解决;hof[0]中即保存着这个全局最优解。若想关闭逐行日志,把verbose=True改为verbose=False即可;log对象仍然完整记录所有数据,供事后分析。

延伸:把短版模式套用到其他算法

deap.algorithms模块还提供了其他常用算法骨架,调用方式与eaSimple完全一致(都接受stats、halloffame、verbose参数):

  • eaMuPlusLambda:(μ + λ)进化策略,后代由varOr生成,选择在亲代+子代并集上进行;
  • eaMuCommaLambda:(μ, λ)进化策略,选择仅在子代中进行(要求lambda_ >= mu);
  • eaGenerateUpdate:ask-tell 模型,适用于 CMA-ES 等基于分布模型的算法;
  • varAnd/varOr:仅执行变异阶段的低层函数,供自定义算法时复用。

完整实现与注释都在 deap/algorithms.py 中。文档 doc/examples/ga_onemax_short.rst 的结尾指出:deap.algorithms中的每个算法都能处理HallOfFame与Statistics这类对象,而verbose关键字则决定算法是否在每一代之后输出结果。理解了 One Max 短版示例,你就掌握了 DEAP 中“注册算子 + 调用现成算法”这一最常用的开发模式,可以直接套用到 examples/ga/nsga2.py、examples/ga/nsga3.py、examples/es/onefifth.py 等各类示例中。

  • 机器学习
  • 人工智能

【免费下载链接】deap

Distributed Evolutionary Algorithms in Python

项目地址:https://gitcode.com/gh_mirrors/de/deap
点击查看免费下载

相关推荐

上一篇:CANN/ops-nn KL散度目标损失梯度算子
下一篇:Rufus XZ流处理:数据流管理深度解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询