我有一个函数,作用于float64(x,y)的2D矩阵。基本概念:对于每一行组合(行数选择2),计算减法后的正值数量(row1-row2)。在int64(y,y)的2D矩阵中,如果该值超过某个阈值,则将其存储在索引[row1,row2]中,如果低于阈值,则存储在索引[row2,row1]中。
我已经实现了这个函数,并使用@njit(parallel=False)进行了修饰,这可以正常工作。但是@njit(parallel=True)似乎没有加速。为了加速整个过程,我看了一下@guvectorize,它也可以工作。然而,在这种情况下,我无法弄清楚如何在parallel true的情况下使用@guvectorize。
我看了numba guvectorize target='parallel' slower than target='cpu',解决方法是使用@vecorize代替,但我无法将解决方案转移到我的问题上,因此现在正在寻求帮助 :)
基本jitted和guvectorized实现
导致:
我已经实现了这个函数,并使用@njit(parallel=False)进行了修饰,这可以正常工作。但是@njit(parallel=True)似乎没有加速。为了加速整个过程,我看了一下@guvectorize,它也可以工作。然而,在这种情况下,我无法弄清楚如何在parallel true的情况下使用@guvectorize。
我看了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 实现此操作,填充生成的 2D 数组并发。
我想这是在尝试将其进一步转移到 GPU 之前的第一步。
非常感谢任何帮助。
if __name__ == '__main__'
保护。 - roganjoshitertools
来生成一个接一个的组合元组,以便只有一个循环,但这有什么帮助呢?PS:我删除了第二个主要部分。 - iR0Nictest_a = np.random.random((10,10)).astype(np.float64); res_a = check_pairs_sg(test_a); test_b = np.random.random((10,10)).astype(np.float64); res_b = check_pairs_sg(test_b); print(np.allclose(test_a,test_b)) // False; print(np.allclose(res_a,res_b)) // False;
抱歉,我无法理解您的意思。该算法是确定性的:相同的输入会得到相同的输出;其他随机输入会得到其他随机输出。 - iR0Nic