Algoritmo de Álgebra Tensorial Básica en Python
El álgebra tensorial es la columna vertebral de muchas técnicas modernas de Machine Learning y Computación Científica. En este artículo descubrirás los conceptos fundamentales, las operaciones más usadas y cómo implementarlas de forma eficiente en Python con NumPy y PyTorch. Además, encontrarás comparativas de rendimiento, buenas prácticas y ejemplos reales que te permitirán aplicar lo aprendido en tus proyectos.
Fundamentos del Álgebra Tensorial
Un tensor es una generalización de escalar (orden 0), vector (orden 1) y matriz (orden 2) a dimensiones arbitrarias. Formalmente, un tensor T de orden n se representa como un arreglo multidimensional T[i₁,i₂,…,iₙ] donde cada índice iₖ recorre el rango de la dimensión k‑ésima.
- Rango (order): número de índices (ej. 3 para un tensor 3‑D).
- Forma (shape): longitud de cada dimensión, por ejemplo
(2,3,4). - Tipo de dato: típicamente
float32ofloat64en aplicaciones numéricas.
Operaciones Tensoriales Clave
Suma y Diferencia
Se realiza elemento a elemento siempre que los tensores tengan la misma forma.
R = A + B # broadcasting también está soportado
Producto Exterior (Outer Product)
Genera un tensor de orden order(A)+order(B). En NumPy se usa np.tensordot con axes=0.
C = np.tensordot(A, B, axes=0)
Contracción (Tensor Dot)
Equivalente a la multiplicación matricial cuando axes=1. Permite reducir dimensiones especificando los ejes a contraer.
D = np.tensordot(A, B, axes=([1],[0])) # contrae la segunda dimensión de A con la primera de B
Transposición y Permutación
Reordena los ejes del tensor mediante np.transpose o tensor.permute en PyTorch.
E = np.transpose(A, (2,0,1))
Implementación en Python con NumPy
NumPy es la referencia de facto para cálculos numéricos en CPU. A continuación, un script completo que muestra las operaciones básicas.
import numpy as np
# Crear tensores aleatorios
A = np.random.rand(2, 3, 4) # shape (2,3,4)
B = np.random.rand(2, 3, 4)
# Suma
C = A + B
# Producto exterior
D = np.tensordot(A, B, axes=0) # shape (2,3,4,2,3,4)
# Contracción de la segunda dimensión de A con la primera de B
E = np.tensordot(A, B, axes=([1],[0])) # shape (2,4,3,4)
# Transposición
F = np.transpose(A, (2,0,1)) # shape (4,2,3)
print('C shape:', C.shape)
print('D shape:', D.shape)
print('E shape:', E.shape)
print('F shape:', F.shape)
Para acelerar los cálculos en GPU, pasa a cupy (API compatible con NumPy) o usa PyTorch.
Implementación con PyTorch (CPU y GPU)
PyTorch ofrece tensores que pueden residir en CPU o GPU con la misma sintaxis. Además, incluye autograd para entrenamiento de modelos.
import torch
# Detectar dispositivo
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# Tensores en el dispositivo seleccionado
A = torch.rand(2, 3, 4, device=device)
B = torch.rand(2, 3, 4, device=device)
# Suma
C = A + B
# Producto exterior
D = torch.tensordot(A, B, dims=0)
# Contracción (equivalente a np.tensordot con axes=[1],[0])
E = torch.tensordot(A, B, dims=([1],[0]))
# Permutación de ejes
F = A.permute(2,0,1)
print('Device:', device)
print('C shape:', C.shape)
print('D shape:', D.shape)
print('E shape:', E.shape)
print('F shape:', F.shape)
Ejecutar el mismo código en una máquina con GPU suele reducir el tiempo de ejecución en un 10‑30× según el tamaño del tensor.
Comparativa de Bibliotecas Tensoriales
| Característica | NumPy | PyTorch |
|---|---|---|
| CPU‑only | ✅ | ✅ |
| Soporte GPU | ❌ (requiere CuPy) | ✅ |
| Autodiferenciación | ❌ | ✅ |
| Distribución (torch.distributed) | ❌ | ✅ |
| Ecosistema de DL | Limitado | Amplio (torchvision, torchaudio…) |
¿Cuándo usar cada una?
- NumPy: prototipado rápido, cálculos científicos en CPU, integración con
scipyypandas. - PyTorch: entrenamiento de redes neuronales, pipelines que requieren GPU y gradientes, o cuando se necesita paralelismo distribuido.
Rendimiento y Escalabilidad
Al trabajar con tensores de gran dimensión (≥10⁶ elementos), considera los siguientes factores:
- Contiguidad de memoria: Usa
.contiguous()en PyTorch antes de operaciones que requieran acceso lineal. - Batching: Procesa datos en lotes para aprovechar la paralelización de la GPU.
- Precisión mixta (FP16): Reduce el consumo de memoria y acelera el cálculo en GPUs modernas (p.ej. NVIDIA Ampere).
- Profiling: Herramientas como
torch.profileronvprofidentifican cuellos de botella.
Ejemplo de uso de precisión mixta en PyTorch:
with torch.cuda.amp.autocast():
out = model(input_tensor)
loss = criterion(out, target)
loss.backward()
Mejores Prácticas y Troubleshooting
1. Evita copias innecesarias
En NumPy, operaciones como np.transpose devuelven una vista; sin embargo, algunas funciones crean copias implícitas. Usa .copy() solo cuando sea estrictamente necesario.
2. Manejo de errores de forma
El error ValueError: shapes (… ) not aligned indica una incompatibilidad en los ejes de contracción. Verifica la lista axes antes de llamar a tensordot.
3. Compatibilidad de versiones
NumPy ≥ 1.20 y PyTorch ≥ 1.9 introducen mejoras en einsum y torch.linalg. Asegúrate de actualizar tu entorno con pip install -U numpy torch.
4. Depuración en GPU
Si la GPU se queda en estado CUDA out of memory, libera memoria con torch.cuda.empty_cache() o reduce el tamaño del batch.
Casos de Uso Reales
- Visión por Computadora: Manipulación de tensores de imágenes (batch, canales, altura, anchura) para augmentación y normalización.
- Procesamiento de Señales: Representación de series temporales como tensores de orden 3 (batch, canales, tiempo) y aplicación de convoluciones 1‑D.
- Simulación Física: Tensores de tensiones y deformaciones en mecánica de sólidos, donde la contracción representa la operación de inner product entre tensores de orden 2.
En todos estos escenarios, la correcta elección de la biblioteca y la optimización de la forma del tensor pueden reducir el tiempo de entrenamiento en un 50 % o más.
Algoritmo de Álgebra Tensorial Básica con Ejemplos en Python