4 回答
TA贡献1824条经验 获得超8个赞
您的代码的两个版本都是矢量化的。您为尝试向量化第二个版本而创建的数组只是开销。
NumPy 向量化不是指硬件向量化。如果编译器足够聪明,它最终可能会使用硬件矢量化,但 NumPy 并没有明确使用 AVX 或任何东西。
NumPy 向量化是指编写一次对整个数组进行操作的 Python 级代码,而不是使用一次对多个操作数进行操作的硬件指令。它是 Python 级别的向量化,而不是机器语言级别的向量化。与编写显式循环相比,这样做的好处是 NumPy 可以在 C 级循环而不是 Python 中执行工作,从而避免了大量的动态调度、装箱、拆箱、遍历字节码评估循环等。
从这个意义上说,您的代码的两个版本都是矢量化的,但是第二个版本在写入和读取巨大的数组时浪费了大量内存和内存带宽。
此外,即使我们谈论的是硬件级矢量化,该1 -
版本也与其他版本一样适用于硬件级矢量化。您只需将标量加载1
到向量寄存器的所有位置并正常进行。与第二个版本相比,它涉及的内存传输要少得多,因此可能仍然比第二个版本运行得更快。
TA贡献1811条经验 获得超6个赞
时间基本相同。正如其他人指出的那样,没有任何类型的硬件或多核并行化,只是解释 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),所有这些都没有复制。
TA贡献1847条经验 获得超7个赞
我当然不是 numpy 专家,但我的猜测是第一个例子只使用一个向量,第二个例子首先创建了一个 1 的向量,然后减去。后者需要双倍的内存和一个额外的步骤来创建 1 的向量。
在 x86 CPU 上,两者都可能是某种 AVX 指令,一次可以处理 4 个数字。当然,除非您使用的是 SIMD 宽度大于向量长度的花哨 CPU,并且该 CPU 由 numpy 支持。
TA贡献1848条经验 获得超10个赞
案例 A 在 mpu 上仅运行一个迭代器,而案例 B 在两个与 X 一样大的向量上具有两个迭代器,如果未优化,则需要在线程中进行大量上下文切换。案例 B 是案例 A 的更通用版本......
添加回答
举报