【问题标题】:Making numpy einsum faster for multidimensional tensors使多维张量的 numpy einsum 更快
【发布时间】:2020-05-17 17:02:38
【问题描述】:

我有一些代码使用以下einsum:

y = np.einsum('wxyijk,ijkd->wxyd', x, f)

其中(例如)x 的形状是 (64, 26, 26, 3, 3, 3),f 的形状是 (3, 3, 3, 1),两者的 dtype=float

%timeit np.einsum('wxyijk,ijkd->wxyd', x, f)
# 2.01 ms ± 55.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

这对我的应用程序来说太慢了,时间紧迫。使用 GPU(通过 CuPy)和路径加速(通过 opt-einsum)似乎都没有使这更快。有什么方法可以在 NumPy 中以原生方式使其更快,或者这是否与它将获得的一样快?

【问题讨论】:

  • 您可以将数组重塑为 (64,26,26,27) 和 (27,1),并使用 @。但在我的测试中,这并没有提高速度。
  • 对此不确定,但 100 个循环可能不足以将字符串的初始解析分摊到一组操作中

标签: python numpy numpy-einsum


【解决方案1】:

在这种情况下,您可以使用 optimize 关键字,自己实现它,或者使用 tensordot。但是,第一个版本实际上应该做同样的事情(重塑-> 点-> 重塑)。

您的实施

x=np.random.rand(64, 26, 26, 3, 3, 3)
f=np.random.rand(3, 3, 3, 1)
%timeit y = np.einsum('wxyijk,ijkd->wxyd', x, f)
#886 µs ± 3.16 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

使用 optimize="optimal"

%timeit y = np.einsum('wxyijk,ijkd->wxyd', x, f,optimize="optimal")
#275 µs ± 23.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

重塑和 BLAS 调用

这通常会导致与optimize="optimal" 相当的性能,可能在这种情况下不必要的数组复制会导致速度变慢。

def contract(x,f):
    s1=x.shape
    x_=x.reshape(s1[0]*s1[1]*s1[2],s1[3]*s1[4]*s1[5])

    s2=f.shape
    f_=f.reshape(s2[0]*s2[1]*s2[2],s2[3])
    return np.dot(x_,f_).reshape(s1[0],s1[1],s1[2],s2[3])

%timeit contract(x,f)
#144 µs ± 3.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

张量点

%timeit np.tensordot(x,f,axes=3)
#176 µs ± 4.32 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

【讨论】:

  • tensordot 确实会重塑(并在需要时转置)将计算减少到您在 contract 中执行的 np.dot
  • optimizeeinsum 中的效果已经转移到 numpy 版本上,因为开发人员尝试了不同的策略。在我的版本(1.18)上它没有帮助。
  • @hpaulj 我也有 1.18.1 使用 tensordot 对您的系统有影响吗?也许它是这种非常特殊情况的 BLAS 后端(使用 dot-> gemm 进行矩阵向量乘法)。我有 MKL
  • 奇怪的是,在我的系统上,naive 版本需要 2 ms,contract 和 tensordot 都需要 4.92 ms,而 'optimal' 需要高达 5.42 ms! 是否有一些设置我需要改变吗?
  • @DiehardTheTryhard 我在 Core i5-8500(双通道 RAM)上进行了计时。我还在低端设备(具有 core-m3 和单通道 RAM 的平板电脑)上进行了尝试。每种方法都在 0.88 到 0.95 毫秒之间。对于该硬件,您的时间太慢了。我想最好安装一个干净的 Anaconda 并在那里进行测试。
猜你喜欢
  • 2020-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 2019-09-10
  • 2021-03-02
  • 2023-03-20
  • 2011-06-25
相关资源
最近更新 更多