反转后 Numpy 乘法慢得多

Numpy multiplication much slower after reversal

我正在将两个 numpy 数组相乘:

import numpy as np
X = np.random.randn(4500,3500)
v = np.random.randn(3500,200)

默认都是C_CONTIGUOUS:

X.flags
# C_CONTIGUOUS : True
v.flags
# C_CONTIGUOUS : True

而且乘法很快:

%timeit X @ v
# 41 ms ± 2.54 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

但是,如果我反转 X 数组,就会发生奇怪的事情:

%timeit X[::-1,::-1] @ v
# 3.97 s ± 54.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

问题:

  1. This post 表示返回操作创建视图。结果视图既不是 C_CONTIGUOUS 也不是 F_CONTIGUOUS。这是什么意思?
X[::-1,::-1].flags
# C_CONTIGUOUS : False
# F_CONTIGUOUS : False
  1. 为什么反转操作会如此严重地减慢乘法?

A c_contiguous 数组是一个数组,表示为对连续缓冲区的行优先扫描。当您创建一个反向视图数组时,情况不再如此,因此数组不再是 c_contiguous.

至于为什么在反向数组上操作速度较慢,像这样的计算细节通常会因系统的 BLAS/LAPACK 安装而异。在这种情况下,我怀疑您的 BLAS 安装针对连续缓冲区上的矩阵乘积的常见情况优化了代码路径,并且没有针对不太常见的非连续缓冲区上的操作优化代码路径。

的确,运行 这在一台机器上使用了针对 ubuntu 的 libblas 构建的 numpy 给出了以下内容:

%timeit X @ v
# 1 loop, best of 3: 200 ms per loop
%timeit X[::-1,::-1] @ v
# 1 loop, best of 3: 4.64 s per loop

而 运行 在带有针对 MKL 构建的 numpy 的机器上显示不同的行为:

%timeit X @ v                                                                          
# 92.6 ms ± 1.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit X[::-1,::-1] @ v                                                               
# 128 ms ± 2.32 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

(不同的 IPython 版本占不同的 %timeit 输出)