如何逐迭代调用scipy优化器并在目标函数中获取迭代次数
需求说明
需要根据优化过程的迭代次数动态调整优化目标:实际场景中存在复杂正则化项,需要依托当前迭代次数控制正则参数。核心技术疑问:
- 是否可以逐单次迭代调用scipy优化器
- 是否支持在目标函数内部访问当前迭代次数
原有实现及问题
原有尝试代码如下:
from scipy.optimize import fmin_slsqp from scipy.optimize import minimize as mini import numpy as np # 定义目标函数 # x为待优化输入 # iteration为迭代次数,意图通过迭代次数控制正则项权重 def objective(x, iteration): return (1 - x[0]) ** 2 + 100 * (x[1] - x[0] ** 2) ** 2 + 10 * np.sum(x ** 2) / iteration x = np.ones(2) * 5 for ii in range(20): x = fmin_slsqp(objective, x, iter=1, args=(ii,), iprint=0) if ii == 5: print('迭代到第5次时,预期结果接近[0, 0],实际得到', x) truex = mini(objective, np.ones(2) * 5, args=(200,)).x print('最终结果为', x, ',但正确结果应接近[1, 1],参考固定iteration=200时的优化结果', truex)
运行输出:
迭代到第5次时,预期结果接近[0, 0],实际得到 [5. 5.] 最终结果为 [5. 5.] ,但正确结果应接近[1, 1],参考固定iteration=200时的优化结果 [0.88613989 0.78485145]
问题原因与解决方案
原有循环调用写法不生效的核心原因:fmin_slsqp的iter参数是单次运行的最大迭代步数上限,不是强制固定只执行1步。每次重新调用优化器时,内部会重新做收敛校验:如果传入的初始点已经满足内部收敛判定条件,优化器会直接返回初始值,不会执行参数更新,因此x一直停在初始的[5,5]。
不需要循环逐次调用优化器,用可变计数器实现目标函数内访问迭代次数是最简单的方案,直接单次调用优化器即可:
- 用列表/字典这类可变对象存储迭代计数,整数是不可变对象,直接传整数不会在函数调用间保留修改
- 目标函数每次被调用时给计数器自增,就能拿到实时的迭代次数,动态调整正则项权重
修正后的实现代码:
from scipy.optimize import minimize import numpy as np # 用可变对象存迭代计数,初始值设为1避免除0 iter_counter = [1] def objective(x): # 取出当前迭代次数 current_iter = iter_counter[0] # 计算目标值后计数器自增 loss = (1 - x[0]) ** 2 + 100 * (x[1] - x[0] ** 2) ** 2 + 10 * np.sum(x ** 2) / current_iter iter_counter[0] += 1 return loss x0 = np.ones(2) * 5 # 单次调用优化器即可,不需要外层循环 res = minimize(objective, x0, method='SLSQP') print('优化结果', res.x)
如果需要严格控制每一步迭代的逻辑,也可以通过callback参数传入回调函数,回调函数会在每次迭代完成后被调用,能拿到当前迭代的x值和迭代计数,但直接在目标函数里用计数器的写法对动态调整正则项的场景更直接。
内容的提问来源于stack exchange,提问作者kilojoules
相关产品推荐
相关产品推荐

