Numpy:将大型数组与dtype = int8相乘是SLOW

Feo*_*ran 12 python arrays performance numpy

考虑下面的一段代码,它生成一些(可能)巨大的多维数组并numpy.tensordot用它执行(无论我们在这里乘以相同或两个不同的数组,并不重要).

import time
import numpy

L, N = 6, 4

shape = (2*L)*[N,]
A = numpy.arange(numpy.prod(shape)).reshape(shape)
A = A % 256 - 128   # [-127,+127]
axes=(range(1,2*L,2), range(0,2*L,2))

def run(dtype, repeat=1):
    A_ = A.astype(dtype)
    t = time.time()
    for i in range(repeat):
        numpy.tensordot(A_, A_, axes)
    t = time.time() - t
    print(dtype, '   \t%8.2f sec\t%8.2f MB' %(t, A_.nbytes/1e6))
Run Code Online (Sandbox Code Playgroud)

现在我们可以比较不同数据类型的性能,例如:

run(numpy.float64)
run(numpy.int64)
Run Code Online (Sandbox Code Playgroud)

由于数组只包含小整数,我想通过使用来节省一些内存dtype=int8.但是,这会减慢矩阵乘法A LOT.

以下是一些测试用例

第一个,对我的用例来说是重要的一个.其他仅供参考.使用Numpy 1.13.1和Python 3.4.2

大阵列

L, N = 6, 4; A.size = 4**12 = 16777216
<class 'numpy.float64'>        59.58 sec      134.22 MB
<class 'numpy.float32'>        44.19 sec       67.11 MB
<class 'numpy.int16'>         711.16 sec       33.55 MB
<class 'numpy.int8'>          647.40 sec       16.78 MB
Run Code Online (Sandbox Code Playgroud)

具有不同数据类型的相同数组.内存按预期减少.但为什么CPU时间差异很大?如果有什么我期望int比...更快float.

大阵列具有不同的形状

L, N = 1, 4**6; A.size = (4**6)**2 = 16777216
<class 'numpy.float64'>        57.95 sec      134.22 MB
<class 'numpy.float32'>        42.84 sec       67.11 MB
Run Code Online (Sandbox Code Playgroud)

形状似乎没有很大的影响.

没有那么大的数组

L, N = 5, 4
<class 'numpy.float128'>       10.91 sec       16.78 MB
<class 'numpy.float64'>         0.98 sec        8.39 MB
<class 'numpy.float32'>         0.90 sec        4.19 MB
<class 'numpy.float16'>         9.80 sec        2.10 MB
<class 'numpy.int64'>           8.84 sec        8.39 MB
<class 'numpy.int32'>           5.55 sec        4.19 MB
<class 'numpy.int16'>           2.23 sec        2.10 MB
<class 'numpy.int8'>            1.82 sec        1.05 MB
Run Code Online (Sandbox Code Playgroud)

较小的值,但同样奇怪的趋势.

小阵列,很多重复

L,N = 2,4; A.size = 4**4 = 256; 重复= 1000000

<class 'numpy.float128'>       17.92 sec        4.10 KB
<class 'numpy.float64'>        14.20 sec        2.05 KB
<class 'numpy.float32'>        12.21 sec        1.02 KB
<class 'numpy.float16'>        41.72 sec        0.51 KB
<class 'numpy.int64'>          14.21 sec        2.05 KB
<class 'numpy.int32'>          14.26 sec        1.02 KB
<class 'numpy.int16'>          13.88 sec        0.51 KB
<class 'numpy.int8'>           13.03 sec        0.26 KB
Run Code Online (Sandbox Code Playgroud)

除了float16慢得多,这里的一切都很好.

为什么int8非常大的阵列要慢得多?有没有办法解决?对于大型阵列,节省内存变得越来越重要

Fil*_*zza 3

很遗憾,

正如评论中正确强调的那样,幕后的“引擎”是 BLAS,并且它没有本机整数类型。这就是为什么 float64 或 32 会运行得更快(在C++ 类似问题的相关答案中进行了一些讨论)。

作为问题核心的旁注,探索加速问题同时限制内存消耗的方法是使用 Cython,您可以在其中直接运行 C 代码并在 Python 中返回结果。