Trabajar con tensores en PyTorch implica vigilar tres factores que determinan si tu código corre o explota en errores: la forma, el tipo de dato y el device donde vive el tensor. Si dominas estos tres, te ahorras horas de debugueo en proyectos de machine learning y deep learning.
Esta guía te muestra cómo inspeccionar y modificar cada uno desde Google Colab, con ejemplos directos del flujo de trabajo en PyTorch.
¿Cómo inspeccionar la forma y dimensiones de un tensor?
La forma de un tensor te dice cuántas dimensiones tiene y cuántos elementos hay en cada una. En PyTorch usas el atributo shape para obtener un objeto torch.size con esa información [01:30].
Por ejemplo, una matriz 2x2 devuelve torch.Size([2, 2]), mientras que un tensor T5 con forma 5x2x3 indica tres dimensiones: cinco grados en la primera, dos en la segunda y tres en la tercera.
También puedes consultar solo el número de dimensiones con el atributo ndim, aunque shape te da más contexto en una sola llamada.
¿Qué diferencia hay entre shape y ndim en PyTorch?shape te devuelve el tamaño de cada dimensión, mientras que ndim solo devuelve un entero con la cantidad total de dimensiones. shape es más informativo para debuguear.
¿Qué tipos de datos puede tener un tensor en PyTorch?
Cada tensor tiene un dtype que define la precisión de sus valores. El default cuando creas un tensor con decimales es torch.float32, también conocido como torch.float [03:30].
Estos son los tipos más usados que encontrarás en la documentación de PyTorch:
torch.float32 o torch.float: punto flotante de 32 bits, el estándar.
torch.float64 o torch.double: punto flotante de 64 bits, mayor precisión.
torch.bool: valores booleanos verdadero o falso.
torch.int8: enteros firmados, positivos y negativos.
torch.uint8: enteros sin firmar, solo positivos.
La cantidad de bits define la precisión: más bits significan más exactitud, pero también más consumo de memoria. Cuando trabajas con un GPU pequeño como el de Colab, float32 es el balance ideal entre precisión y rendimiento.
¿Qué pasa cuando sumas tensores de tipos distintos?
PyTorch toma una decisión automática sobre el tipo del resultado. Si sumas una matriz float32 con una int64, el resultado se convierte a float32, porque PyTorch detecta cuál es el formato más óptimo para conservar la información [05:50].
¿Cómo cambio el tipo de un tensor manualmente?
Usa la función to, que recibe el argumento dtype. Por ejemplo, para convertir una matriz de enteros a flotantes escribes matriz.to(torch.float). Verás cómo cada número aparece con su punto decimal, señal de que ya es float32.
Esta función la vas a usar muchas veces, así que vale la pena memorizarla.
¿Por qué importa el device donde corre tu tensor?
El device es el hardware donde se ejecuta el tensor: puede ser CPU o GPU. Dos tensores solo pueden operar entre sí si están en el mismo dispositivo, y aquí es donde aparecen muchos errores [07:30].
Para consultar el device de un tensor usas el atributo device. Por defecto, los tensores se crean en CPU.
¿Qué es CUDA y cómo lo activo?
CUDA es la plataforma de computación de NVIDIA que permite usar el poder de los GPUs para acelerar operaciones entre tensores, sobre todo la multiplicación de matrices. Es esencial para el entrenamiento y la inferencia en machine learning.
Antes de mover un tensor a GPU, verifica si CUDA está disponible:
python
torch.cuda.is_available()
Si devuelve True, puedes mover tu tensor con la función to:
Lo interesante es que to sirve para dos cosas a la vez: cambia el device y el tipo en una sola línea. Por ejemplo, puedes mover un tensor de CUDA a CPU y, al mismo tiempo, convertirlo de int64 a float32 en un solo comando [10:00].
¿Qué significa cuda:0 en PyTorch? Es el GPU número cero de tu sistema. Si tuvieras cinco GPUs, se numerarían de cero a cuatro. PyTorch empieza el conteo desde cero.
¿Qué error sale cuando los tensores están en devices diferentes?
Si intentas sumar un tensor que vive en CUDA con otro que está en CPU, PyTorch lanza un error claro: expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu [11:30].
La solución es simple: mueve ambos tensores al mismo device antes de operar. Aprender a leer estos errores te ahorra mucho tiempo cuando entrenas modelos.
Los tres factores (shape, dtype y device) son la causa de la mayoría de bugs cuando empiezas con PyTorch. Tenerlos siempre presentes hace que tu código sea más predecible y fácil de depurar.
¿Has tenido errores de device mismatch al entrenar tus modelos? Cuéntame en los comentarios cómo los resolviste.
El tipo de tensor: PyTorch interpretará las unidades de los tensores basándose en sus tipos de datos (por ejemplo, torch.float32, torch.int64, etc.). La conversión implícita puede llevar a resultados no deseados o errores.
Dispositivo del Tensor: Los tensores deben estar en el mismo dispositivo (device) para realizar operaciones entre ellos. Esto significa que todos deben estar en CPU (cpu), GPU (cuda), o cualquier otro dispositivo como NPU o TPU, dependiendo del entorno de ejecución. PyTorch permite mover tensores entre dispositivos usando métodos como .to(), .cuda(), o .cpu().
Forma del Tensor: La forma (shape) de los tensores debe ser compatible para las operaciones que desea realizar. Por ejemplo, la suma de tensores requiere que sus formas sean iguales o que sean broadcastables, mientras que la multiplicación matricial requiere que las dimensiones sean compatibles de acuerdo a las reglas del álgebra lineal.
Si alguien esta utilizando una Mac con los chips nuevos de Apple, se puede usar torch.backends.mps.is_available(), para checar la disponibilidad del GPU
que pasa si dice que es false? yo tengo el chip M3 pero me devuelve clase en el google colab
El tipo float32 es común en PyTorch porque representa un buen equilibrio entre precisión y uso de memoria. Consume menos espacio que float64, lo cual es importante para trabajar con grandes volúmenes de datos y modelos complejos, especialmente en GPU, donde la eficiencia de memoria es crucial. Además, muchas operaciones matemáticas y funciones de activación están optimizadas para float32, lo que mejora la velocidad de entrenamiento y la inferencia en modelos de aprendizaje automático.
El proceso de depuración ("debugging") de operaciones con tensores en PyTorch implica revisar el estado y las transformaciones que sufren los tensores durante el proceso de cálculo. Aquí te ofrezco algunas técnicas y herramientas útiles para depurar operaciones con tensores:
### 1. **Verificar las dimensiones de los tensores (shape)**
Un error común al trabajar con tensores es que no coincidan sus dimensiones para las operaciones. Usar tensor.shape te permite revisar la forma (dimensión) de los tensores.
Si una operación falla, lo primero que deberías hacer es verificar que las dimensiones sean compatibles.
### 2. **Imprimir el tensor en varios puntos del código**
Cuando algo no sale como esperas, puedes imprimir el tensor en diferentes etapas del cálculo para verificar su contenido.
tensor = torch.rand(3,4)print(tensor)# Imprime el contenido del tensor
También puedes verificar propiedades como:
- **dtype** (tipo de dato del tensor)
- **device** (si está en CPU o GPU)
print(tensor.dtype)# Tipo de dato del tensor (float, int, etc.)print(tensor.device)# Verificar si el tensor está en CPU o GPU
### 3. **Usar assert para validar condiciones**
Puedes usar assert para validar que ciertas propiedades del tensor sean las correctas antes de realizar una operación.
tensor = torch.rand(3,4)assert tensor.shape ==(3,4),"El tensor no tiene la forma correcta"
### 4. **Tener cuidado con la asignación en GPU**
Si trabajas con GPU y ocurre un error, asegúrate de que los tensores estén en el mismo dispositivo. No puedes realizar operaciones entre tensores en dispositivos diferentes.
if torch.cuda.is\_available():  tensor\_cpu = torch.rand(3, 4)  tensor\_gpu = tensor\_cpu.to('cuda')  print(tensor\_gpu.device) # Verifica que el tensor esté en la GPU
Si intentas operar entre un tensor en CPU y otro en GPU, obtendrás un error, así que asegúrate de moverlos al mismo dispositivo:
\# tensor\_cpu + tensor\_gpu -> Esto generará un error
tensor\_cpu = tensor\_cpu.to('cuda')# Movemos ambos tensores a la GPUresult = tensor\_cpu + tensor\_gpu
### 5. **Comprobar errores numéricos (NaN, Inf)**
En ocasiones, los valores de los tensores pueden convertirse en NaN o Inf debido a cálculos mal condicionados (como divisiones por cero o logaritmos de valores negativos).
Puedes verificar si un tensor contiene estos valores:
tensor = torch.tensor(\[float('inf'),-float('inf'),float('nan'),1.0])
\# Comprobar si hay NaNs
print(torch.isnan(tensor))# Salida: tensor(\[False, False, True, False])
\# Comprobar si hay Infs
print(torch.isinf(tensor))# Salida: tensor(\[ True, True, False, False])
### 6. **Trazado con autograd para identificar errores en el cálculo de gradientes**
Si estás utilizando autograd y los gradientes no se calculan como esperas, puedes revisar el flujo de cálculo del gradiente mediante torch.autograd.
x = torch.tensor(\[2.0], requires\_grad=True)y = x\*\*2y.backward()print(x.grad)# Imprime el gradiente de `x`
Si en algún momento pierdes el gradiente o se genera un error en el flujo de cálculo, puedes depurar revisando el historial de operaciones.
### 7. **Uso de torch.set\_printoptions para mejorar la visualización**
A veces los tensores grandes no se muestran completamente, lo cual puede dificultar la depuración. Puedes ajustar las opciones de impresión para mostrar más detalles del tensor:
Depurar tensores en GPU puede ser un desafío, ya que los errores son menos descriptivos. Para aislar el problema, puedes copiar el tensor de vuelta a la CPU y revisar su valor:
tensor\_gpu = torch.rand(3,4).to('cuda')tensor\_cpu = tensor\_gpu.cpu()print(tensor\_cpu)# Inspecciona el tensor en CPU
### 9. **Comparación con NumPy**
A veces, puedes comparar resultados de operaciones en PyTorch con NumPy para asegurarte de que todo funcione como esperas.
import numpy as np
tensor = torch.rand(3,4)array = tensor.numpy()
\# Comparar una operación
assert np.allclose(tensor.sum().item(), array.sum()),"Los resultados no coinciden"
### 10. **Uso de herramientas de depuración como PDB**
Si necesitas una depuración más profunda, puedes usar el depurador interactivo de Python, pdb. Por ejemplo, puedes pausar el programa y examinar el estado de las variables en ese punto:
import pdb
tensor = torch.rand(3,4)pdb.set\_trace()# Inicia el depurador interactivo aquí
Esto te permitirá ejecutar comandos para inspeccionar variables y entender el flujo del programa.
Estas técnicas te ayudarán a depurar operaciones con tensores y detectar problemas en tus redes neuronales o cualquier cálculo que estés haciendo en PyTorch.
cuando dice int64 (signed) quiere decir que la representación es con signo. No "firmado" como dice el profe.
Por ejemplo, en el caso de int8 (signed) quiere decir que puede representar desde -128 hasta 127.
Si es int8 (unsigned) va de 0 a 255.
Por fuera de eso, muy buena clase y en particular interesante curso!.
import torch
print(torch.__version__)scalar = torch.tensor(3.0)vector = torch.tensor([1.0,2.0,3.0])matrix = torch.tensor([[1,2,3],[4,5,6]])tensor_3d = torch.randn(5,2,3)print(tensor_3d)# Obtener la forma de una matriz
print(f"Forma de la matriz: {matrix.shape}")# Obtener la forma de un tensor T5print(f"Forma del tensor_3d: {tensor_3d.shape}")# Obtener dimensiones de la matriz
print(f"Dimensiones de la matriz: {matrix.ndim}")# Obtener dimensiones de T5print(f"Dimensiones del tensor_3d: {tensor_3d.ndim}")# Obtener el tipo de datos de una matriz
print(f"Tipo de datos de la matriz: {matrix.dtype}")# Verificar en qué dispositivo está corriendo nuestra matriz
print(f"Dispositivo de la matriz: {matrix.device}")# Verificar si CUDA está disponible
print(f"CUDA disponible: {torch.cuda.is_available()}")def get_device():return torch.device("cuda")if torch.cuda.is_available()else torch.device("cpu")# Obtener el dispositivo a usar(CPU si no hay CUDA)device =get_device()print(f"Dispositivo seleccionado para operaciones: {device}")# Definir un tensor
tensor = torch.tensor([1.0,2.0,3.0])print(f"Tensor inicial en: {tensor.device}")# Mover el tensor al dispositivo determinado(CPU en este caso)tensor = tensor.to(device)print(f"Tensor movido a: {tensor.device}")# Mover el tensor a CPU explícitamente
tensor = tensor.to(torch.device('cpu'))print(f"Tensor movido a CPU: {tensor.device}")# Cambiar tipo y dispositivo(usando el dispositivo determinado)tensor = tensor.to(device=device, dtype=torch.float32)print(f"Tensor cambiado a tipo {tensor.dtype} y dispositivo {tensor.device}")
Pytorch utiliza numpy para esto , por eso es casi igual a como se operan muchas cosas con numpy
¿En caso de tener una GPU de AMD qué alternativa podría usar?
Mis apuntes:
import torchtensor = torch.tensor([[1, 2], [3, 4], [5, 6]])print('tensor: \n',tensor)print("Shape del tensor:", tensor.shape) # Output: (3, 2)print("Número de dimensiones:", tensor.dim()) # Output: 2#tensor = torch.tensor([[[1, 2], [3, 4], [5, 6]],[[1992,1992],[1993,1992],[1994,1994]]]) -> shape = [2,3,2]tensor_float = torch.tensor([[1.0, 2.0], [3.0, 4.0]])tensor_int = torch.tensor([[1, 2], [3, 4]])print("Tipo de datos del tensor float:", tensor_float.dtype) # Output: torch.float32print("Tipo de datos del tensor int:", tensor_int.dtype) # Output: torch.int64#sumamos los dos para ver como hace el broadcasting del tipo -> int a float:tensor_sumado = tensor_float + tensor_intprint('El tensor sumado tiene tipo', tensor_sumado.dtype)#Para cambiar manualmente los dtypes:tensor_float = torch.tensor([[1.0, 2.0], [3.0, 4.0]])tensor_int = tensor_float.to(torch.int64)print("Tensor original (float):", tensor_float.dtype) # Output: torch.float32print("Tensor convertido (int):", tensor_int.dtype) # Output: torch.int64#Operaciones dentro de distintos devices:#Verificamos donde esta el tensor:print('Tensor_float esta en el device: ',tensor_float.device)#Reasignamos al GPU:tensor_float = tensor_float.to(torch.device('cuda'))#Verificamos:print('Tensor_float esta en el device: ',tensor_float.device) #-> cuda:0#Hagamos una operacion entre distintos devices:tensor_sumado = tensor_float + tensor_int#Da Error: RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!#Debemos tener los tensores en el mismo device si queremos operarlos entre ellos:device = torch.device("cuda" if torch.cuda.is_available() else "cpu")tensor_int = tensor_int.to(device)# Operación entre tensores en el mismo dispositivotensor_sumado = tensor_float + tensor_intprint('Suma exitosa entre tensores del mismo device', tensor_sumado)
Runtime> Change RunTime type > T4 GPU
De esta forma se habilita el CUDA
Hola*# Función para operar con cuda si hay en el hardware*if torch.cuda.is_available(): matriz_uinit64_cuda = matriz_uinit64.to(torch.device("cuda"))
print(matriz_uinit64_cuda, matriz_uinit64_cuda.type()) print(matriz_uinit64_cuda.to("cpu", torch.float32))
para el caso que este realizando en local, sino tengo GPU y tengo solo CPU el codigo no deberia mostrarme nada?
# Función para operar con cuda si hay en el hardware
if torch.cuda.is_available(): matriz_uinit64_cuda = matriz_uinit64.to(torch.device("cuda"))print(matriz_uinit64_cuda, matriz_uinit64_cuda.type())print(matriz_uinit64_cuda.to("cpu", torch.float32))
en tal caso te diria que cuda no esta disponible y ya 🤔