python - Entendiendo tensordot
numpy linear-algebra (2)
La idea con
tensordot
es bastante simple:
tensordot
las matrices y los ejes respectivos a los que se destinan las reducciones de suma.
Los ejes que participan en la reducción de suma se eliminan en la salida y todos los ejes restantes de las matrices de entrada se
extienden
como diferentes ejes en la salida manteniendo el orden en que se alimentan las matrices de entrada.
Veamos algunos casos de muestra con uno y dos ejes de reducción de suma y también intercambiemos los lugares de entrada y veamos cómo se mantiene el orden en la salida.
I. Un eje de reducción de suma
Entradas:
In [7]: A = np.random.randint(2, size=(2, 6, 5))
...: B = np.random.randint(2, size=(3, 2, 4))
...:
Caso 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)`
Caso # 2 (igual que el caso # 1 pero las entradas se alimentan intercambiadas):
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 Dos ejes de reducción de suma
Entradas:
In [11]: A = np.random.randint(2, size=(2, 3, 5))
...: B = np.random.randint(2, size=(3, 2, 4))
...:
Caso 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)`
Caso # 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)`
Podemos extender esto a tantos ejes como sea posible.
Después de aprender a usar
einsum
, ahora estoy tratando de entender cómo funciona
np.tensordot
.
Sin embargo, estoy un poco perdido, especialmente con respecto a las diversas posibilidades para los
axes
parámetros.
Para entenderlo, como nunca he practicado el cálculo del tensor, utilizo el siguiente ejemplo:
A = np.random.randint(2, size=(2, 3, 5))
B = np.random.randint(2, size=(3, 2, 4))
En este caso, ¿cuáles son los diferentes
np.tensordot
posibles y cómo lo calcularía manualmente?
tensordot
intercambia ejes y da nueva forma a las entradas para que pueda aplicar
np.dot
a 2 arrays 2d.
Luego se intercambia y se forma de nuevo al objetivo.
Puede ser más fácil experimentar que explicar.
No hay matemática tensorial especial, solo se extiende el
dot
para trabajar en dimensiones más altas.
tensor
solo significa matrices con más de 2d.
Si ya se siente cómodo con el
einsum
, será más sencillo comparar los resultados con eso.
Una prueba de muestra que suma 1 par de ejes.
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
otro, sumando dos.
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
Podríamos hacer lo mismo con el par
(1,0)
.
Dada la combinación de dimensiones, no creo que haya otra combinación.