使用numba對numpy加速遇到的坑


問題一:

numba.errors.UntypedAttributeError: Failed at nopython (nopython frontend)
Unknown attribute 'fill' of type array(float64, 2d, C)

經過查閱以下文檔: numba.pydata.org/numba-doc/latest/reference/numpysupported.html

發現numba並不支持 np.fill()。因此將代碼改成:

    background = np.zeros((sourceIm.shape[0], sourceIm.shape[1])) # supported
    for i, j in np.ndindex(background.shape): # np.fill not supported by numba
        background[i,j] = threshold
    background=background.astype(np.float32)

 

問題二:

numba.errors.TypingError: Failed at nopython (nopython frontend)

Internal error at <numba.typeinfer.CallConstraint object at 0x7f726d5ba8>:

numba.errors.InternalError: 'Integer' object has no attribute 'ndim'

[1] During: resolving callee type: Function(<function where at 0x7f86f67bf8>)

[2] During: typing of call at test_depth_im.py (24)

查看錯誤出現位置,發現在np.where(),但查詢上述文檔,發現numba是支持np.where()的。於是懷疑是數據類型未指明導致nopython模式無法啟動。

在np.where()之前添加如下兩行代碼,以檢查numba推斷出的類型:

@njit(float32[:,:,:](float32[:,:,:], float32),parallel=True, fastmath=True) 
def depthFilter(depthInfo, threshold):
    #print(numba.typeof(depthInfo))
    #print(numba.typeof(threshold))

不料竟然又報錯:

numba.errors.TypingError: Failed at nopython (nopython frontend)
Untyped global name 'numba': cannot determine Numba type of <class 'object'>

numba.errors.UntypedAttributeError: Failed at nopython (nopython frontend)
Unknown attribute 'typeof' of type Module(<module 'numba' from '/usr/lib/python3/dist-packages/numba/__init__.py'>)

解決方法: 將函數上方的njit裝飾器注釋掉即可 ()

數據類型為:

array(int32, 3d, C)
float64

於是考慮將數據類型轉化一致

1. 數組需要用np.astype()轉換: x=x.astype(np.float32)

2. 標量通過加點: 7300 -> 7300. 並在裝飾器中指明signature為 float32

否則可能遇到如下錯誤:

Traceback (most recent call last):
File "test_depth_im.py", line 47, in <module>
depthFilter(float(x),7300.)
TypeError: only size-1 arrays can be converted to Python scalars

或者:

numba.errors.TypingError: Failed at nopython (nopython frontend)
Invalid usage of type(CPUDispatcher(<function SQDIFF at 0x7f8afcc840>)) with parameters (array(float64, 2d, C), array(float32, 2d, A))
Known signatures:
* (array(float32, 2d, A), array(float32, 2d, A)) -> float32
* parameterized

總之,使用裝飾器的signature功能顯示指出形參和返回值類型,並在函數調用前做好類型轉換,確保形參類型一致。

回到一開始的np.where()報錯問題,幸好看到了這個鏈接:github.com/numba/numba/issues/3650

depthInfo = np.where(depthInfo<threshold, depthInfo, threshold)

在普通的python代碼中,如果threshold是標量,depthInfo無論是幾維的數組,代碼都是沒有問題的。但是如果使用如上的numba裝飾器對代碼加速,則出現問題二一開始的錯誤。根據issue中的解決方法,我們需要構造一個維度和尺寸一樣的數組,並將其填滿需要替換的值:

background = np.zeros((depthInfo.shape[0], depthInfo.shape[1], depthInfo.shape[2])) # supported
    for i,j,k in np.ndindex(background.shape):
        background[i,j,k]=threshold
    background=background.astype(np.float32)
    depthInfo = np.where(depthInfo<threshold, depthInfo, background) # supported

numba不再報錯了。

問題三:

numba.errors.InternalError: tuple index out of range

[1] During: typing of static-get-item at test_depth_im.py (28)

同樣出現在以上代碼中(修改前),這主要是維度一致的問題,如果depthInfo和background維度不一樣就會報這個錯誤;此外,裝飾器signature中的數組維度應與實際數據一致。

 

總結:

1.  numba 的nopython模式對數據類型的一致性要求很高,在使用較復雜的數據(多維矩陣、浮點數(小數))進行運算時,最好提前做好類型轉換和聲明的工作,以免產生谷歌都搜不到的錯誤。

2. numba支持的numpy類型和函數等可以查閱官方文檔:numba.pydata.org/numba-doc/latest/reference/numpysupported.html

3.使用以上numba裝飾器對numpy加速的結果:

序號 numba編譯時間(s) numba加速執行時間(s) 無numba加速執行時間(s)
1 1.359856367111206 0.05226278305053711 3.891127586364746
2 1.3733365535736084 0.052794694900512695 2.9139089584350586
3 1.3658461570739746 0.052443504333496094 2.358830451965332

 

threshold


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM