【发布时间】:2014-07-15 02:00:15
【问题描述】:
代码如下,
In [180]: rng = np.random.RandomState(123)
In [181]: A1 = rng.uniform(size=(10000,80))
In [182]: B1 = rng.uniform(size=(10000,30))
In [183]: A2 = rng.uniform(size=(80,10000))
In [184]: B2 = rng.uniform(size=(30,10000))
In [185]: %timeit np.dot(A1.T, B1)
10 loops, best of 3: 136 ms per loop
In [186]: %timeit np.dot(A2, B2.T)
10 loops, best of 3: 25.1 ms per loop
In [4]: %timeit np.dot(A2, B1)
10 loops, best of 3: 56.3 ms per loop
我想将(A1, B1)和(A2, B2)相乘形成一个(80,30)矩阵,这里的区别是A1被定义为A2的转置,10000行在A1但是80 在A2 中的行。 B1,B2 也一样。
性能差别很大,我猜是因为numpy.array 的内存布局对于大列比大行缓存友好 /strong>,对吧?但是怎么做呢?
【问题讨论】:
-
如果您不介意,请问您发布执行 np.dot(A2, B1) 的时间测量吗?
-
您的 numpy 是否使用任何线性代数库编译?我的使用 OpenBLAS,我只看到你的任何版本之间的细微差别,而且它的运行速度比你的最佳时间快了近 6 倍......
-
@Jaime,不确定,但我想这与
numpy.array的内存布局和 CPU 缓存有关。 -
尝试定时
A1.T.copy()或类似操作。在我的系统上运行约 5 毫秒。矩阵乘法几乎是一个 O(n^3) 的运算,所以复制的 O(n^2) 运算对于整个最终时间应该不会太相关。如果您的时间相似,您可以通过一些智能复制将最差时间减少到最佳结果的 20% 以内。一个好的库会为您做到这一点,并添加多线程和其他好东西。 -
基于 (A2, B1) 比 (A2, B2.T) 慢的事实,并假设没有对 np.dot() 进行优化,例如 Strassen/Winograd,我的理论是访问连续的内存块要快得多,假设 rng.uniform(size=(80,10000)) 导致连续内存为每行存储 10000 个元素。因此,在执行矩阵乘法时,当我们从左侧的矩阵中逐行扫描时,当我们从右侧的矩阵中逐列扫描时,对于 (A2, B2.T),我们访问的是连续的每行/列扫描的内存位。
标签: python performance numpy