如何在scipy中终止优化?

How terminate the optimization in scipy?

我编写的代码具有更多的初始猜测值,因此需要很长时间才能完成优化。虽然几个小时后它几乎会收敛,所以我想在那个时候停止优化。

res = minimize(f, x0=x0, bounds=bounds,options={'tol': 1e-6,'maxiter':100})

我已经实现了 maxiter 但它不起作用,因为迭代次数已经超过并且优化没有停止。所以我想知道 maxiter 是如何使用的?我也看到了,作为另一种选择,callback 可以使用,但我不知道如何?所以请帮我解决这些问题。

scipy.optimize.minimize 中的优化可以使用 tolmaxiter 终止(maxfev 也适用于一些优化方法)。还有一些特定于方法的终止符,如 xtolftolgtol 等,如前所述在 scipy.optimize.minimize documentation page 上。还提到,如果您不提供方法,则根据问题使用 BFGS、L-BFGS-B 或 SLSQP。

关于你的第一个问题,你正在以正确的方式使用 maxiter 选项,但我不能说为什么它没有被强制执行,因为你没有提供MWE。但是,tol选项放在options括号中,这是错误的,应该在它之外,如:

res = minimize(f, x0=x0, bounds=bounds, tol=1e-6,options={'maxiter':100})

我的建议是在上述 scipy.optimize.minimize 文档页面上寻找针对您的问题的优化方法,并使用特定的容差选项。

关于你的第二个问题,如果你想在一段时间后终止优化,你可以这样做,这是受 solution proposed by SuperKogito的启发:

from time import time
import warnings
from scipy.optimize import minimize

class TookTooLong(Warning):
    pass

class optimizer():

    def __init__(self, maxtime_sec):
        self.nit = 0
        self.maxtime_sec = maxtime_sec

#    def fun(self, *args):
        # define your function to be minimized here

    def callback(self, x):
        # callback to terminate if maxtime_sec is exceeded
        self.nit += 1
        elapsed_time = time() - self.start_time
        if elapsed_time > self.maxtime_sec:
            warnings.warn("Terminating optimization: time limit reached",
                          TookTooLong)

        else:
            # you could print elapsed iterations and time
            print("Elapsed: %.3f sec" % elapsed_time)
            print("Elapsed iterations: ", self.nit)

    def optimize(self):
        self.start_time = time()
        # set your initial guess to 'x0'
        # set your bounds to 'bounds'
        opt = minimize(self.fun, x0=x0, bounds=bounds, 
                       callback=self.callback, tol=1e-6,options={'maxiter':100})
        return opt

# set maxtime_sec variable to desired stopping time
maxtime_sec = 100
op = optimizer(maxtime_sec)
res = op.optimize()
print(res)

您还可以使用 回调 在所需的迭代后停止优化。然而,这并不优雅。只需将上面代码中的callback函数改成如下:

class TookTooManyIters(Warning):
    pass

class optimizer():

    def __init__(self, maxtime_sec):
        self.nit = 0
        self.maxtime_sec = maxtime_sec

   # def fun(self, *args):
       # define your function to be minimized here

    def callback(self, x):
        # callback to terminate if desired_iteration is reached
        self.nit += 1
        desired_iteration = 10 # for example you want it to stop after 10 iterations
    
        if self.nit == desired_iteration:
            warnings.warn("Terminating optimization: iteration limit reached",
                          TookTooManyIters)

        else:
            # you could print elapsed iterations, current solution
            # and current function value
            print("Elapsed iterations: ", self.nit)
            print("Current solution: ", x)
            print("Current function value: ", self.fun(x))