基于外部代码的Python约束优化:避免重复调用外部代码问题
解决Scipy优化中目标函数与约束函数重复调用外部代码的性能问题
核心思路是对相同输入x的计算结果y进行缓存,避免重复调用耗时的external_code。以下是两种可行的重构方案:
方案一:基于类的缓存实现
通过类的实例变量保存最近一次计算的x和y,让目标函数与约束函数共享缓存状态,结构清晰易维护:
import numpy as np from scipy.optimize import minimize, Bounds def external_code(x): # 替换为你的实际外部代码逻辑 y = np.zeros(6) y[0] = x[0]**2 + x[1]**2 + x[2]**2 y[1] = x[0] + x[1] y[2] = x[2] y[3] = x[0] y[4] = x[1] y[5] = x[2] return y class OptimizationWrapper: def __init__(self): self.last_x = None # 缓存最近一次的输入x self.last_y = None # 缓存对应x的输出y def _get_y(self, x): # 检查输入是否与缓存一致,仅在不一致时调用external_code if self.last_x is None or not np.allclose(x, self.last_x, atol=1e-8): self.last_x = x.copy() # 存副本避免原数组修改导致缓存失效 self.last_y = external_code(x) return self.last_y def objective(self, x): y = self._get_y(x) return y[0] def constraint(self, x): y = self._get_y(x) return np.array([ 5.0 - y[1], 1.0 - y[2], 1.0 - (y[3] + y[4] + y[5]) ]) # 初始化包装器并执行优化 wrapper = OptimizationWrapper() bounds = Bounds([0.0, -np.inf, 0.0], [10.0, 10.0, 2.0]) x0 = np.array([1.0, 0.0, 1.0]) res = minimize( wrapper.objective, x0, method='SLSQP', bounds=bounds, constraints={'fun': wrapper.constraint, 'type': 'ineq'} ) print(res)
方案二:闭包缓存实现
利用闭包特性共享缓存变量,无需定义类,代码更简洁:
import numpy as np from scipy.optimize import minimize, Bounds def external_code(x): # 替换为你的实际外部代码逻辑 y = np.zeros(6) y[0] = x[0]**2 + x[1]**2 + x[2]**2 y[1] = x[0] + x[1] y[2] = x[2] y[3] = x[0] y[4] = x[1] y[5] = x[2] return y def create_optimization_functions(): last_x = None last_y = None def objective(x): nonlocal last_x, last_y if last_x is None or not np.allclose(x, last_x, atol=1e-8): last_x = x.copy() last_y = external_code(x) return last_y[0] def constraint(x): nonlocal last_x, last_y if last_x is None or not np.allclose(x, last_x, atol=1e-8): last_x = x.copy() last_y = external_code(x) return np.array([ 5.0 - last_y[1], 1.0 - last_y[2], 1.0 - (last_y[3] + last_y[4] + last_y[5]) ]) return objective, constraint # 创建共享缓存的目标函数与约束函数 objective, constraint = create_optimization_functions() bounds = Bounds([0.0, -np.inf, 0.0], [10.0, 10.0, 2.0]) x0 = np.array([1.0, 0.0, 1.0]) res = minimize( objective, x0, method='SLSQP', bounds=bounds, constraints={'fun': constraint, 'type': 'ineq'} ) print(res)
关键注意事项
- 使用
np.allclose而非直接比较浮点数,避免因优化器传入的微小数值差异导致不必要的重复计算。 - 缓存的
x需保存副本(x.copy()),防止原数组被修改后缓存失效。 - 该方案仅适用于确定性的external_code(相同输入对应相同输出),若外部代码含随机逻辑则不适用。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

