【发布时间】:2019-04-05 04:38:00
【问题描述】:
我注意到非常奇怪的是,np.sum 比手写 sum 慢 10 倍。
np.sum 与轴:
p1 = np.random.rand(10000, 2)
def test(p1):
return p1.sum(axis=1)
%timeit test(p1)
每个循环 186 µs ± 4.21 µs(7 次运行的平均值 ± 标准偏差,每次 1000 个循环)
np.sum 无轴:
p1 = np.random.rand(10000, 2)
def test(p1):
return p1.sum()
%timeit test(p1)
每个循环 17.9 µs ± 236 ns(平均值 ± 标准偏差,7 次运行,每次 10000 次循环)
+:
p1 = np.random.rand(10000, 2)
def test(p1):
return p1[:,0] + p1[:,1]
%timeit test(p1)
每个循环 15.8 µs ± 328 ns(平均值 ± 标准偏差,7 次运行,每次 100000 次循环)
乘法:
p1 = np.random.rand(10000, 2)
def test(p1):
return p1[:,0]*p1[:,1]
%timeit test(p1)
每个循环 15.7 µs ± 701 ns(7 次运行的平均值 ± 标准偏差,每次 10000 个循环)
我看不出有什么理由。知道为什么吗?我的 numpy 版本是1.15.3。
编辑: 10000000:
np.sum (with axis): 202 ms (5 x)
np.sum (without axis): 12 ms
+ : 46 ms (1 x)
* : 44.3 ms
所以我猜想在某种程度上存在一些开销......
【问题讨论】:
-
一小部分开销可能与成对求和实现有关。不过,只有一小部分 - 据我所知,
prod并没有做成对的事情,在我的测试中,prod的运行时间大约是sum的 5/6。我认为 NumPy 还在为+而不是sum使用SIMD,但我还不确定。 -
你的“乘法”正在做一些不同的事情......其他人只是使用
p1而基本上忽略p2 -
Here's the source 用于成对求和例程。求和的元素数量足够小,以至于例程应该立即进入直接的非成对循环情况,但代码路径似乎仍然比用于
prod之类的代码路径有一些开销。如前所述,这只是相对于+的一小部分开销。 -
@beesleep 乘法和加法在浮点数上没有什么不同;如果有的话,乘法会更容易一些。当然,整数是不同的。
-
这太奇怪了,主要是因为轴应该返回非连续元素的内存视图(这几乎不是优化的代码,因为你在这里对缓存非常不友好)。事实上,我可以通过将
p1 = np.random.rand(10000, 2)更改为p1 = np.random.rand(2, 10000)和p1.sum(axis=1)更改为p1.sum(axis=0)来提高代码性能的10 倍。
标签: python performance numpy