在Scipy中寻求与optimize.fmin的收敛

7

我有一个函数想要用 scipy.optimize.fmin 进行最小化。请注意,在评估我的函数时,我会强制进行一次 print

我的问题是,当我开始最小化时,打印的值会下降到达某个点(值为 46700222.800),然后以非常小的步骤继续下降,例如 46700222.797、46700222.765、46700222.745、46700222.699、46700222.688、46700222.678。因此,直觉上,我已经达到了最小值,因为每个步骤的长度都小于1。但是算法继续运行,直到出现 "Maximum number of function evaluations has been exceeded" 错误。

我的问题是:当函数评估到达一个不再真正发展的值时(例如,我在迭代后没有获得超过1的增益),如何强制我的算法接受参数值?我读过选项 ftol 可以使用,但它对我的代码没有任何影响。事实上,我甚至不知道应该给 ftol 设置什么值。我尝试过 0.00001 到 10000 的所有值,仍然没有收敛。


正如Seth所说,请发布代码,否则除了向文档发送更多链接外我们无法做任何事情。 - Richard Green
1
жҲ‘еҸҜд»Ҙиҝҷж ·йҮҚж–°иЎЁиҝ°жҲ‘зҡ„й—®йўҳпјҡжңүдәәзҹҘйҒ“еҰӮдҪ•дҪҝз”Ёftolе’Ңxtolеҗ—пјҹеҪ“иҫҫеҲ°дёҖе®ҡзЁӢеәҰзҡ„йқһиҝӣеҢ–ж—¶пјҢжңүдәәзҹҘйҒ“еҰӮдҪ•ејәеҲ¶ж”¶ж•ӣеҗ—пјҹиҝҷе®Ңе…ЁзӢ¬з«ӢдәҺд»»дҪ•д»Јз ҒгҖӮ - sweeeeeet
2
我在使用Scipy时遇到了完全相同的问题。我感到非常沮丧,于是把所有东西都翻译成了Matlab,但是与Python相比,它的代码不太用户友好,而且它也遇到了同样的问题。也许优化器在某些情况下会忽略xtol和ftol。 - Titanic
1
@Titanic,优化器不会忽略xtolftol,但需要对它们施加约束以停止。请参见我的回答。 - gg349
4个回答

12
需要翻译的内容:

实际上不需要查看你的代码就能解释接下来发生的事情。我将逐一引用你的问题进行回答。

我的问题是,当我开始最小化时,打印出的值会减少,直到它达到了某个点(值为46700222.800)。在那里,它会缓慢地继续减少,例如46700222.797、46700222.765、46700222.745、46700222.699、46700222.688、46700222.678

请注意,最后2个值之间的差距为-0.009999997913837433,即约为1e-2。在最小化算法的约定中,你所说的值通常标记为x。如果这两个条件在第n次迭代中同时被满足,则算法会停止:

  • 关于x的收敛性:当前值x[n]与下一次迭代x[n+1]之间的差的绝对值小于xtol
  • 关于f(x)的收敛性:当前值f[n]与下一次迭代f[n+1]之间的差的绝对值小于ftol

此外,如果达到最大迭代次数,算法也会停止。

现在请注意,xtol默认值为1e-4,约比你的情况中出现的值1e-2100倍。因此,直到达到最大迭代次数,算法才会停止,因为第一个关于xtol的条件未被满足。

我读到过可以使用ftol选项,但它对我的代码没有任何影响。事实上,我甚至不知道应该为ftol设置什么值。我尝试了从0.00001到10000的所有值,仍然没有任何效果。

这有助于您满足关于ftol的第二个条件,但是第一个条件仍未达到。

要达到您的目标,请也增加xtol

以下方法在调试优化程序的收敛性方面会更有帮助。

  • 在您想要最小化的函数内部,在返回函数之前打印xf(x)的值。然后运行优化例程。从这些打印中,您可以决定xtolftol的合理值。
  • 考虑无量纲化问题。 ftolxtol都默认为1e-4是有原因的。它们期望您将问题阐述为xf(x)的数量级为O(1)O(10),即介于-100+100之间的数字。如果您进行无量纲化,您处理的是一个更简单的问题,通常您知道可以预期什么值以及需要哪些容差。
  • 如果您只对粗略计算感兴趣,无法估计xtolftol的典型值,并且您知道(或者希望)您的问题表现良好,即它会收敛,那么您可以在try块中运行fmin,仅传递maxiter = 20 (例如),并捕获关于已超过最大函数评估次数的错误。

1
谢谢您的帮助,现在我明白了必须同时满足xtol和ftol两个条件才能停止进程。请注意,这在文档中完全无法理解。感谢您最后的提示,当然我知道我可以捕捉错误,但我真的想彻底理解这个xtol/ftol的奥秘。我必须说,我觉得同时需要这两个条件在科学上非常奇怪。 - sweeeeeet
我同意文档可以写得更好,但并没有错误:它们谈论收敛中的可接受误差,对于x和ftol都是如此,表明两者的收敛都是必需的。至于为什么两者都被强制执行,算法策略默认尽可能保守,并将导致更少的假阳性,您需要通过设置较大的“xtol”或“ftol”来放松任何条件的约束。 - gg349

