创建类型

本教程展示了如何使用创建者和工具箱来创建和初始化类型。

健身

提供的 Fitness 类是一个抽象类,需要一个 weights 属性才能正常工作。最小化适应度使用负权重构建,而最大化适应度使用正权重。例如,以下代码在 creator 中创建了一个名为 FitnessMin 的单目标最小化适应度,可以直接使用。

creator.create("FitnessMin", base.Fitness, weights=(-1.0,))

函数 create() 至少需要两个参数,一个为新创建的类命名,另一个是基类。任何后续参数都将成为该类的属性。如 Fitness 文档中所述,weights 属性必须是一个元组,以便多目标和单目标适应度可以以相同的方式处理。一个 FitnessMulti 将以相同的方式创建,但使用:

creator.create("FitnessMulti", base.Fitness, weights=(-1.0, 1.0))

此代码生成一个适应度函数,该函数最小化第一个目标并最大化第二个目标。权重也可以用来调整每个目标之间的重要性。这意味着权重可以是任何实数,只有符号用于确定是进行最大化还是最小化。权重在拥挤距离排序中非常有用,例如在NSGA-II选择算法中进行的排序。

个人

仅仅通过思考不同类型的进化算法(GA、GP、ES、PSO、DE等),我们就会注意到可能存在极其多样的个体,这强化了所有类型不能被开发者全部提供的假设。以下是如何使用 creator 创建其中一些个体,并使用 Toolbox 初始化它们的指南。

警告

在继承自 numpy.ndarray 之前,你应该**绝对**阅读 继承自 Numpy 教程,并查看 One Max 问题:使用 Numpy 示例!

浮动列表

第一个创建的个体将是一个包含浮点数的简单列表。为了生成这种个体,我们需要创建一个 Individual 类,使用创建器,该类将继承自标准的 list 类型并具有一个 fitness 属性。

import random

from deap import base
from deap import creator
from deap import tools

creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, fitness=creator.FitnessMax)

IND_SIZE=10

toolbox = base.Toolbox()
toolbox.register("attr_float", random.random)
toolbox.register("individual", tools.initRepeat, creator.Individual,
                 toolbox.attr_float, n=IND_SIZE)

新引入的 register() 方法至少需要两个参数;一个别名和一个分配给该别名的函数。任何后续参数在调用时都会传递给函数(类似于 functools.partial())。因此,前面的代码在工具箱中创建了两个别名;attr_floatindividual。第一个别名重定向到 random.random() 函数。第二个别名是 initRepeat() 函数的快捷方式,将其 container 参数固定为 creator.Individual 类,其 func 参数固定为 toolbox.attr_float() 函数,并且其重复次数参数固定为 IND_SIZE

现在,调用 toolbox.individual() 将调用 initRepeat() 并使用固定参数,返回一个由 IND_SIZE 个浮点数组成的完整 creator.Individual ,该个体具有最大化单目标 fitness 属性。

通过继承 array.arraynumpy.ndarray 可以实现此类型的变体,如下所示。

creator.create("Individual", array.array, typecode="d", fitness=creator.FitnessMax)
creator.create("Individual", numpy.ndarray, fitness=creator.FitnessMax)

从数组继承的类型在初始化时需要一个 typecode,就像原始类一样。

排列

排列表示的个体与一般的列表个体非常相似。事实上,它们都继承自基本的 list 类型。唯一的区别在于,我们不是用一系列浮点数填充列表,而是需要生成一个随机排列,并将该排列提供给个体。

import random

from deap import base
from deap import creator
from deap import tools

creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", list, fitness=creator.FitnessMin)

IND_SIZE=10

toolbox = base.Toolbox()
toolbox.register("indices", random.sample, range(IND_SIZE), IND_SIZE)
toolbox.register("individual", tools.initIterate, creator.Individual,
                 toolbox.indices)

第一个注册的函数 indices 重定向到 random.sample() 函数,其参数固定为从给定范围中抽取 IND_SIZE 个数。第二个注册的函数 individualinitIterate() 函数的快捷方式,其 container 参数设置为 creator.Individual 类,其 generator 参数设置为 toolbox.indices() 别名。

调用 toolbox.individual() 将调用 initIterate() 并使用固定参数,返回一个由包含最小化单目标 fitness 属性的排列组成的完整 creator.Individual

算术表达式

