【问题标题】:Numpy.dot matrix multiplication: (n-by-m)*(m-by-k) and (m-by-k)*(k-by-n) have very different speedsNumpy.dot 矩阵乘法: (n-by-m)*(m-by-k) 和 (m-by-k)*(k-by-n) 具有非常不同的速度
【发布时间】:2015-01-04 03:03:41
【问题描述】:

我有以下 Python 代码:

import numpy
import time

A = numpy.random.random((10,60000))
B = numpy.random.random((60000,785))
C = numpy.random.random((785,10))

t = time.time()
D = A.dot(B)
print "%.2f s" % (time.time() - t)

t = time.time()
E = B.dot(C)
print "%.2f s" % (time.time() - t)

我认为两个矩阵乘法 A * B 和 B * C 应该花费大约相同的时间,因为这两个乘法都涉及 10 * 60000 * 785 的乘法运算。

但是,在不同的机器上,我得到的时间非常不同。在我的笔记本电脑(Windows 7、2.40 GHz CPU、8G 内存、Python 2.7、Numpy 1.7.1)上,我得到了:

0.21 s
0.21 s

这是正常的。在集群机器上(Linux CentOS 5.6、2.66 GHz CPU、16G 内存、Python 2.7.3、Numpy 1.8.1),我得到了:

6.77 s
1.10 s

其中 A * B 比 B * C 慢得多。

谁能解释为什么这两个乘法需要不同的时间? 我不确定哪些配置是相关的,但我会尽量提供任何必要的信息。

【问题讨论】:

  • numpy.transpose(B).dot(numpy.transpose(A)) 也比B*C 慢很多吗?如果不是,我怀疑这是内存布局问题。
  • 请注意,机器之间的差异可能是由于不同的BLAS库。我打赌你的 C​​entOS numpy 没有链接到“完整”的 BLAS 库,而是使用了 numpy 的内置(但速度慢)BLAS 替代品。查看两个系统上numpy.show_config() 的输出以进行比较。
  • @JoeKington 配置确实不同。在 Windows 上,我有以下内容:blas_opt_info(库:f77blas、cblas、atlas、语言:c)、lapack_opt_info(库:lapack、f77blas、cblas、atlas、语言:f77)、atlas_info(库:lapack、f77blas、cblas、atlas , 语言: f77), atlas_blas_info (图书馆: f77blas, cblas, atlas, 语言: c)。在 Linux 上,我有:blas_info(库:blas,语言:f77),lapack_info(库:lapack,语言:f77),blas_opt_info(库:blas,语言:f77),lapack_opt_info(库:lapack,blas,语言:f77) .
  • @JoeKington 抱歉,列表很长,但配置差异很大。这是导致速度不同的原因吗?
  • @Magio - 好吧,Linux 版本的 numpy 没有链接到 Atlas 或 MKL 版本的 BLAS 或 LAPACK,所以这解释了整体速度要慢得多。您是否有机会尝试安装 Anaconda 的 python(它将安装在您的主目录或您有写入权限的任何地方)并使用完全链接版本的 numpy 重新测试时间?

标签: python performance numpy matrix-multiplication


【解决方案1】:

A 中的元素比 C 多,所以结果很直观。

【讨论】:

  • 我不明白你的意思。将 n×m 矩阵和 m×k 矩阵相乘的时间复杂度为 O(nmk)。此外,我在不同机器上得到不同时间的事实表明它可能与配置有关。
【解决方案2】:

(评论太长,不是答案)

如果您运行以下命令,您会在性能上获得很大差异吗?

#!/usr/bin/env python3.4                                                                 
import numpy
import time

A = numpy.random.random((10,60000))
B = numpy.random.random((60000,785))
C = numpy.random.random((785,10))

t = time.time()
D = A.dot(B)
print("%.2f s" % (time.time() - t))

t = time.time()
D = numpy.transpose(B).dot(numpy.transpose(A))
print("%.2f s" % (time.time() - t))

t = time.time()
D = B.dot(C)
print("%.2f s" % (time.time() - t))

t = time.time()
D = numpy.transpose(C).dot(numpy.transpose(B))
print("%.2f s" % (time.time() - t))

当我运行它时,我得到了

0.21 s
0.22 s
0.44 s
0.22 s

这强烈表明内存访问模式存在差异。

【讨论】:

  • 我得到了有趣的模式:在 Windows 上:0.20s、1.15s、0.20s、1.16s;在 Linux 上:6.82s、6.79s、1.10s、1.31s。
  • 我刚刚根据@JoeKington的评论安装了Anaconda的Python,现在我得到0.22s、0.22s、0.27s、0.27s。这似乎很正常。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-21
  • 1970-01-01
  • 2018-06-18
  • 1970-01-01
  • 2014-02-09
  • 2022-11-12
  • 1970-01-01
相关资源
最近更新 更多