[英]Why is numpy.power 60x slower than in-lining?
也許我正在做一些奇怪的事情,但是在使用numpy時可能會發現令人驚訝的性能損失,無論使用的功率如何都顯得一致。 例如,當x是隨機的100x100陣列時
x = numpy.power(x,3)
比約慢60倍
x = x*x*x
各種陣列尺寸的加速圖顯示了一個最佳尺寸10k左右的陣列和其他尺寸的5-10倍速度。
在你自己的機器上測試下面的代碼(有點亂):
import numpy as np
from matplotlib import pyplot as plt
from time import time
ratios = []
sizes = []
for n in np.logspace(1,3,20).astype(int):
a = np.random.randn(n,n)
inline_times = []
for i in range(100):
t = time()
b = a*a*a
inline_times.append(time()-t)
inline_time = np.mean(inline_times)
pow_times = []
for i in range(100):
t = time()
b = np.power(a,3)
pow_times.append(time()-t)
pow_time = np.mean(pow_times)
sizes.append(a.size)
ratios.append(pow_time/inline_time)
plt.plot(sizes,ratios)
plt.title('Performance of inline vs numpy.power')
plt.ylabel('Nx speed-up using inline')
plt.xlabel('Array size')
plt.xscale('log')
plt.show()
有人有解釋嗎?
眾所周知,處理器可以以非常奇特的方式進行的雙倍乘法非常非常快。 pow
明顯變慢了。
一些性能指南甚至建議人們為此做好計划,甚至可能在某些方面有時可能有點過於熱心。
numpy特殊情況平方,以確保它不是太慢,但它會立即將你的立方體發送到你的libc的pow
,這幾乎沒有幾次乘法快。
我懷疑問題是np.power
總是浮點運算,它不知道如何優化或矢量化你的平台(或者,可能是大多數/所有平台),而乘法很容易折入SSE,即使你不這樣做也很快。
即使np.power
足夠智能分別進行整數求冪,除非將小值展開為重復乘法,否則它仍然不會那么快。
您可以通過比較int-to-int,int-to-float,float-to-int和float-to-float功率與小數組乘法的時間來輕松驗證這一點。 int-to-int的速度是其他的5倍 - 但仍然比乘法慢4倍(盡管我使用PyPy測試了自定義的NumPy,所以對於那些在CPython上安裝了正常NumPy的人來說,它可能會更好地給出真正的結果......)
numpys冪函數的性能與指數非常非線性地成比例。 用天真的方法來做到這一點。 無論矩陣大小如何,都應存在相同類型的縮放。 基本上,除非指數足夠大,否則你不會看到任何實際的好處。
import matplotlib.pyplot as plt
import numpy as np
import functools
import time
def timeit(func):
@functools.wraps(func)
def newfunc(*args, **kwargs):
startTime = time.time()
res = func(*args, **kwargs)
elapsedTime = time.time() - startTime
return (res, elapsedTime)
return newfunc
@timeit
def naive_power(m, n):
m = np.asarray(m)
res = m.copy()
for i in xrange(1,n):
res *= m
return res
@timeit
def fast_power(m, n):
# elementwise power
return np.power(m, n)
m = np.random.random((100,100))
n = 400
rs1 = []
ts1 = []
ts2 = []
for i in xrange(1, n):
r1, t1 = naive_power(m, i)
ts1.append(t1)
for i in xrange(1, n):
r2, t2 = fast_power(m, i)
ts2.append(t2)
plt.plot(ts1, label='naive')
plt.plot(ts2, label='numpy')
plt.xlabel('exponent')
plt.ylabel('time')
plt.legend(loc='upper left')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.