3

我写了一个非常耗时的 numpy 程序。剖析之后,我发现大部分时间都花在了numpy.einsum.

虽然 numpy 是 LAPACK 或 BLAS 的包装器,但我不知道numpy.einsum它的性能是否与 LAPACK 或 BLAS 中的对应物相媲美。

那么,如果我切换到 fortran 或 C,我会得到很大的性能提升吗?

4

1 回答 1

3

Numpy 使用 BLAS 包装仅用于使用 BLAS 指定的原始操作。这包括dot, innerproduct, vdot, matmul(1.10 中的新功能)和依赖它的函数(tensordot等)。einsum另一方面,只为允许回退到它的操作调用 BLAS(从 Numpy 1.14.0 开始)。

如果您的问题可以分解为几个 BLAS 操作,那么我建议您首先在 Numpy 本身中尝试。它可能需要一些临时数组(即使您要编写使用 BLAS 的 C/FORTRAN,情况仍然如此)。out=您可以通过使用函数的参数来消除某些数组创建开销。

但大多数时候,您使用它是einsum因为它在 BLAS 中无法表达。看一个简单的例子:

a = np.arange(60.).reshape(3,4,5)
b = np.arange(24.).reshape(4,3,2)
c = np.einsum('ijk,jil->kl', a, b)

要在原始操作中表达上述内容,您需要交换 中的前两个轴b,对前两个维度进行逐元素乘法,然后对每个索引k和求和l

c2 = np.ndarray((5, 2))
b2 = np.swapaxes(b, 0, 1)
def manualeinsum(c2, a, b):
    ny, nx = c2.shape
    for k in range(ny):
        for l in range(nx):
            c2[k, l] = np.sum(a[..., k]*b2[...,l])
manualeinsum(c2, a, b2)

你不能这样说。更新:上述问题可以表示为可以使用 BLAS 加速的矩阵乘法。请参阅@ali_m 的评论。对于足够大的阵列,BLAS 方法更快。

同时,请注意,einsum它本身是用 C 编写的,为给定的索引创建了一个特定于维度的迭代器,并且还针对 SSE 进行了优化。

于 2016-02-19T16:11:00.100 回答