功能逼近

6

我有一个函数,

P(x0, x1, ..., xn)

它需要100个整数作为输入,并输出一个整数。P的计算速度很慢(可能需要30秒到几分钟不等)。

我需要知道哪些点的值可以使P的输出最大化。

有什么技术可以实现这一点吗?我知道一般人使用遗传算法来解决这个问题,但是我担心即使使用小规模的种群和少量的代数(比如,种群=50,代数=50),由于P计算速度太慢,需要超过40小时才能计算完毕。

是否有更便宜的方法?也许是迭代过程?我不需要得到真正的最优解,但是我不知道它的行为方式(我尝试了线性/二次/指数,但似乎没有得到好的结果。我知道P可以返回至少比我得到的值高5-10倍)。

应该有一些更容易实现的方法(即,我必须自己实现它)。

谢谢!

编辑:P是一个随机过程。


你的意思是 P(x0,x1,...,x99) 吗? - Pascal Cuoq
典型的输入向量是什么样子的?一些输入是否经常取相同的值(可能使部分评估成为可能)? - Pascal Cuoq
我不知道。据我所知,它是一个黑盒子。 - devoured elysium
2
如果它是一个黑盒子,除了通常的一般算法如GA或模拟退火之外,你没有太多可以做的。你所说的随机是什么意思?如果你的意思是从相同的输入中获得不同的输出,我认为这些方法不会起作用。你需要了解问题的一些信息才能提出有效的解决方案。 - David Thornley
2
我知道这不是你要问的,但我会尝试加速P()。任何优化算法都需要对P()进行1000次或更多次的评估。 - Paul
10个回答

4

模拟退火算法,与马尔科夫蒙特卡罗方法 (MCMC)密切相关。你可能需要的变体是Metropolis-Hastings。一旦掌握了它,就会感觉很好。可能有一些优化方法,因为输入和结果都是整数。它需要计算量,可能需要一些调整,但它非常稳健,我不确定其他方法能否做得更好。

这是一些简单的代码:

const int n = 100; // length of vector to optimize
int a[n]; // the vector to optimize
double P(a){..} // Get the probability of vector a.
                // This is the function to optimize.
// for a large number of a samples
for (i = 0; i < large_number; i++){
  // get P(a)
  double p = P(a);
  // for each element of vector a
  for (j = 0; j < n; j++){
    // get an amount by which to change it. This choice has to be symmetric.
    // this is called the Proposal Distribution
    int step = uniform_random_choice_from(-2, -1, 1, 2);
    // make the change to a[j], and get p1, the new value of p
    a[j] += step;
    double p1 = P(a);
    bool bKeepTheStep = true;
    // if p1 is better than p, keep the step
    // if p1 is worse than p, then keep the step p1/p of the time
    if (p1 < p){
      bKeepTheStep = (unif(0,1) < p1/p);
    }
    if (bKeepTheStep) p = p1;
    else a[j] -= step;
  }
  // now a is a sample, and p is its value
  // record a and p
}
// what you have now is a large random sampling of vectors from distribution P
// now you can choose the best one, the average, the variance,
// any statistic you like

调整的方法是扩大或缩小提议分布,这样可以更大或更小地迈出步伐,或者您可以让它最初迈出更大的步伐,然后再迈出较小的步伐。您要寻找的是保持步数的百分比既不太高也不太低。
您可能希望有一个“燃烧期”,即最初约1k个样本被丢弃,而它正在寻找模式区域。
请务必对P进行性能分析。它需要尽可能快。以下是我最喜欢的方法。

2
也许您的算法中有很大一部分是可以并行化的?如果是这样,您考虑过并行化您的代码吗?

我不想走那条路。我从未对任何东西进行过并行处理,而且我没有那么多时间去学习。 - devoured elysium
1
你说你没有太多时间去学习,但你正在谈论优化技术。如果你有一堆可用的处理器,你可以用所有处理器进行暴力计算这个函数,可能只需要一小时的学习和开发时间。这几乎与一个常见的MPI示例完全相同,通过投掷飞镖计算PI。 - Phil Miller

