New*_*wmu 23 python arrays performance numpy
也许我正在做一些奇怪的事情,但是在使用numpy时可能会发现令人惊讶的性能损失,无论使用的功率如何都显得一致.例如,当x是随机的100x100阵列时
x = numpy.power(x,3)
Run Code Online (Sandbox Code Playgroud)
比约慢60倍
x = x*x*x
Run Code Online (Sandbox Code Playgroud)
各种阵列尺寸的加速图显示了一个最佳尺寸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()
Run Code Online (Sandbox Code Playgroud)
有人有解释吗?
我怀疑问题是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')
Run Code Online (Sandbox Code Playgroud)
