【发布时间】:2019-03-28 13:10:04
【问题描述】:
我有一个在 float64(x,y) 上对二维矩阵进行操作的函数。基本概念:对于每个行组合(行数选择 2),计算减法后正值的数量(行 1 - 行 2)。在 int64(y,y) 的 2Dmatrix 中,如果值高于某个阈值,则将此值存储在索引 [row1,row2] 中,如果低于某个阈值,则存储在索引 [row2,row1] 中。
我已经实现了它并用@njit(parallel=False) 对其进行了修饰,效果很好@njit(parallel=True) 似乎没有加速。为了加快整个过程,我查看了@guvectorize,它也很有效。但是,在这种情况下,我也无法弄清楚如何将 @guvectorize 与 parallel true 一起使用。
我查看了numba guvectorize target='parallel' slower than target='cpu',其中的解决方案是改用@vecorize,但我无法将解决方案转移到我的问题上,因此我现在正在寻求帮助:)
基本的jitted和guvectorized实现
import numpy as np
from numba import jit, guvectorize, prange
import timeit
@jit(parallel=False)
def check_pairs_sg(raw_data):
# 2D array to be filled
result = np.full((len(raw_data), len(raw_data)), -1)
# Iterate over all possible gene combinations
for r1 in range(0, len(raw_data)):
for r2 in range(r1+1, len(raw_data)):
diff = np.subtract(raw_data[:, r1], raw_data[:, r2])
num_pos = len(np.where(diff > 0)[0])
# Arbitrary check to illustrate
if num_pos >= 5:
result[r1,r2] = num_pos
else:
result[r2,r1] = num_pos
return result
@jit(parallel=True)
def check_pairs_multi(raw_data):
# 2D array to be filled
result = np.full((len(raw_data), len(raw_data)), -1)
# Iterate over all possible gene combinations
for r1 in range(0, len(raw_data)):
for r2 in prange(r1+1, len(raw_data)):
diff = np.subtract(raw_data[:, r1], raw_data[:, r2])
num_pos = len(np.where(diff > 0)[0])
# Arbitrary check to illustrate
if num_pos >= 5:
result[r1,r2] = num_pos
else:
result[r2,r1] = num_pos
return result
@guvectorize(["void(float64[:,:], int64[:,:])"],
"(n,m)->(m,m)", target='cpu')
def check_pairs_guvec_sg(raw_data, result):
for r1 in range(0, len(result)):
for r2 in range(r1+1, len(result)):
diff = np.subtract(raw_data[:, r1], raw_data[:, r2])
num_pos = len(np.where(diff > 0)[0])
# Arbitrary check to illustrate
if num_pos >= 5:
result[r1,r2] = num_pos
else:
result[r2,r1] = num_pos
@guvectorize(["void(float64[:,:], int64[:,:])"],
"(n,m)->(m,m)", target='parallel')
def check_pairs_guvec_multi(raw_data, result):
for r1 in range(0, len(result)):
for r2 in range(r1+1, len(result)):
diff = np.subtract(raw_data[:, r1], raw_data[:, r2])
num_pos = len(np.where(diff > 0)[0])
# Arbitrary check to illustrate
if num_pos >= 5:
result[r1,r2] = num_pos
else:
result[r2,r1] = num_pos
if __name__=="__main__":
np.random.seed(404)
a = np.random.random((512,512)).astype(np.float64)
res = np.full((len(a), len(a)), -1)
并用
测量%timeit check_pairs_sg(a)
%timeit check_pairs_multi(a)
%timeit check_pairs_guvec_sg(a, res)
%timeit check_pairs_guvec_multi(a, res)
导致:
614 ms ± 2.54 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
507 ms ± 6.87 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
622 ms ± 3.88 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
671 ms ± 4.35 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
我想知道如何将其实现为@vectorized 或适当的并行@guvectorize 以真正并行填充生成的二维数组。
我想这是我尝试将其进一步应用到 gpu 之前的第一步。
非常感谢任何帮助。
【问题讨论】:
-
“我想这是我尝试将其进一步应用于 gpu 之前的第一步。”。你确定你不能在转向
numba之前先摆脱嵌套的for循环吗? -
我不清楚我应该如何运行它来尝试这样做,因为你有两个
if __name__ == '__main__'警卫 -
好吧,我可以使用
itertools依次生成一个组合元组,只有一个循环,但这有什么帮助? ps:我删除了第二个主要 -
好吧,看起来你也可以使用
np.roll()来偏移 1 而不是内部循环,但我不知道,因为我不知道函数在做什么。 -
事实上,我很确定其中大部分都可以被矢量化,删除一些
for循环和if检查。在确保 numpy 方法合适之前跳到 numba 然后再到 GPU 是忽略了问题。
标签: python vectorization numba