2

2

有很多著名的全局优化算法(如模拟退火、随机隧道等),它们可以找到全局最大值,但是没有一个算法能够保证在不做出对函数形状的假设的情况下,在合理的时间内找到全局最大值。

如果你想要优化一个100维的非平凡函数,你不会找到一种快速/简单的方法。你需要大量的处理能力和时间。假设你不想自己编写优化代码(根据你的问题),你还需要一些好的数学软件(例如Mathematica)。


2
另一个不太正式的答案,但值得思考:
这个问题似乎非常庞大,按理说你应该需要像SETI@Home一样的努力才能解决它。成千上万台计算机可以相对轻松地完成这种事情。但我不确定如何联系成千上万的计算机用户来使用他们的计算机。
实际上,我知道怎么做。请暂时忽略一切合法性问题。
有些人在前铁幕背后运行着僵尸网络。我最近看到一个出租僵尸网络的报价是70美元/24小时。想象一下,成千上万的被控制的电脑随时准备为你效力!你可以让它们处理你的问题,而不是用它们攻击互联网站点。:)
不过,在这方面还有两个最后的建议:
  • 不要用自己的信用卡支付 :)
  • 不要从SO上接受陌生人的法律建议 :)
祝好运!

1

对于这种类型的问题,作为第一行算法,我建议使用模拟退火。 SA是一个很好的首选,因为您可以清楚地控制起始点和运行时间。

如果您了解100维空间的结构,使用SA,您可以选择一个良好的起始点,这可能会对结果的质量产生重大影响。此外,使用SA,您可以控制“冷却速率”,它影响运行时间和结果的质量 - 自然相反。我通常先以相对较快的冷却速率运行,以寻找良好的起始向量,然后在随后的运行中减慢冷却速率以改善结果。这是一种可以自动化的元-SA技术。

过去,我成功地使用SA来最大化用于建模中子质子相互作用的非常高维函数。

此外,如果可能的话,我会尝试降低P()的维数。对于您的特定问题,是否需要所有100个变量?如果您可以固定其中的一半,您将加快任何优化器的速度并获得更好的结果。

(而且SA易于实现。)


1

假设:

首先 - 变量必须为整数。
其次 - 目标函数P()是非线性的。

观察:

一般来说,非线性整数规划问题很难解决。实际上,如上所建议,通过放宽整数限制来四舍五入解决方案可能会有所帮助。

有一些通用的无约束优化技术可供选择。其中一种方法来自实验设计,称为“响应面方法”。当实验成本显著时非常有帮助。该方法是通过从一个点开始并将每个输入偏离一组增量来运行一组实验。然后,您计算每个输入的梯度,并沿着该方向迈出一步,然后重复。Fletcher-《实用优化方法》和Box Hunter & Hunter-《实验者统计学》是需要查看的地方。


0

需要疯狂的数据才能真正收敛吗? - devoured elysium
我确实知道泰勒级数。但它们如何帮助我呢? - devoured elysium
完全取决于问题。如果您不介意进行迭代训练,那么可以从过度拟合的网络开始,并进行迭代训练。如果您足够了解问题,也可以手写网络或系列。 - Hassan Syed
他不知道如何解析地使用P()。他该如何使用泰勒级数?这对我来说没有意义。 - Paul
他知道P,但是只有通过不切实际的手段才能得到函数。他想让这个问题变得可行。 - Hassan Syed

0
如果您有Matlab访问权限,可以很快、很容易地并行化您的代码。甚至可以使用其parfor循环使简单的线性for循环并行化。

0
如果Microsoft的解决方案是一个选项,可以看看Solver Foundation。我在Scott Hanselman的播客(#191)上听说过它。

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