7

セクション長が可変の配列の要素を合計する関数を実装する必要があります。それで、

a = np.arange(10)
section_lengths = np.array([3, 2, 4])
out = accumulate(a, section_lengths)
print out
array([  3.,   7.,  35.])

私はここで実装を試みましcythonた:

https://gist.github.com/2784725

numpyパフォーマンスのために、section_lengthsがすべて同じである場合の純粋なソリューションと比較しています。

LEN = 10000
b = np.ones(LEN, dtype=np.int) * 2000
a = np.arange(np.sum(b), dtype=np.double)
out = np.zeros(LEN, dtype=np.double)

%timeit np.sum(a.reshape(-1,2000), axis=1)
10 loops, best of 3: 25.1 ms per loop

%timeit accumulate.accumulate(a, b, out)
10 loops, best of 3: 64.6 ms per loop

パフォーマンスを改善するための提案はありますか?

4

2 に答える 2

2

次のいくつかを試してみてください。

  • @cython.boundscheck(False)コンパイラ指令に加えて、追加してみてください@cython.wraparound(False)

  • setup.pyスクリプトで、いくつかの最適化フラグを追加してみてください。

    ext_modules = [Extension("accumulate", ["accumulate.pyx"], extra_compile_args=["-O3",])]

  • によって生成された.htmlファイルを見て、cython -a accumulate.pyx静的型付けが欠落しているセクションや、PythonC-API呼び出しに大きく依存しているセクションがあるかどうかを確認します。

    http://docs.cython.org/src/quickstart/cythonize.html#determining-where-to-add-types

  • returnメソッドの最後にステートメントを追加します。現在、のタイトループで不要なエラーチェックを行っていますi_el += 1

  • cdef unsigned intそれが違いを生むかどうかはわかりませんが、私は単にループカウンターを作るのではなく、ループカウンターを作る傾向がありますint

また、コードが等しくない場合は、コードをnumpyと比較することもできます。section_lengthsこれは、単純なコードよりも少し多くのコードが必要になる可能性があるためですsum

于 2012-05-25T00:33:48.100 に答える
1

ネストforループの更新out[i_bas]が遅い場合は、一時変数を作成して累積を実行し、out[i_bas]ネストforループが終了したときに更新できます。次のコードは、numpyバージョンと同じくらい高速になります。

import numpy as np
cimport numpy as np

ctypedef np.int_t DTYPE_int_t
ctypedef np.double_t DTYPE_double_t

cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def accumulate(
       np.ndarray[DTYPE_double_t, ndim=1] a not None,
       np.ndarray[DTYPE_int_t, ndim=1] section_lengths not None,
       np.ndarray[DTYPE_double_t, ndim=1] out not None,
       ):
    cdef int i_el, i_bas, sec_length, lenout
    cdef double tmp
    lenout = out.shape[0]
    i_el = 0
    for i_bas in range(lenout):
        tmp = 0
        for sec_length in range(section_lengths[i_bas]):
            tmp += a[i_el]
            i_el+=1
        out[i_bas] = tmp
于 2012-05-25T02:16:56.240 に答える