web-dev-qa-db-ja.com

テンソルドットを理解する

einsumの使用方法を学んだ後、np.tensordot動作します。

ただし、パラメータaxesのさまざまな可能性に関して、特に少し迷っています。

それを理解するために、私はテンソル計算を練習したことがないので、次の例を使用します。

A = np.random.randint(2, size=(2, 3, 5))
B = np.random.randint(2, size=(3, 2, 4))

この場合、可能な異なるnp.tensordotそして、手動でどのように計算しますか?

20
floflo29

tensordotのアイデアは非常に単純です-配列とそれぞれの軸を入力し、それに沿って和の削減が意図されます。 sum-reductionに関与する軸は出力から削除され、入力配列の残りの軸はすべてspread-outです。出力の異なる軸は入力配列の順序を維持します食べた。

1軸と2軸の合計削減のあるいくつかのサンプルケースを見て、入力場所を交換して、出力で順序がどのように保持されるかを見てみましょう。

I.和の削減の1つの軸

入力:

 In [7]: A = np.random.randint(2, size=(2, 6, 5))
   ...:  B = np.random.randint(2, size=(3, 2, 4))
   ...: 

ケース#1:

In [9]: np.tensordot(A, B, axes=((0),(1))).shape
Out[9]: (6, 5, 3, 4)

A : (2, 6, 5) -> reduction of axis=0
B : (3, 2, 4) -> reduction of axis=1

Output : `(2, 6, 5)`, `(3, 2, 4)` ===(2 gone)==> `(6,5)` + `(3,4)` => `(6,5,3,4)`

ケース#2(ケース#1と同じですが、入力はフィード交換されます):

In [8]: np.tensordot(B, A, axes=((1),(0))).shape
Out[8]: (3, 4, 6, 5)

B : (3, 2, 4) -> reduction of axis=1
A : (2, 6, 5) -> reduction of axis=0

Output : `(3, 2, 4)`, `(2, 6, 5)` ===(2 gone)==> `(3,4)` + `(6,5)` => `(3,4,6,5)`.

II。合計削減の2つの軸

入力:

In [11]: A = np.random.randint(2, size=(2, 3, 5))
    ...: B = np.random.randint(2, size=(3, 2, 4))
    ...: 

ケース#1:

In [12]: np.tensordot(A, B, axes=((0,1),(1,0))).shape
Out[12]: (5, 4)

A : (2, 3, 5) -> reduction of axis=(0,1)
B : (3, 2, 4) -> reduction of axis=(1,0)

Output : `(2, 3, 5)`, `(3, 2, 4)` ===(2,3 gone)==> `(5)` + `(4)` => `(5,4)`

ケース#2:

In [14]: np.tensordot(B, A, axes=((1,0),(0,1))).shape
Out[14]: (4, 5)

B : (3, 2, 4) -> reduction of axis=(1,0)
A : (2, 3, 5) -> reduction of axis=(0,1)

Output : `(3, 2, 4)`, `(2, 3, 5)` ===(2,3 gone)==> `(4)` + `(5)` => `(4,5)`

これをできるだけ多くの軸に拡張できます。

27
Divakar

tensordotは、2つの2D配列にnp.dotを適用できるように、軸を交換して入力を整形します。次に、スワップしてターゲットに形状を戻します。説明するよりも実験する方が簡単かもしれません。特別なテンソル計算は行われず、dotを拡張して高次元で機能するようになります。 tensorは、2d以上の配列を意味します。すでにeinsumに慣れている場合は、結果をそれと比較するのが最も簡単です。

1組の軸で合計するサンプルテスト

In [823]: np.tensordot(A,B,[0,1]).shape
Out[823]: (3, 5, 3, 4)
In [824]: np.einsum('ijk,lim',A,B).shape
Out[824]: (3, 5, 3, 4)
In [825]: np.allclose(np.einsum('ijk,lim',A,B),np.tensordot(A,B,[0,1]))
Out[825]: True

別の、2で合計。

In [826]: np.tensordot(A,B,[(0,1),(1,0)]).shape
Out[826]: (5, 4)
In [827]: np.einsum('ijk,jim',A,B).shape
Out[827]: (5, 4)
In [828]: np.allclose(np.einsum('ijk,jim',A,B),np.tensordot(A,B,[(0,1),(1,0)]))
Out[828]: True

(1,0)ペアでも同じことができます。次元の組み合わせを考えると、別の組み合わせはないと思います。

4
hpaulj