Numba - Python実行時コンパイラ

Numba: A High Performance Python Compiler
使い方は簡単(ということにしておく)。pip install numba などでインストールしたあと

from numba import jit

@jit(nopython=True)
def function():
    ~

以下のコードはLBPの基本機能を書いてみたのだが遅すぎて使えなかったもの。
細かくいじれば何割かは速くなるかもしれないが焼け石に水だ。

def lbp(img): 
    h, w = img.shape
    res = np.zeros((h, w), np.uint8)

    order = [0, 1, 2, 5, 8, 7, 6, 3]
    weight = [128, 64, 32, 16, 8, 4, 2, 1]
    for i in range(1, h-1):
        for j in range(1, w-1):
            nb = (img[i-1:i+2, j-1:j+2] <= img[i,j]).ravel()
            val = 0
            for (od, wt) in zip(order, weight):
                if nb[od]: val += wt

            res[i, j] = val

    return res

このコードにnumbaを導入したところ約19倍、十分使える速さになった。

from numba import jit
import timeit

@jit(nopython=True)
def lbp(img):
	~ 略 ~

img = cv2.imread("mandrill.png", 0)
n = 3
result = timeit.repeat(lambda: lbp(img), number=n)
print(min(result)/n)

さらにループの並列処理化(parallel=True、range -> numba.prange)及びlist -> ndarrayで38倍にまで上がった。

from numba import jit, prange

@jit(nopython=True, parallel=True)
def lbp(img): 
		~ 略 ~
    order = np.array([0, 1, 2, 5, 8, 7, 6, 3])
    weight = np.array([128, 64, 32, 16, 8, 4, 2, 1])
    for i in prange(1, h-1):	# 一番外側だけ
        for j in range(1, w-1):	# 内側はそのまま
		~ 略 ~

@jitなし
0.8785514999957135

@jitあり
0.045470933332884066

@jit + prange
0.023035266659765814

ちなみに関数の出力はこんなふうになる。
https://kakasi.skr.jp/images/mandrill-lbp.png