SciPy 中的并行优化

Posted

技术标签:

【中文标题】SciPy 中的并行优化【英文标题】:Parallel optimizations in SciPy 【发布时间】:2012-10-04 04:41:03 【问题描述】:

我有一个简单的功能

def square(x, a=1):
    return [x**2 + a, 2*x]

我想在x 上最小化它,对于几个参数a。我目前有循环,在精神上,做这样的事情:

In [89]: from scipy import optimize

In [90]: res = optimize.minimize(square, 25, method='BFGS', jac=True)

In [91]: [res.x, res.fun]
Out[91]: [array([ 0.]), 1.0]

In [92]: l = lambda x: square(x, 2)

In [93]: res = optimize.minimize(l, 25, method='BFGS', jac=True)

In [94]: [res.x, res.fun]
Out[94]: [array([ 0.]), 2.0]

现在,函数已经向量化了

In [98]: square(array([2,3]))
Out[98]: [array([ 5, 10]), array([4, 6])]

In [99]: square(array([2,3]), array([2,3]))
Out[99]: [array([ 6, 12]), array([4, 6])]

这意味着并行运行所有优化而不是循环运行可能会快得多。使用 SciPy 可以轻松做到这一点吗?还是任何其他 3rd 方工具?

【问题讨论】:

我不明白您要优化什么:您的函数返回两个值。顺便说一句,第一个是抛物线,最小值为零,第二个没有最小值 查看docs,特别注意jac = True 的含义。该函数返回“成本”和梯度。 澄清一下:您是在为这个特定的简单功能或任何简单功能寻找解决方案吗? 为任何给定的函数寻找这个问题的解决方案。这个例子只是一个简单的说明。我真正的问题是尝试实现多类分类算法。我目前正在遍历每个班级并最小化每个班级一次的成本函数。但是我的成本函数可以轻松返回成本向量和梯度向量,但我正在尝试找出如何将其提供给 scipy.optimize。 【参考方案1】:

这是另一个尝试,基于 my original answer 和随后的讨论。

据我所知,scipy.optimize 模块适用于具有标量或矢量输入和标量输出或“成本”的函数。

由于您将每个方程式视为独立于其他方程式,因此我最好的想法是使用多处理模块并行完成工作。如果您要最小化的功能与您的问题中的功能一样简单,我会说这不值得。

如果功能更复杂,并且您想拆分工作,请尝试以下操作:

import numpy as np
from scipy import optimize
from multiprocessing import Pool

def square(x, a=1):
    return [np.sum(x**2 + a), 2*x]

def minimize(args):
    f,x,a = args
    res = optimize.minimize(f, x, method = 'BFGS', jac = True, args = [a])
    return res.x

# your a values
a = np.arange(1,11)

# initial guess for all the x values
x = np.empty(len(a))
x[:] = 25

args = [(square,a[i],x[i]) for i in range(10)]
p = Pool(4)
print p.map(minimize,args)

【讨论】:

【参考方案2】:

我参加聚会有点晚了。但这对于希望通过并行计算减少最小化时间的人来说可能很有趣:

我们在 PyPI 上的 optimparallel 包中实现了 scipy.optimize.minimize(method='L-BFGS-B') 的并行版本。它可以通过并行评估目标函数和(近似)梯度来加速优化。这是一个例子:

from optimparallel import minimize_parallel
def my_square(x, a=1):
    return (x - a)**2
minimize_parallel(fun=my_square, x0=1, args=11)

请注意,并行实现只会减少评估时间较长(例如,超过 0.1 秒)的目标函数的优化时间。以下是可能的并行缩放的说明:

【讨论】:

你在哪里指定处理器的数量? @andy 查看parallel 参数的描述。【参考方案3】:

如果我理解您的意图,您可以为 xa 传递 numpy 数组,这样您就可以一次优化所有 a 参数。

尝试类似:

def square(x, a=1):
    return [np.sum(x**2 + a), 2*x]

# your a values
a = np.arange(1,11)

# initial guess for all the x values
x = np.empty(len(a))
x[:] = 25

# extra arguments to pass to the objective function, in this case, your a values
args = [a]

res = optimize.minimize(square, x, method = 'BFGS', jac = True, args = args)

这似乎得到了正确的结果。

>>> res.x
[ -8.88178420e-16  -8.88178420e-16  -8.88178420e-16  -8.88178420e-16
  -8.88178420e-16  -8.88178420e-16  -8.88178420e-16  -8.88178420e-16
  -8.88178420e-16  -8.88178420e-16]
>>> res.fun
55.0

【讨论】:

我想这对我来说太直观了。将尝试解决我的真正问题,并让您知道它是如何进行的。谢谢! 你使用的是什么版本的 scipy?我实际上得到一个 ValueError 试图运行该代码:ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all() 对不起@ludaavics,我使用的是旧版本的 scipy (0.10) 和外推,我不应该这样做。我已经用 scipy 0.11 测试了上面的内容,它可以工作。不同之处在于“成本”值必须是标量。我使用的版本似乎通过将 square 返回的成本向量相加来隐式执行此操作。 好的,所以这种方法不适用于我的目的,是吗?我想我举的例子有点过于简单了——如果你将成本函数更改为(x+a)**2,那么不同的参数给出不同的最小值位置,对成本向量求和就变得毫无意义(我猜这就是为什么在 0.11 中它们强制你返回一个标量来说明) 好吧,也许我完全误解了你的意图。我是否正确,您试图找到标量值x,它在给定标量输入a 的情况下最小化square() 的输出,但每个方程都独立于其他方程?

以上是关于SciPy 中的并行优化的主要内容,如果未能解决你的问题,请参考以下文章

通过 Python 并行求解具有大量初始条件的 ODE

线程(c++ 中的并行计算)是不是与优化级别(gcc)不兼容?

并行编程双笙子佯谬 - 高性能并行编程与优化 - 视频教程目录

并行编程双笙子佯谬 - 高性能并行编程与优化 - 视频教程目录

.NET中并行开发优化

SQL Server 中的 SQL 查询优化