【问题标题】:Scipy.optimize and callback not working when using workers使用工人时,Scipy.optimize 和回调不起作用
【发布时间】:2019-09-24 19:54:10
【问题描述】:

我正在使用 scipy.optimize (differential evolution) 进行优化。整体效果很好。我已经开始使用 worker 功能(它允许您告诉优化将群体中的个体分拆到其他进程中,从而非常容易地有效地并行化优化过程)。

我发现如果我指定workers=-1,我的所有核心都将投入工作,正如它们应该的那样。

模拟在一个结构中管理:

""" Sandbox stuff """
from scipy.optimize import *

class Simulation:
    def __init__(self):
        self.data = None

    def optim_manager(self):
        optimized_results = differential_evolution(self.optim_loop, 
        bounds=self.bounds, callback=self.optim_callback, workers=-1)

    def optim_loop(self, parameters):
        self.data = run_model(parameters)
        optim_value = self.calc_optim_value(self.data)

        # at this point self.data exist & is not None
        return optim_value


    def optim_callback(self,*args):
        # *args contains the parameters value for that optimal run
        optim_value = self.calc_optim_value(self.data)              # error
        write_optimisation_run_to_dictionnary(args, optim_value)

但是,当我尝试在回调中计算 optim_value 时,我得到:

Traceback (most recent call last):
  File "lancer_modele.py", line 512, in <module>
    mp.launch()
  File "lancer_modele.py", line 234, in launch
    self.do_optim_ghosts()
  File "lancer_modele.py", line 296, in do_optim_ghosts
    opt.opti_manager_ghosts(**merged_kwargs)
  File "/home/atari/PycharmProjects/RT/managers/optimisation.py", line 41, in opti_manager_ghosts
    simul_params = simul.fctopti_ghosts(nbrite=1, free_params_ordereddict=free_init_params[-1], **kwargs)   # it returns other stuff we don't need, a,b,c
  File "/home/atari/PycharmProjects/RT/managers/Simulation.py", line 225, in fctopti_ghosts
    popsize=5, callback=self.optim_callback, workers=2)
  File "/home/atari/.local/lib/python3.6/site-packages/scipy/optimize/_differentialevolution.py", line 272, in differential_evolution
    ret = solver.solve()
  File "/home/atari/.local/lib/python3.6/site-packages/scipy/optimize/_differentialevolution.py", line 701, in solve
    convergence=self.tol / convergence) is True):
  File "/home/atari/PycharmProjects/RT/managers/Simulation.py", line 433, in optim_callback
    optim_value = self.calc_ghost_optimized_value()
  File "/home/atari/PycharmProjects/RT/managers/Simulation.py", line 509, in calc_ghost_optimized_value
    optim_value = np.sum(cubedata[:,:,self.gstart_tick:self.gstop_tick])
TypeError: 'NoneType' object is not subscriptable

因为 self.data 在 optim_callback 的上下文中是 None 。但是,如果我只使用 1 个核心,这可以正常工作。我猜想当使用多个内核时,该类被序列化并传递,并且在每个运行的进程中更新属性。然后它返回到主进程,在该进程中,Simulation 仍然保持原样,因为调用了 worker 分拆(因此它仍然具有 self.data = None)。这意味着我不能轻易计算出最佳值,而且似乎虽然 scipy 的回调给了我所有的参数值,但它并没有传递我告诉它的值,这些值在我的模型中是值得的。

有什么想法吗?我想我可以在 optim_callback 中单独重新创建一个完整的模型,使用提供的参数对其进行更新,再次运行它以获得优化值。但是,运行模型的时间适中,我不想每次获得(中间)最优值时都减慢优化速度。

【问题讨论】:

    标签: python-3.x scipy multiprocessing


    【解决方案1】:

    实际上,DifferentialEvolution 似乎没有理由不返回优化值。因此,可以子类化

    from scipy.optimize._differentialevolution import DifferentialEvolutionSolver
    

    并且只需要在DifferentialEvolutionSolver.solve()的第697行编辑几行:

         if (self.callback and
                 self.callback(self._scale_parameters(self.population[0]),
                               convergence=self.tol / convergence) is True):
    

    变成:

        if (self.callback and
                self.callback(self._scale_parameters(self.population[0]),
                              convergence=self.tol / convergence, optim_value=self.population_energies[0]) is True):
    

    由于 self.population_energies 包含迄今为止的优化值,此时 [0] 是最佳值。

    因此在回调方法中:

    def optim_callback(self,*args, **kwargs):
        # *args contains the parameters value for that optimal run
        optim_value = kwargs['optim_value']
        write_optimisation_run_to_dictionnary(args, optim_value)
    

    将提供优化值,无需重新启动模型。

    【讨论】:

      猜你喜欢
      • 2021-09-11
      • 1970-01-01
      • 1970-01-01
      • 2016-08-23
      • 1970-01-01
      • 1970-01-01
      • 2016-12-20
      • 2017-11-27
      • 2013-10-13
      相关资源
      最近更新 更多