逐元素向量化
Vectorizing an element-wise
是否可以使用 NumPy(和 SciPy)对元素优化进行矢量化(或加速)?
在最抽象的意义上,我有一个函数 y,它是抛物线形的,基本上可以表示为 y=x^2+b*x+z
,其中 x 是已知值的数组,我想找到一个 z使 y 的最小值恰好为零(换句话说,我想找到一个使我的抛物线只有一个零的值 z)。为此,我选择实现一个简单的类似二分法的方法。代码如下:
import numpy as np
def find_single_root():
x = np.arange(-5, 6,0.1) # domain
z = 1 # initial guess
delta = 1 # initial step size
tol = 0.001 # tolerance
while True:
y = x**2-5*x+z
minimum = np.nanmin(y)
# update z
print(delta)
print(z)
if minimum > 0:
if delta > 0:
delta = -1*delta/2
z += delta
else:
if delta < 0:
delta = -1*delta/2
z += delta
# check if step is smaller than tolerance
if np.abs(delta) < tol:
return z
现在假设 x(v,w),我想创建一个 z 值的二维数组,其中每个值都经过优化。我现在有的是下面(注意,新的函数定义和域如下)
def find_single_root(v, w):
x = np.arange(-5*v/w, 6*w,0.1) # domain
... # rest of the function
vs = np.arange(1,5)
ws = np.arange(1,5)
zs = np.zeros((len(vs),len(ws)))
for i, v in enumerate(vs):
for j, w in enumerate(ws):
zs[i][j] = find_single_root(v,w)
现在我只有这些简单的嵌套 for 循环,但是有什么方法可以让我以不同的方式处理这个问题或使用 NumPy 向量化来加速它吗?
当预先准确知道要执行的计算时,矢量化可能适用。喜欢"take two arrays of numbers, and multiply them pairwise"。
当计算适应给定数据时,向量化不适用。任何一种优化算法都是自适应的,因为你在哪里寻找最小值取决于函数returns。如果你有一堆函数,并且需要找到每个函数的最小值,你将不得不在循环中一次最小化它们。如果这个过程很慢,那是因为最小化一堆函数需要很长时间,而不是因为程序中有for
循环
关于您的程序,我会尝试使用一些 SciPy 方法进行最小化和 root-finding。有一个函数 min_of_f(z)
可以找到给定参数 z 值的最小值,可能使用 minimize_scalar
. Then feed min_of_f
to a root-finding routine。这些需要多长时间可以通过它们的公差参数(xtol 和其他)来控制。
OP编辑:
我想将此归功于正确答案,但仍提供更多信息。
我最终使用 numpy.vectorize
进行矢量化而没有重构问题。尽管 numpy.vectorize
并不是为了提高性能,但在我的特定用例中,性能只是快了两倍。对问题中的原始问题应用相同的方法导致 100x100 向量几乎没有加速,所以 YMMV。
尽管由于上述答案中给出的原因,我无法从速度方面对这个问题进行矢量化处理,但能够在我的代码中使用纯矢量语法而不是嵌套 for 循环还是很有用的。
是否可以使用 NumPy(和 SciPy)对元素优化进行矢量化(或加速)?
在最抽象的意义上,我有一个函数 y,它是抛物线形的,基本上可以表示为 y=x^2+b*x+z
,其中 x 是已知值的数组,我想找到一个 z使 y 的最小值恰好为零(换句话说,我想找到一个使我的抛物线只有一个零的值 z)。为此,我选择实现一个简单的类似二分法的方法。代码如下:
import numpy as np
def find_single_root():
x = np.arange(-5, 6,0.1) # domain
z = 1 # initial guess
delta = 1 # initial step size
tol = 0.001 # tolerance
while True:
y = x**2-5*x+z
minimum = np.nanmin(y)
# update z
print(delta)
print(z)
if minimum > 0:
if delta > 0:
delta = -1*delta/2
z += delta
else:
if delta < 0:
delta = -1*delta/2
z += delta
# check if step is smaller than tolerance
if np.abs(delta) < tol:
return z
现在假设 x(v,w),我想创建一个 z 值的二维数组,其中每个值都经过优化。我现在有的是下面(注意,新的函数定义和域如下)
def find_single_root(v, w):
x = np.arange(-5*v/w, 6*w,0.1) # domain
... # rest of the function
vs = np.arange(1,5)
ws = np.arange(1,5)
zs = np.zeros((len(vs),len(ws)))
for i, v in enumerate(vs):
for j, w in enumerate(ws):
zs[i][j] = find_single_root(v,w)
现在我只有这些简单的嵌套 for 循环,但是有什么方法可以让我以不同的方式处理这个问题或使用 NumPy 向量化来加速它吗?
当预先准确知道要执行的计算时,矢量化可能适用。喜欢"take two arrays of numbers, and multiply them pairwise"。
当计算适应给定数据时,向量化不适用。任何一种优化算法都是自适应的,因为你在哪里寻找最小值取决于函数returns。如果你有一堆函数,并且需要找到每个函数的最小值,你将不得不在循环中一次最小化它们。如果这个过程很慢,那是因为最小化一堆函数需要很长时间,而不是因为程序中有for
循环
关于您的程序,我会尝试使用一些 SciPy 方法进行最小化和 root-finding。有一个函数 min_of_f(z)
可以找到给定参数 z 值的最小值,可能使用 minimize_scalar
. Then feed min_of_f
to a root-finding routine。这些需要多长时间可以通过它们的公差参数(xtol 和其他)来控制。
OP编辑: 我想将此归功于正确答案,但仍提供更多信息。
我最终使用 numpy.vectorize
进行矢量化而没有重构问题。尽管 numpy.vectorize
并不是为了提高性能,但在我的特定用例中,性能只是快了两倍。对问题中的原始问题应用相同的方法导致 100x100 向量几乎没有加速,所以 YMMV。
尽管由于上述答案中给出的原因,我无法从速度方面对这个问题进行矢量化处理,但能够在我的代码中使用纯矢量语法而不是嵌套 for 循环还是很有用的。