我正在构建一个脚本,为另一个要计算的程序生成输入数据[参数]。我想优化结果数据。以前我一直在使用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,因此像这样的东西可能会加速代码从一年减少到一周。所有变量都相互依赖,我只是从初始猜测中寻找局部最小值。我已经开始使用粗体矩阵的实现;然而,这是非常复杂的。有没有什么可以做到这一点,是否有更简单的方法,或任何建议开始?
所以主要问题如下: 是否存在一种算法,该算法采用初始猜测,生成多个猜测,然后使用这些多个猜测来创建新猜测,并重复直到找到阈值。只有分析衍生物可用。有什么好办法解决这个问题,是否已经建立了这样的东西,还有其他选择吗?
感谢您的时间。
作为一个小小的更新,我确实通过计算每个维度的三个点的简单抛物线,然后使用最小值作为下一个猜测。这似乎工作得体,但不是最佳的。我还在寻找其他选择。
目前最好的实现是并行化powell方法的内循环。
谢谢大家的意见。不幸的是,似乎根本没有对这个特定问题的简明答案。如果我开始实现这样做的东西,我会把它贴在这里;然而,由于该项目并不是特别重要或者需要结果,我可能会满足于让它占用节点一段时间。
答案 0 :(得分:3)
我在大学期间遇到了同样的问题,我们有一个fortran算法来根据一组变量来计算引擎的效率。当我们使用modeFRONTIER时,如果我没记错的话,没有一种算法可以生成多个猜测。
通常的方法是使用DOE,并在那里生成DOE以最适合您的问题。之后,我们将并行运行单个DOE条目,并且算法将“观察”显示当前最佳设计的优化的开发。
附注:如果您没有群集并且需要更多计算能力,HTCondor可能会帮助您。
答案 1 :(得分:1)
目标功能的衍生物是否可用?如果是,您可以使用gradient descent(旧的,慢的但可靠的)或conjugate gradient。如果不是,您可以使用有限差分来近似导数,并仍然使用这些方法。我认为一般来说,如果对导数使用有限差分近似,那么使用共轭梯度而不是牛顿方法会更好。
更现代的方法是SPSA,这是一种随机方法,不需要衍生物。对于相同的收敛速度,SPSA对目标函数的评估要少于对共轭梯度的有限差分近似,对于一些表现良好的问题。
答案 2 :(得分:1)
有两种估算梯度的方法,一种可以轻松并行化,一种不是:
使用渐变的最小化器是高度发达的,强大的,以二次方式收敛(在足够平滑的函数上)。
用户提供的渐变功能
当然可以是平行梯度估计器
一些最小化器使用“行走”梯度,其中包括Powell的方法,
见Numerical Recipes p。 509.
所以我很困惑:你如何并行化它的内循环?
我建议scipy fmin_tnc 使用平行梯度估计器,可能使用中心,而不是片面的差异 (FWIW, this 比较两个10-d函数中的一些scipy无导数优化器;因人而异。)
答案 3 :(得分:0)
我认为你想要做的是使用内置python的线程功能。 如果你的工作函数或多或少相同的运行时间,无论params,它都会很有效。
在池中创建8个线程,运行8个函数实例,获得8个结果,运行优化算法以更改8个结果的参数,重复....获利?
答案 4 :(得分:0)
如果我没有弄错你的问题,那么你正试图在当时将一个参数最小化。
你可以通过创建一个单个参数的函数来获得它,其中每个函数都冻结除了一个参数之外的所有参数。
然后你继续循环优化每个变量并更新部分解决方案。
这种方法可以通过许多参数的大量功能来加速,其中能量景观不是太复杂(参数之间的依赖性不是太强)。
给出一个函数
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 convergence_condition:
for func in funcs:
optimize fot func
update the guess
check for convergence
这是一种简化但最有效的简化最小化任务的方法。我真的不记得如何调用这个方法,但仔细查看维基百科关于最小化的条目应该可以解决问题。
答案 5 :(得分:0)
你可以在两个部分做并行:1)并行计算单次迭代或2)并行启动N初始猜测。
On 2)你需要一个作业控制器来控制N个初始猜测发现线程。
请在程序中添加一个额外的输出:“下限”,表示当前输入参数的下限的输出值不会低于此下限。
最初的N猜测线程可以相互竞争;如果任何一个线程的下限高于现有线程的当前值,则该线程可以被作业控制器删除。
答案 6 :(得分:0)
并行化本地优化器本质上是有限的:它们从单个初始点开始并尝试下坡,因此后面的点取决于先前评估的值。然而,有一些途径可以添加适量的并行化。
某些算法也可以以适度的算法成本使用更多并行性。例如,准牛顿方法试图建立Hessian矩阵的近似值,通常通过评估梯度来更新它。然后他们向最小化迈出一步,并评估一个新的梯度来更新Hessian。如果你有足够的处理器来评估Hessian和评估函数一样快,你可以通过在每一步评估Hessian来改进它们。
就实施而言,我担心你有点不幸。有很多聪明的和/或经过良好测试的实现,但就我所知,它们都是单线程的。您最好的选择是使用需要渐变的算法并并行计算您自己的算法。编写一个并行运行的自适应算法并为其数值导数选择合理的步长并不难。