【问题标题】:Matlab: poor accuracy of optimizers/solversMatlab:优化器/求解器的准确性差
【发布时间】:2013-02-06 21:09:46
【问题描述】:

我在 Matlab 上的求根问题中难以达到足够的准确度。我有一个函数Lik(k),并想在Lik(k)=L0 处找到k 的值。基本上,问题在于各种内置的 Matlab 求解器(fzerofminbndfmincon)并没有像我希望或期望的那样接近解决方案。

Lik() 是一个用户定义的函数,它涉及大量编码以计算数值拉普拉斯逆变换等,因此我不包括完整的代码。但是,我已经广泛使用了此功能,并且它似乎可以正常工作。 Lik() 实际上有几个输入参数,但是对于当前步骤,除了k 之外,所有这些都是固定的。所以这实际上是一个一维求根问题。

我想找到k >= 165.95 的值,其中Lik(k)-L0 = 0Lik(165.95) 小于 L0 并且我希望 Lik(k) 从这里单调增加。事实上,我可以在感兴趣的范围内评估Lik(k)-L0,它似乎顺利过零:例如Lik(165.95)-L0 = -0.7465, ..., Lik(170.5)-L0 = -0.1594, Lik(171)-L0 = -0.0344, Lik(171.5)-L0 = 0.1015, ... Lik(173)-L0 = 0.5730, ..., Lik(200)-L0 = 19.80。所以看起来这个函数表现得很好。

但是,我尝试用几种不同的方法“自动”找到根,但准确度没有我预期的那么好......

使用fzero(@(k) Lik(k)-L0):如果限制在区间(165.95,173)fzero 将返回k=170.96Lik(k)-L0=-0.045。好吧,虽然不是很好。出于实际目的,如果没有大量的手动试验和错误,我不会知道如此精确的上限。如果我使用区间(165.95,200)fzero 返回k=167.19 其中Lik(k)-L0 = -0.65,这是相当差的。我一直在将 Display 设置为 iter 来运行这些测试,这样我就可以看到发生了什么,而且似乎 fzero 在第 4 次迭代中命中了 167.19,然后在第 5 次迭代时停留在那里,这意味着 k 从一次迭代到下一次迭代的变化小于 TolX(设置为 0.001),因此过程结束。退出标志表示它已成功收敛到一个解。

我还尝试使用fminbnd(给出k 的上限和下限)和fmincon(给出k 的起点)最小化abs(Lik(k)-L0),并遇到了类似的准确性问题。特别是,fmincon 可以同时设置TolXTolFun,但是玩弄这些(低至 10^-6,比我需要的精度高得多)并没有任何区别。令人困惑的是,有时优化器甚至会在较早的迭代中找到一个比它返回的最终 k 值更接近使目标函数为零的 k 值。

因此,算法似乎正在迭代到某个点,然后未能采取任何足够大小的进一步步骤来找到更好的解决方案。有谁知道为什么该算法不采取另一个更大的步骤?有什么我可以调整来改变的吗? (我查看了 optimset 下的列表,但没有提出任何有用的信息。)

非常感谢!

【问题讨论】:

  • 如果求解器不能解决问题,这可能表明您的函数在您尝试评估的点附近表现不佳。

标签: matlab mathematical-optimization solver equation-solving optimization


【解决方案1】:

由于您似乎有一个“野生”功能,该功能在该地区似乎是单调的,感兴趣的范围相当小,并且对精度的要求不是很高,我认为推荐该功能的所有标准都符合 蛮力方法。

假设在一个点上评估函数不需要太多时间,请试试这个:

找到上限xmax 和下限xmin,选择首选stepsize 并评估您的函数

xmin:stepsize:xmax 

如果需要(并且确实适用单调性),您可以通过这样做获得另一个上限和下限,并重复该过程以获得更高的准确性。

【讨论】:

  • 嗨丹尼斯,感谢您的回复!该功能的评估速度相当慢,但我认为你是对的,蛮力方法对于这个特定的评估是有意义的。一般来说,我希望能够多次进行类似的评估(这条线实际上是在一个循环内)并且以一种更加自动化的方式进行,以便该方法可以在没有太多用户反复试验的情况下进行推广。所以我仍然很乐意听到任何人关于更“自动”的方法的任何进一步建议!
  • @HelenAlex 假设单调性,您可以将范围分成 n 部分(比如 5 或 10)。然后找到最小值并将新范围设置为lowestValue+-oldrange/n。这可以很容易地在一个循环中完成,并且只需几个步骤即可为您提供相当好的近似值。
【解决方案2】:

我在使用 fmincon 时也遇到了这个问题。这是我修复它的方法。

我需要在优化循环(多变量)中找到函数(单变量)的解。正因为如此,我需要为单变量函数的解提供一个较大的区间。问题是如果搜索间隔太大,fmincon(或 fzero)不会收敛到一个解。为了解决这个问题,我在一个 while 循环中解决了这个问题,它有一个巨大的起始上限 (1e200),并限制了求解器产生的 fval 值。如果得到的 fval 不够小,我将上限减小一个因子。代码如下所示:

fval = 1;
factor = 1;
while fval>1e-7
    UB = factor*1e200;
    [x,fval,exitflag] = fminbnd(@(x)function(x,...),LB,UB,options);
    factor = factor * 0.001;
end

求解器在找到一个好的解决方案时退出。当然,您也可以通过引入另一个因子和/或增加因子步长来使用 LB。 我的第一语言不是英语,所以对于所犯的任何错误,我深表歉意。

干杯, 克里斯蒂安

【讨论】:

    【解决方案3】:

    为什么不使用简单的二分法呢?您总是评估某个区间的中间值,然后将其减少到右侧或左侧部分,这样您总是有一个边界给出负值,而另一个边界给出正值。您可以非常快速地降低到任意精度。由于您每次将间隔减半,它应该会很快收敛。

    我怀疑该函数还有其他一些问题,因为它有不连续性。 fzero 工作得如此糟糕似乎很奇怪。是确定性函数吧?

    【讨论】:

    • 您好安德烈亚斯,感谢您的回答。是的,我同意一个简单的二分法应该可行,我最终可能会实现这一点。然而,由于 fzero 在其他方法中使用二分法,我最初预计它至少会和我自己编写的任何代码一样好。我也很惊讶 fzero 工作得如此糟糕(是的,我的函数是确定性的)。我尝试在相关范围内的几个点进行评估(请参阅原始帖子)并且该函数看起来是连续的,但确实在我没有检查的点上可能存在问题。我想在二分法中也会出现任何问题?
    • 如果 fzero 已经使用二分法,那么重新实现它是没有意义的。我看到它可以返回error codes
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    相关资源
    最近更新 更多