【问题标题】:How is numpy multi_dot slower than numpy.dot?numpy multi_dot 如何比 numpy.dot 慢?
【发布时间】:2018-08-06 00:38:23
【问题描述】:

我正在尝试优化一些执行大量顺序矩阵运算的代码。

我认为numpy.linalg.multi_dot (docs here) 会在 C 或 BLAS 中执行所有操作,因此它会比使用 arr1.dot(arr2).dot(arr3) 等更快。

我真的很惊讶在笔记本上运行这段代码:

v1 = np.random.rand(2,2)

v2 = np.random.rand(2,2)



%%timeit 
    ​    
v1.dot(v2.dot(v1.dot(v2)))

The slowest run took 9.01 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 3.14 µs per loop



%%timeit        ​

np.linalg.multi_dot([v1,v2,v1,v2])

The slowest run took 4.67 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 32.9 µs per loop

使用multi_dot 发现相同的操作大约慢了 10 倍。

我的问题是:

  • 我错过了什么吗?这有意义吗?
  • 还有其他方法可以优化顺序矩阵运算吗?
  • 我应该期待使用 cython 的相同行为吗?

【问题讨论】:

  • 那个数据太小了。 multidot 有一些设置阶段来优化排序。当然,这只有通过更大的数据才能得到回报。 (并且 dot 也使用 BLAS,如下所示:multidotchain np.dot

标签: python performance numpy cython


【解决方案1】:

这是因为你的测试矩阵太小太规则了;找出最快评估顺序的开销可能超过潜在的性能提升。

使用文档中的示例:

import numpy as snp
from numpy.linalg import multi_dot

# Prepare some data
A = np.random.rand(10000, 100)
B = np.random.rand(100, 1000)
C = np.random.rand(1000, 5)
D = np.random.rand(5, 333)

%timeit -n 10 multi_dot([A, B, C, D])
%timeit -n 10 np.dot(np.dot(np.dot(A, B), C), D)
%timeit -n 10 A.dot(B).dot(C).dot(D)

结果:

10 loops, best of 3: 12 ms per loop
10 loops, best of 3: 62.7 ms per loop
10 loops, best of 3: 59 ms per loop

multi_dot 通过评估标量乘法最少的最快乘法顺序来提高性能。

在上述情况下,默认的正则乘法顺序 ((AB)C)D 被评估为 A((BC)D)--因此 1000x100 @ 100x1000 乘法被简化为 1000x100 @ 100x333,至少减少了 2/3 标量乘法。

您可以通过测试来验证这一点

%timeit -n 10 np.dot(A, np.dot(np.dot(B, C), D))
10 loops, best of 3: 19.2 ms per loop

【讨论】:

  • (A, (B, C)), D) 在这种情况下与multi_dot 给出相同的时间。 np.einsum 现在有一个类似的 optimize 选项。
  • 太棒了,非常感谢。 (i) 多大才算足够大?任何线索? (ii) 在 cython 上使用这两个函数的任何 cmets ?逻辑不同吗?
  • (i) 我认为潜力在于矩阵维度的不同,以及重新排列顺序可以减少标量乘法的数量。只要您在链中的某处有尺寸变化,使用此功能总比不使用要好。 (ii) 我不确定你是否可以直接在 cython 中调用multi_dot,但如果你想从头开始实现它,这里是a reference
猜你喜欢
  • 2015-09-07
  • 2020-04-14
  • 1970-01-01
  • 2018-12-13
  • 2022-08-18
  • 1970-01-01
  • 2014-02-24
  • 1970-01-01
  • 2021-06-15
相关资源
最近更新 更多