下一个常用的个体是数学表达式的前缀树。这次,必须定义一个包含我们个体可以使用的所有可能数学运算符的 PrimitiveSet。这里,集合称为 MAIN,并由 arity 定义了一个变量。运算符 add()sub()mul() 被添加到原始集合中,每个运算符的 arity 为 2。接下来,与之前一样创建 Individual 类,并添加一个静态属性 pset 以记住全局原始集合。这次,个体的内部将由 genHalfAndHalf() 函数生成,该函数基于斜坡过程以列表格式生成树。再次使用 initIterate() 函数初始化个体,以将完整生成的可迭代对象传递给个体类。

import operator

from deap import base
from deap import creator
from deap import gp
from deap import tools

pset = gp.PrimitiveSet("MAIN", arity=1)
pset.addPrimitive(operator.add, 2)
pset.addPrimitive(operator.sub, 2)
pset.addPrimitive(operator.mul, 2)

creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", gp.PrimitiveTree, fitness=creator.FitnessMin,
               pset=pset)

toolbox = base.Toolbox()
toolbox.register("expr", gp.genHalfAndHalf, pset=pset, min_=1, max_=2)
toolbox.register("individual", tools.initIterate, creator.Individual,
                 toolbox.expr)

调用 toolbox.individual() 将立即返回一个完整的个体,该个体是一个以最小化单目标适应度属性为特征的前缀树形式的算术表达式。

进化策略

进化策略个体略有不同,因为它们通常包含两个列表,一个用于实际个体,另一个用于其变异参数。这次,我们将从 array.array 继承,而不是使用列表基类,用于个体和策略。由于没有辅助函数来生成单个对象中的两个不同向量,我们必须自己定义这个函数。initES() 函数接收两个类并实例化它们,为给定大小的个体在提供的范围内生成随机数。

import array
import random

from deap import base
from deap import creator
from deap import tools

creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
creator.create("Individual", array.array, typecode="d",
               fitness=creator.FitnessMin, strategy=None)
creator.create("Strategy", array.array, typecode="d")

def initES(icls, scls, size, imin, imax, smin, smax):
    ind = icls(random.uniform(imin, imax) for _ in range(size))
    ind.strategy = scls(random.uniform(smin, smax) for _ in range(size))
    return ind

IND_SIZE = 10
MIN_VALUE, MAX_VALUE = -5., 5.
MIN_STRAT, MAX_STRAT = -1., 1. 

toolbox = base.Toolbox()
toolbox.register("individual", initES, creator.Individual,
                 creator.Strategy, IND_SIZE, MIN_VALUE, MAX_VALUE, MIN_STRAT, 
                 MAX_STRAT)

调用 toolbox.individual() 将立即返回一个完整的进化策略,包含一个策略向量和一个最小化的单一目标适应度属性。

粒子

粒子是另一种特殊类型的个体,因为它通常具有速度,并且通常会记住其最佳位置。这种类型的个体是通过继承列表的方式创建的(再次)。这次,对象中添加了 speedbest 和速度限制(sminsmax)属性。同样,初始化函数 initParticle() 也被注册,以生成接收粒子类、大小、域和速度限制作为参数的个体。

import random

from deap import base
from deap import creator
from deap import tools

creator.create("FitnessMax", base.Fitness, weights=(1.0, 1.0))
creator.create("Particle", list, fitness=creator.FitnessMax, speed=None,
               smin=None, smax=None, best=None)

def initParticle(pcls, size, pmin, pmax, smin, smax):
    part = pcls(random.uniform(pmin, pmax) for _ in range(size))
    part.speed = [random.uniform(smin, smax) for _ in range(size)]
    part.smin = smin
    part.smax = smax
    return part

toolbox = base.Toolbox()
toolbox.register("particle", initParticle, creator.Particle, size=2,
                 pmin=-6, pmax=6, smin=-3, smax=3)

调用 toolbox.particle() 将立即返回一个完整的粒子,该粒子具有速度向量和适应度属性,用于最大化两个目标。

一个时髦的

假设你的问题有非常特殊的需求,也可以很容易地构建自定义个体。下一个创建的个体是一个交替的整数和浮点数列表,使用 initCycle() 函数。

import random

from deap import base
from deap import creator
from deap import tools

creator.create("FitnessMax", base.Fitness, weights=(1.0, 1.0))
creator.create("Individual", list, fitness=creator.FitnessMax)

