My question has already been partially answered here. I just need to extend the answer to another Scipy function. (Scipy 1.4.0, Python 3.7 on Windows 10)
Referring to the answer given by @ali_m, I tried to apply the same idea to the differential_evolution()
Scipy function which also has the callback
argument.
I would like to make sure that my Scipy differential_evolution()
function stops running after a certain time limit. In this case I chose the Rosenbrock function with 40 input parameters and a threshold of 0.3 seconds to highlight what happens.
import numpy as np
from scipy.optimize import differential_evolution, rosen
import time
import warnings
class TookTooLong(Warning):
pass
class MinimizeStopper(object):
def __init__(self, max_sec=0.3):
self.max_sec = max_sec
self.start = time.time()
def __call__(self, xk=None, convergence=None):
elapsed = time.time() - self.start
if elapsed > self.max_sec:
warnings.warn("Terminating optimization: time limit reached",
TookTooLong)
else:
print("Elapsed: %.3f sec" % elapsed)
n_var = 40
upper_bound_array = np.ones(n_var) * 5
lower_bound_array = np.ones(n_var) * -5
bounds = Bounds(lower_bound_array, upper_bound_array)
# function call
res = differential_evolution(Rosen, bounds, strategy='best1bin',disp=False,
callback=MinimizeStopper(),
maxiter=1000000)
As a result I get no errors, but it seems that the same logic used in Scipy minimize()
doesn't work here. To be more specific, when I run the program, even after the Warning is raised, the program silently continues to calculate all the necessary iterations until the optimization problem converges.
Does anyone know why in this case it doesn't work like in minimize()
case?
I would really appreciate your help.
Thanks in advance
The issue is that the callback
must return True
or False
as whether the optimisation must be halted or not (respectively).
In your case, MinimizeStopper
does not return anything and it basically just raises a warning. So you must hardcode True/False returns as well.
Try this one
class MinimizeStopper(object):
def __init__(self, max_sec=0.3):
self.max_sec = max_sec
self.start = time.time()
def __call__(self, xk=None, convergence=None):
elapsed = time.time() - self.start
if elapsed > self.max_sec:
print("Terminating optimization: time limit reached")
return True
else:
# you might want to report other stuff here
# print("Elapsed: %.3f sec" % elapsed)
return False
There are a couple of things that should be considered:
polish=False
as input to differential_evolution()
, the polishing operation is still carried out after halting the evolution: this adds additional timecallback
is triggered after finishing the evaluation of each generation: this can exceed the limit when an iteration takes substantial time.