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?
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.
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)`.
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.
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.