toolbox = base.Toolbox()

INT_MIN, INT_MAX = 5, 10
FLT_MIN, FLT_MAX = -0.2, 0.8
N_CYCLES = 4

toolbox.register("attr_int", random.randint, INT_MIN, INT_MAX)
toolbox.register("attr_flt", random.uniform, FLT_MIN, FLT_MAX)
toolbox.register("individual", tools.initCycle, creator.Individual,
                 (toolbox.attr_int, toolbox.attr_flt), n=N_CYCLES)

调用 toolbox.individual() 将立即返回一个完整的个体,形式为 [int float int float ... int float],并具有最大化两个目标的适应度属性。

人口

种群非常类似于个体。它们不是通过属性初始化,而是填充了个体、策略或粒子。

袋群是最常用的类型。它没有特定的顺序,尽管它通常使用列表来实现。由于袋子没有特定的属性,因此不需要任何特殊的类。群是通过工具箱和 initRepeat() 函数直接初始化的。

toolbox.register("population", tools.initRepeat, list, toolbox.individual)

调用 toolbox.population() 将立即返回一个完整的种群列表,提供重复辅助函数必须重复的次数作为种群函数的参数。以下示例生成一个包含100个个体的种群。

toolbox.population(n=100)

网格

网格种群是结构化种群的一个特例,其中相邻个体之间有直接影响。个体分布在网格中,每个单元格包含一个个体。然而,其实现仅与袋种群的列表不同,因为它由个体的列表组成。

toolbox.register("row", tools.initRepeat, list, toolbox.individual, n=N_COL)
toolbox.register("population", tools.initRepeat, list, toolbox.row, n=N_ROW)

调用 toolbox.population() 将立即返回一个完整的种群,其中个体可以通过两个索引访问,例如 pop[r][c]。目前,没有专门针对结构化种群的算法,我们正在等待您的提交。

Swarm

在粒子群优化中使用了一个群体。它在某种意义上是不同的,因为它包含一个通信网络。最简单的网络是完全连接的网络,其中每个粒子都知道任何粒子曾经访问过的最佳位置。这通常通过将全局最佳位置复制到 gbest 属性和将全局最佳适应度复制到 gbestfit 属性来实现。

creator.create("Swarm", list, gbest=None, gbestfit=creator.FitnessMax)
toolbox.register("swarm", tools.initRepeat, creator.Swarm, toolbox.particle)

调用 toolbox.swarm() 将立即返回一个完整的群体。每次评估后,算法应设置 gbestgbestfit 以反映找到的最佳位置和适应度。

Demes

一个 deme 是包含在一个总体中的子总体。它类似于岛屿模型中的一个岛屿。Demes,作为子总体,实际上与总体没有区别,除了它们的名称。在这里,我们创建一个包含3个demes的总体,每个demes使用 initRepeat() 函数的 n 参数具有不同数量的个体。

toolbox.register("deme", tools.initRepeat, list, toolbox.individual)

DEME_SIZES = 10, 50, 100
population = [toolbox.deme(n=i) for i in DEME_SIZES]

种群初始化

有时,可以使用初始猜测种群来初始化进化算法。使用非随机个体初始化种群的关键思想是拥有一个以内容为参数的个体初始化器。

import json

from deap import base
from deap import creator

creator.create("FitnessMax", base.Fitness, weights=(1.0, 1.0))
creator.create("Individual", list, fitness=creator.FitnessMax)

def initIndividual(icls, content):
    return icls(content)

def initPopulation(pcls, ind_init, filename):
    with open(filename, "r") as pop_file:
        contents = json.load(pop_file)
    return pcls(ind_init(c) for c in contents)

toolbox = base.Toolbox()

toolbox.register("individual_guess", initIndividual, creator.Individual)
toolbox.register("population_guess", initPopulation, list, toolbox.individual_guess, "my_guess.json")

population = toolbox.population_guess()

种群将从文件 my_guess.json 初始化,该文件应包含一个初始猜测个体的列表。这种初始化可以与常规初始化结合使用,以拥有部分随机和部分非随机的个体。请注意,定义 initIndividual() 和注册 individual_guess() 是可选的,因为列表的默认构造函数类似。删除这些行会导致以下结果:

toolbox.register("population_guess", initPopulation, list, creator.Individual, "my_guess.json")