【问题标题】:DEAP: make mutation probability depend on generation numberDEAP:使突变概率取决于代数
【发布时间】:2020-03-18 06:59:40
【问题描述】:

我正在使用通过 Python 的 DEAP 库实现的遗传算法。为了避免过早收敛,并强制探索特征空间,我希望第一代的突变概率很高。但是为了防止一旦识别出它们就偏离极值,我希望最后几代的突变概率更低。如何使突变概率在几代人中减少? DEAP 中是否有任何内置函数可以完成这项工作?

当我注册一个变异函数时,例如

toolbox.register('mutate', tools.mutPolynomialBounded, eta=.6, low=[0,0], up=[1,1], indpb=0.1)

indpb 参数是一个浮点数。我怎样才能使它成为其他东西的功能?

【问题讨论】:

  • 我不是特别确定 DEAP 是如何发生变异的,但我确信它在你的程序中被调用,即 deap.tools.mutGaussian(xx)。您不能对每个生成步骤使用 1-prob 的步骤减少来确定何时触发变异步骤吗?

标签: python genetic-algorithm deap


【解决方案1】:

听起来像是Callbackproxy 的工作,每次调用函数参数时都会对其进行评估。我添加了一个简单的例子,我修改了官方的 DEAP n-queen example 这样突变率设置为2/N_GENS(为了说明这一点,任意选择)。

请注意,Callbackproxy 接收 lambda,因此您必须将突变率参数作为函数传递(使用完全成熟的函数或仅使用 lambda)。无论如何,结果是每次评估 indpb 参数时都会调用这个 lambda,如果 lambda 包含对全局变量生成计数器的引用,你就会得到你想要的。

#    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/>.

import random
from objproxies import CallbackProxy
import numpy

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

# Problem parameter
NB_QUEENS = 20
N_EVALS = 0
N_GENS = 1

def evalNQueens(individual):
    global N_EVALS, N_GENS
    """Evaluation function for the n-queens problem.
    The problem is to determine a configuration of n queens
    on a nxn chessboard such that no queen can be taken by
    one another. In this version, each queens is assigned
    to one column, and only one queen can be on each line.
    The evaluation function therefore only counts the number
    of conflicts along the diagonals.
    """
    size = len(individual)
    # Count the number of conflicts with other queens.
    # The conflicts can only be diagonal, count on each diagonal line
    left_diagonal = [0] * (2 * size - 1)
    right_diagonal = [0] * (2 * size - 1)

    # Sum the number of queens on each diagonal:
    for i in range(size):
        left_diagonal[i + individual[i]] += 1
        right_diagonal[size - 1 - i + individual[i]] += 1

    # Count the number of conflicts on each diagonal
    sum_ = 0
    for i in range(2 * size - 1):
        if left_diagonal[i] > 1:
            sum_ += left_diagonal[i] - 1
        if right_diagonal[i] > 1:
            sum_ += right_diagonal[i] - 1

    N_EVALS += 1
    if N_EVALS % 300 == 0:
        N_GENS += 1
    return sum_,


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

# Since there is only one queen per line,
# individual are represented by a permutation
toolbox = base.Toolbox()
toolbox.register("permutation", random.sample, range(NB_QUEENS), NB_QUEENS)

# Structure initializers
# An individual is a list that represents the position of each queen.
# Only the line is stored, the column is the index of the number in the list.
toolbox.register("individual", tools.initIterate, creator.Individual, toolbox.permutation)
toolbox.register("population", tools.initRepeat, list, toolbox.individual)

toolbox.register("evaluate", evalNQueens)
toolbox.register("mate", tools.cxPartialyMatched)
toolbox.register("mutate", tools.mutShuffleIndexes, indpb=CallbackProxy(lambda: 2.0 / N_GENS))
toolbox.register("select", tools.selTournament, tournsize=3)





def main(seed=0):
    random.seed(seed)

    pop = toolbox.population(n=300)
    hof = tools.HallOfFame(1)
    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("Avg", numpy.mean)
    stats.register("Std", numpy.std)
    stats.register("Min", numpy.min)
    stats.register("Max", numpy.max)

    algorithms.eaSimple(pop, toolbox, cxpb=0.5, mutpb=1, ngen=100, stats=stats,
                        halloffame=hof, verbose=True)

    return pop, stats, hof


if __name__ == "__main__":
    main()

【讨论】:

  • 你如何计算每一代有 300 次评估?
  • 嗯,这很好。我假设每一代人都会对每个人进行评估,但事实并非如此。更好的选择是直接从进化循环更新全局 N_GENS 变量,但这需要编辑 eaSimple 函数或创建自己的函数。还没有找到更好的方法来做到这一点。
  • eaSimple 在运行时会在屏幕上打印出评估次数。也许有一种方法可以访问并使用该信息?
  • 您可以将 sys.stdout 重新分配给一个文件,然后跟踪打印在该文件上的行,尽管这听起来确实有点矫枉过正。我只会复制 eaSimple 函数并进行必要的调整。
猜你喜欢
  • 2014-10-17
  • 2020-12-24
  • 2015-07-05
  • 2021-09-28
  • 1970-01-01
  • 2010-12-24
  • 2015-01-13
  • 2020-03-03
  • 1970-01-01
相关资源
最近更新 更多