Datasets y DataLoaders
Los Dataset y DataLoader de PyTorch alimentan los bucles de entrenamiento con datos agrupados, mezclados y opcionalmente aumentados. Las pipelines de entrada eficientes mantienen la GPU ocupada y el entrenamiento rápido.
Receta
Tarjeta de referencia rápida - lista para copiar y pegar.
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
loader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=4, pin_memory=True)
for batch_x, batch_y in loader:
batch_x = batch_x.to(device, non_blocking=True)Cuándo usar esto:
- Cargar imágenes, texto o datos tabulares en bucles de entrenamiento.
- Aplicar transformaciones por muestra (aumento, tokenización).
- Agrupar secuencias de longitud variable con una
collate_fnpersonalizada. - Prefetching de datos a la GPU con
pin_memoryynon_blocking.
Ejemplo de Trabajo
"""datasets_dataloaders.py - Dataset y DataLoader personalizados para datos CSV."""
from __future__ import annotations
import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader, random_split
class TabularDataset(Dataset):
def __init__(self, df: pd.DataFrame, feature_cols: list[str], target_col: str):
self.X = torch.tensor(df[feature_cols].values, dtype=torch.float32)
self.y = torch.tensor(df[target_col].values, dtype=torch.long)
def __len__(self) -> int:
return len(self.y)
def __getitem__(self, idx: int) -> tuple[torch.Tensor, torch.Tensor]:
return self.X[idx], self.y[idx]
df = pd.read_csv("train.csv")
dataset = TabularDataset(df, feature_cols=["f1", "f2", "f3"], target_col="label")
train_size = int(0.8 * len(dataset))
train_ds, val_ds = random_split(dataset, [train_size, len(dataset) - train_size])
train_loader = DataLoader(train_ds, batch_size=128, shuffle=True, num_workers=2, pin_memory=True)
val_loader = DataLoader(val_ds, batch_size=256, shuffle=False, num_workers=2)
for epoch in range(3):
for x_batch, y_batch in train_loader:
# x_batch: (128, 3), y_batch: (128,)
passLo que esto demuestra:
Datasetpersonalizado con__len__y__getitem__.random_splitpara la partición de entrenamiento/validación.DataLoadermaneja la agrupación y la mezcla.pin_memory=Trueacelera la transferencia de CPU a GPU cuando CUDA está disponible.
Análisis Profundo
Cómo Funciona
Dataset.__getitem__(i)devuelve una muestra;DataLoaderrecopilabatch_sizemuestras.shuffle=Truealeatoriza el orden cada época.num_workersinicia subprocesos para la carga paralela de datos.collate_fnpersonaliza cómo se fusionan las muestras en un lote (relleno para secuencias).IterableDatasettransmite datos para fuentes muy grandes o en línea.
Opciones de DataLoader
| Parámetro | Efecto | Valor Típico |
|---|---|---|
batch_size | Muestras por lote | 32-256 (dependiente de la memoria de la GPU) |
shuffle | Aleatorizar orden | True para entrenamiento |
num_workers | Cargadores paralelos | 4-8 en multinúcleo |
pin_memory | Memoria de host bloqueada por página | True con CUDA |
drop_last | Descartar el último lote incompleto | True para entrenamiento de BatchNorm |
Notas de Python
from torchvision import datasets, transforms
# Conjunto de datos de imágenes incorporado con transformaciones
transform = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
train_set = datasets.CIFAR10(root="./data", train=True, download=True, transform=transform)Errores Comunes
- Aumento en datos de validación - las transformaciones aleatorias corrompen la evaluación. Solución: pipelines de transformaciones separadas para entrenamiento/validación; la validación solo recibe transformaciones deterministas.
- num_workers en Windows/notebooks - problemas de multiprocesamiento en Jupyter. Solución:
num_workers=0en notebooks; usar scripts para carga paralela. - No usar pin_memory con CUDA - copias más lentas de host a dispositivo. Solución:
pin_memory=Trueynon_blocking=Trueen.to(device). - Cargar todo el conjunto de datos en RAM - OOM (Out Of Memory) en conjuntos de datos grandes. Solución: carga perezosa en
__getitem__, archivos con mapeo de memoria oIterableDataset. - Tipos de datos de tensor inconsistentes - mezclar flotantes/enteros causa errores en el modelo. Solución: convertir explícitamente en
__getitem__. - Mezclar datos de validación - innecesario y hace que las curvas de pérdida sean ruidosas. Solución:
shuffle=Falsepara los cargadores de validación/prueba.
Alternativas
| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
DataLoader | Entrenamiento por lotes estándar | Transmisión de datos infinitos (usar IterableDataset) |
torchvision.datasets | Benchmarks de imágenes comunes | Formatos de datos personalizados |
HuggingFace datasets | Datasets de NLP/texto | Clasificación de imágenes simple |
| WebDataset | Entrenamiento a gran escala en la web | Datasets locales pequeños |
Preguntas Frecuentes
¿Cuándo necesito un Dataset personalizado?
- Los datos no están en un formato estándar (CSV, binario personalizado, multimodal).
- El preprocesamiento por muestra es costoso y debe ser perezoso.
- Los datasets incorporados no coinciden con su esquema.
¿Qué es collate_fn?
def pad_collate(batch):
xs, ys = zip(*batch)
lengths = [len(x) for x in xs]
padded = torch.nn.utils.rnn.pad_sequence(xs, batch_first=True)
return padded, torch.tensor(ys), torch.tensor(lengths)
loader = DataLoader(ds, collate_fn=pad_collate)- Personaliza el ensamblaje del lote para secuencias de longitud variable.
¿Cómo acelero la carga de datos?
- Aumente
num_workershasta que la CPU esté saturada. - Use
pin_memory=Truecon CUDA. - Preprocesar y almacenar en caché en disco (archivos LMDB, parquet, .pt).
¿Qué es persistent_workers?
DataLoader(ds, num_workers=4, persistent_workers=True)- Mantiene los procesos trabajadores activos entre épocas.
- Evita la sobrecarga de reinicio en entrenamientos de múltiples épocas.
¿Puedo usar pandas DataFrames directamente?
- Convertir a tensores en
__getitem__o precargar en__init__para datos pequeños. - Para datos grandes, lea una fila por llamada a
__getitem__.
¿Cómo difieren las transformaciones de entrenamiento y validación?
- Entrenamiento: aumento aleatorio (volteo, recorte, fluctuación de color).
- Validación: solo redimensionamiento y normalización deterministas.
- Nunca aumente los datos de validación.
¿Qué es IterableDataset?
- Para transmitir datos sin acceso aleatorio (
__getitem__). - Sin
shuffle- implementar la mezcla en el iterador o búfer. - Se utiliza para fuentes de datos a escala web o en tiempo real.
¿Cómo reproduzco la mezcla?
generator = torch.Generator().manual_seed(42)
loader = DataLoader(ds, shuffle=True, generator=generator)- Una semilla de generador fija proporciona un orden de lote reproducible.
¿Qué tamaño de lote debo usar?
- El más grande que quepa en la memoria de la GPU sin OOM.
- Las potencias de 2 a menudo optimizan los kernels de la GPU.
- La acumulación de gradientes simula lotes más grandes.
¿Cómo manejo el desequilibrio de clases en el cargador?
from torch.utils.data import WeightedRandomSampler
sampler = WeightedRandomSampler(weights, num_samples=len(weights))
loader = DataLoader(ds, sampler=sampler)- El muestreador ponderado sobremuestrea las clases minoritarias.
¿DataLoader funciona en Apple Silicon?
- Sí, en CPU y MPS (Metal Performance Shaders).
pin_memoryno tiene efecto en MPS; usedevice="mps".
¿Cómo depuro un DataLoader lento?
- Perfile con
num_workers=0vs4para aislar E/S frente a cómputo. - Verifique si
__getitem__realiza un trabajo pesado (decodificación de imágenes sobre la marcha).
Relacionado
- Bucles de Entrenamiento - consumo de lotes
- Conceptos Básicos de PyTorch - tipos de datos de tensor
- GPUs y Precisión Mixta - pin_memory y non_blocking
- Aprendizaje por Transferencia y Ajuste Fino - transformaciones preentrenadas
- Entrenamiento Distribuido - DistributedSampler
Versiones de la Pila: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.