什么样的 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。
安装 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。