2017-04-04 3 views
2

こんにちはnumpyを使用して、LSTMのタイムステップと複数の機能を持つ新しい配列を作成しています。タイムステップと複数のフィーチャ(LSTMなど)を使用して新しい配列を作成する

私は、ストライドと再形成を使っていくつかのアプローチを検討しましたが、効率的な解決策を見つけることはできませんでした。

ここにおもちゃの問題を解決する関数がありますが、私はそれぞれが100個の特徴を持つ30,000サンプルを持っています。

def make_timesteps(a, timesteps): 
     array = [] 
     for j in np.arange(len(a)): 
      unit = [] 
      for i in range(timesteps): 
       unit.append(np.roll(a, i, axis=0)[j]) 
      array.append(unit) 
     return np.array(array) 

inArr = np.array([[1, 2], [3,4], [5,6]])

inArr.shape =>(3、2)

outArr = make_timesteps(inArr, 2)

outArr.shape =>(3、2、2)

assert(np.array_equal(outArr, 
      np.array([[[1, 2], [3, 4]], [[3, 4], [5, 6]], [[5, 6], [1, 2]]]))) 

=> True

誰かが助けてくれますか?これを行うもっと効率的な方法がありますか?

答えて

1

最後に、L-1の行を最後に追加して、配列の先頭に追加する方法があります。それでは、非常に効率的なNumPy stridesを使用する単純なケースになります。このトリックのコストについて疑問を抱く人にとっては、タイミングテストを通して後で説明するように、それは何も得意ではありません。

両方の前方と後方のコードに跨ぐはこのようになりますサポートする最終的な目標件までをリードするトリック -

後方ストライド:

def strided_axis0_backward(inArr, L = 2): 
    # INPUTS : 
    # a : Input array 
    # L : Length along rows to be cut to create per subarray 

    # Append the last row to the start. It just helps in keeping a view output. 
    a = np.vstack((inArr[-L+1:], inArr)) 

    # Store shape and strides info 
    m,n = a.shape 
    s0,s1 = a.strides 

    # Length of 3D output array along its axis=0 
    nd0 = m - L + 1 

    strided = np.lib.stride_tricks.as_strided  
    return strided(a[L-1:], shape=(nd0,L,n), strides=(s0,-s0,s1)) 

フォワードストライド:

def strided_axis0_forward(inArr, L = 2): 
    # INPUTS : 
    # a : Input array 
    # L : Length along rows to be cut to create per subarray 

    # Append the last row to the start. It just helps in keeping a view output. 
    a = np.vstack((inArr , inArr[:L-1])) 

    # Store shape and strides info 
    m,n = a.shape 
    s0,s1 = a.strides 

    # Length of 3D output array along its axis=0 
    nd0 = m - L + 1 

    strided = np.lib.stride_tricks.as_strided  
    return strided(a[:L-1], shape=(nd0,L,n), strides=(s0,s0,s1)) 

サンプルラン -

In [42]: inArr 
Out[42]: 
array([[1, 2], 
     [3, 4], 
     [5, 6]]) 

In [43]: strided_axis0_backward(inArr, 2) 
Out[43]: 
array([[[1, 2], 
     [5, 6]], 

     [[3, 4], 
     [1, 2]], 

     [[5, 6], 
     [3, 4]]]) 

In [44]: strided_axis0_forward(inArr, 2) 
Out[44]: 
array([[[1, 2], 
     [3, 4]], 

     [[3, 4], 
     [5, 6]], 

     [[5, 6], 
     [1, 2]]]) 

ランタイムテスト - strided_axis0

In [53]: inArr = np.random.randint(0,9,(1000,10)) 

In [54]: %timeit make_timesteps(inArr, 2) 
    ...: %timeit strided_axis0_forward(inArr, 2) 
    ...: %timeit strided_axis0_backward(inArr, 2) 
    ...: 
10 loops, best of 3: 33.9 ms per loop 
100000 loops, best of 3: 12.1 µs per loop 
100000 loops, best of 3: 12.2 µs per loop 

In [55]: %timeit make_timesteps(inArr, 10) 
    ...: %timeit strided_axis0_forward(inArr, 10) 
    ...: %timeit strided_axis0_backward(inArr, 10) 
    ...: 
1 loops, best of 3: 152 ms per loop 
100000 loops, best of 3: 12 µs per loop 
100000 loops, best of 3: 12.1 µs per loop 

In [56]: 152000/12.1 # Speedup figure 
Out[56]: 12561.98347107438 

タイミングが、我々は、出力にサブアレイの長さを増加させたとしても同じまま。それはちょうど私達にstridesと巨大な恩恵を示してくれるだけでなく、元の偽のバージョンよりも狂気のスピードアップを示しています。タイミングはかなり効率的な一つであることがスタッキングの考えを支持

In [417]: inArr = np.random.randint(0,9,(1000,10)) 

In [418]: L = 10 

In [419]: %timeit np.vstack((inArr[-L+1:], inArr)) 
100000 loops, best of 3: 5.41 µs per loop 

- 開始時に約束したよう

、ここでタイミングがnp.vstackとコストを積み重ねの上にあります。

+0

本当に助けてくれました。以前はas_stridedと思っていましたが、あなたの例とリンクまで理解できませんでした。私は最終的なコードを表示するために質問を編集しました。同じ順序を得るために、私は最初の行を最後に追加し、次に軸1にnp.flipを追加しました。 – nickyzee

+0

@nickyzeeなぜ私は「フリップ」が必要なのか分かりません。あなたの 'make_timesteps'は正しいですか?' make_timesteps'と同じ結果を出すようにコーディングしたからです。あなたのフリップの提案では、私のコードは 'make_timesteps'とは異なる結果をもたらします。これを明確にする?面白い - 私は元のものと同じ出力を作るためにフリップが必要です。 – Divakar

+0

出力の目視検査もこれを確認します。私が元々返す 'array [[[1、2]、 [3,4]]、 [[3,4]、 [5、6]] 、 [5,6]、 [7、8]、 [7、8]、 [1、2]]]) ' – nickyzee

関連する問題