python遺傳算法(GA)DEAP-Overview學習摘要
DEAP-Overview
DEAP是一個python遺傳算法框架,這里是它的簡介。 DEAP documentation
今天整理一下DEAP的概覽,大體了解一下它的流程。初學,不嚴謹,僅作為自己的備忘學習筆記。
一. Types
The first thing to do is to think of the appropriate type for your problem.This is done with the creator module.
第一件事就是思考你問題的合適類型(是什么樣的優化問題,最小值?最大值?單目標?多目標?)。在 creator 模塊中可以實現。
For example, the following creates a FitnessMin class for a minimization problem and an Individual class that is derived from a list with a fitness attribute set to the just created fitness.
例如,下面為一個最小化問題創建一個 FitnessMin 類和個體類,它來自于剛剛創建的適應度帶有fitness屬性值集合的列表。
from deap import base, creator creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) creator.create("Individual", list, fitness=creator.FitnessMin)
That’s it. More on creating types can be found in the Creating Types tutorial.
更多關于創建類型的問題可以在 Creating Types tutorial 查看。
</div>
二. Initialization
Once the types are created you need to fill them with sometimes random values, sometime guessed ones. Again, DEAP provides an easy mechanism to do just that.一旦這些類型被創建,你就需要用一些隨機的值來填充它們,有時是猜測值。同樣的, DEAP極大的提供了這樣的一個簡單的機制來做這件事兒。
The Toolbox is a container for tools of all sorts including initializers that can do what is needed of them. The following takes on the last lines of code to create the initializers for individuals containing random floating point numbers and for a population that contains them.
toolbox 是一個工具容器,可用來包含各種“初始化體”(可以做它們需要的事兒)。以下是以代碼來創建包含隨機浮點數的初始化和個人人口包含他們最后的線。下面最后幾行代碼用來創建“初始化體”,為包含那些隨機值的“個體”和包含它們的種群。
import random from deap import toolsIND_SIZE = 10
toolbox = base.Toolbox() toolbox.register("attribute", random.random) toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attribute, n=IND_SIZE) toolbox.register("population", tools.initRepeat, list, toolbox.individual) #是吧,創建的individual放入了population中</pre>
This creates functions to initialize populations from individuals that are themselves initialized with random float numbers. The functions are registered in the toolbox with their default arguments under the given name.這將創建函數來初始化種群(來自那些用隨機浮點數初始化而成的個體們)。這些函數在給定名字的默認參數下被“注冊到”toolbox中,
register 感覺這個單詞在這兒的理解可以看做是“創建”的意思,然后 toolbox 中就有了 toolbox.individual 。具體理解,還得看后面的詳細介紹。
toolbox 貌似和 function 有關,里邊的第一個參數就是函數名。因為在 Algorithm 步驟里時,出現了這樣的用法 toolbox.population() 。
More initialization methods are found in the Creating Types tutorial and the various Examples.
更多初始化的方法可以在 Creating Types tutorial 和 Examples 中查看。
三. Operator
toolbox.register("mate", tools.cxTwoPoint)Operators 都在toolbox模塊里,要給每個算子選擇合適算法。在 Operator 里邊可以給每個步驟的算子分別選擇合適的算法。
In addition you must create your evaluation function. This is how it is done in DEAP.就是這個評價功能函數得自己寫,其實,也就是適應度函數了!
Note also that fitness values must be iterable, that is why we return a tuple in the evaluate function.就是注意評價函數返回值必須是可迭代的。
def evaluate(individual): return sum(individual),toolbox.register("mate", tools.cxTwoPoint) toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.1) toolbox.register("select", tools.selTournament, tournsize=3) toolbox.register("evaluate", evaluate)</pre>
四. Algorithms
Now that everything is ready, we can start to write our own algorithm. It is usually done in a main function. For the purpose of completeness we will develop the complete generational algorithm.現在一切具備,我們可以開始寫自己的算法了。通常在主函數里邊寫。完整性的目的,我們將開發完整的分代算法。
def main(): pop = toolbox.population(n=50) CXPB, MUTPB, NGEN = 0.5, 0.2, 40# Evaluate the entire population fitnesses = map(toolbox.evaluate, pop) for ind, fit in zip(pop, fitnesses): ind.fitness.values = fit for g in range(NGEN): # Select the next generation individuals offspring = toolbox.select(pop, len(pop)) # Clone the selected individuals offspring = 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 # The population is entirely replaced by the offspring pop[:] = offspring return pop</pre>
縱觀整個步驟,可以發現 DEAP 在實現GA過程中的思路一般是很清晰的。
確定 Types -- creator 創建,選好解決問題的類型
初始化 Initialization -- toolbox 注冊個體啊,種群啊等等函數。
Operator --算子選擇,交叉,變異,選擇,進化等等。每個算子都有不同的算法,可以選擇的!
Algorithms --算法就是具體將上面注冊的函數啊,等等應用結合起來,編寫流程。
例子
# 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 1
import random
from deap import base from deap import creator from deap import tools
creator.create("FitnessMax", base.Fitness, weights=(1.0,)) #這里這個base.Fitness是干嘛的??? creator.create("Individual", list, fitness=creator.FitnessMax) #這里的list,fitness是參數,干嘛的???
toolbox = base.Toolbox() #base是個很基本的類啊!!!看來很重要
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) #包含了0,1的隨機整數。不明白這里是干嘛的???
Structure initializers: define 'individual' to be an individual
consisting of 100 'attr_bool' elements ('genes')
toolbox.register("individual", tools.initRepeat, creator.Individual, #tools.initRepeat是干嘛的??? toolbox.attr_bool, 100)
define the population to be a list of 'individual's
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
the goal ('fitness') function to be maximized 注意!!!這里就定義了我們的適應度fitness函數啦!!!因為我們要解決的就是求和問題
只要返回一個值給我們的這個適應度函數啊!利用自帶的sum函數!
這里取名為evalOneMax是因為這里的適應度函數就是我們后面要用來評價的依據,evaluate
def evalOneMax(individual): return sum(individual),
----------
Operator registration
----------
register the goal / fitness function
這里的toolbox register語句的理解:注冊了一個函數evaluae依據的是后面的evalOneMax 理通了!!!
toolbox.register("evaluate", evalOneMax)
瞧瞧,這里的交叉函數,尼瑪,crossover不用,非得用個mate,還以為是華為mate呢!你看,這里的交叉算子采用的函數,也是已經停供的,可以選擇的
register the crossover operator
toolbox.register("mate", tools.cxTwoPoint)
register a mutation operator with a probability to
flip each attribute/gene of 0.05
toolbox.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) #這里選擇的tournsize又是什么意思呢?
----------
def main(): random.seed(64)
# hash(64)is used # random.seed方法的作用是給隨機數對象一個種子值,用于產生隨機序列。 # 對于同一個種子值的輸入,之后產生的隨機數序列也一樣。 # 通常是把時間秒數等變化值作為種子值,達到每次運行產生的隨機系列都不一樣 # create an initial population of 300 individuals (where # each individual is a list of integers) pop = toolbox.population(n=300) #定義了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 進化運行的代數!果然,運行40代之后,就停止計算了 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)) #這時候,pop的長度還是300呢 # Begin the evolution 開始進化了哈!!!注意注意注意!就是一個for循環里了!40次--代數 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()</pre> </div>