numpy 为什么ufuncs在一个轴上比另一个轴快2倍?

oyt4ldly  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(82)

我在不同的轴上测量了像np.cumsum这样的ufunc的性能:

In [51]: arr = np.arange(int(1E6)).reshape(int(1E3), -1)

In [52]: %timeit arr.cumsum(axis=1)
2.27 ms ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [53]: %timeit arr.cumsum(axis=0)
4.16 ms ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

cumsum在轴1上比在轴0上快近2倍。幕后到底发生了什么?

bbuxkriu

bbuxkriu1#

你有一个正方形数组。它看起来像这样:
但是计算机内存是线性寻址的,所以对于计算机来说,它看起来像这样:
或者,如果你仔细想想,它可能看起来像这样:
如果您尝试对[1 2 3][4 5 6](一行)求和,则第一个布局更快。如果您尝试对[1 4 7][2 5 8]求和,则第二种布局更快。
这是因为从内存中加载数据一次发生一个“缓存行”,通常为64字节(8个值,NumPy的默认dtype为8字节浮点型)。
您可以使用order参数控制NumPy在构造数组时使用的布局。
有关此方面的更多信息,请参阅:https://en.wikipedia.org/wiki/Row-_and_column-major_order

0s0u357o

0s0u357o2#

数组是row-major。因此,当你在轴1上求和时,数字是在连续的内存数组中找到的。这允许更好的缓存性能,因此更快的内存访问(参见“Locality of reference“)。我想这就是你在这里看到的效果。

tuwxkamq

tuwxkamq3#

实际上,性能将取决于数组在内存中的顺序:

In [36]: arr = np.arange(int(1E6)).reshape(int(1E3), -1)

In [37]: arrf = np.asfortranarray(arr) # change order

In [38]: %timeit arr.cumsum(axis=1)
1.99 ms ± 32.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [39]: %timeit arr.cumsum(axis=0)
14.6 ms ± 229 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [41]: %timeit arrf.cumsum(axis=0)
1.96 ms ± 19.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [42]: %timeit arrf.cumsum(axis=1)
14.6 ms ± 148 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

有关详细信息,请访问https://docs.scipy.org/doc/numpy-1.13.0/reference/internals.html#multidimensional-array-indexing-order-issues

相关问题