多进程下使用differential_evolution无法更新类属性,如何获取最后迭代参数?
解决scipy differential_evolution多进程下类属性无法更新的问题
问题根源
启用workers=10多进程时,每个worker进程会复制一份你的Model类实例。子进程内对p1、p2的修改只会作用于当前子进程的副本,完全不会同步回主进程的实例,这就是你调用post()时pp为空的原因。
可行解决方案
方案1:利用callback回调函数(推荐)
differential_evolution的callback参数是在主进程中执行的(即使开启多进程),可以通过它捕获每次迭代的最优参数,直接更新主进程的Model实例属性。
示例代码:
from scipy.optimize import differential_evolution import numpy as np class Model: def __init__(self): self.p1 = None self.p2 = None self.pp = [] def objective(self, x): # 你的目标函数逻辑,示例为简单误差计算 return (x[0] - self.p1)**2 + (x[1] - self.p2)**2 if self.p1 is not None else x[0]**2 + x[1]**2 def post(self): print("pp:", self.pp) # 这里可以用最后一次的p1、p2做后续计算 # 定义回调函数,在主进程执行 def update_model_callback(x, convergence): # x是当前迭代的最优参数数组 model.p1 = x[0] model.p2 = x[1] model.pp.append((x[0], x[1])) # 返回False表示继续优化,返回True会终止优化 return False if __name__ == "__main__": model = Model() # 定义参数边界 bounds = [(-5, 5), (-5, 5)] # 启动优化,指定callback result = differential_evolution(model.objective, bounds, workers=10, callback=update_model_callback) # 优化结束后调用post model.post() # 最后一次迭代的p1、p2也可以直接从result.x获取 print("最后一次迭代参数:", result.x[0], result.x[1])
方案2:使用多进程共享变量
如果需要在子进程中也能同步访问参数,可以用multiprocessing.Manager创建共享字典,让所有进程共享同一份参数存储:
from scipy.optimize import differential_evolution import numpy as np from multiprocessing import Manager class Model: def __init__(self, shared_params): self.shared_params = shared_params self.pp = [] def objective(self, x): # 从共享字典读取参数 p1 = self.shared_params.get('p1', 0) p2 = self.shared_params.get('p2', 0) # 计算目标值 res = (x[0] - p1)**2 + (x[1] - p2)**2 # 更新共享字典 self.shared_params['p1'] = x[0] self.shared_params['p2'] = x[1] return res def post(self): # 从共享字典获取最终参数 final_p1 = self.shared_params['p1'] final_p2 = self.shared_params['p2'] self.pp.append((final_p1, final_p2)) print("pp:", self.pp) if __name__ == "__main__": with Manager() as manager: shared_params = manager.dict() model = Model(shared_params) bounds = [(-5, 5), (-5, 5)] result = differential_evolution(model.objective, bounds, workers=10) model.post()
关键注意点
- 不要在目标函数里直接修改
Model的实例属性,因为目标函数运行在子进程,修改的是副本,主进程无法感知。 - 优先选择
callback方案,它更贴合differential_evolution的设计,不需要额外处理多进程共享的复杂问题,且能直接拿到每次迭代的最优解,完美匹配你“每次迭代后更新属性”的需求。
内容的提问来源于stack exchange,提问作者jasmine
相关产品推荐
相关产品推荐

