2

このコードから始めて、単純な行列の乗算を計算しました。私のマシンでは約7.85秒で%timeitで実行されます。

これを高速化するために、時間を 0.4 秒に短縮した cython を試しました。また、numba jit コンパイラーを使用して、(より少ない労力で) 同様の速度向上が得られるかどうかを確認したいと考えています。しかし、@jit アノテーションを追加すると、まったく同じタイミング (~7.8 秒) が得られるようです。calculate_z_numpy() 呼び出しのタイプを理解できないことはわかっていますが、それを強制するために何ができるかわかりません。何か案は?

from numba import jit
import numpy as np

@jit('f8(c8[:],c8[:],uint)')
def calculate_z_numpy(q, z, maxiter):
    """use vector operations to update all zs and qs to create new output array"""
    output = np.resize(np.array(0, dtype=np.int32), q.shape)
    for iteration in range(maxiter):
        z = z*z + q
        done = np.greater(abs(z), 2.0)
        q = np.where(done, 0+0j, q)
        z = np.where(done, 0+0j, z)
        output = np.where(done, iteration, output)
    return output

def calc_test():
    w = h = 1000
    maxiter = 1000
    # make a list of x and y values which will represent q
    # xx and yy are the co-ordinates, for the default configuration they'll look like:
    # if we have a 1000x1000 plot
    # xx = [-2.13, -2.1242,-2.1184000000000003, ..., 0.7526000000000064, 0.7584000000000064, 0.7642000000000064]
    # yy = [1.3, 1.2948, 1.2895999999999999, ..., -1.2844000000000058, -1.2896000000000059, -1.294800000000006]
    x1, x2, y1, y2 = -2.13, 0.77, -1.3, 1.3

    x_step = (float(x2 - x1) / float(w)) * 2
    y_step = (float(y1 - y2) / float(h)) * 2
    y = np.arange(y2,y1-y_step,y_step,dtype=np.complex)
    x = np.arange(x1,x2,x_step)
    q1 = np.empty(y.shape[0],dtype=np.complex)
    q1.real = x
    q1.imag = y
    # Transpose y
    x_y_square_matrix = x+y[:, np.newaxis] # it is np.complex128
    # convert square matrix to a flatted vector using ravel
    q2 = np.ravel(x_y_square_matrix)
    # create z as a 0+0j array of the same length as q
    # note that it defaults to reals (float64) unless told otherwise
    z = np.zeros(q2.shape, np.complex128)
    output = calculate_z_numpy(q2, z, maxiter)
    print(output)

calc_test()
4

1 に答える 1

4

他の人の助けを借りてこれを行う方法を見つけました。

@jit('i4[:](c16[:],c16[:],i4,i4[:])',nopython=True)
def calculate_z_numpy(q, z, maxiter,output):
    """use vector operations to update all zs and qs to create new output array"""
    for iteration in range(maxiter):
        for i in range(len(z)):
            z[i] = z[i] + q[i]
            if z[i] > 2:
                output[i] = iteration
                z[i] = 0+0j
                q[i] = 0+0j
    return output

私が学んだことは、numpy データ構造を入力として (入力用に) 使用することですが、内部では c のようなパラダイムをループに使用するということです。

これは cython コード 0.45 秒よりもわずかに速い 402 ミリ秒で実行されるため、ループを明示的に書き換えるかなり最小限の作業のために、C(just) よりも高速な Python バージョンがあります。

于 2014-12-07T19:13:49.290 に答える