8

Python アルゴリズムを Cython に実装して最適化しようとしています。私の質問は、次のコードに存在する特定のパフォーマンスのボトルネックに関するものです。

@cython.boundscheck(False) # turn off bounds-checking for entire function
def anglesToRGB( np.ndarray[double, ndim=2] y, np.ndarray[double, ndim=2] x ):

cdef double angle
cdef double Hp
cdef double C
cdef double X
cdef np.ndarray[double, ndim=3] res = np.zeros([y.shape[0], y.shape[1], 3], dtype=np.float64)

for i in xrange(y.shape[0]):
    for j in xrange(y.shape[1]):
        angle = atan2( y[i,j], x[i,j] )*180.0/PI+180

        C = sqrt(pow(y[i,j],2)+pow(x[i,j],2))/360.0 #Chroma
        Hp = angle/60.0
        X = C*(1-fabs( Hp%2-1))

        C *= 255
        X *= 255

        if (0. <= Hp < 1.):
            res[i,j,:] = [C,X,0]
        elif (1. <= Hp < 2.):
            res[i,j,:] = [X,C,0]
        elif (2. <= Hp < 3.):
            res[i,j,:] = [0,C,X]
        elif (3. <= Hp < 4.):
            res[i,j,:] = [0,X,C]
        elif (4. <= Hp < 5.):
            res[i,j,:] = [X,C,C]
        else:
            res[i,j,:] = [C,0,X]

return res

次のように、値のリストを res 配列のスライスに割り当てるときに、主要なボトルネックを特定しました。

res[i,j,:] = [C,X,0]

ただし、割り当てを変更すると

res[i,j,0] = C
res[i,j,1] = X
res[i,j,2] = 0

その後、コードは桁違いに速く実行されます。確かにCythonコンパイラは私のためにこれを行うのに十分スマートでなければならないので、私にとってこれは奇妙です? それとも、最初にいくつかのヒントを提供する必要がありますか? スライスを : ではなく 0:3 に変更し、値のリストを numpy 配列にしても、パフォーマンスは向上しないことに注意してください。

私が知りたいのは、この操作がパフォーマンスを大幅に低下させる理由と、便利なリストとスライス表記を犠牲にすることなく解決する方法があるかどうかです。

よろしくお願いします

4

1 に答える 1

3

いいえ、Cython (0.17 でテスト済み) は、このスライス割り当てを最適化するほどスマートではありません。生成された C コードを見ると ( cython -aHTML レポートの任意の行を使用してクリックすると、生成されたコードが表示されます)、次のことがわかります。

res[i,j,:] = [C,X,0]

にコンパイルされます

  • C と Python の浮動小数点型間の変換
  • リストの割り当て[C,X,0]
  • タプルの割り当て(i, j, slice(None))
  • への呼び出しres.__setitem__
  • これらすべてのエラーチェック
  • 割り当てられた構造の割り当て解除

つまり、このコードを実行するために CPython が行うこととほとんど同じです。

これを回避するためにできることは次のとおりです。

  1. 3 つの変数を宣言しますcdef double v1, v2, v3
  2. v1, v2, v3 = C, X, 03 つの C 割り当てに最適化されている条件などでこれらに割り当てます。
  3. 条件付きブロックの後、 3 つの別々の代入v1, v2, v3res[i,j,0]etc. に代入します。
于 2012-11-05T23:32:32.920 に答える