什么样的 numpy 工作负载会产生最高的加速?嗯?二维码?奇异值分解?

What numpy workload would the yield the highest speed up? MMM? QR? SVD?

安装 MKL、OPENBLAS 时,什么 numpy 工作负载会产生最高的速度?嗯?二维码?奇异值分解?我曾尝试使用 MMM,但我没有看到加速,相反情况变得更糟。我的测试代码如下:

import numpy as np
import time
import gc

sizes = [2000, 20000]
samples = np.zeros(5)
for n in sizes:
   # allocate outside the benchmark
   X = np.random.normal(size=(n, n))
   Y = X
   
   for i in range(2):
       Z = X @ Y

   # run 5 times
   for r in range(5):
      start_time = time.process_time()
      Z = X @ Y
      samples[r] = time.process_time() - start_time

   X = Y = Z = None
   # remove unnecessary memory consumption 
   gc.collect()

   print(np.mean(samples))
   print(np.std(samples))

当我重新运行 增加可用线程的数量(此框中的最大核心数为 8)时,我看到响应时间增加而不是减少。

不冒险,所以我每次都更改所有这些环境变量(这里更改为 1,但我更改为 2、4、8):

export MKL_NUM_THREADS=1
export OMP_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
export NUMEXPR_MAX_THREADS=1
export VECLIB_MAXIMUM_THREADS=1

您看到响应时间增加而不是减少,因为测量时间的方法可能不正确。您可能想要的是 挂钟时间 而不是累积的并行时间。实际上,time.process_time() returns 是“内核和用户 space CPU 时间的总和”。您可以使用 time.time() 来解决这个问题。

请注意,由于使用多线程的开销,并行时间会增加:N 个线程的工作速度不是快 N 倍,而是比 N 倍少一点(参见 Amdahl's law)。


一般信息:

默认情况下 Numpy select 机器上可用的实现。在大多数 Linux 发行版中,通常已经使用了 OpenBLAS。因此显式使用 OpenBLAS 不会改变结果。

线性代数库的操作性能随用例和输入类型而变化:具有双精度复数的 MMM 的行为可能与具有单精度实数的 MMM 不同。一些库针对某些特定情况和特定输入类型进行了更好的优化。更不用说非常重要的目标平台的影响。 BLIS benchmark page 清楚地表明了这一点。我将专注于在 x86-64 Intel 平台上处理双精度实数 运行 的通用原语。

MMM 非常受计算限制,并且扩展性非常好。它针对大多数体面的 BLAS 实现进行了非常优化。当 BLAS 实现不优化它时,通常意味着它不优化所有其他原语。在主流 x86-64 平台上,OpenBLAS 和 MKL 通常在这个原语上很接近(MKL 通常略胜一筹)。

QR 主要受内存限制,更难优化。 AFAIK,OpenBLAS 中提供的那个几乎没有优化。它基于 LAPACK 的 Netlib 实现,它也不是很优化。 MKL 中的那个应该明显更好。这些结果可能会在不久的将来发生变化。但是,内存吞吐量可能会限制这两种实现的性能,从而导致目标硬件的性能结果相似。

与其他两个相比,SVD 是最难优化的操作。这也是最昂贵的。 SVD 是一种 LAPACK 操作,因此情况与 QR 类似。因此,我希望 MKL 在此操作上明显优于 OpenBLAS。