为什么numpy.power比lining慢60倍?

2024-06-22 04:41:22 发布

您现在位置:Python中文网/ 问答频道 /正文

也许我在做一些奇怪的事情,但是也许在使用numpy时发现了一个令人惊讶的性能损失,不管使用的是什么功率,看起来都是一致的。例如,当x是随机的100x100数组时

x = numpy.power(x,3) 

大约比

x = x*x*x

不同阵列大小的加速曲线图显示,阵列大小在10k左右时是一个最佳点,其他大小的阵列的加速速度为5-10倍。

enter image description here

下面要在自己的机器上测试的代码(有点混乱):

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()

有人有解释吗?


Tags: inimportnumpyfortimeasnpinline
3条回答

众所周知,双倍乘法是非常非常快的,你的处理器可以用一种非常奇特的方式来完成。pow明显要慢一些。

Some performance guides甚至建议人们对此进行计划,甚至可能在某种程度上有时会有点过分热情。

numpy特殊情况下会进行平方运算,以确保速度不会太慢,但它会将cubing直接发送到libc的pow,这几乎没有两个乘法运算快。

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')

performance plot

我怀疑问题是np.power总是做浮点求幂,它不知道如何在您的平台(或者,可能是大多数/所有的平台)上优化或矢量化,而乘法很容易被抛到SSE中,即使您不知道,它也相当快

即使np.power足够聪明,可以分别进行整数幂运算,除非它将小值展开成重复乘法,否则它仍然不会快得多。

通过比较int到int、int到float、float到int和float到float的时间,您可以很容易地验证这一点:对于一个小数组,int到int的速度大约是其他数组的5倍,但仍然比乘法慢4倍(尽管我使用PyPy测试了一个定制的NumPy,所以对于具有正常的NumPy安装在CPython上,以提供真正的结果…)

相关问题 更多 >