基于scipy.minimize的优化方法选择、收敛与波动问题技术咨询
问题解答
1. 优化算法选择
你当前场景的核心特征决定了不能用默认的梯度类优化算法,选择时优先判断三个特征:是否能获取目标函数的梯度、优化维度高低、是否需要全局搜索能力。
你的目标函数是物理测量得到的黑箱函数,无法提供解析梯度,且存在噪声和步长限制,默认的L-BFGS-B等梯度类算法会通过有限差分估算梯度,受噪声和步长限制影响估算结果完全失准,这也是你看到三个电机输出完全相同指令的原因。
适合你场景的scipy内置算法有三类,可按需求选择:
- 优先选Nelder-Mead:无梯度单纯形法,对噪声有天然鲁棒性,适配3维低维场景,调用次数少,适合你单步调用成本高的情况,调用时指定
method="Nelder-Mead"即可。 - 次选Powell:无梯度方向集搜索法,不需要估算梯度,对连续型黑箱函数适配性好,也适合你的场景。
- 如果需要避免局部最优,可选择差分进化(differential_evolution):属于全局优化算法,不需要初始点先验,能遍历参数空间找全局最优,缺点是调用次数比前两种多,你的1000次迭代上限对3维场景完全够用。
2. 场景问题处理
(a)电机最小步长限制处理
有两种成熟的处理方案:
- 方案1:在目标函数中增加参数预处理逻辑,优化器输出的参数先做对齐处理再传给电机,示例代码如下:
def s21_mag_wrapper(x): # 将参数对齐到100的整数倍 x_aligned = np.round(x / 100) * 100 # 限制参数在边界内 x_aligned = np.clip(x_aligned, 0, 45000) # 调用原目标函数 return s21_mag(x_aligned)
优化时传入这个包装后的函数即可,不管优化器输出多小的参数变化,实际电机都只会执行100整数倍的有效调整。
- 方案2:如果使用Nelder-Mead算法,可通过
initial_simplex参数设置初始搜索步长不小于100,同时设置xatol=50,当参数调整幅度小于50时就判定收敛,避免无效迭代。
(b)测量噪声处理
可通过三种方法组合解决:
- 每次调用目标函数时,连续测量3~5次,去掉最高最低值后取平均值作为返回结果,可过滤掉大部分小幅随机噪声,单步增加的测量成本很低。
- 调整优化器的收敛阈值,比如使用Nelder-Mead时设置
fatol=0.02,只要两次迭代的函数值变化小于0.02dB(大于你的噪声波动范围)就不认为是有效优化,避免被噪声误导。 - 全程不要使用对噪声敏感的梯度类优化算法,坚持用无梯度的鲁棒性算法。
内容的提问来源于stack exchange,提问作者Coto TheArcher
相关产品推荐
相关产品推荐

