【问题标题】:Why is matrix subtraction much slower than dot product in numpy?为什么矩阵减法比numpy中的点积慢得多?
【发布时间】:2017-12-07 06:21:35
【问题描述】:

假设我们有一个向量和一个矩阵:

X = np.random.random((1, 384)).astype('float32')
Y = np.random.random((500000, 384)).astype('float32')

为什么np.dot(X, Y.T)X - Y 快很多?

In [8]: %timeit np.dot(X, Y.T)
10 loops, best of 3: 42.4 ms per loop

In [9]: %timeit X - Y
1 loop, best of 3: 501 ms per loop

我能做些什么来让这样的减法和点积一样快?

【问题讨论】:

  • 维度不同时矩阵的减法?
  • numpy 广播进行减法可能会导致更多时间
  • @lamandy 是的,形状不同,这是计算曼哈顿距离的步骤之一。
  • @skrubber 是的,你认为这是由于实施吗?还是理论上不可能像点积一样快地做减法?
  • 如果输入数组是浮点数,np.dot 通常会调用 BLAS 例程进行矩阵乘法。这些通常经过高度优化并且可能是多线程的,具体取决于您的 numpy 版本所链接的 BLAS 库。 np.subtract 始终是单线程的。

标签: python numpy


【解决方案1】:

输出的大小很重要,因为输出必须写入内存,并且写入一个大数组需要时间。 dot(X, Y.T) 的形状是 (1, 500000)。 X-Y 的形状是 (500000, 384)。

在我的测试中,X-Y 花费的大部分时间都在为输出分配一个数组。比较:

%timeit X - Y   
1 loop, best of 3: 449 ms per loop

预分配空间Z = np.zeros_like(Y)

%timeit np.subtract(X, Y, out=Z)
10 loops, best of 3: 181 ms per loop

所以,如果你必须反复做这种减法,拥有一个预先分配的合适形状和类型的数组将节省一半以上的执行时间。

我不认为在你的情况下减法可以像乘法一样快。要做的算术量大致相同:X 的每个条目都满足 Y 的 500000 个条目。当您进行乘法(求和步骤)时合并结果这一事实只会有所帮助,因为 CPU 会快速处理它已经存在的数字,因此它只有一个数字可以发回。所以:大约相同的工作量,但是对于减法的情况,内存写入量是 384 倍。

这是一个证明,当两个(方阵)的输出大小相同时,减法 更快:

X = np.random.random((1000, 1000)).astype('float32')
Y = np.random.random((1000, 1000)).astype('float32')

%timeit np.dot(X, Y.T)
100 loops, best of 3: 28.7 ms per loop

%timeit X - Y
1000 loops, best of 3: 579 µs per loop

【讨论】:

    【解决方案2】:

    这只是一个评论,虽然你已经检查过了。

    我测试了广播是否是一个原因,但在这种情况下它与性能完全无关。

    In [1]: import numpy as np
    
    In [2]: X = np.random.random((1, 384)).astype('float32')
       ...: Y = np.random.random((500000, 384)).astype('float32')
    
    In [3]: %timeit np.dot(X, Y.T)
       ...: %timeit X - Y
    27.4 ms ± 910 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    324 ms ± 16.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    In [4]: import numpy.matlib
       ...: X = np.matlib.repmat(X, 500000, 1)
       ...: print(X.shape)
       ...: %timeit X - Y
    (500000, 384)
    351 ms ± 20.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    请原谅我不知道如何提高这个性能。

    【讨论】:

      【解决方案3】:

      使用 np.subtract(X,Y) 几乎可以将执行时间减半。它比 X-Y 快,但速度一直低于点积。可以帮忙

      【讨论】:

      • 最好直接写你的代码,而不是截图。
      • 我相信 np.subtract 或多或少与直接减去相同。它不会更快。
      猜你喜欢
      • 2012-07-14
      • 1970-01-01
      • 2019-09-22
      • 2015-07-19
      • 1970-01-01
      • 2018-02-17
      • 2019-11-21
      • 2015-03-31
      • 2018-11-29
      相关资源
      最近更新 更多