Operaciones con tensores y conversión NumPy-PyTorch
Resumen
Si trabajas con redes neuronales, tarde o temprano vas a mover datos entre NumPy y PyTorch, y vas a operar tensores como si fueran matrices de álgebra lineal. Aquí aprendes cómo hacer esa conversión en ambos sentidos y cómo ejecutar las operaciones que sostienen casi toda la inteligencia artificial moderna.
La idea es simple: prototipas con NumPy, mueves a PyTorch cuando quieres aprovechar la GPU y el autograd, y operas tensores con sumas, restas, multiplicaciones elemento a elemento o multiplicación de matrices. Vamos por partes.
¿Cómo convierto un tensor de PyTorch a NumPy y viceversa?
La conversión entre ambas librerías es directa y la vas a usar todo el tiempo cuando combines herramientas de visualización, preprocesamiento o despliegue.
Para pasar un tensor de PyTorch a un array de NumPy, llamas al método .numpy() sobre el tensor. Puedes confirmar el tipo con la función type() de Python y verás que el resultado es un numpy.ndarray.
Para el camino inverso, usas torch.from_numpy(vector). Si creas un vector de unos en NumPy con floats, al convertirlo obtendrás un tensor con dtype=torch.float64 de manera automática [01:00].
¿Qué hace torch.from_numpy? Convierte un array de NumPy en un tensor de PyTorch conservando el tipo de dato original, para que puedas operarlo con todas las funciones de la librería.
¿Por qué importa esta interoperabilidad?
Porque te permite prototipar rápido en NumPy y luego mover el modelo a PyTorch cuando necesites entrenarlo con gradientes o GPU. No tienes que reescribir el código desde cero.
¿Qué son las operaciones element-wise en tensores?
Las operaciones element-wise son aquellas donde cada elemento de un tensor opera con el elemento en la misma posición del otro tensor. Suma, resta, multiplicación y división entran en esta categoría [02:30].
Para que funcionen, ambos tensores deben tener la misma forma. Si defines un zeros_tensor y un ones_tensor de tamaño 3x4, puedes sumarlos, restarlos o multiplicarlos usando los símbolos +, - y * directamente, igual que en Python básico.
Suma: zeros_tensor + ones_tensor.
Resta: zeros_tensor - ones_tensor.
Multiplicación elemento a elemento: zeros_tensor * ones_tensor.
La lógica es la misma para todas: posición por posición, sin mezclar filas ni columnas.
¿Qué pasa si las formas no coinciden? El broadcasting
Aquí viene lo interesante. Si divides un tensor aleatorio de forma (4,) entre un tensor de unos de forma (3, 4), PyTorch no falla: extiende automáticamente el vector para que tenga la forma de la matriz. Eso se llama broadcasting.
El resultado tendrá los mismos valores repetidos en cada fila, porque el vector original se replicó tres veces para alinear las dimensiones.
¿Cuándo funciona el broadcasting en PyTorch? Cuando una de las dimensiones del tensor más pequeño coincide con la del tensor más grande, o cuando es 1. Si tienes un vector de tamaño 3 intentando operar contra una matriz 3x4, falla porque las columnas no coinciden.
Si cambias el vector aleatorio a tamaño 3 e intentas la misma división, obtendrás un error indicando que el tamaño del tensor debe coincidir con el tensor B (de tamaño 4) y no es un singleton de dimensión uno [05:40].
¿Cómo se hace la multiplicación de matrices en PyTorch?
Citando a Jeremy Howard, creador de Fast.ai: la inteligencia artificial no es más que muchas multiplicaciones de matrices. Matrices grandes, muchas operaciones, pero al final, eso.
La multiplicación de matrices no eselement-wise. Es la operación clásica del álgebra lineal donde combinas filas con columnas. Para ejecutarla en PyTorch usas torch.matmul(matrix1, matrix2).
Si creas matrix1 de forma 2x3 y matrix2 de forma 3x2, ambas con valores aleatorios, no podrías sumarlas porque sus formas son distintas. Pero sí puedes multiplicarlas como matrices, y el resultado tendrá forma 2x2 [07:20].
Forma de matrix1: 2x3.
Forma de matrix2: 3x2.
Forma del resultado: 2x2.
La regla es que el número de columnas de la primera matriz debe coincidir con el número de filas de la segunda. Verifica las dimensiones del resultado con .shape, siempre.
¿Por qué torch.matmul se llama así?
Porque matmul es la convención compartida con NumPy y significa matrix multiplication. Si ya conoces np.matmul, la sintaxis te resultará familiar.
Habilidades y conceptos que se quedan contigo
En este recorrido viste cómo crear tensores con torch.zeros, torch.ones y torch.rand, cómo inspeccionar su forma con .shape, y cómo decidir entre operaciones element-wise y multiplicación de matrices según el problema que estés resolviendo.
También entendiste por qué el broadcasting es útil pero no mágico: solo funciona cuando las dimensiones son compatibles. Y aprendiste que mover datos entre NumPy y PyTorch es cuestión de una sola línea.
Con esto cierras el primer módulo: hola mundo, manipulación de tensores, debugging, operaciones e interoperabilidad con NumPy. ¿Te sientes listo para entrenar tu primer modelo con PyTorch? Cuéntalo en los comentarios.
Hace mucho vi como un video con respecto a esto y quiero compartirselos, habla de las operaciones de tensores y las reglas que es tiene y lo explica de una manera muy directa y sencilla.
VIDEO
Hola,
Quiero compartirles 2 cosas. La primera que los tensores también se pueden multiplicar por medio del comando @. Por ejemplo: matriz1@matriz2 nos da el mismo resultado que torch.matmul(matriz1,matriz2).
También me gustaría compartirles un sitio web donde se desarrolla paso a paso la multiplicación de matrices. Puedes ingresar los valores que desees y paso a paso observarás el resultado: matrixmultiplication.xyz (la plataforma no me deja ingresar el link porque no contiene el cerficado https pero pueden copiar y pegar).
Hola :) solo para completar, me gustaría mencionar que torch. mm(mx1, mx2) también se puede utilizar. Es una abreviatura en PyTorch.
Para quienes tengan problemas con los temas vistos en esta clase les recomiendo este par de cursos donde se profundiza mas en el tema:
La multiplicación de matrices , es el famoso producto punto o producto interno , que es lo que viene siendo una operación que se hace entre vectores que devuelve un escalar que a la final vienen siendo combinaciones lineales , que nos sirven a nosotros para poder representar la información en diferentes espacios y encontrar información muy especifica
El broadcasting de tensores es una técnica en PyTorch que permite realizar operaciones element-wise entre tensores de diferentes formas, adaptando automáticamente sus dimensiones. Por ejemplo, si tienes un tensor de 3x4 y otro de 1x4, PyTorch expandirá el tensor de 1x4 a 3x4 para realizar operaciones como suma o multiplicación. Esta funcionalidad es crucial para simplificar cálculos sin necesidad de reestructurar manualmente los datos. Sin embargo, el broadcasting solo se aplica si las dimensiones son compatibles.
El broadcasting no es exclusivo de PyTorch, es una técnica que viene del álgebra lineal computacional. Permite operar entre arreglos (vectores, matrices, tensores) de diferentes tamaños expandiendo automáticamente las dimensiones más pequeñas para que coincidan
La **conversión** y **operación** de tensores en PyTorch es esencial para manipular y procesar datos de manera eficiente. A continuación, te explico los conceptos clave y cómo realizar estas tareas.
### 1. **Creación de Tensores**
En PyTorch, los tensores son similares a los arrays de NumPy, pero con la ventaja de que pueden ser utilizados en GPU para realizar cálculos más rápidos.
import torch
\# Crear un tensor vacío
tensor\_vacio = torch.empty(3,4)# Crea un tensor vacío de 3x4
\# Crear un tensor con ceros
tensor\_ceros = torch.zeros(3,4)# Tensor de 3x4 lleno de ceros
\# Crear un tensor con unos
tensor\_unos = torch.ones(3,4)# Tensor de 3x4 lleno de unos
\# Crear un tensor con valores aleatorios
tensor\_aleatorio = torch.rand(3,4)# Valores aleatorios en \[0, 1)
### 2. **Conversiones entre Tensores y NumPy**
Los tensores de PyTorch pueden convertirse fácilmente en arrays de NumPy y viceversa. Esto es útil cuando ya tienes código que utiliza NumPy y quieres aprovechar PyTorch.
- **De Tensor a NumPy:**
```python
tensor = torch.rand(3, 3)
array_numpy = tensor.numpy()
print(array_numpy) # Conversión de tensor a array NumPy
```
- **De NumPy a Tensor:**
```python
import numpy as np
array_numpy = np.array([[1, 2], [3, 4]])
tensor = torch.from_numpy(array_numpy)
print(tensor) # Conversión de array NumPy a tensor PyTorch
```
### 3. **Operaciones con Tensores**
PyTorch permite realizar operaciones matemáticas con tensores, similares a las que se pueden hacer con arrays de NumPy.
- **Suma de Tensores:**
```python
x = torch.rand(2, 3)
y = torch.rand(2, 3)
suma = x + y # Suma elemento por elemento
print(suma)
```
- **Multiplicación Elemento por Elemento (Hadamard):**
Los tensores en PyTorch pueden ser de varios tipos, como float32, int64, etc. Puedes convertir el tipo de un tensor usando el método to() o cambiando el dtype directamente.
- **Especificar el Tipo de Dato al Crear el Tensor:**
- **Convertir el Tipo de Dato Después de Crear el Tensor:**
```python
tensor = torch.rand(3, 3)
tensor_entero = tensor.to(torch.int32) # Convertir a enteros
```
### 5. **Mover Tensores entre CPU y GPU**
PyTorch soporta operaciones en GPU, lo cual acelera significativamente los cálculos. Puedes mover tensores entre CPU y GPU con .to().
- **Mover un Tensor a la GPU:**
```python
if torch.cuda.is_available():
tensor_gpu = tensor.to('cuda')
print(tensor_gpu.device) # Verifica que el tensor esté en la GPU
```
- **Mover un Tensor de la GPU a la CPU:**
```python
tensor_cpu = tensor_gpu.to('cpu')
```
### 6. **Operaciones de Redimensionado y Transposición**
A veces necesitas cambiar la forma de un tensor o reordenar sus dimensiones. Estas operaciones son muy comunes en procesamiento de datos.
- **Cambiar la Forma (view):**
```python
tensor = torch.rand(4, 4)
tensor_reshaped = tensor.view(2, 8) # Redimensionar a 2x8
print(tensor_reshaped.shape) # Verifica la nueva forma
```
- **Transponer un Tensor (transpose):**
```python
tensor = torch.rand(2, 3)
tensor_transpose = torch.transpose(tensor, 0, 1) # Intercambia las dimensiones 0 y 1
print(tensor_transpose.shape) # Verifica la forma después de transponer
```
### 7. **Operaciones de Agregación**
Puedes calcular estadísticas como sumas, medias, mínimos y máximos a lo largo de un eje del tensor.
- **Suma de Todos los Elementos:**
```python
tensor = torch.rand(3, 3)
suma_total = tensor.sum()
print(suma_total) # Imprime la suma de todos los elementos del tensor
```
- **Media por Ejes Específicos:**
```python
media_filas = tensor.mean(dim=1) # Media a lo largo de las filas (dimensión 1)
print(media_filas)
```
### 8. **Operaciones de Corte e Indexado**
Al igual que con los arrays de NumPy, puedes acceder a subconjuntos de un tensor o modificar partes específicas de él.
- **Acceder a un Elemento:**
```python
tensor = torch.rand(4, 4)
print(tensor[1, 2]) # Acceder al elemento en la fila 1, columna 2
```
- **Modificar un Elemento:**
```python
tensor[1, 2] = 10 # Asignar un valor al elemento en la fila 1, columna 2
```
- **Cortar Tensores:**
```python
tensor_slice = tensor[:, 1] # Seleccionar la segunda columna de todas las filas
```
### 9. **Operaciones de Concatenación**
Puedes unir varios tensores a lo largo de un eje específico.
- **Concatenar Tensores:**
```python
tensor_a = torch.rand(2, 3)
tensor_b = torch.rand(2, 3)
tensor_concat = torch.cat((tensor_a, tensor_b), dim=0) # Concatenar a lo largo de las filas
print(tensor_concat)
```
### 10. **Operaciones de Comparación**
Puedes comparar tensores para obtener un tensor booleano (True/False) en cada posición.
- **Comparar Elementos:**
```python
tensor = torch.rand(2, 3)
comparacion = tensor > 0.5 # Comparar si los elementos son mayores que 0.5
print(comparacion)
```
### Conclusión
PyTorch ofrece una gran flexibilidad para trabajar con tensores y realizar operaciones numéricas de manera eficiente. Las operaciones de conversión entre NumPy y PyTorch, junto con la posibilidad de mover tensores entre CPU y GPU, permiten un flujo de trabajo robusto y acelerado para el desarrollo de modelos de aprendizaje profundo y otras tareas.
■ Resumen:
Operaciones Elemento a Elemento: Operaciones como suma, resta, multiplicación y división entre tensores se realizan de forma "element-wise", es decir, se aplican a cada par de elementos correspondientes de los tensores involucrados. Por ejemplo, si A y B son tensores, entonces C = A + B sumará cada elemento de A con el elemento correspondiente en B.
Compatibilidad de Dimensiones y Broadcasting: Para que las operaciones elemento a elemento funcionen, las dimensiones de los tensores deben ser iguales o compatibles a través de broadcasting. Broadcasting extiende las dimensiones de uno o ambos tensores para que sus formas sean compatibles sin copiar datos innecesarios. Por ejemplo, sumar un tensor de forma (3, 1) con uno de forma (3, 4) aplicará broadcasting al primer tensor para que se comporte como si tuviera la forma (3, 4).
Conversión de NumPy a PyTorch: La función torch.from\_numpy(array) convierte un array de NumPy a un tensor de PyTorch, manteniendo los datos subyacentes sin copiarlos. Esto es especialmente útil cuando se trabaja con datasets en NumPy y se necesita usar las capacidades de PyTorch para entrenamiento y modelado.