Checkpoints#

Sometimes, it might be useful to store some checkpoints while executing an algorithm. In particular, if a run is very time-consuming. pymoo offers to resume a run by serializing the algorithm object and loading it. Resuming runs from checkpoints is possible

  • the functional way by calling the minimize method,

  • the object-oriented way by repeatedly calling the next() method or

  • from a text file (Biased Initialization from Population )

Functional#

[1]:
import dill
from pymoo.problems import get_problem

from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.optimize import minimize
from pymoo.termination.max_gen import MaximumGenerationTermination

problem = get_problem("zdt1", n_var=5)

algorithm = NSGA2(pop_size=100)

res = minimize(problem,
               algorithm,
               ('n_gen', 5),
               seed=1,
               copy_algorithm=False,
               verbose=True)

with open("checkpoint", "wb") as f:
    dill.dump(algorithm, f)

with open("checkpoint", 'rb') as f:
    checkpoint = dill.load(f)
    print("Loaded Checkpoint:", checkpoint)

# only necessary if for the checkpoint the termination criterion has been met
checkpoint.termination = MaximumGenerationTermination(20)

res = minimize(problem,
               checkpoint,
               seed=1,
               copy_algorithm=False,
               verbose=True)
==========================================================================
n_gen  |  n_eval  | n_nds  |      igd      |       gd      |       hv
==========================================================================
     1 |      100 |      6 |  0.8742936714 |  1.9701230739 |  0.000000E+00
     2 |      200 |      6 |  0.6603562486 |  1.8052056899 |  0.0450569418
     3 |      300 |      9 |  0.6603562486 |  1.4557787239 |  0.0450569418
     4 |      400 |      4 |  0.5509360994 |  1.1819612945 |  0.0701694142
     5 |      500 |      5 |  0.3820798775 |  0.7384772831 |  0.2199755956
Loaded Checkpoint: <pymoo.algorithms.moo.nsga2.NSGA2 object at 0x73ce7d6f6fd0>
     6 |      600 |      8 |  0.3504821904 |  0.4506459838 |  0.2420590544
     7 |      700 |     11 |  0.3428477093 |  0.4052163133 |  0.2631834563
     8 |      800 |     13 |  0.2806740976 |  0.4773649342 |  0.3172787204
     9 |      900 |     15 |  0.2544731196 |  0.4961727044 |  0.3586946917
    10 |     1000 |     19 |  0.1999042119 |  0.2488085881 |  0.4017205041
    11 |     1100 |     18 |  0.1477726447 |  0.1884635848 |  0.4408628744
    12 |     1200 |     23 |  0.1314754559 |  0.1594860909 |  0.4680012278
    13 |     1300 |     32 |  0.1036901199 |  0.1172998701 |  0.5110173081
    14 |     1400 |     30 |  0.0794008107 |  0.0983678383 |  0.5391111751
    15 |     1500 |     38 |  0.0658098163 |  0.0901692909 |  0.5576479791
    16 |     1600 |     50 |  0.0568115718 |  0.0845418283 |  0.5723120033
    17 |     1700 |     57 |  0.0487834128 |  0.0658195897 |  0.5885410008
    18 |     1800 |     59 |  0.0393834535 |  0.0526742063 |  0.6031562589
    19 |     1900 |     61 |  0.0342133598 |  0.0386242119 |  0.6101324566
    20 |     2000 |     64 |  0.0275837998 |  0.0337949472 |  0.6211244207

Object Oriented#

[2]:
import dill

from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.problems import get_problem

problem = get_problem("zdt1", n_var=5)

algorithm = NSGA2(pop_size=100)

algorithm.setup(problem, seed=1, termination=('n_gen', 20))

for k in range(5):
    algorithm.next()
    print(algorithm.n_gen)

    with open("checkpoint", "wb") as f:
        dill.dump(algorithm, f)


with open("checkpoint", 'rb') as f:
    checkpoint = dill.load(f)
    print("Loaded Checkpoint:", checkpoint)

while checkpoint.has_next():
    checkpoint.next()
    print(checkpoint.n_gen)
2
3
4
5
6
Loaded Checkpoint: <pymoo.algorithms.moo.nsga2.NSGA2 object at 0x73ce4b12be10>
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

From a Text File#

First, load the data from a file. Usually, this will include the variables X, the objective values F (and the constraints G). Here, they are created randomly. Always make sure the Problem you are solving would return the same values for the given X values. Otherwise the data might be misleading for the algorithm.

(This is not the case here. It is really JUST for illustration purposes)

[3]:
import numpy as np
from pymoo.problems.single import G1

problem = G1()

N = 300
np.random.seed(1)
X = np.random.random((N, problem.n_var))

# here F and G is re-evaluated - in practice you want to load them from files too
F, G = problem.evaluate(X, return_values_of=["F", "G"])

Then, create a population object using your data:

[4]:
from pymoo.core.evaluator import Evaluator
from pymoo.core.population import Population
from pymoo.problems.static import StaticProblem

# now the population object with all its attributes is created (CV, feasible, ...)
pop = Population.new("X", X)
pop = Evaluator().eval(StaticProblem(problem, F=F, G=G), pop)

And finally run it with a non-random initial population sampling=pop:

[5]:
from pymoo.algorithms.soo.nonconvex.ga import GA
from pymoo.optimize import minimize

# the algorithm is now called with the population - biased initialization
algorithm = GA(pop_size=100, sampling=pop)

res = minimize(problem,
               algorithm,
               ('n_gen', 10),
               seed=1,
               verbose=True)
=================================================================================================
n_gen  |  n_eval  |     cv_min    |     cv_avg    |     f_avg     |     f_min     |     f_gap
=================================================================================================
     1 |        0 |  0.000000E+00 |  0.1192400898 | -1.037973E+00 | -3.869005E+00 |  1.113099E+01
     2 |      100 |  0.000000E+00 |  0.000000E+00 | -2.271906E+00 | -3.869005E+00 |  1.113099E+01
     3 |      200 |  0.000000E+00 |  0.000000E+00 | -2.818306E+00 | -4.062760E+00 |  1.093724E+01
     4 |      300 |  0.000000E+00 |  0.000000E+00 | -3.303222E+00 | -4.811746E+00 |  1.018825E+01
     5 |      400 |  0.000000E+00 |  0.000000E+00 | -3.740373E+00 | -5.676009E+00 |  9.3239906574
     6 |      500 |  0.000000E+00 |  0.000000E+00 | -4.239895E+00 | -5.676009E+00 |  9.3239906574
     7 |      600 |  0.000000E+00 |  0.000000E+00 | -4.700497E+00 | -5.848033E+00 |  9.1519665825
     8 |      700 |  0.000000E+00 |  0.000000E+00 | -5.200533E+00 | -6.552622E+00 |  8.4473781141
     9 |      800 |  0.000000E+00 |  0.000000E+00 | -5.632671E+00 | -6.634862E+00 |  8.3651379271
    10 |      900 |  0.000000E+00 |  0.000000E+00 | -6.069812E+00 | -7.208883E+00 |  7.7911169982