python 进化算法框架 DEAP

python的Deap库用于进化类算法进行优化问题的迭代求解。其有几个重要组件,creator、register,operator。

creator

creator类的create方法用于创建一个新的类,其至少需要传入两个参数,第一个参数为字符串,表示新类的类名,第二个参数是新类的基类(父类),后续的参数视作对类的属性赋值。官方例子:

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

上述代码表示基于base.Fitness类创建名为“FitnessMin”的类,并对类属性weights赋值为(-1.0,)。

Fitness

base.Fitness类代表一类适应度,其类属性weights用于表征这类适应度代表的是哪种优化目标的适应度(单目标或多目标优化、最大值优化或是最小值优化)。

单目标优化

当为单目标优化问题时,weights为只有一个元素的元组,该元素为正数时,代表该类适应度是最大值优化问题的适应度,当该元素为负值时,代表是该类适应度是最小值优化问题的适应度。该元素的绝对值无意义。

多目标优化

当为多目标优化问题时,weights为有多个元素的元组,每个元素对应一个优化目标。其中某个元素为正数时,代表对应的优化目标是最大值优化问题的目标,当该元素为负值时,代表对应的优化目标是最小值优化问题的目标。该类适应度的值由这多个目标加权得到。weights中的元素代表权值,决定每个优化目标对最终适应度的贡献大小。

例子:

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

上述例子代表创建一个2目标优化问题的适应度,第一个优化目标是一个最小值优化,第二个优化目标是一个最大值优化。两个优化目标对最终适应度的贡献是相同的。

register

toolbox.register函数用于创建其他函数的"shortcut(减少参数版本)"。其至少接受两个参数,第一个参数是一个字符串,代表一个函数别名。第二个参数是一个函数句柄,其被赋值给第一个参数代表的别名函数,其他参数将在别名函数被调用时传入该函数。

例子:

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)

上述代码首先基于base.Fitness创建了一个FitnessMin类,该类该表一个单目标最小值优化问题的适应度。然后又基于list创建了一个Individual类,该类代表进化算法中的个体,其拥有一个属性fitness,是一个FitnessMin类型的对象。接着,创建了一个函数indices,当indices被调用时,等效于调用random.sample(range(IND_SIZE), IND_SIZE)。接着又创建了一个函数individual,当其被调用时,等效于调用tools.initIterate(creator.Individual, toolbox.indices)。

这样一来,只需要下列的语句便可以创建一个个体。

toolbox.individual()

若要创建一个拥有50个个体的种群则只需要如下的代码

toolbox.register("population", tools.initRepeat, list, creator.Individual)
group = toolbox.population(n=50)

tools.initRepeat、tools.initIterate均为tools模块提供的"初始化操作" Operator

详见:Evolutionary Tools — DEAP 1.4.1 documentation

operators

利用creator和register可以方便的初始化一个种群。在进化类算法中,变异、交叉、选择等步骤则需要Operators去定义。例如,可以利用如下代码去使一个个体发生发变异。

ind1 = toolbox.individual()
ind2, = tools.mutGaussian(ind1, mu=0.0, sigma=0.2, indpb=0.2)

上述代码中的tools.mutGaussian就是一个"变异操作"Operator。

官网对他的介绍:

deap.tools.mutGaussian(individual, mu, sigma, indpb)[source]
This function applies a gaussian mutation of mean mu and standard deviation sigma on the input individual. This mutation expects a sequence individual composed of real valued attributes. The indpb argument is the probability of each attribute to be mutated.

Parameters:  individual – Individual to be mutated.
mu – Mean or sequence of means for the gaussian addition mutation.
sigma – Standard deviation or sequence of standard deviations for the gaussian addition mutation.
indpb – Independent probability for each attribute to be mutated.
Returns: A tuple of one individual.

This function uses the random() and gauss() functions from the python base random module.

大概意思是这个函数以参数mu为均值,sigma为方差,indpb为个体上每个基因发生突变的概率,对第一个参数individual个体上的基因进行变异(不懂的建议先了解下遗传算法)。

除了"变异操作"Operator,tools模块还提供了"选择操作"、"交叉操作"、"初始化操作"(前面见到过的tools.initIterate、tools.initRepeat)、"迁移操作"的Operator。详见:

Evolutionary Tools — DEAP 1.4.1 documentation

当然我们可以使用register去定义一个现有Operator的shortcut版本,作为一个新的operator。

toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=0.2, indpb=0.2)

当要执行编译操作时只需:

ind2 = toolbox.mutate(ind1)

 这样一来,今后要替换变异(交叉、选择等操作也是一样)策略时,只需要修改使用register创建别名函数"mutate"那一行的代码,从而避免了在主体算法流程中对每个使用到变异操作的地方进行霰弹式修改。

算法整体流程

说到底,DEAP框架只是起到方便搭建遗传算法的作用,最终流程还是我们自己在main函数中进行搭建。下面是官方给出的一个单目标最大值优化的例子,看大家自己是否能够看懂。

import random

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

def evalOneMax(individual):
    return sum(individual),

creator.create("FitnessMax", base.Fitness, weights=(1.0,))
creator.create("Individual", list, 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)

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

def main():
    pop = toolbox.population(n=300)
    # Evaluate the entire population
    fitnesses = list(map(toolbox.evaluate, pop))
    for ind, fit in zip(pop, fitnesses):
        ind.fitness.values = fit
    # CXPB  is the probability with which two individuals
    #       are crossed
    #
    # MUTPB is the probability for mutating an individual
    CXPB, MUTPB = 0.5, 0.2
    fits = [ind.fitness.values[0] for ind in pop]
    # Variable keeping track of the number of generations
    g = 0

    # Begin the evolution
    while max(fits) < 100 and g < 1000:
        # A new generation
        g = g + 1
        print("-- Generation %i --" % g)
        # Select the next generation individuals
        offspring = toolbox.select(pop, len(pop))
        # Clone the selected individuals
        offspring = list(map(toolbox.clone, offspring))
        # Apply crossover and mutation on the offspring
        for child1, child2 in zip(offspring[::2], offspring[1::2]):
            if random.random() < CXPB:
                toolbox.mate(child1, child2)
                del child1.fitness.values
                del child2.fitness.values

        for mutant in offspring:
            if random.random() < MUTPB:
                toolbox.mutate(mutant)
                del mutant.fitness.values
        # Evaluate the individuals with an invalid fitness
        invalid_ind = [ind for ind in offspring if not ind.fitness.valid]
        fitnesses = map(toolbox.evaluate, invalid_ind)
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit
        pop[:] = offspring
        # Gather all the fitnesses in one list and print the stats
        fits = [ind.fitness.values[0] for ind in pop]

        length = len(pop)
        mean = sum(fits) / length
        sum2 = sum(x*x for x in fits)
        std = abs(sum2 / length - mean**2)**0.5

        print("  Min %s" % min(fits))
        print("  Max %s" % max(fits))
        print("  Avg %s" % mean)
        print("  Std %s" % std)

  • 28
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值