簡體   English   中英

為什么numpy.power比內襯慢60倍?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM