【问题标题】:Parallel many dimensional optimization并行多维优化
【发布时间】:2017-07-08 00:17:41
【问题描述】:

我正在构建一个脚本来生成输入数据 [参数] 供另一个程序计算。我想优化结果数据。以前我一直在使用 numpy powell 优化。伪代码看起来像这样。

def value(param):
     run_program(param)
     #Parse output
     return value

scipy.optimize.fmin_powell(value,param) 

这很好用;但是,它非常慢,因为程序的每次迭代都可能需要数天才能运行。我想做的是粗粒度并行化这个。因此,它不会一次运行一次迭代,而是一次运行(参数数量)*2。例如:

Initial guess: param=[1,2,3,4,5]

#Modify guess by plus minus another matrix that is changeable at each iteration
jump=[1,1,1,1,1]
#Modify each variable plus/minus jump.
for num,a in enumerate(param):
    new_param1=param[:]
    new_param1[num]=new_param1[num]+jump[num]
    run_program(new_param1)
    new_param2=param[:]
    new_param2[num]=new_param2[num]-jump[num]
    run_program(new_param2)

#Wait until all programs are complete -> Parse Output
Output=[[value,param],...]
#Create new guess
#Repeat

变量的数量可以从 3 到 12 不等,因此这样的事情可能会加速代码从一年缩短到一周。所有变量都相互依赖,我只是从最初的猜测中寻找局部最小值。我已经开始使用 hessian 矩阵实现;但是,这涉及很多。有没有什么可以做到这一点,有没有更简单的方法,或者有什么建议可以开始?

所以主要问题如下: 是否有一种算法可以进行初始猜测,生成多个猜测,然后使用这些多个猜测来创建新的猜测,然后重复直到找到阈值。只有解析导数可用。有什么好的方法可以解决这个问题,是否已经构建了可以做到这一点的东西,还有其他选择吗?

感谢您的宝贵时间。

作为一个小更新,我确实通过计算每个维度的三个点的简单抛物线,然后使用最小值作为下一个猜测来实现这一点。这似乎工作得很好,但不是最佳的。我仍在寻找其他选择。

目前最好的实现是并行化鲍威尔方法的内循环。

感谢大家的 cmets。不幸的是,对于这个特定问题,似乎没有一个简明的答案。如果我开始实施一些可以做到这一点的东西,我会把它贴在这里;但是,由于该项目不是特别重要或需要紧迫的结果,我可能会满足于让它占用一个节点一段时间。

【问题讨论】:

  • 这与您的问题没有直接关系;但是由于您的任务是资源密集型的,使用像 C 这样的编译语言来提高性能不是更有意义吗?
  • @Ophion 您可能希望先审查您的代码。还要考虑这些性能提示。 wiki.python.org/moin/PythonSpeed/PerformanceTips
  • 主要代码是 C 语言并经过高度优化,不幸的是,跨多个计算节点并行化它的实现并不是特别有效。我需要一些东西来与主要代码交互并优化一组它不是设计用来做的参数。重新编写主要代码以执行此操作是一种选择,但可能更复杂,最终收效甚微。
  • 那么你到底想要什么并行? run_program() 有什么作用?如果它没有弄乱任何变量,您可以轻松使用池及其映射函数 (docs.python.org/2/library/…)
  • run_program(param) 使用输入参数执行主代码并返回一个奇异值。基本上我想要做的是拥有鲍威尔算法的并行版本或其他一些最好不需要导数并且可以同时考虑多个猜测的最小化算法。

标签: python numpy mathematical-optimization


【解决方案1】:

我在大学时遇到了同样的问题,我们有一个 fortran 算法来根据一组变量计算引擎的效率。当时我们使用 modeFRONTIER,如果我没记错的话,没有一个算法能够产生多个猜测。

通常的方法是有一个 DOE,并在那里有一些算法来生成 DOE 以最适合您的问题。之后,我们将并行运行单个 DOE 条目,算法将“观察”优化的发展,显示当前的最佳设计。

附注:如果您没有集群并且需要更多计算能力,HTCondor 可能会帮助您。

【讨论】:

  • 您好,很高兴听到其他人遇到类似问题。感谢您向我介绍modeFRONTIER,它看起来是一个非常有趣的软件包。观察各种优化的东西可能很有趣 - 我会研究它。幸运的是,我的集群能够满足我的计算需求;然而,对于这个特定的项目来说,购买一个小型 linux 盒子并将其推到桌子下一年似乎是解决这个问题的最佳方式。
【解决方案2】:

您的目标函数的导数是否可用?如果是,您可以使用gradient descent(旧的、缓慢但可靠的)或conjugate gradient。如果不是,您可以使用有限差分来近似导数,并且仍然使用这些方法。我认为一般来说,如果对导数使用有限差分近似,则使用共轭梯度而不是牛顿法要好得多。

更现代的方法是SPSA,它是一种随机方法,不需要导数。对于某些表现良好的问题,SPSA 在相同的收敛速度下需要对目标函数的评估比对共轭梯度的有限差分逼近要少得多。

【讨论】:

  • 解析导数可用,但值得怀疑。共轭梯度方法非常适合这类工作。我当前的实现是 Powell 的,内部循环是并行化的。 SPSA 真的很棒,但不是我在这里寻找的。真正的主要问题归结为如何并行化最小化算法。
【解决方案3】:

