2016-04-30 85 views
1

我有兩個3維numpy陣列A,B(大小〜(1000,1000,3) - >圖像處理)和它的元素明智的功能。numpy函數的時間效率組合

功能依次是:

import numpy as np 
A = A ** 3 
A = np.maximum(A, 0.001) 
C = np.divide(B, A) 

由於操作這些3個命令的功能是時間要求苛刻的處理的瓶頸,我想詢問是否存在執行所有那些具有的一種方式單次訪問內存中的每個元素,即最快的性能。

我能找到的唯一組合是分割部分,例如, hereherethis one由於愛因斯坦和,這是一種特殊情況。

有沒有辦法做到一次訪問內存中的每個元素(從而使其時間效率),而無需編寫自定義的ufunc?

+0

數據類型允許使用第三個鏈接執行'np.einsum('ijk,ijk,ijk-> ijk',A,A,A)'來模擬'A *** 3'嗎?這應該是非常有效的。 – Divakar

回答

3

有沒有辦法做到一次訪問內存中的每個元素(從而使其時間效率),而無需編寫自定義的ufunc?

是的,這正是numexpr的設計目的。

import numpy as np 
import numexpr as ne 

def func1(A, B): 
    A = A ** 3 
    A = np.maximum(A, 0.001) 
    return np.divide(B, A) 

def func2(A, B): 
    return ne.evaluate("B/where(A**3 > 0.001, A**3, 0.001)", 
         local_dict={'A':A,'B':B}) 

A, B = np.random.randn(2, 1000, 1000, 3) 

print(np.allclose(func1(A, B), func2(A, B))) 
# True 

numexpr給出了關於70改進了原來的碼的因素:

In [1]: %%timeit A, B = np.random.randn(2, 1000, 1000, 3) 
func1(A, B) 
    ....: 
1 loop, best of 3: 837 ms per loop 

In [2]: %%timeit A, B = np.random.randn(2, 1000, 1000, 3) 
func2(A, B) 
    ....: 
The slowest run took 8.87 times longer than the fastest. This could mean that an 
intermediate result is being cached. 
100 loops, best of 3: 11.5 ms per loop 

這部分是因爲numexpr將使用多個線程在默認情況下計算的,但即使有一個線程它還是擊碎天真矢量:

In [3]: ne.set_num_threads(1) 
Out[3]: 8 

In [4]: %%timeit A, B = np.random.randn(2, 1000, 1000, 3) 
func2(A, B) 
    ....: 
10 loops, best of 3: 47.3 ms per loop 
+0

加速只是巨大的!在我的最後確認了類似的數字。 – Divakar

+0

確實令人印象深刻。謝謝! – GrigorisG

2

坦率地說,numexpr一個班輪在上市考慮到相關的加速數字,看起來像要走的路。在NumPy中保留的東西,在這篇文章中列出是一個替代建議

咱們,那些個指令的時間,看看是否有任何的瓶頸 -

In [108]: # Random input arrays 
    ...: A = np.random.rand(1000,1000,3) 
    ...: B = np.random.rand(1000,1000,3) 
    ...: 

In [109]: %timeit A**3 
1 loops, best of 3: 442 ms per loop 

In [110]: A = A ** 3 

In [111]: %timeit np.maximum(A, 0.001) 
100 loops, best of 3: 16.4 ms per loop 

In [112]: A = np.maximum(A, 0.001) 

In [113]: %timeit np.divide(B, A) 
10 loops, best of 3: 19.7 ms per loop 

所以,似乎功率計算佔據了總運行時間的很大一部分。

讓我們在那裏介紹np.einsum,但請注意涉及的數據類型。

In [114]: # Random input arrays 
    ...: A = np.random.rand(1000,1000,3) 
    ...: B = np.random.rand(1000,1000,3) 
    ...: 

In [115]: %timeit A**3 
1 loops, best of 3: 442 ms per loop 

In [116]: %timeit np.einsum('ijk,ijk,ijk->ijk',A,A,A) 
10 loops, best of 3: 28.3 ms per loop 

In [117]: np.allclose(A**3,np.einsum('ijk,ijk,ijk->ijk',A,A,A)) 
Out[117]: True 

這是一個很好的加速。