11

我需要解决Java程序中的非线性最小化(N个未知数的最小残差平方)问题。解决这些问题的常用方法是Levenberg-Marquardt算法。我有几个问题数值求解非线性方程

  • 有没有人有不同的LM实现可用的经验? LM存在稍微不同的风味,我听说算法的确切实现对其数值稳定性有重大影响。我的功能非常好,所以这可能不会成为问题,但我当然想选择一个更好的替代方案。以下是我找到的一些替代方案:

  • 是否有任何常用启发式方法来做LM需要的初始猜测?

  • 在我的应用程序中,我需要对解决方案设置一些限制,但幸运的是它们很简单:我只是要求解决方案(为了成为物理解决方案)是非负的。稍微负面的解决方案是数据测量不准确的结果,显然应该为零。我正在考虑使用“常规”LM,但是迭代,以便如果某些未知变成负数,我将它设置为零,并从中解决其余部分。真正的数学家可能会嘲笑我,但你认为这可能有用吗?

感谢您的意见!这不是火箭科学,需要解决的参数数(N)最多为5,而且数据集勉强够大以至于不能解决问题,所以我相信Java非常高效,足以解决这个问题。这个。我相信这个问题已经被聪明的应用数学家解决了很多次,所以我只是寻找一些现成的解决方案,而不是自己做。例如。 Scipy.optimize.minpack.leastsq可能会很好,如果它是纯Python的话。

+0

你是否认为许多非线性算法只在正确初始化的情况下才起作用?初始化通常来自一个更简单的线性算法(通常优化次优度量)? – Vlad 2015-04-30 06:35:16

回答

0

我实际上没有使用过任何这些Java库,所以请带上一点盐:基于后端,我可能会看首先在JLAPACK。我相信LAPACK是Numpy的后端,它本质上是在Python中进行线性代数/数学操作的标准。至少,您绝对应该使用经过良好优化的C或Fortran库而不是纯Java,因为对于大型数据集,这些类型的任务可能会非常耗时。

对于创建初始猜测,它实际上取决于您尝试适合什么样的函数(以及您拥有哪种类型的数据)。基本上,只要寻找一些相对较快(可能是O(N)或更好)的计算,就可以给出所需参数的近似值。(我最近在Numpy中做了一个高斯分布,我估计的平均值只是average(values, weights = counts) - 也就是直方图中的计数的加权平均值,这是数据集的真实平均值,它不是确切的中心我期待的峰值,但它已经足够接近了,算法就走了。)

至于保持约束正面,你的方法似乎是合理的。既然你正在编写一个程序来完成这项工作,也许只需要制作一个布尔标志,让你轻松地启用或禁用“强制非负面”行为,并通过两种方式进行比较。只有当你得到很大的差异(或者如果算法的一个版本需要不合理的长时间),它可能是值得担心的。 (REAL数学家会从头开始分析最小二乘法的最小化; -P所以我认为你是那个可以嘲笑他们的人....也许吧)

2

你最初的猜测越接近解决方案,你会收敛得越快。

你说这是一个非线性问题。你可以做一个线性化的最小二乘解。也许你可以使用该解决方案作为第一个猜测。一些非线性迭代会告诉你一些假设的好坏。

另一个想法是尝试另一种优化算法。如果可以在许多CPU上运行它们,遗传和蚁群算法可能是一个不错的选择。他们也不需要连续的衍生工具,所以如果你有不连续的,不连续的数据,他们会很好。

2

如果问题有限制,则不应使用无约束求解器。对于 实例,如果知道您的某些变量必须是非负的,则应该将 告知解算器。

如果您乐于使用Scipy,我会推荐scipy.optimize.fmin_l_bfgs_b 您可以使用L-BFGS-B在变量上放置简单的界限。请注意,L-BFGS-B采用一般的非线性目标函数,而不仅仅是一个非线性最小二乘问题。

1

FPL软件包相当可靠,但由于其对Fortran代码的字面解释,有一些怪癖(数组访问从1开始)。如果你的功能表现良好,LM方法本身就相当可靠。强制非负约束的一个简单方法是直接使用参数的平方而不是参数。这可能会引入虚假解决方案,但对于简单的型号,这些解决方案很容易筛选出来。

有一种可用于“约束”LM方法的代码。在这里看看http://www.physics.wisc.edu/~craigm/idl/fitting.html为mpfit。有一个python(不幸的是依赖于Numeric)和一个C版本。 LM方法大约有1500行代码,因此您可能倾向于将C移植到Java。事实上,“约束”LM方法与您所设想的方法没有多大区别。在mpfit中,代码调整相对于变量边界的步长。我用mpfit也有很好的效果。

我对BFGS没有太多的经验,但代码更加复杂,我从来没有清楚过授权代码。

祝你好运。

2

我同意codehippo;我认为解决约束问题的最好方法是使用专门设计来处理它们的算法。在这种情况下,L-BFGS-B算法应该是一个很好的解决方案。

但是,如果使用python的scipy.optimize。在你的情况下fmin_l_bfgs_b模块不是一个可行的选择(因为你使用的是Java),你可以尝试使用我编写的库:用于L-BFGS-B算法原始Fortran代码的Java包装器。您可以从http://www.mini.pw.edu.pl/~mkobos/programs/lbfgsb_wrapper下载并查看它是否符合您的需求。