Python遺傳演算法框架DEAP-Operators and Algorithms

MichaelXoX發表於2016-01-27

Before starting with complex algorithms, we will see some basics of DEAP. First, we will start by creating simple individuals (as seen in the Creating Types tutorial) and make them interact with each other using different operators. Afterwards, we will learn how to use the algorithms and other tools.
在開始複雜的演算法之前,我們將會看到一些基礎的東西。首先,我們開始建立簡單的個體(之前的教程中介紹了)和讓它們利用操作運算元互相作用。然後,我們將學習怎麼使用演算法和其他工具。

A First Individual(第一個個體)

First import the required modules and register the different functions required to create individuals that are lists of floats with a minimizing two objectives fitness.
一開始匯入需要模組和註冊不同的函式去建立個體(浮點數列表),求解的是一個最小化二目標適應度問題。

import random
 
from deap import base
from deap import creator
from deap import tools
 
IND_SIZE = 5
 
creator.create("FitnessMin", base.Fitness, weights=(-1.0, -1.0))
creator.create("Individual", list, fitness=creator.FitnessMin)
 
toolbox = base.Toolbox()
toolbox.register("attr_float", random.random)
toolbox.register("individual", tools.initRepeat, creator.Individual,
                 toolbox.attr_float, n=IND_SIZE)

The first individual can now be built by adding the appropriate line to the script.
第一個個體現在能用合適一行程式碼去建立新增了。

ind1 = toolbox.individual()

Printing the individual ind1 and checking if its fitness is valid will give something like this
列印出個體ind1,檢查它的適應度是否有效:

print ind1               # [0.86..., 0.27..., 0.70..., 0.03..., 0.87...]
print ind1.fitness.valid # False

The individual is printed as its base class representation (here a list) and the fitness is invalid because it contains no values.
這個個體列印出來了。這個適應度是無效的,因為沒有值。

Evaluation(重頭戲來了,評價函式/適應度函式)

The evaluation is the most personal part of an evolutionary algorithm, it is the only part of the library that you must write yourself. A typical evaluation function takes one individual as argument and returns its fitness as a tuple. As shown in the in the core section, a fitness is a list of floating point values and has a property valid to know if this individual shall be re-evaluated. The fitness is set by setting the values to the associated tuple. For example, the following evaluates the previously created individual ind1 and assigns its fitness to the corresponding values.
評價函式部分是評價演算法中最“個人”的部分,它是庫中你必須自己寫的一部分。一個典型的評價函式需要一個個體作為引數,然後返回這個個體的fitness(以tuple格式)。在核心部分所示,一個適應度值是一個浮點值的列表並有一個有效的屬性來知道這個個體是否應當重新評估。這個適應度值是通過設定值和元祖關聯。舉個例子,下面的選擇評價之前建立的個體ind1,同時,分配它的fitness給相應的值。
(⊙o⊙)…讓我回憶起專業英語翻譯文章的感覺了,難以讀懂。硬著頭皮往下看吧。

def evaluate(individual):
    # Do some hard computing on the individual
    a = sum(individual)
    b = len(individual)
    return a, 1. / b
 
ind1.fitness.values = evaluate(ind1)
print ind1.fitness.valid    # True    原來有`fitness`是True!搜嘎
print ind1.fitness          # (2.73, 0.2)上面建立的個體IND_SIZE=5,所以這裡是1/5=0.2

Dealing with single objective fitness is not different, the evaluation function must return a tuple because single-objective is treated as a special case of multi-objective.
與處理單目標適應度不同,這裡評價函式必須返回一個元祖因為單目標是作為多目標的一個特例而已。

Mutation(變異)

There is a variety of mutation operators in the deap.tools module. Each mutation has its own characteristics and may be applied to different types of individuals. Be careful to read the documentation of the selected operator in order to avoid undesirable behaviour.
deap.tools module模組那兒有很多變異操作運算元。每個變異運算元有它自己的特徵,可以應用到不同型別的個體上。仔細閱讀選擇運算元的文件,從而避免無法理解的行為。

