控制停止准则:BI-POP CMA-ES¶
协方差矩阵自适应进化策略 (CMA-ES) [Hansen2001] 的一个变体意味着在世代循环中非常具体地控制终止条件。这可以通过在具有特定停止条件的循环内手动调用 generate()
和 update()
来部分实现算法。实际上,BI-POP CMA-ES [Hansen2009] 有9个不同的停止条件,用于控制具有不同种群大小的标准 CMA-ES 的独立重启。
像往常一样,首先要做的是创建类型,并且像往常一样,我们需要一个最小化的适应度和一个作为 列表
的个体。
N = 30
主函数包括一些参数的设置,即增加种群重启的次数和初始的sigma值。然后,在主函数中实例化了 Toolbox
,因为它会随着重启而改变。接下来初始化了 HallOfFame
, statistics
和 Logbook
对象的列表,每个重启对应一个。
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