【问题标题】:Halt optimization according to threshold on objective function in Scipy根据 Scipy 中目标函数的阈值停止优化
【发布时间】:2020-04-04 15:40:19
【问题描述】:

Scipy 的 differential_evolution(在许多其他优化例程中,例如 minimize)有可能声明一个 callback 函数以事先以某种方式停止优化。

在 StackOverflow 上,主要讨论了这个 callback,以便在时间限制后停止优化(参见例如 herehere)。

由于minimizedifferential_evolution 都处理最小化问题,我的问题是:如果到目前为止找到的最佳目标函数值低于用户,是否有人知道callback 是否可用于停止优化-定义阈值?

【问题讨论】:

    标签: python python-3.x optimization evolutionary-algorithm scipy-optimize


    【解决方案1】:

    鉴于这个问题缺乏答案和cmets,起初我认为这是不可能完成的。所以我在 Scipy 的 GitHub 页面上打开了一个enhancement issue,并询问是否要添加这个功能。

    其中一位贡献者结束了我的问题,他说,尽管以一种棘手的方式(而且在我看来不是很优雅),这是可以做到的,他给了我一些提示。

    这是我想出的解决方案,希望对您有所帮助

    from scipy.optimize import differential_evolution
    from scipy.optimize import rosen
    import numpy
    
    class MinimizeStopper(object):
        def __init__(self, f=rosen, tau=1):
            self.fun = f                     # set the objective function
            self.best_x = None
            self.best_func = numpy.inf
            self.tau = tau                   # set the user-desired threshold
    
        def __call__(self, xk, convergence=None,  *args, **kwds):
            fval = self.fun(xk, *args, **kwds)
            if fval < self.best_func:
                self.best_func = fval
                self.best_x = xk
            if self.best_func <= self.tau:
                print("Terminating optimization: objective function threshold triggered")
                print(self.best_x)
                return True
            else:
                return False
    
    
    bounds = [(0,2), (0, 2), (0, 2), (0, 2), (0, 2)]
    result = differential_evolution(rosen, bounds, callback=MinimizeStopper(), polish=False,disp=True, maxiter=100, popsize=100)
    print(result)
    

    返回

    differential_evolution step 1: f(x)= 10.7709
    differential_evolution step 2: f(x)= 10.7709
    differential_evolution step 3: f(x)= 8.02332
    differential_evolution step 4: f(x)= 2.16592
    differential_evolution step 5: f(x)= 2.16592
    differential_evolution step 6: f(x)= 2.16592
    differential_evolution step 7: f(x)= 0.812177
    Terminating optimization: objective function threshold triggered
    [1.01141374 0.95894166 0.91957732 0.87022813 0.70102066]
         fun: 0.8121773465012827
     message: 'callback function requested stop early by returning True'
        nfev: 4000
         nit: 7
     success: False
           x: array([1.01141374, 0.95894166, 0.91957732, 0.87022813, 0.70102066])
    

    几点说明:

    1. 解决方案不优雅,因为它需要对适应度函数进行额外评估以检查停止标准。不幸的是,由于scipy.optimize 模块的内部结构,没有解决方法
    2. 我已经在rosen 上测试过这种方法,如果目标函数不需要任何额外的参数,它通常可以工作,但如果目标函数需要额外的参数,那么我认为必须使用*args
    3. 当然,在第二个if 分支中打印self.best_x 不是强制性的。这只是我添加的一个调试检查,以查看 callback 找到的最佳解决方案是否实际上在 result 中返回(即,differential_evolution() 找到的整体最佳解决方案)

    【讨论】:

      【解决方案2】:

      您的解决方案运行良好,但缺点是每次都评估函数(在回调内部)。

      经过一番挖掘并基于https://github.com/scipy/scipy/issues/6878,我找到了避免这种情况的解决方案。它使用来自 Scipy 库的受保护成员,所以我不认为这是不可取的。

      from scipy.optimize._differentialevolution import DifferentialEvolutionSolver
      
      function_limit = -9   
      
      with DifferentialEvolutionSolver(func, args=(*args,), bounds=bounds, popsize=100) as solver:
          for step in solver:
              step = next(solver)  # Returns a tuple of xk and func evaluation
              func_value = step[1]  # Retrieves the func evaluation
              print(func_value)
              if solver.converged() or func_value == function_limit:
                  break
      
      x_result = solver.x
      

      func(*args) 将是要优化的函数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-10-21
        • 2022-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-02
        • 2016-08-13
        • 2016-07-24
        相关资源
        最近更新 更多