pymoo
Latest Version: pymoo==0.4.1

CallbackΒΆ

A Callback class can be used to receive a notification of the algorithm object each generation. This can be useful to keep track of metrics, do additional calculations or even modify the algorithm object during the run. The latter is only recommend for experienced users.

For instance, to keep track of the best solution each generation:

[1]:
import matplotlib.pyplot as plt
import numpy as np

from pymoo.algorithms.so_genetic_algorithm import GA
from pymoo.factory import get_problem
from pymoo.model.callback import Callback
from pymoo.optimize import minimize


class MyCallback(Callback):

    def __init__(self) -> None:
        super().__init__()
        self.data["best"] = []

    def notify(self, algorithm):
        self.data["best"].append(algorithm.pop.get("F").min())


problem = get_problem("sphere")

algorithm = GA(pop_size=100)

res = minimize(problem,
               algorithm,
               ('n_gen', 20),
               seed=1,
               callback=MyCallback(),
               save_history=True,
               verbose=True)

val = res.algorithm.callback.data["best"]
plt.plot(np.arange(len(val)), val)
plt.show()


=============================================
n_gen |  n_eval |     fopt     |     favg
=============================================
    1 |     100 |  0.387099336 |  0.831497479
    2 |     200 |  0.302189349 |  0.578035582
    3 |     300 |  0.267733594 |  0.443801185
    4 |     400 |  0.188215259 |  0.347200983
    5 |     500 |  0.083479177 |  0.272644726
    6 |     600 |  0.083479177 |  0.212567874
    7 |     700 |  0.072492126 |  0.173574163
    8 |     800 |  0.051256476 |  0.140740462
    9 |     900 |  0.041778020 |  0.110370322
   10 |    1000 |  0.041778020 |  0.089125798
   11 |    1100 |  0.031644566 |  0.071339910
   12 |    1200 |  0.030055810 |  0.057941249
   13 |    1300 |  0.021855327 |  0.047786695
   14 |    1400 |  0.017620999 |  0.040676540
   15 |    1500 |  0.014756395 |  0.034902705
   16 |    1600 |  0.014756395 |  0.029778240
   17 |    1700 |  0.012976416 |  0.026185115
   18 |    1800 |  0.008637920 |  0.022664820
   19 |    1900 |  0.006399439 |  0.019648350
   20 |    2000 |  0.006399439 |  0.016725603
../_images/interface_callback_3_1.png

If the analysis of the run should be done during post-processing the option save_history can be used as well. If a callback is used the history does not need to be saved. By using the history object the same as above can be achieved by using the stored information during the run:

[2]:
val = [e.pop.get("F").min() for e in res.history]
plt.plot(np.arange(len(val)), val)
plt.show()
../_images/interface_callback_5_0.png

If the save_history is true a deep copy of the algorithm object takes place each generation. Please note that this can be quite expensive and might not be desired for all runs. However, it provides great post-processing options because all data can be accessed respectively.