1

我刚刚花了三个小时研究scipy.minimize的源代码。在其中,函数"_minimize_neldermead"中的"while"循环处理了收敛规则:

if (numpy.max(numpy.ravel(numpy.abs(sim[1:] - sim[0]))) <= xtol and
               numpy.max(numpy.abs(fsim[0] - fsim[1:])) <= ftol):
    break"

"fsim"是存储功能评估结果的变量。然而,我发现fsim[0] = f(x0),这是初始值的函数评估,而且在“while”循环期间它永远不会改变。fsim[1:]一直在更新自己。while循环的第二个条件从未满足过。这可能是一个错误。但我的数学优化知识还远远不够去判断它。
我的当前解决方案:设计自己的系统来控制收敛性。在您的函数中添加以下内容:
global x_old, Q_old
if (np.absolute(x_old-x).sum() <= 1e-4) and (np.absolute(Q_old-Q).sum() <= 1e-4):
    return None
x_old = x; Q_old = Q

这里Q=f(x)。不要忘记给它们一个初始值。

更新01/30/15: 我明白了!这应该是if函数第二行的正确代码(即删除numpy.absolute):

numpy.max(fsim[0] - fsim[1:]) <= ftol)

顺便说一句,这是我第一次调试开源软件。我在GitHub上创建了一个问题

更新 01/31/15 - 1: 我不认为我的上一个更新是正确的。尽管如此,这是使用原始代码迭代函数的截图。 enter image description here

它打印了sim和fsim变量的每次迭代值。正如您所看到的,每次迭代的更改都小于xtol和ftol值,但它仍在继续而没有停止。原始代码比较fsim [0]与其余fsim值之间的差异,即该值始终为87.63228689-87.61312213 = .01916476,大于ftol = 1e-2。

更新 01/31/15 - 2:这是我用来重现以前结果的data and code,其中包括两个数据文件和一个iPython笔记本文件。

关于第一部分,请提供一个示例代码,其中fsim [0]不会随时间变化。在您提到的循环结束时,实际上更新了fsim,请参见行。关于更新,我不明白在这种情况下删除abs有什么意义。 - gg349
我稍后会更深入地研究它。但你可以自己尝试一下,它非常有效。 - Titanic
  1. 你为什么只有代码?原始帖子没有发布任何代码。
  2. blp() 函数的代码中为什么要递减全局变量 Delta?你不能在 blp() 函数内部更改全局变量。如果你真的想要,你可以在 blp() 函数内部读取全局变量。这就是为什么 fmin 函数行为怪异的原因。
- gg349
1
哇!@gg349,你让我今天过得很愉快!我花了很多时间试图找出问题的原因。这是全局变量的问题。回答你的问题,1. OP没有发布任何示例代码,而我正在经历与OP完全相同的问题,所以我发布了自己的代码,用于一个众所周知的经济模型。 - Titanic
在该模型中,对于每个 theta 值,需要找到适合模型的 Delta 值。为了加快速度,给定每个 theta 的初始 Delta 值设置为给定前一个 theta 的 Delta 值。我将其递减只是为了使 Delta_New 和 Delta 具有不同的初始值,以便 while 循环开始工作。我肯定需要更深入地了解全局变量的工作原理。 - Titanic
你不能那样做。你必须使Delta成为x的一部分。还要考虑使用fmin的args=()参数,放弃使用全局变量。 - gg349

0

文档来看,您确实想要更改ftol参数。

发布您的代码,以便我们查看您的进展。 编辑:也可以尝试增加xtol


正如我在帖子中所说,我尝试更改参数ftol,但没有帮助。实际上,它对收敛没有任何影响。我甚至不知道它是否是0到1之间的常数。 - sweeeeeet

0

你的问题有些含糊不清。你是要打印函数的值,还是在它被评估的点上打印?

我对 xtolftol 的理解如下。迭代停止:

  • 当连续两次迭代之间函数值的变化少于 ftol

  • 当连续两次迭代之间 x 值的变化少于 xtol

当你说“...接受参数的值...”时,这意味着你应该更改 xtol


抱歉有些含糊。每次函数被评估时,我都会打印其值。当函数的值变化小于某个特定值时,我希望算法接受参数。因此,我一定要使用ftol。事实是,这个ftol根本不起作用,因为当我将ftol从0.000001变化到1000000时,过程中完全没有任何区别。根据您的理解,如果我将ftol = 10000000,算法应该立即接受我的参数。但事实并非如此。 - sweeeeeet
1
@FuzzyDuck,这个答案是错误的。算法必须同时满足两个条件才能停止。 - gg349
感谢澄清。回答已经修正。 - FuzzyDuck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接