控制停止准则:BI-POP CMA-ES

协方差矩阵自适应进化策略 (CMA-ES) [Hansen2001] 的一个变体意味着在世代循环中非常具体地控制终止条件。这可以通过在具有特定停止条件的循环内手动调用 generate()update() 来部分实现算法。实际上,BI-POP CMA-ES [Hansen2009] 有9个不同的停止条件,用于控制具有不同种群大小的标准 CMA-ES 的独立重启。

像往常一样,首先要做的是创建类型,并且像往常一样,我们需要一个最小化的适应度和一个作为 列表 的个体。

N = 30

主函数包括一些参数的设置,即增加种群重启的次数和初始的sigma值。然后,在主函数中实例化了 Toolbox ,因为它会随着重启而改变。接下来初始化了 HallOfFamestatisticsLogbook 对象的列表,每个重启对应一个。

creator.create("Individual", list, fitness=creator.FitnessMin)

def main(verbose=True):
    NRESTARTS = 10  # Initialization + 9 I-POP restarts
    SIGMA0 = 2.0    # 1/5th of the domain [-5 5]

    toolbox = base.Toolbox()
    toolbox.register("evaluate", benchmarks.rastrigin)

    halloffame = 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)

    logbooks = list()

然后设置控制重启的第一个循环。它封装了包含多个停止条件的代际循环。这个最后一个循环的内容仅仅是 deap.algorithms.eaGenerateUpdate() 函数中呈现的生成-更新循环。

    while i < (NRESTARTS + nsmallpopruns):
        strategy = cma.Strategy(centroid=numpy.random.uniform(-4, 4, N), sigma=sigma, lambda_=lambda_)
        toolbox.register("generate", strategy.generate, creator.Individual)
        toolbox.register("update", strategy.update)

        logbooks.append(tools.Logbook())
        logbooks[-1].header = "gen", "evals", "restart", "regime", "std", "min", "avg", "max"

        conditions = {"MaxIter" : False, "TolHistFun" : False, "EqualFunVals" : False,
                      "TolX" : False, "TolUpSigma" : False, "Stagnation" : False,
                      "ConditionCov" : False, "NoEffectAxis" : False, "NoEffectCoor" : False}
        while not any(conditions.values()):
            # Generate a new population
            population = toolbox.generate()

            # Evaluate the individuals
            fitnesses = toolbox.map(toolbox.evaluate, population)
            for ind, fit in zip(population, fitnesses):
                ind.fitness.values = fit

            halloffame.update(population)
            record = stats.compile(population)
            logbooks[-1].record(gen=t, evals=lambda_, restart=i, regime=regime, **record)
            if verbose:
                print(logbooks[-1].stream)

            # Update the strategy with the evaluated individuals
            toolbox.update(population)
            if t >= MAXITER:
                # The maximum number of iteration per CMA-ES ran
                conditions["MaxIter"] = True

            mins.append(record["min"])
            if (len(mins) == mins.maxlen) and max(mins) - min(mins) < TOLHISTFUN:
                # The range of the best values is smaller than the threshold
                conditions["TolHistFun"] = True

            if t > N and sum(equalfunvalues[-N:]) / float(N) > EQUALFUNVALS:
                # In 1/3rd of the last N iterations the best and k'th best solutions are equal
                conditions["EqualFunVals"] = True

            if all(strategy.pc < TOLX) and all(numpy.sqrt(numpy.diag(strategy.C)) < TOLX):
                # All components of pc and sqrt(diag(C)) are smaller than the threshold
                conditions["TolX"] = True

            # Need to transfor strategy.diagD[-1]**2 from pyp/numpy.float64 to python
            # float to avoid OverflowError
            if strategy.sigma / sigma > float(strategy.diagD[-1]**2) * TOLUPSIGMA:
                # The sigma ratio is bigger than a threshold
                conditions["TolUpSigma"] = True

            if len(bestvalues) > STAGNATION_ITER and len(medianvalues) > STAGNATION_ITER and \
               numpy.median(bestvalues[-20:]) >= numpy.median(bestvalues[-STAGNATION_ITER:-STAGNATION_ITER + 20]) and \
               numpy.median(medianvalues[-20:]) >= numpy.median(medianvalues[-STAGNATION_ITER:-STAGNATION_ITER + 20]):
                # Stagnation occurred
                conditions["Stagnation"] = True

            if strategy.cond > 10**14:
                # The condition number is bigger than a threshold
                conditions["ConditionCov"] = True

            if all(strategy.centroid == strategy.centroid + 0.1 * strategy.sigma * strategy.diagD[-NOEFFECTAXIS_INDEX] * strategy.B[-NOEFFECTAXIS_INDEX]):
                # The coordinate axis std is too low
                conditions["NoEffectAxis"] = True

            if any(strategy.centroid == strategy.centroid + 0.2 * strategy.sigma * numpy.diag(strategy.C)):
        stop_causes = [k for k, v in conditions.items() if v]
        print("Stopped because of condition%s %s" % ((":" if len(stop_causes) == 1 else "s:"), ",".join(stop_causes)))
        i += 1

为了清晰起见,省略了一些变量,更多详情请参阅完整示例 examples/es/cma_bipop

[Hansen2001]

Hansen 和 Ostermeier, 2001. 完全去随机化的进化策略中的自适应。进化计算

[Hansen2009]

Hansen, 2009. 在BBOB-2009函数测试平台上对双种群CMA-ES进行基准测试。GECCO’09