估计梯度有两种方法,一种易于并行化,一种不可并行化:

  • 围绕单个点,例如(f( x + h 方向i ) - f(x)) / h; 这很容易并行到 Ndim
  • “行走”梯度:从 x0 沿方向 e0 走到 x1, 然后从 x1 在方向 e1 到 x2 ...; 这是顺序的。

使用梯度的最小化器高度发达,功能强大,二次收敛(在足够平滑的函数上)。 用户提供的梯度函数 当然可以是并行梯度估计器。
一些最小化器使用“行走”梯度,其中包括 Powell 方法, 见Numerical Recipes p。 509.
所以我很困惑:你如何并行化它的内部循环?

我建议使用 scipy fmin_tnc 使用并行梯度估计器,可能使用中心差异,而不是单边差异。
(哇, this 在两个 10-d 函数上比较一些 scipy 无导数优化器; ymmv。)

【讨论】:

  • 有趣的是,当我查看实现的函数列表时,我跳过了它,它在很大程度上取决于产生的渐变。我将使用抛物线解析导数来试一试。数字食谱是一本好书!对于鲍威尔方法,您可以使用其他可以并行化的方法找到维度的最小值。如果可能的话,仍在寻找已经为第一点实施的东西。
【解决方案4】:

我认为您想要做的是使用 python 内置的线程功能。 只要您的工作函数具有或多或少相同的运行时间,无论参数如何,它都会很有效。

在一个池中创建 8 个线程,运行 8 个函数实例,获得 8 个结果,运行优化算法以更改具有 8 个结果的参数,重复......利润?

【讨论】:

  • 问题在于优化算法。我将重写正文以使其清楚。主要问题是:是否已经建立了一个最小化算法,它接受多个输入并可以创建多个猜测来获得值?
  • 你不能创建一个异步进程,每次线程完成工作时运行优化函数以获得一个结果吗?因为无论参数如何,如果您的工作函数具有非常相似的计算时间,您想要实现的实现只会比这更好。
  • 功函数计算时间变化在几个百分点左右。异步过程会是一个更高级的步骤,我需要先获得一个更好的最小化算法。
【解决方案5】:

如果我没有弄错你的问题,那么你当时正试图最小化你的函数一个参数。

您可以通过创建一组具有单个参数的函数来获得它,其中对于每个函数,您冻结除一个之外的所有参数。

然后您继续循环优化每个变量并更新部分解决方案。

这种方法可以在能源格局不太复杂(参数之间的依赖性不太强)的情况下通过许多参数的大量函数来加速。

给定一个函数

energy(*args) -> value

您创建猜测和函数:

guess = [1,1,1,1]
funcs = [ lambda x,i=i: energy( guess[:i]+[x]+guess[i+1:] ) for i in range(len(guess)) ]

比你把它们放在一个while循环中进行优化

while convergence_condition:
    for func in funcs:
        optimize fot func
        update the guess
    check for convergence

这是一种简化最小化任务的非常简单而有效的方法。我真的不记得这个方法是怎么被调用的了,但是仔细看看 wikipedia entry on minimization 应该可以解决问题。

【讨论】:

  • 是的,如果所有变量不相互依赖,这将非常容易。
  • 该方法很有用,因为它甚至适用于因变量,它只需要不止一次迭代即可收敛。
  • 你说得对;但是,这并不是对我当前实现的改进。我将再次说明我真正在寻找的是一种并行化最小化算法的方法,而不是分段的。重申一个很好的例子。 Powell 的算法使用两个循环,如果你并行化内循环,你可以加速外循环,从而加速整个算法。
【解决方案6】:

您可以在两个部分进行并行:1)并行计算单次迭代或 2)并行开始 N 初始猜测。

在 2) 上,您需要一个作业控制器来控制 N 个初始猜测发现线程。

请在您的程序中添加额外的输出:“下限”,表示当前输入参数的输出值不会低于此下限。

最初的N个猜测线程可以相互竞争;如果任何一个线程的下限高于现有线程的当前值,则您的作业控制器可以删除该线程。

【讨论】:

    【解决方案7】:

    并行化局部优化器本质上是有限的:它们从单个初始点开始并尝试下坡工作,因此后面的点取决于先前评估的值。尽管如此,还是有一些途径可以添加适量的并行化。

    • 正如另一个答案指出的那样,如果您需要使用有限差分法评估您的导数,最好使用自适应步长,这可能需要多次函数评估,但每个变量的导数可能是独立的;您可能会获得两倍于问题维度数量的加速。如果您的处理器数量多于您不知道的用途,则可以使用需要更多(并行)评估的高阶准确梯度公式。
    • 一些算法,在某些阶段,使用有限差分来估计Hessian矩阵;这需要大约一半的矩阵维数平方,所有这些都可以并行完成。

    某些算法还可以以适度的算法成本使用更多的并行性。例如,准牛顿方法尝试构建 Hessian 矩阵的近似值,通常通过评估梯度来更新它。然后他们向最小值迈出一步,并评估一个新的梯度来更新 Hessian。如果您有足够多的处理器,因此评估 Hessian 的速度与评估一次函数的速度一样快,那么您可以通过在每一步都评估 Hessian 来改进这些。

    实现而言,恐怕你有点不走运。那里有许多聪明和/或经过良好测试的实现,但据我所知,它们都是单线程的。您最好的选择是使用需要梯度并并行计算您自己的算法。编写一个并行运行并为其数值导数选择合理步长的自适应算法并不难。

    【讨论】:

      猜你喜欢
      • 2014-05-30
      • 2023-03-25
      • 2019-05-31
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 2012-07-19
      • 2017-06-28
      相关资源
      最近更新 更多