The general rule for mutation operators is that they only mutate, this means that an independent copy must be made prior to mutating the individual if the original individual has to be kept or is a reference to another individual (see the selection operator).
變異運算元的總體規則就是他們只是變異,這意味著一個獨立的副本必須在變異個體操作之前,如果原始個體必須要儲存或者是另外個體的參考(看選擇運算元)。

In order to apply a mutation (here a gaussian mutation) on the individual ind1, simply apply the desired function.
為了在個體ind1上施行變異(這裡是高斯變異),簡單應用了所需的函式。

mutant = toolbox.clone(ind1)
ind2, = tools.mutGaussian(mutant, mu=0.0, sigma=0.2, indpb=0.2)
del mutant.fitness.values

The fitness’ values are deleted because they’re not related to the individual anymore. As stated above, the mutation does mutate and only mutate an individual it is neither responsible of invalidating the fitness nor anything else. The following shows that ind2 and mutant are in fact the same individual.
適應度值被刪除了,因為它們不再和這個個體相關了(因為變異了嘛!!!)。如上面所述,這個變異運算元只是變異並且只是變異一個個體,它也不對適應度的無效負責或者其它。下面展示了ind2,變異運算元事實上同樣的個體。(不是很明白這裡)

print ind2 is mutant    # True
print mutant is ind1    # False

Crossover(交叉)

The second kind of operator that we will present is the crossover operator. There is a variety of crossover operators in the deap.tools module. Each crossover has its own characteristics and may be applied to different types of individuals. Be careful to read the documentation of the selected operator in order to avoid undesirable behaviour.
我們將要展示的第二種操作運算元是交叉運算元。在deap.tools module模組中有很多交叉運算元。每種交叉運算元有它自己的特性,可能適用於不同型別的個體。仔細閱讀選擇運算元的文件從而避免無法理解的的行為。

The general rule for crossover operators is that they only mate individuals, this means that an independent copies must be made prior to mating the individuals if the original individuals have to be kept or are references to other individuals (see the selection operator).
交叉運算元的總體規則是它們值負責交叉個體,這意味著在交叉個體之前需獨立的副本,如果原始個體不得不被儲存或者作為其他個體的參考(看選擇運算元)。

Lets apply a crossover operation to produce the two children that are cloned beforehand.
讓我們施行交叉運算元來產生兩個子孫(事先已經被“克隆”了)。

child1, child2 = [toolbox.clone(ind) for ind in (ind1, ind2)]
tools.cxBlend(child1, child2, 0.5)
del child1.fitness.values
del child2.fitness.values

Selection(選擇)

Selection is made among a population by the selection operators that are available in the deap.tools module. The selection operator usually takes as first argument an iterable container of individuals and the number of individuals to select. It returns a list containing the references to the selected individuals. The selection is made as follow.
選擇是通過選擇運算元在種群中操作的,它可以在deap.tools module模組中獲得。這個選擇運算元操作通常第一個引數是個體們的可迭代容器,以及要選擇個體的個數。它返回的是選擇個體們的應用列表。選擇運算元操作示例如下:

selected = tools.selBest([child1, child2], 2)
print child1 in selected    # True

Usually duplication of the entire population will be made after selection or before variation.
通常在選擇或者變異之後,會做整個種群的副本。

selected = toolbox.select(population, LAMBDA)
offspring = [toolbox.clone(ind) for ind in selected]

Using the Toolbox(使用工具箱)

The toolbox is intended to contain all the evolutionary tools, from the object initializers to the evaluation operator. It allows easy configuration of each algorithm. The toolbox has basically two methods, register() and unregister(), that are used to add or remove tools from the toolbox.
工具箱是來包含所有進化工具的,從物件的初始化到評價操作運算元。它允許每種演算法的配置。工具箱有兩個基本的方法,register()unregister(),這個用來從工具箱中增加或者移除工具的。

This part of the tutorial will focus on registration of the evolutionary tools in the toolbox rather than the initialization tools. The usual names for the evolutionary tools are mate(), mutate(), evaluate() and select(), however, any name can be registered as long as it is unique. Here is how they are registered in the toolbox.
教程的這部分將會專注於工具箱中進化工具的註冊而不是初始化工具。進化工具通常的名字是mate(),mutate(),evaluate(),select(),然而,任何名字都是可以被註冊的,只要它是獨一無二的。這裡展示了它們是怎麼被註冊進工具箱的:

