我正在实现一个具有特定结构的顺序算法(卡尔曼滤波器),其中许多内部循环可以并行完成。我需要尽可能多地从这个功能中获得性能。目前,它在我的机器上运行大约600ms,具有代表性数据输入(n,p = 12,d = 3,T = 3000)
我使用@numba.jit
和nopython=True, parallel=True
并用numba.prange
注释我的范围。然而,即使有非常大的数据输入(n> 5000),显然也没有发生并行性(基于仅使用top
查看核心)。
这里有相当多的代码,我只显示主要的块。有没有理由Numba无法在prange
下并行化阵列操作?我还检查了numba.config.NUMBA_NUM_THREADS
(它是8)并且使用不同的numba.config.THREADING_LAYER
(目前是'tbb'
)。我也试过openblas和mumpy + scipy的MKL版本,MKL版本看起来稍慢,但仍然没有并行化。
注释是:
@numba.jit(nopython=True, cache=False, parallel=True,
fastmath=True, nogil=True)
而功能的主要部分:
P = np.empty((T + 1, n, p, d, d))
m = np.empty((T + 1, n, p, d))
P[0] = P0
m[0] = m0
phi = 0.0
Xt = np.empty((n, p)
for t in range(1, T + 1):
sum_P00 = 0.0
v = y[t - 1]
# Purely for convenience, little performance impact
for tau in range(1, p + 1):
Xt[:, tau - 1] = X[p + t - 1 - tau]
# Predict
for i in numba.prange(n):
for tau in range(p):
# Prediction step
m[t, i, tau] = Phi[i, tau] @ m[t - 1, i, tau]
P[t, i, tau] = Phi[i, tau] @ P[t - 1, i, tau] @ Phi[i, tau].T
# Auxiliary gain variables
for i in numba.prange(n):
for tau in range(p):
v = v - Xt[i, tau] * m[t, i, tau, 0]
sum_P00 = sum_P00 + P[t, i, tau, 0, 0]
# Energy function update
s = np.linalg.norm(Xt)**2 * sum_P00 + sv2
phi += np.pi * s + 0.5 * v**2 / s
# Update
for i in numba.prange(n):
for tau in range(p):
k = Xt[i, tau] * P[t, i, tau, :, 0] # Gain
m[t, i, tau] = m[t, i, tau] + (v / s) * k
P[t, i, tau] = P[t, i, tau] + (k / s) @ k.T
在Ipython中以交互方式运行似乎只是一个问题。正如预期的那样,从控制台运行测试脚本会导致并行执行。