numpy - (np.add(X, Y, out=X); np.add(X, Y, out=X)) 比起 np.add(X, 2*Y, out=X) 更优。

3

问题

np.add(X, 2*Y, out=X)np.add(X, Y, out=X); np.add(X, Y, out=X) 更慢。在实际情况下,使用 np.add(X, Y, out=X); np.add(X, Y, out=X) 来提高性能是一种常见的做法吗?我没有在numpy中进行大量数值计算,因此想从那些实际处理这种差异可能很重要的问题的人那里了解情况。

我认为是这样的,但还有其他简单的方法来实现相同的性能而使语句更加简单吗?

背景

临时复制演示了临时复制的影响。

问题在于还有许多其他情况需要创建这样的副本,这会影响性能...

  • 代码与参考文献中的代码不同。
import numpy as np
import timeit

setup = """
import numpy as np

X = np.ones(100000, dtype=np.int)
Y = np.ones(100000, dtype=np.int)
"""
iterations = 100000

elepased = timeit.timeit(
    stmt="np.add(X, 2*Y, out=X)",
    setup=setup,
    number=iterations
)
elepased / iterations * 1e6  

84.75939844996901

elepased = timeit.timeit(
    stmt="np.add(X, Y, out=X); np.add(X, Y, out=X)",
    setup=setup,
    number=iterations
)
elepased / iterations * 1e6  

57.947089899971616

环境

在Ubuntu 20.04LTS上的jupyter笔记本中运行,使用1CPU 8核

  • numpy 1.19.2
  • Python 3.8.5 (默认版本,Sep 4 2020, 07:30:14) [GCC 7.3.0]

在numpy中,每个表达式都是独立计算的。因此,在您的示例np.add(X, 2*Y, out=X)中,首先为2*Y的结果分配内存,然后再为np.add(X, TMP, out=X)的结果分配内存。还有其他一些包可以获得更好的性能,例如numexpr https://numexpr.readthedocs.io/en/latest/intro.html#expected-performance。 - max9111
1个回答

1
我认为速度的提升主要来自于操作2*Y对新内存进行的读写操作。我已经添加了另一个场景,您可以通过将Y加到自身上来简单地覆盖Y,这也会更快一些。

情况1:

X、Y和2Y必须在内存中,并且它们有相应的读写操作。

Y = np.ones((10000,))
X = np.zeros((10000,))

#Case 1:
np.add(X, 2*Y, out=X) #Double Y, store somewhere, and add to X

13.3 µs ± 929 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

案例2:

只有X和Y在内存中,但X有多个写操作。

Y = np.ones((10000,))
X = np.zeros((10000,))

#Case 2:
np.add(X, Y, out=X) #Add to X
np.add(X, Y, out=X) #Add to X again

12.8 µs ± 830 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

案例三(最快):

只有X和Y在内存中,但X有一个写操作,Y也有一个写操作。

Y = np.ones((10000,))
X = np.zeros((10000,))

#Case 3:
np.add(Y, Y, out=Y) #double Y
np.add(X, Y, out=X) #then add to X

12.2 µs ± 136 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

检查共享内存 -
#2*Y is a brand new array in memory
print(np.shares_memory(Y, 2*Y))

#np.add(Y, Y, out=Y) Adding Y to itself shares memory
print(np.shares_memory(Y, np.add(Y, Y, out=Y)))

False
True

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接