web-dev-qa-db-fra.com

Comprendre Tensordot

Après avoir appris à utiliser einsum, j'essaie maintenant de comprendre comment np.tensordot travaux.

Cependant, je suis un peu perdu surtout en ce qui concerne les différentes possibilités pour le paramètre axes.

Pour le comprendre, comme je n'ai jamais pratiqué le calcul tensoriel, j'utilise l'exemple suivant:

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

Dans ce cas, quelles sont les différentes possibilités np.tensordot et comment le calculeriez-vous manuellement?

20
floflo29

L'idée avec tensordot est assez simple - Nous entrons les tableaux et les axes respectifs le long desquels les sommes-réductions sont destinées. Les axes qui participent à la réduction de somme sont supprimés dans la sortie et tous les axes restants des tableaux d'entrée sont répartis en tant qu'axes différents dans la sortie en gardant l'ordre dans lequel les tableaux d'entrée sont nourris.

Examinons quelques exemples de cas avec un et deux axes de réduction de somme et échangeons également les emplacements d'entrée et voyons comment l'ordre est conservé dans la sortie.

I. Un axe de réduction des sommes

Contributions :

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

Cas 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)`

Cas # 2 (identique au cas # 1 mais les entrées sont échangées):

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. Deux axes de somme-réduction

Contributions :

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

Cas 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)`

Cas n ° 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)`

Nous pouvons l'étendre à autant d'axes que possible.

27
Divakar

tensordot permute les axes et remodèle les entrées pour pouvoir les appliquer np.dot à 2 tableaux 2D. Il échange ensuite et remodèle vers la cible. Il peut être plus facile d'expérimenter que d'expliquer. Il n'y a pas de calcul tensoriel spécial en cours, il suffit d'étendre dot pour travailler dans des dimensions plus élevées. tensor signifie simplement des tableaux avec plus de 2d. Si vous êtes déjà à l'aise avec einsum alors il sera plus simple de comparer les résultats à cela.

Un échantillon de test, additionnant sur 1 paire d'axes

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

un autre, résumant à deux.

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

Nous pourrions faire de même avec le (1,0) paire. Étant donné le mélange de dimensions, je ne pense pas qu'il y ait une autre combinaison.

4
hpaulj