我试图最小化一个成本函数,我从scipy.optimize.minimize (使用方法和'SLSQP',‘L B’)得到了非常奇怪的结果。
每次评估后,我会打印成本函数的值。首先,它在进入所谓的正确方向之前执行小扰动(ok)。但后来又发生了一些奇怪的事情:它似乎改变了最初的成本函数在第一次评估中的价值--成本函数在当前评估中的价值,并收敛到成本函数的第一次评估的值。
为了说明我创建了一个由2个参数组成的玩具函数(0.25 + 1000 * x1 ** 2+ 100 * x2 ** 2+ 0.1 *随机())。x1和x2仅限于间隔0,1。X0设置为(0.5,0.5)。我得到的是:
cost function: 275.3414617153509 x1: 0.5 x2: 0.5
cost function: 275.34428666473536 x1: 0.5000000149011612 x2: 0.5
cost function: 275.3542128554434 x1: 0.5 x2: 0.5000000149011612
cost function: 0.2665482586461191 x1: 0.0 x2: 0.0
cost function: 68.9989043756609 x1: 0.24986835289808013 x2: 0.24986835289808013
cost function: 154.87646326641064 x1: 0.374835397734792 x2: 0.374835397734792
cost function: 210.70119869030185 x1: 0.4373600232007103 x2: 0.4373600232007103
cost function: 241.8621094503892 x1: 0.4686490613793924 x2: 0.4686490613793924
cost function: 258.36597245010955 x1: 0.4843084999840323 x2: 0.4843084999840323
cost function: 266.6807722679986 x1: 0.4921461216177911 x2: 0.4921461216177911
cost function: 270.96794190195914 x1: 0.49606891372760337 x2: 0.49606891372760337
cost function: 273.0999396362265 x1: 0.49803236262951744 x2: 0.49803236262951744
cost function: 274.23903284113646 x1: 0.4990151079476797 x2: 0.4990151079476797
cost function: 274.7564047455383 x1: 0.4995070260788122 x2: 0.4995070260788122
fun: 274.7564047455383
jac: array([189579.1440506 , 855714.52631378])
message: 'Optimization terminated successfully'
nfev: 14
nit: 1
njev: 1
status: 0
success: True
x: array([0.49950703, 0.49950703])所以我不明白:
使我认为成本函数是“修正的”(也就是说,它试图最小化的不是成本函数,而是初始成本函数评估-当前的成本函数评估)是,有时,由于玩具函数的随机()部分,第一个猜测的评估值高于扰动评估,而且它也收敛到X0。
我使用的是Python3.9.6和ciply1.6.1
编辑:
以下是完整的代码:
def toto(X):
val = 0.25 + 1000 * X[0] ** 2 + 100 * X[1] ** 2 + 0.1 * random();
print("cost function:", val, 'x1:', X[0], 'x2:', X[1])
return val
optimization = minimize(toto, [0.5, 0.5], method=”SLSQP”, bounds= [[0.0, 1.0], [0.0, 1.0]])
print(optimization)马蒂厄
发布于 2021-09-09 19:35:32
尝试你的代码,我得到了基本相同的结果。
我不能说我对你的问题有一个完全的解决办法,但我可以指出一些问题。一个是scipy.optimize.minimize默认使用一个非常小的步骤来计算数值梯度(例如,对于B,默认的步长eps = 1e-8)。要了解为什么这是一个问题,请考虑是否从最优解(0,0)计算了一个数值导数。导数的确定性部分约为0,但随机部分是什么。它应该是两个随机值除以1e-8的差值。差额最有可能的数值是0.05 (基于有三角形分布的差分),所以你的导数大约是1e6。因此,虽然函数与随机噪声没有太大的不同,但它对数值导数有很大的影响。
但是如果梯度这么大,为什么要说它收敛了呢?您列出的两个方法都有一个ftol收敛标准,当步骤之间的函数值的相对变化低于阈值时,这将导致收敛。SLSQP没有在它的收敛消息中提供任何描述,但是least B至少给出了它为什么收敛的简短描述。对于远离(0,0)的情况,收敛性与ftol准则有关。我不认为代码中有任何东西特别地将它拉回到初始点;相反,它似乎只是随机的一步,并不会导致函数值发生很大的变化。如果我反复运行代码,它将收敛到许多不同的解决方案,而不是总是回到这个初始点附近。
您不能只使用基于数值梯度的优化器来完全修复这个问题,但是您至少可以通过更改eps的值来改进结果。我发现,如果我将eps改为1e-4,它就趋向于收敛到(0,0)或接近它。增加eps并不完全固定,因为梯度仍然可以被随机部分显着地改变。
在前面的文章中讨论了其他选项,包括在评估梯度或在范围内评估函数、用样条拟合函数之前去噪函数的方法,然后优化拟合函数。
如果您感兴趣的是诊断这个特定代码的问题,那么更了解can实现的技术细节的人可能会有所帮助。但是,如果您感兴趣的通常是寻找含噪函数的最小值,那么我认为这个例子清楚地表明,基于数值梯度的优化器是不够的。
https://stackoverflow.com/questions/69077658
复制相似问题