scipy.optimize.minimize Newton-CG二阶导为负时提前终止问题咨询
这是个很有意思的测试问题,刚好能暴露Newton-CG这类依赖二阶信息的优化器在初始点选在函数“平台区”且海森矩阵符号异常时的行为问题。咱们一步步来解决你的疑问:
为什么算法会停在x=100?
sigmoid函数在x=100处的梯度jac(100)已经小到接近机器精度(3.7e-44),而Newton-CG的默认收敛判断逻辑里,只要梯度的范数小于gtol的默认值(1e-5),就会认为已经收敛。但这里的关键问题是:x=100是局部极大值点(海森矩阵为负),但优化器因为梯度太小,直接触发了收敛条件,根本没去检查海森矩阵的符号是否符合极小值的要求。
如何避免警告信息?
警告的根源是优化器在尝试迭代时,因x=100处的函数值和梯度都趋近于极限,遇到了数值精度瓶颈。要消除警告,可以从调整收敛阈值和优化器行为入手:
- 调小
gtol参数,比如设为gtol=1e-10,避免因梯度接近机器精度就过早停止; - 开启调试输出
options={'disp': True},能直观看到迭代过程中的数值变化,方便定位问题。
如何强制算法找到hess(x)>0的点?
Newton-CG的核心是依赖海森矩阵计算下降方向,但如果初始点的海森矩阵是负定的,计算出的搜索方向反而会让函数值上升(对应sigmoid的x增大,函数值趋近于1)。要让优化器离开这个局部极大值区域,有几种可行方案:
1. 切换到更鲁棒的二阶优化方法:trust-ncg
信赖域类的方法(比如trust-ncg)会限制步长范围,并且会主动检查海森矩阵的正定性。如果发现海森负定,它会自动调整搜索方向(比如对海森做正则化,或临时切换到梯度下降步),非常适合这种初始点选在极大值区域的场景。
测试代码示例:
import numpy as np from scipy.optimize import minimize # 定义目标函数、梯度、海森 def f(x): return 1/(1+np.exp(-x)) def jac(x): return 1/(np.exp(-x/2)+np.exp(x/2))**2 def hess(x): return -(np.exp(x)*(np.exp(x)-1))/(np.exp(x)+1)**3 # 使用trust-ncg方法,调整收敛阈值并开启调试 result = minimize(f, 100, jac=jac, hess=hess, method='trust-ncg', options={'gtol': 1e-10, 'disp': True}) print(result)
这个方法会主动往x负方向搜索,直到进入海森矩阵正定的区域(x<0时,sigmoid的二阶导数为正,海森矩阵正定),最终函数值会趋近于0。
2. 给海森矩阵添加正则化(针对坚持用Newton-CG的场景)
如果你一定要用Newton-CG,可以给海森矩阵手动添加一个小的正定正则项,确保即使初始点海森负定,也能得到正定的矩阵用于计算下降方向。比如修改海森函数:
def hess_reg(x): hess_val = -(np.exp(x)*(np.exp(x)-1))/(np.exp(x)+1)**3 # 添加1e-3的正则项,保证矩阵正定 return hess_val + 1e-3
将这个正则化后的海森传入minimize,Newton-CG就能计算出往x减小方向的步长,从而离开x=100的极大值点。
3. 调整初始点(最直接的方案)
当然,如果不是故意测试极端情况,选择一个更合理的初始点(比如x=0),优化器就能直接进入海森正定的区域,不会出现停在极大值点的问题。
额外补充:sigmoid的极小值特性
需要注意的是,sigmoid函数没有有限的极小值点,它在x→-∞时趋近于0。所以无论用哪种方法,优化器最终都会往x负方向迭代,直到数值下溢(比如x小到一定程度,np.exp(-x)溢出,函数值变为0),此时梯度会小于设定的收敛阈值,优化器停止。
内容的提问来源于stack exchange,提问作者Bananach

