如何在 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)
比较两个二维数组 a
和 b
在函数内部,我将gaussian_filter
和sigma=k
应用于a
我的想法是估计我必须对图像a
进行多少平滑才能使其与图像b
相似
问题是我的函数 compare_images
只会在 k
变化超过 0.5
时返回不同的值,如果我这样做 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 张图片,A
和 B
,包含一些科学数据。
A
看起来像几个具有可变值的点(它是一个矩阵,其中每个值点代表事件发生的位置和强度)
B
看起来像一个平滑的热图(它是观察到的出现密度)
B
看起来就像您对 A
应用了高斯滤波器,带有一点半随机噪声。
我们通过应用具有常数sigma
到A
的高斯滤波器来逼近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
的合理范围内进行暴力搜索。
但是,正如您所描述的问题,如果b
是a
的平滑版本,通常只会有一个明确的全局最小值compare_images
。如果您想确定使两个图像最相似的a
的平滑量,您的方法是有意义的。
如果问题是“图像有多相似”,那么我认为像素比较(可能需要一点平滑)是可行的方法。根据我们谈论的图像,可能需要先对齐图像(例如比较照片)。请澄清:-)
编辑:另一个可能有帮助的想法:重写 compare_images 以便计算平滑的两个版本-a
- 一个使用 sigma=floor(k)
,一个使用 ceil(k)
(即圆形k 到下一个更低/更高的 int)。然后计算a_smooth = a_floor*(1-kfrac)+a_ceil*kfrac
,其中kfrac
是k
的小数部分。这样比较函数就变得连续 w.r.t k
。
祝你好运!
【讨论】:
你说得对,不是k
,而是compare_images
里面的fmin
。将尝试在原帖中澄清以上是关于如何在 scipy.optimize 函数上强制执行更大的步骤?的主要内容,如果未能解决你的问题,请参考以下文章
当您想与目标函数一起计算梯度时,如何使用 scipy.optimize.minimize 函数?
如何在 scipy.optimize.minimize 上为 Powell 方法设置正确的方向向量?
scipy.optimize.leastsq 用 NaN 调用目标函数
使用 scipy.optimize.minimize 提前停止损失函数