HeinzKurt
HeinzKurt

Reputation: 612

Stop scipy.optimize.minimize after maximum runtime

I run scipy.optimize.minimize(method='L-BFGS-B') on a cluster. Tasks running longer than 72 hours will be killed without any option of saving the result. Is there a way to exit scipy.optimize.minimize() after a runtime of T=48h has passed?

Upvotes: 2

Views: 1966

Answers (1)

Nairolf
Nairolf

Reputation: 2556

  1. One approach is to estimate the evaluation time of one iteration and then set maxiter in the options argument accordingly.

  2. Another approach is to define a class, which modifies a function fun such that it returns an error after a specified time and records the last input value x and its output fun(x):

    from scipy.optimize import minimize
    import numpy as np
    import time
    
    class TimedFun:
        def __init__(self, fun, stop_after=10):
            self.fun_in = fun
            self.started = False
            self.stop_after = stop_after
    
        def fun(self, x):
            if self.started is False:
                self.started = time.time()
            elif abs(time.time() - self.started) >= self.stop_after:
                raise ValueError("Time is over.")
            self.fun_value = self.fun_in(x)
            self.x = x
            return self.fun_value
    

    With that the optimization can be stopped after fun is called, say, later than 2 seconds after the first call:

    ## Objective function:
    def fun(x):
        time.sleep(5)
        return sum(x**2)
    
    ## Minimize with early stopping:
    fun_timed = TimedFun(fun=fun, stop_after=2)
    try:
        minimize(fun=fun_timed.fun, x0=np.array([100]), method='L-BFGS-B')
    except Exception as e:
        print("Error: " + str(e))
    # Error: Time is over.
    
    ## Retrieve last evaluated `x` and `fun(x)`:
    print('x=', fun_timed.x, ', fun(x)=', fun_timed.fun_value, sep='')
    # x=[100.], fun(x)=10000.0
    

BTW, checkout my package optimparallel, which allows you to speedup the optimization with parallel computing and to return the evaluated value x, fun(x), and jac(x) of every step.

from optimparallel import minimize_parallel
minimize_parallel(fun=fun, x0=np.array([100]), parallel={'loginfo': True})
#      fun: 2.565413976271745e-17
# hess_inv: array([[0.50000039]])
#      jac: array([-1.29983171e-10])
#  loginfo: {'x': array([[ 1.00000000e+02],
#       [ 9.90000000e+01],
#       [ 9.50000000e+01],
#       [ 7.90000000e+01],
#       [ 8.22875951e-05],
#       [-5.06499159e-09]]), 'fun': array([[1.00000000e+04],
#       [9.80100000e+03],
#       [9.02500000e+03],
#       [6.24100000e+03],
#       [6.77124832e-09],
#       [2.56541398e-17]]), 'jac': array([[ 1.99999886e+02],
#       [ 1.97999907e+02],
#       [ 1.89999810e+02],
#       [ 1.57999875e+02],
#       [ 1.64585190e-04],
#       [-1.29983171e-10]])}
#  message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
#     nfev: 6
#      nit: 3
#   status: 0
#  success: True
#        x: array([-5.06499159e-09])

Upvotes: 1

Related Questions