私はできるだけ早く実行するためにPythonでループを取得しようとしています。だから私はNumPyとCythonに飛び込んだ。これは、k個のインデックスを超えるだけの合計ですPython/Cythonループを高速化します。
def calculate_bsf_u_loop(uvel,dy,dz):
"""
Calculate barotropic stream function from zonal velocity
uvel (t,z,y,x)
dy (y,x)
dz (t,z,y,x)
bsf (t,y,x)
"""
nt = uvel.shape[0]
nz = uvel.shape[1]
ny = uvel.shape[2]
nx = uvel.shape[3]
bsf = np.zeros((nt,ny,nx))
for jn in range(0,nt):
for jk in range(0,nz):
for jj in range(0,ny):
for ji in range(0,nx):
bsf[jn,jj,ji] = bsf[jn,jj,ji] + uvel[jn,jk,jj,ji] * dz[jn,jk,jj,ji] * dy[jj,ji]
return bsf
: はここで、元のPythonコードです。配列のサイズは、nt = 12、nz = 75、ny = 559、nx = 1442、〜725万要素です。 それは68秒かかりました。さて、私はcythonで
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False) # turn off bounds-checking for entire function
@cython.wraparound(False) # turn off negative index wrapping for entire function
## Use cpdef instead of def
## Define types for arrays
cpdef calculate_bsf_u_loop(np.ndarray[np.float64_t, ndim=4] uvel, np.ndarray[np.float64_t, ndim=2] dy, np.ndarray[np.float64_t, ndim=4] dz):
"""
Calculate barotropic stream function from zonal velocity
uvel (t,z,y,x)
dy (y,x)
dz (t,z,y,x)
bsf (t,y,x)
"""
## cdef the constants
cdef int nt = uvel.shape[0]
cdef int nz = uvel.shape[1]
cdef int ny = uvel.shape[2]
cdef int nx = uvel.shape[3]
## cdef loop indices
cdef ji,jj,jk,jn
## cdef. Note that the cdef is followed by cython type
## but the np.zeros function as python (numpy) type
cdef np.ndarray[np.float64_t, ndim=3] bsf = np.zeros([nt,ny,nx], dtype=np.float64)
for jn in xrange(0,nt):
for jk in xrange(0,nz):
for jj in xrange(0,ny):
for ji in xrange(0,nx):
bsf[jn,jj,ji] += uvel[jn,jk,jj,ji] * dz[jn,jk,jj,ji] * dy[jj,ji]
return bsf
とそれをして49分を要しました。 しかし、
for jn in range(0,nt):
for jk in range(0,nz):
bsf[jn,:,:] = bsf[jn,:,:] + uvel[jn,jk,:,:] * dz[jn,jk,:,:] * dy[:,:]
のためのループを交換することのみ0.29秒かかります!残念ながら、私は完全なコードでこれを行うことはできません。
NumPyがCythonループよりもはるかに高速にスライスするのはなぜですか? 私はNumPyが速かったと思っていました。それで、彼らは似たようなスピードではないでしょうか?
ご覧のとおり、私はcythonで境界チェックを無効にしました。また、「高速数学」を使用してコンパイルしました。しかし、これはわずかなスピードアップしか与えません。 NumPyスライシングと同様の速度のループを作成するにはどうしてですか?またはスライスより常に遅くループしていますか?
ご協力いただきありがとうございます。 /ヨアキム
あなたはループ変数に型を宣言するのを忘れました。 – jepio
現在のCythonバージョンでループ変数を宣言する必要はありません。 – jakevdp
@jakevdpこの場合、それらを宣言しても正しく型を推測できるようには思えませんが、型を持たない 'cdef ji、jj、jk、jn'として宣言すると、それを放棄するようです。 – DavidW