通过显式评估提高还原性能

时间:2020-02-13 22:22:49

标签: numexpr

我想使用numexpr计算2D数组作为3D数组单轴上的总和。 3D阵列足够大,无法存储在内存中。

最简单的方法是减少numexpr,但这很慢。

import numpy as np
import numexpr as ne

numx = 1e3
xaxis = np.arange(numx) * 10 / numx
dx = xaxis[:, None] - xaxis[None, :]

qrange = np.arange(0, 20)

# naive ne implimentations
qb = qrange[None, None, :]
dxb = dx[:, :, None]
tes = "sum(1j * exp(1j * qb * dxb), axis=2)"
Gf1 = ne.evaluate(tes)

可以通过在numexpr之外执行求和来提高性能。这遇到了存储中间3D阵列的问题。代替计算整个事情,有必要以小块迭代地进行计算。

# avoid sum in ne, but chunk calculation to be gentle on memory
nq = 10
nes = "1j * exp(1j * qx * dxb)"
num_chunks = int(np.ceil(qrange.size / nq))
ier = np.array_split(np.arange(qrange.size), num_chunks, axis=-1)

Gf2 = np.zeros(dx.shape, dtype=np.complex)
for ix in ier:
    qx = qb[:, :, ix]
    temp = ne.evaluate(nes)
    temp = np.sum(temp, axis=-1)
    Gf2 += temp

迭代方法可以提高性能,但是需要以numpy进行操作,而这不是numexpr的速度。通过动态生成评估字符串,可以将整个计算作为一个长而明确的表达式执行。

# generate sum as a long string
template = np.array("1j * exp( 1j * qx * dx )".split(" "))

delt_vars = {}
bes = ""
for i, _ in enumerate(qrange):
    delt_vars['qn'+str(i)] = q
    temp = template.copy()
    temp[temp == 'qx'] = 'qn' + str(i)
    bes += '+' + ''.join(temp.tolist())

Gf3 = ne.evaluate(bes, local_dict=delt_vars)

在此示例中,Gf3的显式表达式提供了最佳性能。但是,移动到更复杂的表达式会遇到numexpr的意外限制。较长的表达式( qrange = np.arange(0, 100))会引起两个错误之一:

ValueError: bytes must be in range(0, 256) 要么 ValueError: too many inputs

第二个错误似乎与numpy的限制有关,在下面讨论: Pytables NumExpr ValueError: too many inputs when querying with a lot of conditions

是否可以通过长而显式的评估字符串来提高numexpr的复杂约简的性能?如果不是,是否有更好的方法来执行这种计算,从而保持numexpr的性能?

0 个答案:

没有答案