Search code examples
pythonoptimizationminimizationautosave

Save intermediate results in minimization problem


I am running a minimization problem using the next code:

import numpy as np
from scipy.optimize import minimize

Nfeval = 1

def objective_fnc(x):
    ....
    return y

def callbackF(x):
    global Nfeval
    print('{0:4d}   {1: 3.6f}   {2: 3.6f}   {3: 3.6f}   {4: 3.6f}   {5: 3.6f}'.format(Nfeval, x[0], x[1], x[2], x[3], objective_fnc(x)))
    Nfeval += 1

res=minimize(objective_fnc, x0, method='Nelder-Mead', bounds=bnds, callback=callbackF, options={'disp': True})

I want to save intermediate results in a txt file in case the optimization process is stopped for any reason. The idea is to save only those results better than the previous one or better during the optimization process.

I have access to the variables and the objective function using the callbackF function defined previously. However, I am still trying to figure out how to save the best results when convenient.


Solution

  • I'd suggest something like this:

    import numpy as np
    
    class CallbackFunctor:
        def __init__(self, obj_fun):
            self.best_fun_vals = [np.inf]
            self.best_sols = []
            self.num_calls = 0
            self.obj_fun = obj_fun
        
        def __call__(self, x):
            fun_val = self.obj_fun(x)
            self.num_calls += 1
            if fun_val < self.best_fun_vals[-1]:
                self.best_sols.append(x)
                self.best_fun_vals.append(fun_val)
       
        def save_sols(self, filename):
            sols = np.array([sol for sol in self.best_sols])
            np.savetxt(filename, sols)
    

    Here, you don't need ugly global variables and the callback saves each now found solution, i.e. a solution with a lower objective function value than the last found solution. Example usage:

    cb = CallbackFunctor(objective_fun)
    res = minimize(objective_fun, x0=x0, callback=cb)
    
    print(cb.best_sols)       # contains all your collected solutions
    print(cb.best_fun_vals)   # contains the corresponding objective function values
    cb.save_sols("dummy.txt") # writes all solutions to a file 'dummy.txt'
    

    However, in case you really want to write all solutions to a file for each new found solution, you can modify the callback such that it calls save_sol after each new solution:

    import numpy as np
    
    class CallbackFunctor:
        def __init__(self, obj_fun, filename):
            self.best_fun_vals = [np.inf]
            self.best_sols = []
            self.num_calls = 0
            self.obj_fun = obj_fun
            self.filename = filename
        
        def __call__(self, x):
            fun_val = self.obj_fun(x)
            self.num_calls += 1
            if fun_val < self.best_fun_vals[-1]:
                self.best_sols.append(x)
                self.best_fun_vals.append(fun_val)
                self.save_sols(self.filename)
       
        def save_sols(self, filename):
            sols = np.array([sol for sol in self.best_sols])
            np.savetxt(filename, sols)
    
    cb = CallbackFunctor(objective_fun, "dummy.txt")
    res = minimize(objective_fun, x0=x0, callback=cb)