如何在scipy.optimize函数中强制使用更大的步长?

13

我有一个函数compare_images(k, a, b),用于比较两个2d-数组ab

在这个函数中,我对a应用了σ=k的高斯滤波器。我的想法是估计必须平滑图像a多少才能使其类似于图像b

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

我认为问题在于fmin(和minimize)倾向于从非常小的步骤开始,这在我的情况下将重复compare_images的完全相同的返回值,因此该方法认为它已经找到了最小值。它只会尝试几次。

是否有一种方法可以强制fmin或任何其他从scipy最小化函数采取更大的步骤?或者是否有任何更适合我的需要的方法?

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

当然,这非常缓慢,但现在我已经让它运行起来了。对于所有我的数据,它将需要大约20小时才能运行完成,但我不需要再次运行它。

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

  • 我有2张图片,AB,包含一些科学数据。
  • A 看起来像是一些具有变量值的点 (它是一个矩阵,其中每个值代表事件发生的位置和强度)
  • B 看起来像是一个平滑后的热图 (它是观察到的事件密度)
  • B 看起来就像是对 A 应用了高斯滤波器,并添加了一些半随机噪声。
  • 我们通过将常数为 sigma 的高斯滤波器应用于 A 来逼近 B。这个 sigma 是通过视觉选择得出的,但只适用于某些类型的图片。
  • 我试图为每张图片获取最优的 sigma,以便稍后可以找到每张图片中显示的事件类型与 sigma 的关系。

不管怎样,感谢您的帮助!


1
那么你是在寻找一个不同的最小值吗? - Aleksander Lidtke
2
也许不是最好的方法,但肯定是最简单的方法就是对变量或最小化值应用线性缩放。scipy优化函数中有相当多的硬编码值。调整“xtol”可能也有帮助。 - Daniel
我觉得你可能需要对图像a和图像b进行平滑处理,使它们变得相似,除非b已经被平滑处理过。如果是这种情况,那么(取决于您如何测量两个图像之间的相似性),仅对a应用任何平滑处理实际上会使它与b不相似而不是更相似。或者,您可以尝试在compare_images()中使用不同的相似度度量方法,以便即使k的变化小于0.5,它也返回不同的相似度值。如果您展示您的函数compare_images(),人们可能会有建议? - Simon
4个回答

4

快速检查:你可能真正想要的是fmin(compare_images, init_guess, (a,b))

如果gaussian_filter的行为如你所说,那么你的函数是分段常数函数,这意味着依赖导数(即大多数优化器)的优化器都不适用。你可以尝试使用全局优化器,如模拟退火或在合理范围内对k进行暴力搜索。

然而,按照你描述的问题,通常只有ba的平滑版本时才会存在明显的全局最小值
如果你想确定使两个图像最相似的a的平滑量,则你的方法是有道理的。

如果问题是“图像有多相似”,那么我认为像素比较(可能需要一些平滑处理)是正确的方法。根据我们所讨论的图像类型,可能需要先对图像进行对齐(例如比较照片)。请澄清一下 :-)。

编辑:另一个可能有帮助的想法:重写compare_images函数,使其计算平滑的a的两个版本 - 一个是floor(k)的sigma值,另一个是ceil(k)(即将k四舍五入到更低/更高的整数)。然后计算a_smooth = a_floor*(1-kfrac)+a_ceil*kfrac,其中kfrack的小数部分。这样比较函数就变成了关于k连续的。

祝好运!


你是对的,不是 k,而是 fmin 内部的 compare_images。我会尝试在原始帖子中澄清。 - user2329994

3

盆地跳跃可能做得更好,因为它在平台期卡住时继续的机会很高。

我发现在这个示例函数中,使用较低温度时效果还不错:

>>> 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

3

我知道这是一个老问题,但我没有找到太多类似主题的讨论。我遇到了scipy.optimize.least_squares类似的问题。我发现xtol并没有起到太大的作用。它似乎根本没有改变步长。真正有用的是diff_step。这个参数设置数字求解雅可比矩阵时所采用的步长,按照以下公式进行计算:step_size = x_i*diff_step,其中x_i是每个自变量。由于您使用fmin,所以不需要计算雅可比矩阵,但如果您在同一个问题中使用了另一个scipy函数,例如minimize,则可以尝试设置该参数。


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',只是为了以防万一添加了它们。
在示例中,我有两个变量,它们被初始化为1,并且具有边界[0,15],因为我正在近似beta分布的参数,但它也适用于您的情况。

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