python DEAP学习2(遗传算法) 最大值问题
来源:互联网 发布:amd游戏优化档案 编辑:程序博客网 时间:2024/05/18 02:10
One Max Problem
This is the first complete example built with DEAP. It will help new users to overview some of the framework possibilities. The problem is very simple, we search for a 1
filled list individual. This problem is widely used in the evolutionary computation community since it is very simple and it illustrates well the potential of evolutionary algorithms.
了解DEAP整体框架之后,我们来看一个简单的例子。
Setting Things Up
Here we use the one max problem to show how simple can be an evolutionary algorithm with DEAP. The first thing to do is to elaborate the structures of the algorithm. It is pretty obvious in this case that an individual that can contain a series of booleans is the most interesting kind of structure available. DEAP does not contain any explicit individual structure since it is simply a container of attributes associated with a fitness. Instead, it provides a convenient method for creating types called the creator.
这里我们用最大值问题来展示一下利用DEAP做遗传算法有多简单。
First of all, we need to import some modules.
import randomfrom deap import basefrom deap import creatorfrom deap import tools
Creator
The creator is a class factory that can build at run-time new classes that inherit from a base classe. It is very useful since an individual can be any type of container from list to n-ary tree. The creator allows build complex new structures convenient for evolutionary computation.
Let see an example of how to use the creator to setup an individual that contains an array of booleans and a maximizing fitness. We will first need to import the deap.base
and deap.creator
modules.
The creator defines at first a single function create()
that is used to create types. The create()
function takes at least 2 arguments plus additional optional arguments. The first argument name is the actual name of the type that we want to create. The second argument base is the base classe that the new type created should inherit from. Finally the optional arguments are members to add to the new type, for example a fitness
for an individual or speed
for a particle.
creator.create("FitnessMax", base.Fitness, weights=(1.0,))creator.create("Individual", list, fitness=creator.FitnessMax)
The first line creates a maximizing fitness by replacing, in the base type Fitness
, the pure virtual weights
attribute by (1.0,)
that means to maximize a single objective fitness. The second line creates an Individual
class that inherits the properties of list
and has a fitness
attribute of the type FitnessMax
that was just created.
在Fitness内,weights属性为1表示求最大化,注意1.0后面有一个逗号,即使是在求解单目标问题,weights也需要迭代。
In this last step, two things are of major importance. The first is the comma(逗号) following the 1.0
in the weights declaration, even when implementing a single objective fitness, the weights (and values) must be iterable. We won’t repeat it enough, in DEAP single objective is a special case of multiobjective. The second important thing is how the just created FitnessMax
can be used directly as if it was part of the creator
. This is not magic.
Toolbox
A Toolbox
can be found in the base module. It is intended to store functions with their arguments. The toolbox contains two methods, register()
andunregister()
that are used to do the tricks.
toolbox = base.Toolbox()# Attribute generator toolbox.register("attr_bool", random.randint, 0, 1)#参数:函数名、方法、参数# Structure initializerstoolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, 100)toolbox.register("population", tools.initRepeat, list, toolbox.individual)
In this code block we registered a generation function and two initialization functions. The generator toolbox.attr_bool()
when called, will draw a random integer between 0 and 1. The two initializers for their part will produce respectively initialized individuals and populations.
上面的代码我们创建了三个函数,toolbox.attr_bool()将随机生成0和1的序列,后面来个将分别产生个体和总体。(不太明白为什么要产生总体...)
Again, looking a little closer shows that there is no magic. The registration of tools in the toolbox only associates an alias to an already existing function and freezes part of its arguments. This allows to call the alias as if the majority of the (or every) arguments have already been given. For example, theattr_bool()
generator is made from the randint()
that takes two arguments a and b, with a <= n <= b
, where n is the returned integer. Here, we fix a = 0
and b= 1
.
It is the same thing for the initializers. This time, the initRepeat()
is frozen with predefined arguments. In the case of the individual()
method, initRepeat()
takes 3 arguments, a class that is a container – here the Individual
is derived from a list
–, a function to fill the container and the number of times the function shall be repeated. When called, the individual()
method will thus return an individual initialized with what would be returned by 100 calls to theattr_bool()
method. Finally, the population()
method uses the same paradigm, but we don’t fix the number of individuals that it should contain.
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, 100)
individual指向tools.initRepeat,tools.initRepeat有三个参数,分别是creator.Individual、toolbox.attr_bool,100。调用individual的时候,将使用toolbox.attr_bool方法重复100次填充creator.Individual。
The Evaluation Function
The evaluation function is pretty simple in this case, we need to count the number of ones in the individual. This is done by the following lines of code.
def evalOneMax(individual): return sum(individual),
The returned value must be an iterable of length equal to the number of objectives (weights).
The Genetic Operators
There is two way of using operators, the first one, is to simply call the function from the tools
module and the second one is to register them with their argument in a toolbox as for the initialization methods. The most convenient way is to register them in the toolbox, because it allows to easily switch between operators if desired. The toolbox method is also used in the algorithms, see the One Max Problem: Short Version for an example.
Registering the operators and their default arguments in the toolbox is done as follow.
toolbox.register("evaluate", evalOneMax)toolbox.register("mate", tools.cxTwoPoint)#交配toolbox.register("mutate", tools.mutFlipBit, indpb=0.05)#变异,0.05为变异概率toolbox.register("select", tools.selTournament, tournsize=3)#选择,3是什么?三个操作算子,分别是交配、变异、选择。The evaluation is given the alias evaluate. Having a single argument being the individual to evaluate we don’t need to fix any, the individual will be given later in the algorithm. The mutation, for its part, needs an argument to be fixed (the independent probability of each attribute to be mutated indpb). In the algorithms the
mutate()
function is called with the signature mutant, = toolbox.mutate(mutant)
. This is the most convenient way because each mutation takes a different number of arguments, having those arguments fixed in the toolbox leave open most of the possibilities to change the mutation (or crossover, or selection, or evaluation) operator later in your researches.Evolving the Population
Once the representation and the operators are chosen, we have to define an algorithm. A good habit to take is to define the algorithm inside a function, generally named main()
.
Creating the Population
Before evolving it, we need to instantiate a population. This step is done effortless using the method we registered in the toolbox.
def main(): pop = toolbox.population(n=300)创建种群,pop是一个list,包含300个体。
pop
will be a list
composed of 300 individuals, n is the parameter left open earlier in the toolbox. The next thing to do is to evaluate this brand new population.
# Evaluate the entire population fitnesses = list(map(toolbox.evaluate, pop)) for ind, fit in zip(pop, fitnesses): ind.fitness.values = fit
We first map()
the evaluation function to every individual, then assign their respective fitness. Note that the order in fitnesses
and population
are the same.
map()对可迭代函数'iterable'中的每一个元素应用‘function’方法,将结果作为list返回。
def add100(x): return x+100h=[1,2,3]map(add100,h)[101,102,103]
The Appeal of Evolution
The evolution of the population is the last thing to accomplish. Let say that we want to evolve for a fixed number of generation NGEN
, the evolution will then begin with a simple for statement.
# Begin the evolution for g in range(NGEN): print("-- Generation %i --" % g)
Is that simple enough? Lets continue with more complicated things, selecting, mating and mutating the population. The crossover and mutation operators provided within DEAP usually take respectively 2 and 1 individual(s) on input and return 2 and 1 modified individual(s), they also modify inplace these individuals.
In a simple GA, the first step is to select the next generation.
第一步选择子代,然后克隆被选择的子代,toolbox.clone保证我们拥有独立的子代,而不是只保存子代的引用。
# Select the next generation individuals offspring = toolbox.select(pop, len(pop)) # Clone the selected individuals offspring = list(map(toolbox.clone, offspring))
This step creates an offspring list that is an exact copy of the selected individuals. The toolbox.clone()
method ensure that we don’t own a reference to the individuals but an completely independent instance.
Next, a simple GA would replace the parents by the produced children directly in the population. This is what is done by the following lines of code, where a crossover is applied with probability CXPB
and a mutation with probability MUTPB
. The del
statement simply invalidate the fitness of the modified individuals.
# 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
The population now needs to be re-evaluated, we then apply the evaluation as seen earlier, but this time only on the individuals with an invalid fitness.
第三步重新评估个体。
# 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
And finally, last but not least, we replace the old population by the offspring.
最后我们拥有了全新的子代。
pop[:] = offspring
This is the end of the evolution part, it will continue until the predefined number of generation are accomplished.
Although, some statistics may be gathered on the population, the following lines print the min, max, mean and standard deviation of the population.
这就是进化的过程,它会不断进化直到达到预设的进化代数。
# 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)
A Statistics
object has been defined to facilitate how statistics are gathered. It is not presented here so that we can focus on the core and not the gravitating helper objects of DEAP.
The complete examples/ga/onemax.
完整的代码如下:
# This file is part of DEAP.## DEAP is free software: you can redistribute it and/or modify# it under the terms of the GNU Lesser General Public License as# published by the Free Software Foundation, either version 3 of# the License, or (at your option) any later version.## DEAP is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU Lesser General Public License for more details.## You should have received a copy of the GNU Lesser General Public# License along with DEAP. If not, see <http://www.gnu.org/licenses/>.# example which maximizes the sum of a list of integers# each of which can be 0 or 1import randomfrom deap import basefrom deap import creatorfrom deap import toolscreator.create("FitnessMax", base.Fitness, weights=(1.0,))creator.create("Individual", list, fitness=creator.FitnessMax)toolbox = base.Toolbox()# Attribute generator # define 'attr_bool' to be an attribute ('gene')# which corresponds to integers sampled uniformly# from the range [0,1] (i.e. 0 or 1 with equal# probability)toolbox.register("attr_bool", random.randint, 0, 1)# Structure initializers# define 'individual' to be an individual# consisting of 100 'attr_bool' elements ('genes')toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, 100)# define the population to be a list of individualstoolbox.register("population", tools.initRepeat, list, toolbox.individual)# the goal ('fitness') function to be maximizeddef evalOneMax(individual): return sum(individual),#----------# Operator registration#----------# register the goal / fitness functiontoolbox.register("evaluate", evalOneMax)# register the crossover operatortoolbox.register("mate", tools.cxTwoPoint)# register a mutation operator with a probability to# flip each attribute/gene of 0.05toolbox.register("mutate", tools.mutFlipBit, indpb=0.05)# operator for selecting individuals for breeding the next# generation: each individual of the current generation# is replaced by the 'fittest' (best) of three individuals# drawn randomly from the current generation.toolbox.register("select", tools.selTournament, tournsize=3)#----------def main(): random.seed(64) # create an initial population of 300 individuals (where # each individual is a list of integers) pop = toolbox.population(n=300) # CXPB is the probability with which two individuals # are crossed # # MUTPB is the probability for mutating an individual # # NGEN is the number of generations for which the # evolution runs CXPB, MUTPB, NGEN = 0.5, 0.2, 40 print("Start of evolution") # Evaluate the entire population fitnesses = list(map(toolbox.evaluate, pop)) for ind, fit in zip(pop, fitnesses): ind.fitness.values = fit print(" Evaluated %i individuals" % len(pop)) # Begin the evolution for g in range(NGEN): 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]): # cross two individuals with probability CXPB if random.random() < CXPB: toolbox.mate(child1, child2) # fitness values of the children # must be recalculated later del child1.fitness.values del child2.fitness.values for mutant in offspring: # mutate an individual with probability MUTPB 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 print(" Evaluated %i individuals" % len(invalid_ind)) # The population is entirely replaced by the offspring 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) print("-- End of (successful) evolution --") best_ind = tools.selBest(pop, 1)[0] print("Best individual is %s, %s" % (best_ind, best_ind.fitness.values))if __name__ == "__main__": main()
- python DEAP学习2(遗传算法) 最大值问题
- python DEAP学习1(遗传算法) 概览
- python DEAP学习4(遗传算法)函数使用
- python DEAP学习3(遗传算法) 0-1背包问题
- Deap : 遗传算法算法解决 背包问题
- Deap: python中的遗传算法工具箱
- python DEAP PSO 算法的学习
- python 的 DEAP框架学习
- Python实现遗传算法求解n-queens问题(2)
- pso-svm 算法实现(1):python DEAP
- 最大流问题 (使用遗传算法解决 --Python 实现)
- Python实现遗传算法求解n-queens问题(1)
- 遗传算法(python版)
- 遗传算法_求最大值
- 遗传算法解TSP问题 python实现
- 使用遗传算法计算 f(x) = 1-x^2的最大值
- 遗传算法Python实现
- python遗传算法模块
- Linux_FastDFS 安装笔记
- 做的非常不错的网站
- IO
- String、StringBuffer、StringBuilder区别
- Python 请用sorted对上述列表按名字和分数排序
- python DEAP学习2(遗传算法) 最大值问题
- Freeline
- R-MAC(Regional Raximum Activation of Convolutions)
- Unity3D-优化之二 代码质量
- vi命令的使用
- Unity获取隐藏物体
- 不同型号DVR的通道模式选择
- Tomcat最基本的五脏六腑与经络运行
- 网络地址处理方法<arpa/inet.h>