为什么与使用两个 Numpy 数组的向量化相比,使用 Numpy 数组和 int 进行算术运算时减

我对为什么这段代码感到困惑:


start = time.time()

for i in range(1000000):

    _ = 1 - np.log(X)

print(time.time()-start)

执行速度比这个实现快:


start = time.time()

for i in range(1000000):

    _ = np.subtract(np.ones_like(X), np.log(X))

print(time.time()-start)

我的理解是它应该是相反的,因为在第二个实现中我正在利用矢量化提供的加速,因为它能够同时操作 X 中的元素而不是顺序操作,这就是我假设第一个实现的方式功能。


有人可以为我解释一下吗,因为我真的很困惑?谢谢!


噜噜哒
浏览 114回答 4
4回答

有只小跳蛙

您的代码的两个版本都是矢量化的。您为尝试向量化第二个版本而创建的数组只是开销。NumPy 向量化不是指硬件向量化。如果编译器足够聪明,它最终可能会使用硬件矢量化,但 NumPy 并没有明确使用 AVX 或任何东西。NumPy 向量化是指编写一次对整个数组进行操作的 Python 级代码,而不是使用一次对多个操作数进行操作的硬件指令。它是 Python 级别的向量化,而不是机器语言级别的向量化。与编写显式循环相比,这样做的好处是 NumPy 可以在 C 级循环而不是 Python 中执行工作,从而避免了大量的动态调度、装箱、拆箱、遍历字节码评估循环等。从这个意义上说,您的代码的两个版本都是矢量化的,但是第二个版本在写入和读取巨大的数组时浪费了大量内存和内存带宽。此外,即使我们谈论的是硬件级矢量化,该1 -版本也与其他版本一样适用于硬件级矢量化。您只需将标量加载1到向量寄存器的所有位置并正常进行。与第二个版本相比,它涉及的内存传输要少得多,因此可能仍然比第二个版本运行得更快。

杨魅力

时间基本相同。正如其他人指出的那样,没有任何类型的硬件或多核并行化,只是解释 Python 和编译numpy函数的混合。In [289]: x = np.ones((1000,1000))In [290]: timeit 1-np.log(x)                                                    15 ms ± 1.94 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)In [291]: timeit np.subtract(np.ones_like(x), np.log(x))                        18.6 ms ± 1.89 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)取出np.ones_like定时循环:In [292]: %%timeit y = np.ones_like(x)      ...: np.subtract(y,np.log(x))      ...:       ...:                                                                       15.7 ms ± 441 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)2/3 的时间花在log函数上:In [303]: timeit np.log(x)                                                      10.7 ms ± 211 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)In [306]: %%timeit y=np.log(x)      ...: np.subtract(1, y)                                                                  3.77 ms ± 5.16 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)生成方式的变化1只是时间的一小部分。使用“广播”,使用标量和数组或数组和数组进行数学运算同样容易。,1无论是标量(实际上是一个形状为 的数组()),被广播到 (1,1),然后到 (1000,1000),所有这些都没有复制。

aluckdog

我当然不是 numpy 专家,但我的猜测是第一个例子只使用一个向量,第二个例子首先创建了一个 1 的向量,然后减去。后者需要双倍的内存和一个额外的步骤来创建 1 的向量。在 x86 CPU 上,两者都可能是某种 AVX 指令,一次可以处理 4 个数字。当然,除非您使用的是 SIMD 宽度大于向量长度的花哨 CPU,并且该 CPU 由 numpy 支持。

慕桂英546537

案例 A 在 mpu 上仅运行一个迭代器,而案例 B 在两个与 X 一样大的向量上具有两个迭代器,如果未优化,则需要在线程中进行大量上下文切换。案例 B 是案例 A 的更通用版本......
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python