如何在 scipy.optimize 函数上强制执行更大的步骤?

Posted

技术标签:

【中文标题】如何在 scipy.optimize 函数上强制执行更大的步骤?【英文标题】:How to force larger steps on scipy.optimize functions? 【发布时间】:2013-12-27 01:17:28 【问题描述】:

我有一个函数 compare_images(k, a, b) 比较两个二维数组 ab

在函数内部,我将gaussian_filtersigma=k 应用于a 我的想法是估计我必须对图像a 进行多少平滑才能使其与图像b 相似

问题是我的函数 compare_images 只会在 k 变化超过 0.5 时返回不同的值,如果我这样做 fmin(compare_images, init_guess, (a, b) 它通常会卡在 init_guess 值上。

我相信问题是fmin(和minimize)往往从非常小的步骤开始,在我的情况下,这将重现与compare_images完全相同的返回值,因此该方法认为它已经找到了一个最低限度。它只会尝试几次。

有没有办法强制fminscipy 的任何其他最小化函数采取更大的步骤?或者有没有更适合我需要的方法?

编辑: 我找到了一个临时解决方案。 首先,按照建议,我使用xtol=0.5 及更高版本作为fmin 的参数。 即便如此,我仍然有一些问题,有几次fmin 会返回init_guess。 然后我创建了一个简单的循环,如果fmin == init_guess,我会生成另一个随机的init_guess,然后再试一次。

当然,它很慢,但现在我让它运行起来了。为我的所有数据运行它需要 20 小时左右,但我不需要再这样做了。

无论如何,为了更好地为那些仍然有兴趣寻找更好解决方案的人解释问题:

我有 2 张图片,AB,包含一些科学数据。 A 看起来像几个具有可变值的点(它是一个矩阵,其中每个值点代表事件发生的位置和强度) B 看起来像一个平滑的热图(它是观察到的出现密度) B 看起来就像您对 A 应用了高斯滤波器,带有一点半随机噪声。 我们通过应用具有常数sigmaA 的高斯滤波器来逼近B。这个sigma 是在视觉上选择的,但仅适用于特定类别的图像。 我正在尝试为每张图片获取一个最佳的sigma,所以后来我可以找到sigma 和每张图片中显示的事件类别的一些关系。

无论如何,谢谢你的帮助!

【问题讨论】:

那么您是否正在寻找不同的最小值? 也许不是最好的方法,但最简单的方法就是对变量或最小值应用线性缩放。 scipy 优化函数中有很多硬编码值。与xtol 一起玩也可能有所帮助。 在我看来,您可能必须同时平滑图像 a 和图像 b 以使它们相似,除非 b i> 已经平滑。如果是这种情况,可能是(取决于您如何测量两个图像之间的相似性)单独应用于 a 的任何平滑实际上会使它 less 类似于b 而不是更相似。或者,您可以尝试在compare_images() 中使用不同的相似度度量,以便即使k 中的变化小于0.5,它也会返回不同的相似度值。如果你显示你的函数compare_images(),人们可能会有建议吗? 【参考方案1】:

我遇到了同样的问题,并让它与“TNC”方法一起工作。

  res = minimize(f, [1] * 2, method = 'TNC', bounds=[(0,15)] * 2, jac = '2-point', options='disp': True, 'finite_diff_rel_step': 0.1, 'xtol': 0.1, 'accuracy': 0.1, 'eps': 0.1)

'finite_diff_rel_step' 和将 'jac' 设置为 '2-point', '3-point', 'cs' 之一的组合对雅可比计算步骤起到了作用,而 'accuracy' 做了步长的技巧。 'xtol' 和 'eps' 我认为不需要,我只是添加它们以防万一。

在示例中,我有 2 个变量初始化为 1,边界为 [0,15],因为我正在逼近 beta 分布的参数,但它也应该适用于您的情况。

【讨论】:

【参考方案2】:

我意识到这是一个老问题,但我找不到很多关于类似主题的讨论。我面临与scipy.optimize.least_squares 类似的问题。我发现xtol 对我没有多大好处。它似乎根本没有改变步长。有很大不同的是diff_step。这设置了根据公式step_size = x_i*diff_step 数值估计雅可比行列式时采用的步长,其中x_i 是每个自变量。您正在使用fmin,所以您没有计算雅可比行列式,但如果您使用另一个 scipy 函数(如 minimize)来解决相同的问题,这可能会对您有所帮助。

【讨论】:

【参考方案3】:

Basin hopping 可能会做得更好一点,因为当它卡在高原时它很有可能继续。

我在这个示例函数中发现它在低温下表现得相当好:

>>> opt.basinhopping(lambda (x,y): int(0.1*x**2 + 0.1*y**2), (5,-5), T=.1)
    nfev: 409
     fun: 0
       x: array([ 1.73267813, -2.54527514])
 message: ['requested number of basinhopping iterations completed successfully']
    njev: 102
     nit: 100

【讨论】:

【参考方案4】:

快速检查:您可能真的是指fmin(compare_images, init_guess, (a,b))

如果gaussian_filter 的行为如您所说,则您的函数是分段常量,这意味着依赖于导数(即大多数)的优化器已失效。您可以尝试像anneal 这样的全局优化器,或者在k 的合理范围内进行暴力搜索。

但是,正如您所描述的问题,如果ba 的平滑版本,通常只会有一个明确的全局最小值compare_images。如果您想确定使两个图像最相似的a 的平滑量,您的方法是有意义的。

如果问题是“图像有多相似”,那么我认为像素比较(可能需要一点平滑)是可行的方法。根据我们谈论的图像,可能需要先对齐图像(例如比较照片)。请澄清:-)

编辑:另一个可能有帮助的想法:重写 compare_images 以便计算平滑的两个版本-a - 一个使用 sigma=floor(k),一个使用 ceil(k)(即圆形k 到下一个更低/更高的 int)。然后计算a_smooth = a_floor*(1-kfrac)+a_ceil*kfrac,其中kfrack 的小数部分。这样比较函数就变得连续 w.r.t k

祝你好运!

【讨论】:

你说得对,不是k,而是compare_images里面的fmin。将尝试在原帖中澄清

以上是关于如何在 scipy.optimize 函数上强制执行更大的步骤?的主要内容,如果未能解决你的问题,请参考以下文章

当您想与目标函数一起计算梯度时,如何使用 scipy.optimize.minimize 函数?

如何在 scipy.optimize.minimize 上为 Powell 方法设置正确的方向向量?

scipy.optimize.leastsq 用 NaN 调用目标函数

使用 scipy.optimize.minimize 提前停止损失函数

避免在 scipy.optimize.minimize 中调用函数两次

如何将 2 个矩阵放入 scipy.optimize.minimize?