from deap import base
from deap import tools

toolbox = base.Toolbox()

def evaluateInd(individual):
    # Do some computation
    return result,

toolbox.register("mate", tools.cxTwoPoint)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=1, indpb=0.2)
toolbox.register("select", tools.selTournament, tournsize=3)
toolbox.register("evaluate", evaluateInd)

Using the toolbox for registering tools helps keeping the rest of the algorithms independent from the operator set. Using this scheme makes it very easy to locate and change any tool in the toolbox if needed.
使用工具箱註冊工具有助於保持其餘演算法獨立於操作符的集合。使用這種方案使得它很容易定位和改變工具箱中的任何工具。

Using the Tools(使用工具)

When building evolutionary algorithms the toolbox is used to contain the operators, which are called using their generic name. For example, here is a very simple generational evolutionary algorithm.
當建立進化演算法時,工具箱是用來容納這個操作運算元的,就是被稱為使用它們的通用名字。例如,這裡是一個非常簡單的進化演算法。

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 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

    # Apply mutation on the offspring
    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 = toolbox.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

This is a complete algorithm. It is generic enough to accept any kind of individual and any operator, as long as the operators are suitable for the chosen individual type. As shown in the last example, the usage of the toolbox allows to write algorithms that are as close as possible to pseudo code. Now it is up to you to write and experiment on your own.
這是一個完整的演算法。它是足夠通用的來接收各種個體和任何操作運算元,只要操作運算元是是適合選擇的個體型別。正如最後一個例子所示,工具箱的使用允許寫演算法(和虛擬碼儘可能相近)。現在取決於你自己寫、實驗你的演算法。

Tool Decoration(工具裝飾)

Tool decoration is a very powerful feature that helps to control very precise things during an evolution without changing anything in the algorithm or operators. A decorator is a wrapper that is called instead of a function. It is asked to make some initialization and termination work before and after the actual function is called.
工具裝飾是一個非常強大的特性,在進化過程中它有助於控制非常精確的東西而不需要改變演算法或者運算元的其他東西。一個裝飾器被稱為一個包裝器而不是一個函式。它是在一些初始化和終止工作的時候被訪問,在實際函式呼叫之前或者之後。

For example, in the case of a constrained domain, one can apply a decorator to the mutation and crossover in order to keep any individual from being out-of-bound. The following defines a decorator that checks if any attribute in the list is out-of-bound and clips it if this is the case. The decorator is defined using three functions in order to receive the min and max arguments. Whenever the mutation or crossover is called, bounds will be checked on the resulting individuals.
例如,在約束域的例子裡,一個能對變異和交叉引用裝飾器為了避免個體出界,如果出界就去除它。裝飾器使用三個函式來定義為了接受最小和最大的引數。變異或交叉操作無論什麼時候被呼叫,都會對結果個體們進行範圍檢查。
╮(╯▽╰)╭無奈,不明白啊,加油

def checkBounds(min, max):
    def decorator(func):
        def wrapper(*args, **kargs):
            offspring = func(*args, **kargs)
            for child in offspring:
                for i in xrange(len(child)):
                    if child[i] > max:
                        child[i] = max
                    elif child[i] < min:
                        child[i] = min
            return offspring
        return wrapper
    return decorator

toolbox.register("mate", tools.cxBlend, alpha=0.2)
toolbox.register("mutate", tools.mutGaussian, mu=0, sigma=2)

toolbox.decorate("mate", checkBounds(MIN, MAX))
toolbox.decorate("mutate", checkBounds(MIN, MAX))

This will work on crossover and mutation because both return a tuple of individuals. The mutation is often considered to return a single individual but again like for the evaluation, the single individual case is a special case of the multiple individual case.
這將會作用在交叉和變異運算元上因為兩者都返回一個個體們的元祖。變異通常被認為返回一個單一個體但是卻像評估運算元一樣,單一個體的例子是多目標的一個特殊例子。

相關文章