あなたが得ることができます
にそれを減少させることに注意してください最終的な3次元結果E
は、大きな中間配列を作成せずにbatched_dot
を使用します。
import theano.tensor as tt
A = tt.tensor3('A') # A.shape = (D, N, H)
B = tt.tensor3('B') # B.shape = (D, H, K)
E = tt.batched_dot(A, B) # E.shape = (D, N, K)
残念ながら、これでは入力配列と出力配列の次元を並べ替える必要があります。これはTheanoにdimshuffle
で行うことができますが、batched_dot
が任意にストライドの配列に対応することができないので、次のことが上げ思わValueError: Some matrix has no unit stride
E
が評価されている場合:
import theano.tensor as tt
A = tt.tensor3('A') # A.shape = (N, H, D)
B = tt.tensor3('B') # B.shape = (K, H, D)
A_perm = A.dimshuffle((2, 0, 1)) # A_perm.shape = (D, N, H)
B_perm = B.dimshuffle((2, 1, 0)) # B_perm.shape = (D, H, K)
E_perm = tt.batched_dot(A_perm, B_perm) # E_perm.shape = (D, N, K)
E = E_perm.dimshuffle((1, 2, 0)) # E.shape = (N, K, D)
batched_dot
は最初(サイズD
)の次元に沿ってscan
を使用しています。順次に実行されるので、GPU上で実行されている場合、すべての製品を並列に計算するよりも計算効率が悪くなる可能性があります(scan
)。
scan
を明示的に使用してブロードキャストのアプローチでbatched_dot
アプローチと並列性のメモリ効率をトレードオフすることができます。アイデアは、並行してサイズM
のバッチのための完全な製品C
を計算することであろうscan
でバッチを反復処理、(M
と仮定するとD
の正確な要因である):
import theano as th
import theano.tensor as tt
A = tt.tensor3('A') # A.shape = (N, H, D)
B = tt.tensor3('B') # B.shape = (K, H, D)
A_batched = A.reshape((N, H, M, D/M))
B_batched = B.reshape((K, H, M, D/M))
E_batched, _ = th.scan(
lambda a, b: (a[:, :, None, :] * b[:, :, :, None]).sum(1),
sequences=[A_batched.T, B_batched.T]
)
E = E_batched.reshape((D, K, N)).T # E.shape = (N, K, D)
どの次元あなたがオーバー合計したいですか?最初の、0?または元の配列の最後から2番目の 'H'ですか? – hpaulj
'numpy'では、これは' np.einsum( 'nhd、khd-> nkd'、A、B) 'と表現することができます。 – hpaulj
私はそれをH以上にしたいと思います。これは、テンソル合計の前に形状(1、H、D)である。 – Theo