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.
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)