我有很多非常大的矩阵AFeatures
,我正在将它们与其他一些非常大的矩阵进行比较BFeatures
,它们的形状都是(878, 2, 4, 15, 17, 512)
,使用欧几里得距离。我正在尝试并行化此过程以加快比较速度。我在 Conda 环境中使用 Python 3,我的原始代码平均 100% 使用两个 CPU 内核:
per_slice_comparisons = np.zeros(shape=(878, 878, 2, 4))
for i in range(878):
for j in range(878):
for k in range(2):
for l in range(4):
per_slice_comparisons[i, j, k, l] = np.linalg.norm(AFeatures[i, k, l, :] - BFeatures[j, k, l, :])
我尝试了两种加快代码速度的方法。
使用多处理
def fill_array(i): comparisons = np.zeros(shape=(878, 2, 4)) for j in range(878): for k in range(2): for l in range(4): comparisons[j, k, l] = np.linalg.norm(AFeatures[i, k, l, :] -BFeatures[j, k, l, :]) comparisons[j, k, l] = 0 return comparisons pool = Pool(processes=6) list_start_vals = range(878) per_slice_comparisons = np.array(pool.map(fill_array, list_start_vals)) pool.close()
这种方法将运行时间增加了大约 5%,尽管所有 8 个 CPU 内核现在都以 100% 的速度使用。我尝试了许多不同的过程,越多越慢。
这是一种稍微不同的方法,我使用 numexpr 库来执行更快的 linal.norm 操作。对于单个操作,这种方法将运行时间减少了 10 倍。
os.environ['NUMEXPR_MAX_THREADS'] = '8' os.environ['NUMEXPR_NUM_THREADS'] = '4' import numexpr as ne def linalg_norm(a): sq_norm = ne.evaluate('sum(a**2)') return ne.evaluate('sqrt(sq_norm)') per_slice_comparisons = np.zeros(shape=(878, 878, 2, 4)) for i in range(878): for j in range(878): for k in range(2): for l in range(4): per_slice_comparisons[i, j, k, l] = linalg_norm(AFeatures[i, k, l, :] - BFeatures[j, k, l, :])
但是,对于嵌套的 for 循环,这种方法将总执行时间增加了 3 倍。我不明白为什么简单地将这个操作放在嵌套的 for 循环中会如此显着降低性能?如果有人对如何解决此问题有任何想法,我将不胜感激!