En el tema anterior vimos qué son los tensores y por qué ocupan un lugar central dentro de PyTorch. Aprendimos que los tensores representan datos, parámetros, salidas y gradientes.
Sin embargo, conocer un objeto no es suficiente. El paso siguiente es aprender a operar con él. En Deep Learning no solo almacenamos tensores: los sumamos, multiplicamos, reorganizamos, recortamos, combinamos y transformamos constantemente.
Por eso este tema es fundamental. Aquí veremos las operaciones básicas con tensores, explicadas de forma clara y gradual, pensando en un estudiante que está dando sus primeros pasos en PyTorch.
Operar con un tensor significa aplicar sobre él alguna transformación matemática o estructural.
Por ejemplo:
Estas operaciones son las que permiten que una red neuronal procese información y produzca resultados.
Cuando una red neuronal funciona, lo hace a través de operaciones sobre tensores. No hay magia: lo que ocurre en cada capa es, en gran parte, cálculo entre tensores.
Por ejemplo:
Por eso, antes de construir modelos más completos, conviene dominar bien estas operaciones básicas.
Para estudiar operaciones conviene partir de ejemplos pequeños. Por ejemplo:
Con estos dos tensores podemos practicar suma, resta, multiplicación y otras operaciones de manera simple.
Trabajar con ejemplos pequeños tiene una ventaja didáctica muy importante: permite entender la lógica antes de pasar a estructuras más grandes.
Una de las operaciones más básicas es la suma. Si dos tensores tienen la misma forma, PyTorch puede sumarlos elemento por elemento.
El resultado será un tensor con valores [5, 7, 9].
Es importante notar que la suma se hace posición por posición: el primer elemento con el primero, el segundo con el segundo y así sucesivamente.
La resta funciona de manera similar a la suma. Si dos tensores tienen formas compatibles, PyTorch resta cada elemento con el correspondiente.
El resultado será [9, 18, 27].
Esta operación aparece constantemente cuando calculamos diferencias entre predicciones y valores reales.
Una cuestión importante es distinguir entre distintos tipos de multiplicación. Si escribimos:
PyTorch realiza una multiplicación elemento a elemento.
El resultado será [4, 10, 18]. Cada posición se multiplica con la posición correspondiente.
Esta idea es muy importante, porque no debe confundirse con el producto matricial, que tiene otra lógica.
También podemos dividir tensores elemento por elemento:
La lógica vuelve a ser la misma: cada componente de un tensor se divide por el componente correspondiente del otro tensor.
En este caso conviene usar números de punto flotante para evitar confusiones y obtener resultados decimales cuando haga falta.
No siempre operamos tensor contra tensor. Muchas veces también combinamos un tensor con un número escalar.
En el primer caso, se suma 10 a cada elemento. En el segundo, cada elemento se multiplica por 2.
Esta forma de trabajo es muy frecuente y resulta muy cómoda para aplicar transformaciones uniformes.
También podemos elevar cada elemento de un tensor a una potencia o aplicar otras operaciones matemáticas básicas.
El resultado será [1.0, 4.0, 9.0].
Estas transformaciones son útiles en muchas expresiones matemáticas, por ejemplo en algunos tipos de funciones de pérdida.
PyTorch ofrece muchas funciones matemáticas que se aplican a tensores completos. Por ejemplo, se pueden calcular raíces, exponenciales, logaritmos, senos y otras transformaciones.
Aquí la raíz cuadrada se calcula para cada elemento del tensor.
Esto refuerza una idea central: muchas operaciones en PyTorch se aplican de manera natural a todos los valores de la estructura.
Además de transformar tensores, muchas veces necesitamos resumir la información que contienen.
Por ejemplo, podemos calcular:
Estas operaciones se conocen como reducciones, porque toman muchos valores y producen un resultado más pequeño.
Para obtener la suma total de un tensor, se usa sum():
La salida será 10.
Esto puede ser útil, por ejemplo, al acumular errores, contar activaciones o construir algunas métricas.
PyTorch también permite obtener medidas básicas de un tensor:
Estas funciones ayudan a inspeccionar valores y comprender la escala de los datos o de los resultados de una capa.
Una operación muy importante es acceder a elementos específicos de un tensor. Esto se hace mediante índices, igual que en muchas estructuras de Python.
El índice 0 accede al primer elemento y el índice 2 al tercero.
La indexación es fundamental porque nos permite inspeccionar o manipular partes concretas de un tensor.
Cuando el tensor tiene dos dimensiones, necesitamos indicar fila y columna.
En el primer caso accedemos a la fila 0, columna 1. En el segundo, a la fila 1, columna 2.
Esto resulta muy parecido a trabajar con una matriz.
Sin embargo, conviene notar una diferencia de sintaxis con las listas bidimensionales del lenguaje Python. En una lista común escribiríamos lista[0][1], mientras que en un tensor de PyTorch usamos x[0, 1], separando los índices con coma dentro de un único par de corchetes.
No siempre queremos un solo elemento. A veces necesitamos una parte del tensor. Para eso usamos slicing.
El resultado será un tensor con [20, 30, 40].
El slicing permite recortar subconjuntos de datos, lo cual es muy útil en procesamiento y preparación de información.
También es posible modificar valores específicos:
Después de la asignación, el tensor pasa a contener [1, 99, 3].
Esto puede ser útil en ejemplos simples, aunque en muchos flujos de trabajo de Deep Learning conviene evitar modificaciones innecesarias si afectan claridad o gradientes.
Muchas veces los datos vienen con una forma y el modelo necesita otra. Para eso PyTorch permite reorganizar la estructura usando reshape().
Ahora el tensor deja de verse como una secuencia de seis elementos y pasa a verse como una tabla de dos filas por tres columnas.
Es importante notar que la cantidad total de valores no cambia; solo cambia la organización.
La operación inversa también es muy frecuente: convertir una estructura de varias dimensiones en una secuencia lineal. Esto suele llamarse flatten.
El resultado será un tensor unidimensional con los mismos seis valores.
Esta operación aparece, por ejemplo, al conectar la salida de una parte del modelo con una capa totalmente conectada.
En tensores bidimensionales, otra operación útil es intercambiar filas por columnas. Esto se conoce como transposición.
La forma pasa de 2 por 3 a 3 por 2.
La transposición aparece con frecuencia en operaciones matriciales y en formulaciones matemáticas del entrenamiento.
En algunos casos necesitamos unir tensores. Una forma común es usar torch.cat().
El resultado será [1, 2, 3, 4, 5, 6].
Concatenar resulta útil cuando queremos combinar información proveniente de distintas partes.
Otra operación relacionada es torch.stack(). A diferencia de concatenar en una dimensión ya existente, apilar suele crear una nueva dimensión.
En este caso, el resultado será una estructura de dos filas, donde la primera corresponde a a y la segunda a b.
Esta diferencia entre concatenar y apilar conviene entenderla bien, porque cambia la forma del tensor resultante.
Hasta ahora vimos multiplicación elemento a elemento. Pero en Deep Learning también es muy importante el producto matricial.
Una forma de hacerlo es mediante torch.matmul():
Esta operación no multiplica simplemente posición por posición. Sigue las reglas del producto entre matrices.
Es una operación fundamental en redes neuronales, porque las capas lineales se basan precisamente en este tipo de cálculo.
No todas las operaciones se pueden hacer entre tensores cualesquiera. Muchas requieren que las formas sean compatibles.
Por ejemplo, para sumar dos tensores elemento a elemento normalmente necesitamos que tengan la misma forma o una compatibilidad especial que permita broadcasting.
En el caso del producto matricial, también existen reglas específicas sobre cuántas columnas y filas deben coincidir.
Por eso, revisar shape antes de una operación importante es una costumbre excelente.
Una característica poderosa de PyTorch es el broadcasting. Esto permite operar tensores de formas diferentes cuando esas formas son compatibles según ciertas reglas.
Un ejemplo simple sería sumar un escalar a un tensor:
Aunque 5 no tenga la misma forma que el tensor, PyTorch “expande” conceptualmente ese valor para aplicarlo a todos los elementos.
Más adelante veremos casos más complejos, pero desde ya conviene saber que broadcasting es una herramienta muy útil.
PyTorch también permite algunas operaciones que modifican el tensor original en lugar de crear uno nuevo. Estas se llaman operaciones in-place.
Por ejemplo, ciertos métodos terminan en guion bajo. Sin embargo, al comenzar conviene usarlas con cuidado, porque pueden volver el código menos claro o interferir en algunos contextos con el sistema de gradientes.
Para aprender, suele ser mejor empezar con operaciones más explícitas y fáciles de seguir.
Todas las operaciones que estamos viendo no son ejercicios aislados. Forman parte del trabajo real de un modelo de Deep Learning.
Por ejemplo:
Por eso, aprender estas operaciones es prepararse para entender el funcionamiento interno de las redes.
Los errores más frecuentes en este tema suelen venir de:
La mejor forma de evitar estos problemas es practicar con ejemplos pequeños y mirar siempre el resultado junto con su forma.
Si estás empezando, estas recomendaciones suelen ayudar mucho:
shape con frecuencia.Comprender bien estas bases evita muchos problemas cuando luego se trabaja con modelos reales.
sum, max, min y mean resumen información.reshape, transposición, concatenación y apilado modifican o reorganizan la estructura.Las operaciones básicas con tensores son una parte esencial del trabajo con PyTorch. A través de ellas, los datos dejan de ser simples valores almacenados y se convierten en estructuras activas que pueden transformarse, combinarse y analizarse.
Dominar estas operaciones significa estar mucho mejor preparado para entender cómo se construye una red, cómo procesa entradas y cómo aprende durante el entrenamiento.
En el próximo tema comenzaremos a dar un paso todavía más concreto: la construcción de una red neuronal simple con PyTorch.