Cython

Cythonはまだまだ全然だけど.

Cythonの書き方入門[備忘録] – Qiita

for elm in array:
….

な書き方はPythonな書き方なので,これをCに書き下すだけでかなり違うと思う.

記事をなぞっていく.

import time
import numpy as np

if __name__ == "__main__":
    start_t = time.perf_counter()

    arr_a = np.arange(1000)
    arr_b = np.arange(1000)

    res = 0
    for elem_a in arr_a:
        for elem_b in arr_b:
            res = res + elem_a + elem_b
    print(res)

    all_time = time.perf_counter() - start_t
    print("Execution time:{0} [sec]".format(all_time))

999000000
Execution time:0.4780349113991029 [sec]

%load_ext Cython
%%cython
cimport numpy as np

def cy_algo(np.ndarray[int, ndim=1] arr_a, np.ndarray[int, ndim=1] arr_b):
    cdef int res
    cdef int elem_a
    cdef int elem_b

    res = 0
    for elem_a in arr_a:
        for elem_b in arr_b:
            res = res + elem_a +elem_b
    return res
if __name__ == "__main__":
    start_t = time.perf_counter()

    arr_a = np.arange(1000)
    arr_b = np.arange(1000)

    res = cy_algo(arr_a, arr_b)
    print(res)

    all_time = time.perf_counter() - start_t
    print("Execution time:{0} [sec]".format(all_time))

999000000
Execution time:0.11450570024641138 [sec]

これを,思い付く範囲で書き直してみる.

%%cython
cimport numpy as np

ctypedef np.int_t DTYPE_t

cdef int _cy_algo(np.ndarray[DTYPE_t, ndim=1] arr_a, np.ndarray[DTYPE_t, ndim=1] arr_b):
    cdef int res = 0
    cdef int n = len(arr_a)
    cdef int m = len(arr_b)
    cdef int elem_a
    cdef int elem_b

    for elem_a in range(n):
        for elem_b in range(m):
            res = res + arr_a[elem_a] + arr_b[elem_b]
    return res


def cy_algo(arr_a, arr_b):
    return _cy_algo(arr_a, arr_b)
if __name__ == "__main__":
    start_t = time.perf_counter()

    arr_a = np.arange(1000)
    arr_b = np.arange(1000)

    res = cy_algo(arr_a, arr_b)
    print(res)

    all_time = time.perf_counter() - start_t
    print("Execution time:{0} [sec]".format(all_time))

999000000
Execution time:0.0019004301284439862 [sec]

これだけで,Cファイル呼び出しと遜色ない結果に.

len(arr_a)の部分とか,res = res + arr_a[elem_a] + arr_b[elem_b]とか,
最適化できる部分はまだまだあるんだろうけど.numpyを高速化しようと思って,
mallocに置き換えたり,いろいろ試行錯誤した事があるけど,結果はパッとせず泥沼に.
結局,Cythonは難しいなあ……という思いだけ残ったり…….

numpyを高速化する場合,Numbaの方がお手軽な上実効性が高い(事が期待できる).
(ちなみに,その時も結局Numbaの方が良いパフォーマンスを示した)

from numba import jit

@jit
def numba_algo(arr_a, arr_b):
    res = 0
    for elem_a in arr_a:
        for elem_b in arr_b:
            res = res + elem_a +elem_b
    return res
if __name__ == "__main__":
    start_t = time.perf_counter()

    arr_a = np.arange(1000)
    arr_b = np.arange(1000)

    res = numba_algo(arr_a, arr_b)
    print(res)

    all_time = time.perf_counter() - start_t
    print("Execution time:{0} [sec]".format(all_time))

999000000
Execution time:0.0005042525647240836 [sec]

Cythonを使いこなせれば,Numbaよりも良いパフォーマンスを出せるのだろうか.
 
 
 
ちなみに,Numpy(的な方法)と比較.

start_t = time.perf_counter()
print(np.sum(arr_a[:, np.newaxis]+arr_b))
all_time = time.perf_counter() - start_t
print("Execution time:{0} [sec]".format(all_time))

999000000
Execution time:0.005895126601899392 [sec]

広告
カテゴリー: 未分類 パーマリンク

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中