我有一个计算机视觉算法,我想使用scipy.optimize.minimize来调整。我目前只想调整两个参数,但参数的数量可能会增加,所以我想使用一种能够进行高维梯度搜索的技术。SciPy中的Nelder-Mead实现似乎是一个不错的选择。
我已经设置好了代码,但看起来minimize函数非常希望使用小于1的浮点值作为步长。当前的参数集都是整数,一个参数的步长为1,另一个参数的步长为2(即该值必须是奇数,如果不是,我试图优化的对象会将其转换为奇数)。大致来说,一个参数是像素中的窗口大小,另一个参数是一个阈值(从0到255的值)。
值得一提的是,我使用的是从git仓库中新构建的scipy。有人知道如何告诉scipy为每个参数使用特定的步长吗?我是否可以自己编写梯度函数?有没有scipy的标志可以帮助我?我知道这可以通过简单的参数扫描来完成,但我最终希望将此代码应用于更大的一组参数。
代码本身非常简单:
import numpy as npfrom scipy.optimize import minimizefrom ScannerUtil import straightenImg import bsondef doSingleIteration(parameters): # 进行一些机器视觉魔法 # 返回我的值与真实值之间的差异parameters = np.array([11,10])res = minimize( doSingleIteration, parameters, method='Nelder-Mead',options={'xtol': 1e-2, 'disp': True,'ftol':1.0,}) #不确定这些参数是否有用print "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"print res
这是我的输出看起来的样子。正如你所见,我们重复了很多次运行,但在最小化方面没有取得任何进展。
*+++++++++++++++++++++++++++++++++++++++++[ 11. 10.] <-- scipy minimize的输出{'block_size': 11, 'degree': 10} <-- 输入到我的算法中并四舍五入为整数+++++++++++++++++++++++++++++++++++++++++120 <-- 我试图最小化的函数的输出+++++++++++++++++++++++++++++++++++++++++[ 11.55 10. ]{'block_size': 11, 'degree': 10}+++++++++++++++++++++++++++++++++++++++++120+++++++++++++++++++++++++++++++++++++++++[ 11. 10.5]{'block_size': 11, 'degree': 10}+++++++++++++++++++++++++++++++++++++++++120+++++++++++++++++++++++++++++++++++++++++[ 11.55 9.5 ]{'block_size': 11, 'degree': 9}+++++++++++++++++++++++++++++++++++++++++120+++++++++++++++++++++++++++++++++++++++++[ 11.1375 10.25 ]{'block_size': 11, 'degree': 10}+++++++++++++++++++++++++++++++++++++++++120+++++++++++++++++++++++++++++++++++++++++[ 11.275 10. ]{'block_size': 11, 'degree': 10}+++++++++++++++++++++++++++++++++++++++++120+++++++++++++++++++++++++++++++++++++++++[ 11. 10.25]{'block_size': 11, 'degree': 10}+++++++++++++++++++++++++++++++++++++++++120+++++++++++++++++++++++++++++++++++++++++[ 11.275 9.75 ]{'block_size': 11, 'degree': 9}+++++++++++++++++++++++++++++++++++++++++120+++++++++++++++++++++++++++++++++++++++++~~~SNIP ~~~+++++++++++++++++++++++++++++++++++++++++[ 11. 10.0078125]{'block_size': 11, 'degree': 10}+++++++++++++++++++++++++++++++++++++++++120Optimization terminated successfully. Current function value: 120.000000 Iterations: 7 Function evaluations: 27~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ status: 0 nfev: 27 success: True fun: 120.0 x: array([ 11., 10.]) message: 'Optimization terminated successfully.' nit: 7*
回答:
假设要最小化的函数是任意复杂的(非线性的),这通常是一个非常困难的问题。除非你尝试了所有可能的选项,否则无法保证得到最优解。我不知道是否有任何整数约束的非线性优化器(我对此有些怀疑),我假设你知道如果它是一个连续函数,Nelder-Mead应该可以很好地工作。
编辑:考虑到@Dougal的评论,我在这里补充一点:首先设置一个粗略加精细的网格搜索,如果你然后想尝试你的Nelder-Mead是否工作(并且收敛得更快),下面的几点可能会有所帮助…
但也许有些点可以帮助你:
- 考虑到整个整数约束非常困难,也许可以考虑做一些简单的插值来帮助优化器。它仍然应该收敛到一个整数解。当然,这需要计算额外的点,但它可能会解决许多其他问题。(据我所知,即使在线性整数规划中,通常也是先解决无约束系统)
- Nelder-Mead从N+1个点开始,这些点在scipy中是硬编码的(至少在旧版本中)为
(1+0.05) * x0[j]
(对于所有维度的j
,除非x0[j]
为0),你会在你的第一次评估步骤中看到这些。也许在新版本中可以提供这些,否则你可以简单地更改/复制scipy代码(它是纯Python的)并将其设置为更合理的值。或者如果你觉得这样更简单,可以将所有输入变量缩小,使得(1+0.05)*x0的大小合理。 - 也许你应该缓存所有函数评估,因为如果你使用Nelder-Mead,我猜你总是会遇到重复评估(至少在最后)。
- 你必须检查Nelder-Mead是否会仅仅收缩到一个值然后放弃,因为它总是找到相同的结果。
- 你通常必须检查你的函数在所有情况下是否表现良好…如果函数在参数空间上不平滑变化,这个优化注定会失败,即使如此,如果你有局部最小值,它也可能很容易陷入其中。(因为你缓存了所有评估 – 见2. – 你至少可以绘制这些并查看错误景观,而无需进行任何额外的评估)