检查点

在本教程中,我们将介绍如何在您的进化过程中实现持久性。唯一需要的工具是一个简单的 字典 和一个序列化方法。重要数据将被插入字典并序列化到文件中,以便在出现问题时,可以从最后一个保存的检查点恢复进化。它还可以用于在预设的终止条件之外继续进化。

在标准算法如eaSimple、eaMuPlus/CommaLambda和eaGenerateUpdate中不提供检查点功能。您必须创建自己的算法(或复制现有的算法)并自行引入此功能。

从一个非常基础的例子开始,我们将涵盖所有必要的步骤来检查点化所需的一切以恢复进化。我们跳过类定义和工具箱中的工具注册,直接进入算法和主函数。我们的主函数接收一个可选的字符串参数,该参数包含要恢复的检查点文件的路径。:

import pickle

def main(checkpoint=None):
    if checkpoint:
        # A file name has been given, then load the data from the file
        with open(checkpoint, "rb") as cp_file:
            cp = pickle.load(cp_file)
        population = cp["population"]
        start_gen = cp["generation"]
        halloffame = cp["halloffame"]
        logbook = cp["logbook"]
        random.setstate(cp["rndstate"])
    else:
        # Start a new evolution
        population = toolbox.population(n=300)
        start_gen = 0
        halloffame = tools.HallOfFame(maxsize=1)
        logbook = tools.Logbook()

    stats = tools.Statistics(lambda ind: ind.fitness.values)
    stats.register("avg", numpy.mean)
    stats.register("max", numpy.max)

    for gen in range(start_gen, NGEN):
        population = algorithms.varAnd(population, toolbox, cxpb=CXPB, mutpb=MUTPB)

        # Evaluate the individuals with an invalid fitness
        invalid_ind = [ind for ind in population if not ind.fitness.valid]
        fitnesses = toolbox.map(toolbox.evaluate, invalid_ind)
        for ind, fit in zip(invalid_ind, fitnesses):
            ind.fitness.values = fit

        halloffame.update(population)
        record = stats.compile(population)
        logbook.record(gen=gen, evals=len(invalid_ind), **record)

        population = toolbox.select(population, k=len(population))

        if gen % FREQ == 0:
            # Fill the dictionary using the dict(key=value[, ...]) constructor
            cp = dict(population=population, generation=gen, halloffame=halloffame,
                      logbook=logbook, rndstate=random.getstate())

            with open("checkpoint_name.pkl", "wb") as cp_file:
                pickle.dump(cp, cp_file)

现在,整个数据将在每 FREQ 代写入一个序列化的字典中。如果主函数给定了一个检查点文件的路径,则会加载检查点。在这种情况下,进化将从最后一个检查点继续。它将产生与未停止并重新加载时完全相同的结果,因为我们还恢复了随机模块的状态。如果你使用 numpy 的随机数,别忘了保存和重新加载它们的状态。