scipy.optimize.minimize使用SLSQP等方法优化结果异常问题咨询
问题根本原因
你的优化异常完全是代价函数引入的随机噪声干扰了梯度估算导致的,具体逻辑如下:
- 你没有给
scipy.optimize.minimize传入自定义梯度函数,SLSQP、L-BFGS-B这类梯度优化算法会默认用有限差分法估算梯度:通过给参数加极小的扰动(默认步长eps=1e-8),计算扰动前后的代价差除以步长得到梯度。 - 你的代价函数加了
0.1*random()的随机项,参数扰动带来的真实代价变化量级远小于随机噪声的波动:以初始点x1=0.5为例,x1加1e-8扰动带来的真实代价变化只有1000*2*0.5*1e-8=1e-5,比0.1的随机波动小了4个数量级,最终估算出来的梯度完全是噪声,连符号都是错的。
两个疑问的具体解释
- 为什么最终优化结果是274.756左右,而非代价更低的0.2666?
优化器的迭代逻辑完全依赖梯度判断方向,梯度完全错误的情况下,它不会判断点的绝对代价高低,只会跟着错误的梯度走:你输出里的
jac值(估算的梯度)达到了十几万的量级,和真实梯度(初始点真实梯度为(1000,100))偏差超过100倍,线搜索逻辑完全失效,自然不会保留代价更低的(0,0)点。
- 为什么优化过程会朝着初始点X0收敛?
错误的梯度会让优化器误以为往初始点方向是下降方向,你看到的从(0,0)一步步退回0.5附近的过程,就是优化器沿着错误梯度迭代的结果。最后在初始点附近停止迭代,是因为错误梯度计算出来的搜索方向已经没有“下降空间”,优化器误判已经收敛,所以返回了初始点附近的结果。
修复方案
你可以任选一种方式解决问题:
- 去掉代价函数里的随机项,优化会正常收敛到(0,0)附近
- 保留随机项,自行编写代价函数的解析梯度,传入
minimize的jac参数 - 保留随机项和自动差分逻辑,调用
minimize时传入参数eps=1e-3,把有限差分步长调到比随机噪声大一个量级以上,梯度估算恢复正常后优化也会正常收敛。
内容的提问来源于stack exchange,提问作者Mathieu
相关产品推荐
相关产品推荐

