2017-01-16 36 views
0

私は、いくつかの計算にそれを使用するために、collections.dequeを使用してPythonで循環バッファを実装しています。これは私のオリジナルコードです:dequeを使用するよりもPythonの高速循環バッファ?

clip=moviepy.editor.VideoFileClip('file.mp4') 
clip_size= clip.size[::-1] 
Depth=30 
dc=5 
TempKern = # some array of size Depth 
RingBuffer=deque(np.zeros(clip_size, dtype=float),maxlen=NewDepth) 
modified_clip = clip.fl_image(new_filtered_output) 
modified_clip.write_videofile('output.mp4')) 

def new_filtered_output(image): 
    global RingBuffer 
    inter_frame=somefunction(image)# inter_frame and image shape is same as clip_size 
    RingBuffer.append(inter_frame) 
    # Apply kernel 
    Output = dc + np.sum([np.asarray(RingBuffer)[j]*TempKern[j] for j in range(Depth)],axis=0) 
    return Output 

これは最も速い方法ですか?私は指輪がオプションであると聞きました。しかし、私はそれが上記のコードのように振る舞うようにする方法を知らないのですか?

+0

このバッファのための現実的なサイズは何ですか?内容は常にこのような2次元配列の固定サイズですか? – hpaulj

+0

使用する予定のバッファは(30、1080、720)です。したがって、バッファのmaxlenはここでは012です。 – GKS

+0

合計部分は 'np.einsum( 'ijk、i'、np.array(buf)、TempKern)'や 'tensordot'等価でスチーム化することができます。 – hpaulj

答えて

1

をあなたはサイズやスライスを倍にすることによって、numpyの配列としてリングバッファを持つことができます。

clipsize = clip.size[::-1] 
depth = 30 
ringbuffer = np.zeros((2*depth,) + clipsize) 

framecounter = 0 

def new_filtered_output(image): 
    global ringbuffer, framecounter 
    inter_frame = somefunction(image) 

    idx = framecounter % depth 
    ringbuffer[idx] = ringbuffer[idx + depth] = inter_frame 
    buffer = ringbuffer[idx + 1 : idx + 1 + depth] 
    framecounter += 1 

    # Apply kernel 
    output = dc + np.sum([buffer[j]*kernel[j] for j in range(depth)], axis=0) 
    return output 

今、あなたが持っていませんdequeをフレームごと(およびすべてのループ反復..)のnumpy配列に変換します。

コメントで述べたように、あなたはより多くのeffecientlyカーネルを適用することができますが:

output = dc + np.einsum('ijk,i->jk', buffer, kernel) 

または:

output = dc + np.tensordot(kernel, buffer, axes=1) 
+0

この回答は本当に物事をスピードアップ。ありがとう。私の他の質問も見ていただけますか?http://stackoverflow.com/questions/41686611/fast-cubic-spline-output-computation-given-segments-and-coefficients – GKS

2

私は上記のコードを変更気づいたが、あなたのオリジナルのコードは:

def one(): 
    TempKern=np.array([1,2,3,4,5]) 
    depth=len(TempKern) 
    buf=deque(np.zeros((2,3)),maxlen=5) 
    for i in range(10): 
     buf.append([[i,i+1,i+2],[i+3,i+4,i+5]]) 
    total= + np.sum([np.asarray(buf)[j]*TempKern[j] for j in range(depth)],axis=0) 
    print('total') 
    print(total) 
    return total 

あなたが大幅に物事を簡素化し、あなたが最初の計算のための配列を平ら場合、それはかなり高速に実行することができます。

def two(): 
    buf = np.zeros((5,6), dtype=np.int32) 
    for idx, i in enumerate(range(5, 10)): 
     buf[idx] = np.array([[i,i+1,i+2,i+3,i+4,i+5]], dtype=np.int32) 
    return (buf.T * np.array([1, 2, 3, 4, 5])).sum(axis=1).reshape((2,3)) 

第2の実現には、同じ値を返し、

one() 

>> [[115 130 145] 
    [160 175 190]] ~ 100µs/loop 

two() 

>> array([[115, 130, 145], 
      [160, 175, 190]]) ~~ 26µs/loop 

あなたはさらに簡素化し、そのようにこれをパラメータ化することができますより速く私のマシンでは約4倍を実行します:

def three(n, array_shape): 
    buf = np.zeros((n,array_shape[0]*array_shape[1]), dtype=np.int32) 
    addit = np.arange(1, n+1, dtype=np.int32) 
    for idx, i in enumerate(range(n, 2*n)): 
     buf[idx] = np.arange(i, i+n+1) 
    return (buf.T * addit).sum(axis=1).reshape(array_shape) 

three(5, (2,3))

>> array([[115, 130, 145], 
      [160, 175, 190]]) ~ 17µs/loop 

2番目と3番目のバージョンはnumpyの配列を返します。必要に応じて.tolist()を使用してリストにキャストすることができます。あなたのフィードバックに基づいて

- 以下の編集:

def four(array_shape): 
    n = array_shape[0] * array_shape[1] - 1 
    buf = [] 
    addit = np.arange(1, n+1, dtype=np.int32) 
    for idx, i in enumerate(range(n, 2*n)): 
     buf.append(np.arange(i, i+n+1)) 
    buf = np.asarray(buf) 
    summed = (buf.T * addit).sum(axis=1) 
    return summed.reshape(array_shape) 
+0

答えグレッグありがとうございます。しかし、追加の部分は、現在のバージョンの質問ではそれほど簡単ではありません。関数は、バッファに要素を追加するために使用されます。そして、私は、どれだけの要素が合計で追加されるかを事前に知っていません。しかし、バッファサイズは固定です。 – GKS

+0

次に、buf [idx] = np.arange(i、n + 1)をbuf [idx] = func(idx、i、n)に変更するだけで、 ) '?私の編集 'four()'を参照してください –

+0

buf_tmpとは何ですか?buf_tmpでdoenに追加していますか?それは私にとってはうまくいかないようです。 buf_tmp = np.ones(n、dtype = np.int32) i <10: buf_tmp.append(np.random.randn(2,3).flatten()) i + = 1 print buf_tmp buf = np.asarray(buf_tmp) 合計=(buf.T * addit).sum(軸= 1).reshape(array_shape)。 ValueError: 'axis'エントリが範囲外です---> 15合計=(buf.T * addit).sum(軸= 1).reshape(array_shape) – GKS

関連する問題