📖 Teoría

Deep Learning y Big Data

Del ecosistema Big Data a los centros de datos para IA: historia y evolución de las tecnologías de datos masivos, scaling laws, aceleradores hardware, computación eficiente (vectorización, GPU, TPU), y entrenamiento distribuido (Data Parallelism, Model Parallelism, FSDP, DeepSpeed, Megatron-LM).

¿Qué es Big Data?

Big Data se refiere a conjuntos de datos cuyo volumen, velocidad de generación o variedad hacen que las herramientas tradicionales de procesamiento sean insuficientes. El término no describe sólo un tamaño, sino un paradigma: nuevas arquitecturas, algoritmos y tecnologías diseñadas para capturar, almacenar, procesar y analizar datos a escalas antes inimaginables.

El concepto de Big Data nació a principios de los años 2000, impulsado por la necesidad de empresas como Google, Yahoo y Facebook de gestionar cantidades de información que crecían a un ritmo exponencial. Google fue la pionera: para indexar toda la web necesitaba un sistema de almacenamiento y procesamiento radicalmente diferente a las bases de datos relacionales que existían hasta entonces. Sus publicaciones internas —el Google File System (GFS, 2003) y MapReduce (2004)— sentaron las bases técnicas de lo que hoy conocemos como el ecosistema Big Data.

Desde entonces, el paradigma ha evolucionado en tres grandes eras: la era Hadoop (2006–2012), centrada en el procesamiento batch sobre clusters de máquinas commodity; la era Spark (2012–2018), que introdujo el procesamiento in-memory y el análisis iterativo necesario para el machine learning; y la era cloud-native + AI (2018–actualidad), donde la infraestructura se despliega en la nube, los datos se almacenan en lakehouses y los pipelines están optimizados para alimentar modelos de deep learning a escala masiva.

💡 Definición formal (NIST, 2015): "Big Data consists of extensive datasets — primarily in the characteristics of volume, velocity, variety, and/or variability — that require a scalable architecture for efficient storage, manipulation, and analysis." NIST Big Data Interoperability Framework, SP 1500-1 (2015) · nist.gov

Línea temporal del Big Data

La siguiente línea temporal recorre los hitos tecnológicos más importantes en la evolución del ecosistema Big Data, desde la publicación del paper de GFS hasta las arquitecturas AI-native actuales. Cada uno de estos hitos supuso un cambio fundamental en cómo se almacenan, procesan y explotan los datos a gran escala.

2003 Google File System (GFS) 2004 MapReduce (Google) 2006 Hadoop (Doug Cutting) 2009 Spark (UC Berkeley) 2011 Kafka (LinkedIn) 2014 Spark 1.0 + MLlib 2017 Ray / Dask Python-native 2020+ Lakehouse Delta · Iceberg 2023+ AI-native Data + GPU Era Hadoop (batch) Era Spark (in-memory) Era Cloud-native + AI Evolución del ecosistema Big Data (2003–2025)
Click en el diagrama para ampliarlo

Las V's del Big Data

El modelo original de Doug Laney (2001) describió tres V's. Con el tiempo se han añadido más dimensiones que caracterizan la complejidad de los datos a gran escala. Comprender estas dimensiones es fundamental para diseñar sistemas de procesamiento adecuados: no es lo mismo un problema donde el reto principal es el volumen (como almacenar petabytes de imágenes médicas) que uno donde el reto es la velocidad (como procesar millones de transacciones financieras por segundo).

📦
Volumen
Cantidad de datos: desde TB a EB. CERN genera ~1 PB/día. YouTube recibe 500 horas de vídeo/minuto.
Velocidad
Ritmo de generación y procesamiento. Datos en streaming, real-time analytics, latencia < ms.
🎨
Variedad
Datos estructurados (SQL), semi-estructurados (JSON, XML), no estructurados (imágenes, texto, audio).
Veracidad
Calidad y fiabilidad de los datos. Datos ruidosos, incompletos, sesgados o contradictorios.
💎
Valor
Capacidad de extraer conocimiento útil. El dato crudo sin procesar tiene valor limitado.
📖 Referencia: Laney, D. (2001). "3D Data Management: Controlling Data Volume, Velocity and Variety". META Group Research Note (texto original). Posteriormente extendido a 5V's por Demchenko et al. (2013). Para una perspectiva más actual, ver también el informe de IDC "Data Age 2025".

En la práctica, un proyecto de Big Data rara vez se enfrenta a las cinco V's con la misma intensidad. Un pipeline de IoT industrial, por ejemplo, genera datos a altísima velocidad (miles de sensores muestreando a kHz) pero con poca variedad (siempre los mismos tipos de señal). En cambio, un proyecto de procesamiento de lenguaje natural a escala web tiene enorme variedad (texto, HTML, PDFs, imágenes con texto, audio transcrito) pero la velocidad de ingesta puede ser moderada (batch de crawls periódicos). Identificar cuáles son las V's dominantes en tu caso de uso es el primer paso para elegir la arquitectura correcta.

Tecnologías clave del ecosistema Big Data

Almacenamiento distribuido

TecnologíaTipoModeloCaso de uso
HDFSFilesystem distribuidoBloques replicados (3×)Data lakes on-premise, Hadoop
Amazon S3Object storageObjetos + metadataData lakes cloud, modelo estándar
Google Cloud StorageObject storageObjetos + bucketsDatos para BigQuery, Vertex AI
Azure Data LakeObject storageNamespaces jerárquicosEcosistema Microsoft, Synapse
MinIOObject storage (S3-compat)On-premise / hybridAlternativa S3 auto-hospedada
Delta LakeTable formatACID sobre ParquetLakehouse, versionado datos
Apache IcebergTable formatSnapshots, schema evolutionAnalytics a escala, Netflix

Procesamiento batch

Hadoop (2006) fue el primer framework open-source para procesamiento distribuido masivo, inspirado directamente en los papers de Google sobre GFS (Ghemawat et al., 2003) y MapReduce (Dean & Ghemawat, 2004). Divide los datos en bloques de 128 MB distribuidos en un cluster, y ejecuta funciones map (transformación local) y reduce (agregación global) en paralelo.

Limitación: alto I/O a disco entre etapas → lento para algoritmos iterativos como los del machine learning. Esto motivó la creación de Spark.

Dean, J. & Ghemawat, S. (2004). MapReduce: Simplified Data Processing on Large Clusters. OSDI'04.

Ghemawat, S., Gobioff, H. & Leung, S.-T. (2003). The Google File System. SOSP'03.

Spark (Zaharia et al., 2010, UC Berkeley) introdujo los Resilient Distributed Datasets (RDDs): colecciones distribuidas inmutables que se procesan en memoria, evitando el I/O a disco de MapReduce. Hasta 100× más rápido que Hadoop para workloads iterativos.

Componentes: Spark SQL (consultas estructuradas), MLlib (machine learning distribuido), Spark Streaming (micro-batches), GraphX (grafos).

Zaharia, M. et al. (2010). Spark: Cluster Computing with Working Sets. HotCloud'10.

Zaharia, M. et al. (2012). Resilient Distributed Datasets: A Fault-Tolerant Abstraction for In-Memory Cluster Computing. NSDI'12.

Dask (2015, Anaconda): extiende NumPy, Pandas y Scikit-learn a datos que no caben en RAM. Usa grafos de tareas perezosos (lazy DAG) y ejecuta en paralelo. API casi idéntica a Pandas → curva de aprendizaje mínima.

Ray (2017, UC Berkeley / Anyscale): framework general de computación distribuida para Python. Incluye Ray Train (entrenamiento distribuido DL), Ray Data (pipelines de datos) y Ray Serve (serving). Usado internamente en OpenAI, Uber, Ant Financial.

Moritz, P. et al. (2018). Ray: A Distributed Framework for Emerging AI Applications. OSDI'18.

Procesamiento en streaming

TecnologíaModeloLatenciaCaso de uso típico
Apache KafkaPub/sub log distribuidomsEvent streaming, pipelines de datos real-time
Apache FlinkStream processing nativomsProcesamiento de eventos complejo (CEP)
Spark Structured StreamingMicro-batch~100ms–sETL near-real-time con Spark
Apache PulsarPub/sub + queuingmsMulti-tenancy, geo-replicación
AWS KinesisManaged streaming~200msIngesta cloud-native AWS
Google Pub/SubManaged messaging~100msIngesta cloud-native GCP

Bases de datos para Big Data

Base de datosTipoEscalaUso típico
CassandraWide-columnPB, write-heavyIoT, time-series, alta disponibilidad
MongoDBDocumento (JSON)TB–PBDatos semi-estructurados, flexibilidad
HBaseWide-column (Hadoop)PBRandom read/write sobre HDFS
RedisKey-value (in-memory)GB–TBCaching, sesiones, features real-time
ElasticsearchSearch engineTBBúsqueda full-text, logs (ELK)
ClickHouseColumnar analyticsPBOLAP, analytics tiempo real
CockroachDBNewSQL (distributed SQL)TB–PBSQL distribuido, ACID global

Con la era de los LLMs y la generación de embeddings, las bases de datos vectoriales se han convertido en infraestructura esencial:

Base de datosTipoÍndiceMejor para
PineconeManagedHNSWRAG en producción, serverless
WeaviateOpen-sourceHNSWBúsqueda semántica multimodal
MilvusOpen-sourceIVF, HNSW, DiskANNEscala masiva, on-premise
QdrantOpen-sourceHNSWRust-based, alto rendimiento
ChromaDBOpen-sourceHNSWPrototipado rápido, in-process
pgvectorExtensión PostgreSQLIVFFlat, HNSWVectores + SQL en misma DB

Las mayores fuentes de producción de datos

La cantidad de datos generados globalmente ha crecido exponencialmente. Según IDC (International Data Corporation), en 2025 se generarán más de 180 zettabytes (ZB) de datos, frente a los ~2 ZB de 2010.

FuenteVolumen estimadoTipo de datosVelocidad
🌐 Internet / Web ~5 EB/día (2025) Texto, imágenes, vídeo, logs Continuo
📱 Redes sociales ~500 PB/día Posts, imágenes, vídeos, stories Real-time streaming
📡 IoT / Sensores ~73 ZB (acumulado 2025) Series temporales, telemetría Alta frecuencia (ms–s)
🏥 Salud / Genómica ~1 GB/genoma, 30 EB/año Secuencias, imágenes médicas Batch + streaming
🔬 Investigación científica CERN: 1 PB/día; SKA: 1 EB/día Eventos físicos, señales Burst (colisiones, observaciones)
🚗 Vehículos autónomos ~20 TB/vehículo/día LiDAR, cámaras, radar, GPS Continuo, alta frecuencia
💰 Finanzas NYSE: ~1 TB/día de transacciones Ticks, órdenes, posiciones Ultra-baja latencia (μs)
🛰️ Observación de la Tierra Sentinel: ~12 TB/día Imágenes satelitales multiespectrales Batch (órbitas)
📈 Crecimiento exponencial: según Statista e IDC, la datasfera global (datos creados, capturados, copiados y consumidos) pasará de 64.2 ZB (2020) a 181 ZB (2025). Más del 80% serán datos no estructurados (vídeo, imágenes, texto libre). IDC, "Data Age 2025" (Reinsel, Gantz & Rydning, 2018)

📊 Widget: Calculadora de volumen de datos

Estima el volumen total de datos generados por diferentes fuentes en un periodo.

Evolución del almacenamiento de datos

La capacidad de almacenamiento y su coste han evolucionado dramáticamente, siendo un factor clave en la viabilidad del Big Data:

AñoMedioCapacidad típicaCoste/GB
1956IBM 305 RAMAC (primer HDD)5 MB~$10,000,000
1980HDD estándar26 MB~$500
1995HDD1 GB~$10
2000HDD20 GB~$1
2010HDD / SSD1–2 TB$0.10 / $1.00
2020NVMe SSD / HDD8–20 TB$0.02 / $0.10
2025NVMe SSD / Cloud30+ TB / ilimitado$0.01 / $0.023/mo (S3)

📚 Referencias históricas clave

  • GFS paper: Ghemawat, S., Gobioff, H. & Leung, S.-T. (2003). "The Google File System". SOSP'03. PDF
  • MapReduce paper: Dean, J. & Ghemawat, S. (2004). "MapReduce: Simplified Data Processing on Large Clusters". OSDI'04. PDF
  • Bigtable paper: Chang, F. et al. (2006). "Bigtable: A Distributed Storage System for Structured Data". OSDI'06. PDF
  • Dynamo paper: DeCandia, G. et al. (2007). "Dynamo: Amazon's Highly Available Key-value Store". SOSP'07. PDF
  • Kafka paper: Kreps, J., Narkhede, N. & Rao, J. (2011). "Kafka: a Distributed Messaging System for Log Processing". NetDB'11. PDF
  • Spark paper: Zaharia, M. et al. (2012). "Resilient Distributed Datasets". NSDI'12. PDF
  • Lakehouse paper: Armbrust, M. et al. (2021). "Lakehouse: A New Generation of Open Platforms that Unify Data Warehousing and Advanced Analytics". CIDR'21. PDF

💡 Para profundizar en los fundamentos del procesamiento de datos, consulta también el submódulo de Tensores, donde se explica cómo estas estructuras de datos son la base del cómputo en deep learning.

¿Por qué el Deep Learning necesita Big Data?

La relación entre Big Data y Deep Learning es simbiótica: los modelos de DL necesitan cantidades masivas de datos para aprender representaciones útiles, y al mismo tiempo son los únicos modelos capaces de escalar su rendimiento proporcionalmente con la cantidad de datos disponibles.

Esta relación simbiótica no es un accidente: tiene raíces teóricas profundas. Los modelos de deep learning son aproximadores universales —con suficientes parámetros, pueden aproximar cualquier función continua— pero esa capacidad de representación viene con un coste: necesitan enormes cantidades de ejemplos para aprender las regularidades estadísticas del dominio sin caer en overfitting. Un modelo con millones o miles de millones de parámetros tiene un espacio de hipótesis tan grande que, sin datos suficientes, memorizará el training set en lugar de generalizar. Aquí es donde el Big Data se vuelve indispensable: cuantos más datos diversos y representativos alimenten al modelo, mejor será su capacidad de generalización. Para profundizar en conceptos de overfitting y generalización, consulta el submódulo de Machine Learning Clásico.

La siguiente gráfica ilustra la idea clave: mientras que los algoritmos de ML tradicional (SVM, Random Forest, XGBoost) saturan su rendimiento a partir de cierta cantidad de datos —porque su capacidad de representación es limitada—, los modelos de deep learning escalan sin saturar, siempre que el modelo sea suficientemente grande. Este fenómeno, demostrado empíricamente por las scaling laws de Kaplan et al. (2020), es la razón fundamental por la que los grandes avances en IA de los últimos años han venido de la mano de datasets cada vez más masivos.

Cantidad de datos Rendimiento ML tradicional (SVM, RF, XGBoost) DL pequeño DL grande (GPT, ViT, Gemini...) + datos → + rendimiento DL escala sin saturar
Rendimiento vs cantidad de datos para distintos tipos de modelos
📐
Representaciones
Los modelos DL aprenden features jerárquicas directamente de los datos crudos. Más datos → features más ricas y generalizables.
🎯
Generalización
Con millones de parámetros, los modelos grandes necesitan millones/billones de ejemplos para evitar overfitting.
📈
Scaling
Las leyes de escala (Kaplan et al., 2020) demuestran que el rendimiento mejora como ley de potencias con N, D y C.
🔄
Pre-training
Modelos como GPT o CLIP se pre-entrenan con internet completo: trillones de tokens, miles de millones de pares imagen-texto.

Leyes de escala (Scaling Laws)

Las leyes de escala son relaciones empíricas que describen cómo el rendimiento de un modelo (medido como pérdida L) depende del número de parámetros (N), cantidad de datos (D) y compute (C) como leyes de potencias.

El descubrimiento de estas leyes fue un punto de inflexión para la industria del deep learning. Antes de 2020, la intuición dominante era que "más grande no siempre es mejor": se asumía que existían rendimientos decrecientes al escalar modelos. Los trabajos de Kaplan et al. en OpenAI demostraron que, al menos para modelos de lenguaje, el rendimiento mejora de forma predecible y suave siguiendo leyes de potencias, sin señales de saturación en los rangos estudiados (hasta cientos de miles de millones de parámetros). Esto transformó la estrategia de entrenamiento: en lugar de buscar arquitecturas más ingeniosas, las empresas empezaron a invertir en escalar los modelos existentes con más datos y más compute. Para una visión completa del entrenamiento de redes, consulta el submódulo de Optimización avanzada.

📐 Kaplan et al. (2020) — Leyes de escala para LLMs

$$L(N) \approx \left(\frac{N_c}{N}\right)^{\alpha_N}, \quad \alpha_N \approx 0.076$$
$$L(D) \approx \left(\frac{D_c}{D}\right)^{\alpha_D}, \quad \alpha_D \approx 0.095$$
$$L(C) \approx \left(\frac{C_c}{C}\right)^{\alpha_C}, \quad \alpha_C \approx 0.050$$

Donde \(N_c, D_c, C_c\) son constantes y \(\alpha\) son los exponentes de escala. Los tres factores (modelo, datos, compute) contribuyen al rendimiento, pero con retornos decrecientes predecibles.

Kaplan, J. et al. (2020). "Scaling Laws for Neural Language Models". arXiv:2001.08361.

🦫 Chinchilla (Hoffmann et al., 2022)

El paper de Chinchilla demostró que los modelos anteriores (GPT-3, Gopher) estaban under-trained: tenían demasiados parámetros para la cantidad de datos usados. La regla óptima:

$$D_{\text{optimal}} \approx 20 \times N$$

Para un modelo de 70B parámetros, la cantidad óptima de datos es ~1.4T tokens. Chinchilla (70B, 1.4T tokens) superó a Gopher (280B, 300B tokens) con 4× menos parámetros.

Hoffmann, J. et al. (2022). "Training Compute-Optimal Large Language Models". arXiv:2203.15556.

ModeloParámetrosTokens entrenamientoRatio D/N¿Chinchilla-optimal?
GPT-3175B300B1.7❌ Under-trained
Chinchilla70B1.4T20✅ Óptimo
LLaMA-1 7B7B1T143✅ Over-trained (eficiente en inferencia)
LLaMA-2 70B70B2T29✅ Ligeramente sobre-óptimo
LLaMA-3 70B70B15T214✅ Deliberadamente over-trained
Mistral-7B7.3B~8T (est.)~1000✅ Over-trained (optimizar inferencia)
DeepSeek-V3671B (37B activos)14.8T22 (total) / 400 (activos)✅ MoE-optimized
💡 Tendencia 2024–2025: la industria ha pasado de "modelos Chinchilla-optimal" a "inference-optimal": entrenar modelos más pequeños con muchos más datos de los teóricamente óptimos, porque un modelo más pequeño es más barato de servir (menor latencia, menos GPU en inferencia). Esto explica por qué LLaMA-3 7B se entrena con 15T tokens (ratio D/N > 2000×), muy lejos del ratio 20× de Chinchilla. El razonamiento es que el coste de entrenamiento se paga una sola vez, pero el coste de inferencia se paga cada vez que alguien usa el modelo, así que invertir más en training para obtener un modelo más pequeño y eficiente es económicamente racional. Sardana, N. & Frankle, J. (2023). "Beyond Chinchilla-Optimal: Accounting for Inference in Language Model Scaling Laws". arXiv:2401.00448

Datasets masivos para Deep Learning

El entrenamiento de modelos de deep learning a escala requiere datasets cada vez más grandes, diversos y cuidadosamente curados:

Datasets de texto (NLP / LLMs)

DatasetTamañoFuenteUsado en
Common Crawl~250B páginas web (PBs)Web crawl mensualBase de casi todos los LLMs
FineWeb15T tokensCommon Crawl filtrado (HF)Open-source training
RedPajama v230T tokensWeb + libros + papers + códigoLLMs open-source
The Pile825 GB22 fuentes diversasGPT-NeoX, Pythia
C4~750 GB (~156B tokens)Common Crawl limpiado (Google)T5, mT5
RefinedWeb5T tokensCommon Crawl (Falcon)Falcon 40B/180B
StarCoder Data~783 GBCódigo de GitHubStarCoder, Code Llama

Datasets de visión

DatasetTamañoContenidoUsado en
ImageNet14M imágenes, 1000 clasesObjetos clasificadosResNet, ViT (pre-training)
LAION-5B5.85B pares imagen-textoWeb crawlStable Diffusion, OpenCLIP
JFT-300M300M imágenesInternal GoogleViT, EfficientNet (Google)
WebLI10B pares imagen-textoInternal GooglePaLI, Gemini
COCO330K imágenesDetección, segmentaciónObject detection benchmarks
SA-1B11M imágenes, 1.1B máscarasSegmentación (Meta)SAM (Segment Anything)

Datasets de audio y multimodal

DatasetTamañoContenidoUsado en
LibriSpeech~1000 h audioAudiolibros en inglésASR benchmarks
Common Voice~19,000 h, 100+ idiomasVoz crowdsourced (Mozilla)Whisper, multilingüe ASR
Whisper data (internal)680,000 h audioWeb audio supervisadoWhisper (OpenAI)
WebVid-10M10M vídeos + captionsWeb vídeosVideo generation models
  • Calidad vs cantidad: datos web contienen ruido, duplicados, contenido tóxico, PII. Se necesitan pipelines de limpieza sofisticados.
  • Sesgo: datos web reflejan sesgos culturales, de género, raciales. Modelos amplifican estos sesgos.
  • Copyright: uso de datos con copyright (libros, artículos, código) es legalmente controvertido. Casos: NYT vs OpenAI, Getty vs Stability AI.
  • Data contamination: benchmarks de evaluación pueden estar en los datos de training, inflando métricas.
  • Coste de curación: filtrar, deduplicar y etiquetar datos masivos requiere compute significativo.

El coste del compute para DL

El compute necesario para entrenar modelos SOTA ha crecido ~10× cada año desde 2012, mucho más rápido que la ley de Moore:

ModeloAñoCompute (PF-days)Coste estimadoDatos
AlexNet2012~0.01~$100ImageNet (1.2M)
ResNet-1522015~0.5~$1KImageNet (1.2M)
BERT-large2018~64~$10KBooksCorpus + Wikipedia
GPT-22019~256~$50KWebText (40GB)
GPT-32020~3,640~$5M~300B tokens
PaLM2022~25,000~$10M780B tokens
GPT-4 (est.)2023~80,000–200,000~$50–100M~13T tokens (est.)
Gemini Ultra (est.)2024~100,000+~$100M+Multimodal masivo
LLaMA-3 405B2024~40,000~$30M (est.)15T tokens
📊 Epoch AI (2024): el compute de entrenamiento de modelos SOTA se ha multiplicado por ~4× cada año desde 2010, con una aceleración adicional desde 2020 con LLMs. El coste total de un frontier model en 2025 supera los $100M, haciendo del entrenamiento a escala un privilegio de pocas organizaciones. Sevilla, J. et al. (2022). "Compute Trends Across Three Eras of Machine Learning". arXiv:2202.05924.

📚 Papers fundamentales sobre escala

Centros de datos para Deep Learning

Entrenar modelos de Deep Learning a escala requiere infraestructura especializada que va mucho más allá de un simple servidor con GPU. Los AI data centers modernos son instalaciones de miles de millones de dólares diseñadas específicamente para workloads de entrenamiento e inferencia de modelos de IA.

Un AI data center se diferencia de un data center tradicional en prácticamente todos sus aspectos: el hardware está dominado por aceleradores (GPUs, TPUs) en lugar de CPUs genéricas; la red necesita un ancho de banda entre nodos órdenes de magnitud superior al de un data center web convencional (porque el entrenamiento distribuido requiere sincronizar gradientes constantemente entre miles de GPUs); el almacenamiento necesita un throughput sostenido de TB/s para alimentar los pipelines de datos; la energía se multiplica (una sola GPU H100 consume 700W, frente a los ~100W de un servidor web) y la refrigeración requiere sistemas de liquid cooling directo porque la densidad de calor por rack es demasiado alta para los sistemas de aire acondicionado tradicionales.

Los siguientes componentes forman la arquitectura típica de un AI data center moderno. Cada uno de ellos es un cuello de botella potencial: si cualquier componente está subdimensionado, las costosas GPUs pasan tiempo ociosas.

Arquitectura de un AI Data Center

Aceleradores de hardware para DL

GPUs NVIDIA

GPUArq.VRAMFP16 TFLOPSFP8 TFLOPSInterconexiónTDPCoste cloud ($/h)
V100Volta32 GB HBM2125NVLink 300 GB/s300W~$1.5
A100Ampere80 GB HBM2e312NVLink 600 GB/s400W~$2.0
H100 SXMHopper80 GB HBM39901979NVLink 900 GB/s700W~$3.5
H200Hopper141 GB HBM3e9901979NVLink 900 GB/s700W~$4.5
B200Blackwell192 GB HBM3e22504500NVLink 1800 GB/s1000W~$6 (est.)
GB200 (Grace)Blackwell384 GB (2×192)45009000NVLink + Grace CPU2700WEnterprise

Otros aceleradores

Las TPUs son ASICs diseñados por Google específicamente para operaciones de tensor (MatMul + activaciones). Ventajas: eficiencia energética, integración con JAX/TensorFlow, disponibilidad en Google Cloud.

TPUAñoHBMBF16 TFLOPSInterconexión
TPU v2201716 GB HBM46ICI (custom)
TPU v3201832 GB HBM123ICI 656 GB/s
TPU v4202132 GB HBM2275ICI 1.1 TB/s
TPU v5e202316 GB HBM2197ICI
TPU v5p202395 GB HBM2e459ICI 4800 GB/s
Trillium (v6)202432 GB HBM~900ICI (next-gen)

TPU pods pueden escalar a miles de chips interconectados con ICI (Inter-Chip Interconnect), formando un mesh 3D de alta bandwidth. Un TPU v5p pod tiene 8960 chips con 459 TFLOPS cada uno.

Jouppi, N. et al. (2017). "In-Datacenter Performance Analysis of a Tensor Processing Unit". ISCA'17.

AMD Instinct MI300X ofrece 192 GB HBM3 (más que H100) con ~5.3 TB/s de bandwidth. Usa ROCm (stack open-source alternativo a CUDA). Adoptado por Microsoft Azure, Meta, y varios supercomputadores (Frontier).

MI325X (2024): 256 GB HBM3e, mayor bandwidth. Compite directamente con H200 en memoria.

AceleradorEmpresaEnfoque
Gaudi 2/3Intel (Habana Labs)Training/inference, integración Intel
Trainium2AWS (Annapurna Labs)Training en AWS, optimizado para SageMaker
Inferentia2AWSInferencia eficiente en AWS
WSE-3Cerebras SystemsWafer-scale: un chip = un wafer completo
CS-3Cerebras900K cores en un solo chip, 44 GB SRAM
Groq LPUGroqInferencia: deterministic scheduling, ultra-baja latencia

Redes de interconexión para AI

La red es el cuello de botella #1 en entrenamiento distribuido. El entrenamiento de un LLM requiere sincronizar gradientes entre miles de GPUs, lo que genera tráfico de red intensísimo (all-reduce).

TecnologíaBandwidthLatenciaNivelUso típico
NVLink (NVIDIA)900 GB/s (H100)<1 μsIntra-nodo (GPU↔GPU)Tensor parallelism dentro de un nodo
NVSwitchAll-to-all 900 GB/s<1 μsIntra-nodo (8 GPUs)Full mesh entre 8 GPUs en DGX
InfiniBand NDR400 Gb/s (50 GB/s)~1 μsInter-nodoAll-reduce entre nodos
InfiniBand XDR800 Gb/s (100 GB/s)<1 μsInter-nodoNext-gen clusters
RoCE v2100-400 Gb/s~2-5 μsInter-nodo (Ethernet)Alternativa Ethernet a IB
ICI (Google TPU)4.8 TB/s (v5p)<1 μsInter-chip (TPU)Mesh 3D dentro de TPU pod
💡 ¿Por qué importa tanto la red? En entrenamiento distribuido con data parallelism, cada GPU computa gradientes locales que deben sincronizarse (all-reduce) con todas las demás GPUs cada paso de training. Con un modelo de 70B parámetros (280 GB en FP32), cada all-reduce mueve cientos de GB. Si la red es lenta, las GPUs pasan más tiempo esperando que computando.

Almacenamiento para pipelines de DL

El almacenamiento en un AI data center tiene dos roles: datos de entrenamiento (TB–PB de datasets) y checkpoints (snapshots del modelo durante training).

CapaTecnologíaCapacidadThroughputRol
L1: GPU HBMHBM3/HBM3e80–192 GB/GPU~3 TB/sPesos, activaciones, gradientes
L2: NVMe localNVMe SSD1–8 TB/nodo~7 GB/sCache de datos, checkpoints rápidos
L3: Filesystem paraleloLustre, GPFS, WekaFSPBsTB/s (agregado)Datasets de training compartidos
L4: Object storeS3, GCS, MinIOIlimitadoGB/sAlmacenamiento a largo plazo, archival

Un error común es invertir millones en GPUs pero no dimensionar el storage. Si el data pipeline no puede alimentar las GPUs a velocidad suficiente, las GPUs están idle (esperando datos):

  • Prefetching: cargar el siguiente batch en CPU/RAM mientras la GPU procesa el actual.
  • Multi-worker DataLoader: PyTorch num_workers > 0, TF tf.data con prefetch(AUTOTUNE).
  • Memory mapping: archivos Parquet, Arrow, WebDataset evitan copias innecesarias.
  • Streaming datasets: HuggingFace load_dataset(streaming=True) para datos que no caben en disco local.
  • DALI (NVIDIA): pipeline de data augmentation acelerado por GPU.

Clusters de referencia en la industria

ClusterOrganizaciónAceleradoresRedModelos entrenados
Grand Teton Meta 16,000× A100 → 24,576× H100 InfiniBand NDR 400G LLaMA 2, LLaMA 3
Colossus xAI (Elon Musk) 100,000× H100 InfiniBand Grok-2
Eagle Microsoft/OpenAI ~25,000× A100 / H100 InfiniBand NDR GPT-4, GPT-4o
TPU v5p pod Google 8,960× TPU v5p ICI 4.8 TB/s Gemini
Frontier ORNL (DOE) 37,888× AMD MI250X HPE Slingshot 1.194 EFLOPS (primer exascale)
Leonardo CINECA (EU) 13,824× A100 InfiniBand HDR Modelos científicos europeos

⚡ El reto de la energía

Un cluster de 10,000 H100 consume ~7 MW solo en GPUs (sin cooling ni overhead). Un AI data center completo puede consumir 100–500 MW, equivalente al consumo de una ciudad pequeña. Microsoft, Google y Amazon están invirtiendo en energía nuclear (SMR) y renovables para alimentar sus futuros centros de IA.

PUE (Power Usage Effectiveness) = Energía total / Energía IT. Un PUE de 1.1 significa que por cada 1W de compute, se gastan 0.1W en cooling/overhead. Los mejores DCs modernos alcanzan PUE ~1.07 (Google).

🏗️ Widget: Estimador de coste de cluster

Estima el coste mensual de un AI cluster según su configuración.

Computación eficiente para Deep Learning

La eficiencia computacional es crucial tanto a nivel de usuario (optimizar el código en tu máquina) como a nivel de centro de datos (maximizar la utilización del hardware). Comprender las diferencias entre procesamiento secuencial, paralelo en CPU y paralelo en GPU es fundamental para escribir código de DL eficiente.

En deep learning, la operación dominante es la multiplicación de matrices (MatMul): cada capa fully-connected, cada atención en un Transformer, cada convolución se reduce internamente a multiplicaciones de matrices. Estas operaciones son inherentemente paralelizables: cada elemento del resultado es independiente de los demás y puede calcularse simultáneamente. Por eso, la elección del hardware de ejecución —CPU, GPU o ASIC especializado— tiene un impacto dramático en el rendimiento. La diferencia no es de porcentajes, sino de órdenes de magnitud.

Los tres tipos principales de hardware para deep learning difieren en su filosofía de diseño. Comprender estas diferencias ayuda a elegir el hardware correcto para cada tarea y a escribir código que explote al máximo la arquitectura subyacente. Para una introducción a las operaciones tensoriales que subyacen a todo esto, consulta el submódulo de Tensores.

🔲
CPU
Pocos núcleos potentes
  • 4–128 cores a ~5 GHz
  • Branch prediction, ejecución fuera de orden
  • Gran caché L1/L2/L3
  • RAM: hasta 2 TB DDR5
  • Excelente para lógica compleja e I/O
Ideal: preprocesamiento, data loading, lógica de control
🟩
GPU
Miles de cores simples (SIMT)
  • 16,000+ CUDA cores a ~2 GHz
  • Tensor Cores para MatMul (FP16/BF16/FP8)
  • HBM3e: hasta 192 GB, ~5 TB/s bandwidth
  • NVLink: 900 GB/s intra-nodo
  • Programable (CUDA, ROCm)
Ideal: training DL, operaciones vectorizadas, MatMul masivo
🔷
TPU / ASIC
Diseño ad-hoc para DL
  • MXU: Systolic Arrays 128×128 para BF16 MatMul
  • Hasta 95 GB HBM2e (TPU v5p)
  • ICI: 4.8 TB/s inter-chip (mesh 3D)
  • Pods de miles de chips
  • Programable vía JAX/TensorFlow
Ideal: training a escala masiva, modelos JAX/TF en cloud
💡 ¿Por qué las GPUs dominan el deep learning? La clave está en el paralelismo de datos. Una multiplicación de matrices de dimensión \(N \times N\) requiere \(N^3\) multiplicaciones escalares, todas independientes entre sí. Una CPU con 16 cores puede hacer 16 en paralelo; una GPU H100 con 16,384 CUDA cores + Tensor Cores puede hacer millones en paralelo. Para una operación como la atención en un Transformer (que implica múltiples MatMuls sobre matrices de dimensión \(d_{\text{model}} \times \text{seq\_len}\)), la diferencia es de 100–1000× en tiempo de ejecución. Jia, Z. et al. (2019). "Dissecting the NVIDIA Volta GPU Architecture via Microbenchmarking"

De bucles for a operaciones vectorizadas

La diferencia de rendimiento entre código Python puro y código vectorizado puede ser de órdenes de magnitud. Veamos con el ejemplo de la multiplicación de matrices:

import time

def matmul_python(A, B):
    """Multiplicación de matrices con bucles for puros.
    Complejidad: O(n³). Extremadamente lento para n > 500.
    """
    n = len(A)
    m = len(B[0])
    k = len(B)
    C = [[0.0] * m for _ in range(n)]
    for i in range(n):
        for j in range(m):
            for p in range(k):
                C[i][j] += A[i][p] * B[p][j]
    return C

# Benchmark: matrices 512×512
n = 512
A = [[float(i + j) for j in range(n)] for i in range(n)]
B = [[float(i * j) for j in range(n)] for i in range(n)]

start = time.time()
C = matmul_python(A, B)
print(f"Python puro: {time.time() - start:.2f}s")
# → Python puro: ~45-120 segundos (¡minutos para n=1024!)
import numpy as np
import time

def matmul_numpy(A, B):
    """NumPy usa BLAS optimizado (OpenBLAS/MKL) internamente.
    Operaciones vectorizadas en C/Fortran con SIMD y multi-core.
    """
    return A @ B  # equivalente a np.matmul(A, B)

# Benchmark: matrices 512×512
n = 512
A = np.random.randn(n, n).astype(np.float32)
B = np.random.randn(n, n).astype(np.float32)

start = time.time()
C = matmul_numpy(A, B)
print(f"NumPy (CPU): {time.time() - start:.4f}s")
# → NumPy (CPU): ~0.005-0.02 segundos (¡~2000-10000× más rápido!)

# ¿Por qué? NumPy llama a BLAS (Basic Linear Algebra Subprograms)
# implementado en C/Fortran con instrucciones SIMD (AVX-512)
# y multi-threading automático.

# Para matrices más grandes:
n = 4096
A = np.random.randn(n, n).astype(np.float32)
B = np.random.randn(n, n).astype(np.float32)
start = time.time()
C = A @ B
print(f"NumPy 4096×4096: {time.time() - start:.3f}s")
# → ~1-3 segundos (4096³ = 68B operaciones)
import cupy as cp
import time

def matmul_cupy(A, B):
    """CuPy: API idéntica a NumPy pero ejecuta en GPU.
    Internamente usa cuBLAS (NVIDIA's BLAS para CUDA).
    """
    return A @ B

# Benchmark: matrices 4096×4096 en GPU
n = 4096
A_gpu = cp.random.randn(n, n, dtype=cp.float32)
B_gpu = cp.random.randn(n, n, dtype=cp.float32)

# Warm-up (primera ejecución compila kernels)
_ = A_gpu @ B_gpu
cp.cuda.Stream.null.synchronize()

start = time.time()
C_gpu = matmul_cupy(A_gpu, B_gpu)
cp.cuda.Stream.null.synchronize()  # Esperar a que GPU termine
print(f"CuPy (GPU): {time.time() - start:.4f}s")
# → CuPy (GPU): ~0.005-0.02 segundos para 4096×4096
# ¡~100-500× más rápido que NumPy para matrices grandes!

# Transferencia CPU ↔ GPU (el coste oculto)
A_cpu = np.random.randn(n, n).astype(np.float32)

start = time.time()
A_gpu = cp.asarray(A_cpu)       # CPU → GPU
elapsed_to_gpu = time.time() - start

start = time.time()
A_back = cp.asnumpy(A_gpu)     # GPU → CPU
elapsed_to_cpu = time.time() - start

print(f"CPU→GPU: {elapsed_to_gpu:.4f}s, GPU→CPU: {elapsed_to_cpu:.4f}s")
# ¡La transferencia puede ser más lenta que el cómputo!
Método4096×4096 MatMulSpeedup vs PythonDónde ejecutaCuándo usar
Python puro (for)~horasCPU (1 core, interpretado)Nunca para cómputo numérico
NumPy~1-3 s~10,000×CPU (multi-core, BLAS)Datos pequeños-medianos, CPU
CuPy~0.01-0.02 s~500,000×GPU (CUDA, cuBLAS)Datos grandes, GPU disponible
PyTorch tensor~0.01-0.02 s~500,000×GPU (CUDA)Training DL, autograd
JAX (jit)~0.005-0.01 s~1,000,000×GPU/TPU (XLA compiled)Máxima performance, TPUs
💡 Lección clave: nunca uses bucles for en Python para operaciones numéricas. Usa operaciones vectorizadas (NumPy, CuPy, PyTorch, JAX) que delegan el cómputo a bibliotecas compiladas (BLAS, cuBLAS, XLA) que explotan paralelismo SIMD, multi-core y GPU automáticamente.

Devices en TensorFlow y PyTorch

Tanto TensorFlow como PyTorch permiten mover tensores y modelos entre diferentes devices (CPU, GPU, TPU). Entender cómo gestionar devices es esencial para el rendimiento.

import torch

# ═══════════════════════════════════════════════════
# Detectar devices disponibles
# ═══════════════════════════════════════════════════
print(f"CUDA disponible: {torch.cuda.is_available()}")
print(f"MPS disponible: {torch.backends.mps.is_available()}")  # Apple Silicon
print(f"Nº GPUs CUDA: {torch.cuda.device_count()}")
if torch.cuda.is_available():
    print(f"GPU actual: {torch.cuda.get_device_name(0)}")

# ═══════════════════════════════════════════════════
# Crear tensores en devices específicos
# ═══════════════════════════════════════════════════
x_cpu = torch.randn(1000, 1000)                    # CPU (por defecto)
x_gpu = torch.randn(1000, 1000, device='cuda')     # GPU directamente
x_gpu2 = torch.randn(1000, 1000, device='cuda:1')  # Segunda GPU

# ═══════════════════════════════════════════════════
# Mover tensores entre devices
# ═══════════════════════════════════════════════════
x_to_gpu = x_cpu.to('cuda')      # CPU → GPU
x_to_cpu = x_gpu.cpu()           # GPU → CPU
x_to_gpu_fp16 = x_cpu.to('cuda', dtype=torch.float16)  # + cambio de tipo

# ═══════════════════════════════════════════════════
# Mover modelos completos
# ═══════════════════════════════════════════════════
model = torch.nn.Linear(1000, 100)
model = model.to('cuda')         # Todos los parámetros a GPU
# ⚠️ Los datos de entrada también deben estar en el mismo device
output = model(x_to_gpu)

# ═══════════════════════════════════════════════════
# Device-agnostic code (buena práctica)
# ═══════════════════════════════════════════════════
device = torch.device(
    'cuda' if torch.cuda.is_available()
    else 'mps' if torch.backends.mps.is_available()
    else 'cpu'
)
model = model.to(device)
data = data.to(device)
import tensorflow as tf

# ═══════════════════════════════════════════════════
# Detectar devices disponibles
# ═══════════════════════════════════════════════════
print("Devices:", tf.config.list_physical_devices())
gpus = tf.config.list_physical_devices('GPU')
print(f"GPUs: {gpus}")
tpus = tf.config.list_physical_devices('TPU')
print(f"TPUs: {tpus}")

# ═══════════════════════════════════════════════════
# Configurar memoria GPU
# ═══════════════════════════════════════════════════
# TF por defecto reserva TODA la memoria GPU.
# Para permitir crecimiento dinámico:
for gpu in gpus:
    tf.config.experimental.set_memory_growth(gpu, True)

# O limitar a una cantidad fija:
# tf.config.set_logical_device_configuration(
#     gpus[0],
#     [tf.config.LogicalDeviceConfiguration(memory_limit=4096)]  # 4 GB
# )

# ═══════════════════════════════════════════════════
# Placement explícito de operaciones
# ═══════════════════════════════════════════════════
with tf.device('/CPU:0'):
    a = tf.random.normal([1000, 1000])  # En CPU

with tf.device('/GPU:0'):
    b = tf.random.normal([1000, 1000])  # En GPU

# TF automáticamente mueve datos entre devices si es necesario
c = tf.matmul(a, b)  # a se copia a GPU automáticamente

# ═══════════════════════════════════════════════════
# TPU setup (Google Cloud / Colab)
# ═══════════════════════════════════════════════════
# resolver = tf.distribute.cluster_resolver.TPUClusterResolver()
# tf.config.experimental_connect_to_cluster(resolver)
# tf.tpu.experimental.initialize_tpu_system(resolver)
# strategy = tf.distribute.TPUStrategy(resolver)

Comparativa de devices soportados

CaracterísticaPyTorchTensorFlow
CPU✅ Siempre✅ Siempre
NVIDIA GPU (CUDA)✅ Nativo (device='cuda')✅ Nativo (auto-detect)
Multi-GPUDataParallel, DistributedDataParallelMirroredStrategy, MultiWorkerStrategy
Google TPU⚠️ Via PyTorch/XLA (limitado)✅ Nativo (TPUStrategy)
Apple Silicon (MPS)device='mps' (M1/M2/M3/M4)⚠️ Soporte limitado (metal plugin)
AMD GPU (ROCm)✅ Nativo (PyTorch ROCm)⚠️ Soporte parcial
Intel GPU (XPU)⚠️ Via Intel Extensions⚠️ Via Intel plugin
AWS Trainium/Inferentia⚠️ Via Neuron SDK⚠️ Via Neuron SDK
Gestión de memoriaManual (.to(device))Automática (soft placement)
Mixed precisiontorch.cuda.amptf.keras.mixed_precision
Compilación (graph)torch.compile (2.0+)tf.function + XLA
⚡ PyTorch vs TensorFlow — device management:
  • PyTorch: control explícito (.to('cuda')). Más verboso, pero más predecible. Error si tensores en devices distintos.
  • TensorFlow: placement automático ("soft placement"). Más cómodo, pero a veces difícil de depurar qué está en qué device.
  • Para TPUs: TensorFlow/JAX tienen soporte nativo muy superior.
  • Para GPUs NVIDIA: ambos excelentes, PyTorch domina en investigación.

Prácticas de eficiencia computacional

A nivel de usuario

Usar half-precision (FP16 o BF16) en lugar de FP32 para la mayor parte del cómputo reduce el uso de memoria a la mitad y duplica el throughput en GPUs con Tensor Cores. Se mantiene una copia "master" en FP32 para estabilidad.

from torch.cuda.amp import autocast, GradScaler

scaler = GradScaler()

for batch in dataloader:
    optimizer.zero_grad()
    
    # Forward pass en FP16
    with autocast(dtype=torch.float16):
        output = model(batch['input'].cuda())
        loss = criterion(output, batch['target'].cuda())
    
    # Backward con gradient scaling (evita underflow en FP16)
    scaler.scale(loss).backward()
    scaler.step(optimizer)
    scaler.update()
# → ~2× más rápido, ~50% menos memoria

Simula batch sizes grandes acumulando gradientes durante varios mini-batches antes de hacer optimizer.step(). Útil cuando la GPU no tiene suficiente memoria para el batch size deseado.

accumulation_steps = 4  # Effective batch = micro_batch × 4

for i, batch in enumerate(dataloader):
    output = model(batch['input'].cuda())
    loss = criterion(output, batch['target'].cuda())
    loss = loss / accumulation_steps  # Normalizar
    loss.backward()
    
    if (i + 1) % accumulation_steps == 0:
        optimizer.step()
        optimizer.zero_grad()
# Effective batch size = 32 × 4 = 128, usando memoria de batch=32

En lugar de almacenar todas las activaciones intermedias para el backward pass (que consume mucha memoria), gradient checkpointing re-computa las activaciones durante el backward. Reduce memoria ~5× a cambio de ~30% más de tiempo de cómputo.

from torch.utils.checkpoint import checkpoint

class EfficientModel(torch.nn.Module):
    def forward(self, x):
        # En lugar de almacenar activaciones de cada bloque,
        # re-computa durante backward:
        x = checkpoint(self.block1, x, use_reentrant=False)
        x = checkpoint(self.block2, x, use_reentrant=False)
        x = checkpoint(self.block3, x, use_reentrant=False)
        return self.head(x)

# En HuggingFace Transformers:
model.gradient_checkpointing_enable()

torch.compile (PyTorch 2.0+) compila el modelo en un grafo optimizado que fusiona operaciones, elimina overhead de Python y genera kernels CUDA eficientes. Puede dar 20-50% de speedup sin cambiar código.

# PyTorch 2.0+
model = torch.compile(model, mode='reduce-overhead')
# Opciones de mode:
#   'default':         balance entre compilación y rendimiento
#   'reduce-overhead': minimiza overhead de Python (mejor para inference)
#   'max-autotune':    prueba múltiples estrategias (más lento en compilar)

# TensorFlow equivalente:
# @tf.function(jit_compile=True)  # Activa XLA
# def train_step(data, labels):
#     with tf.GradientTape() as tape:
#         predictions = model(data, training=True)
#         loss = loss_fn(labels, predictions)
#     gradients = tape.gradient(loss, model.trainable_variables)
#     optimizer.apply_gradients(zip(gradients, model.trainable_variables))

A nivel de centro de datos

PrácticaQué haceAhorro típico
MFU optimizationMaximizar Model FLOPs Utilization (~30-60% típico)2× throughput efectivo
Job scheduling (Slurm)Empaquetar jobs para minimizar GPUs idle20-40% utilización
Spot/preemptible instancesUsar instancias baratas con checkpointing60-80% coste
Liquid coolingReducir PUE de 1.4 a 1.1~20% energía total
Flash AttentionAtención IO-aware, evita materializar la matriz de atención2-4× speedup atención
Quantización (INT8/INT4)Reducir precisión de pesos en inferencia2-4× throughput inference

⚡ Widget: Calculadora de speedup

Estima el speedup de un pipeline al aplicar diferentes optimizaciones.

¿Por qué entrenamiento distribuido?

Los modelos modernos de Deep Learning son demasiado grandes para caber en una sola GPU y requieren demasiado compute para entrenarse en un tiempo razonable. El entrenamiento distribuido resuelve ambos problemas dividiendo el trabajo entre múltiples aceleradores.

Para entender por qué es necesario, consideremos las cifras: entrenar LLaMA-3 70B desde cero requirió aproximadamente 6.4 millones de GPU-horas. En una sola GPU H100, eso serían ~730 años. Meta utilizó 2,048 H100 durante ~30 días, reduciendo el tiempo casi linealmente. Sin entrenamiento distribuido, los modelos que hoy consideramos state-of-the-art simplemente no existirían: nadie puede esperar siglos para entrenar un modelo. El entrenamiento distribuido no es un lujo o una optimización; es un requisito fundamental para el deep learning a escala.

El reto principal del entrenamiento distribuido es la comunicación entre GPUs. Cada GPU calcula gradientes de forma local, pero estos deben sincronizarse con las demás GPUs para que el modelo aprenda de forma coherente. Esta sincronización (llamada all-reduce) genera un tráfico de red enorme que puede convertirse en el cuello de botella dominante si la infraestructura no está diseñada adecuadamente. Para más contexto sobre cómo funcionan los gradientes y el backpropagation, consulta el submódulo de Perceptrón y MLP.

💾
Memoria
GPT-3 (175B params) necesita ~700 GB solo para pesos en FP32. Una H100 tiene 80 GB. Se necesitan ≥ 9 GPUs solo para los pesos.
⏱️
Tiempo
LLaMA-3 70B tardó ~30 días en 2048 H100. En una sola GPU: ~170 años. Escalar = reducir tiempo linealmente.
🎯
Batch size
LLMs usan batch sizes de millones de tokens. Distribuir los datos entre GPUs permite batch sizes enormes sin agotar memoria.

📐 ¿Qué consume memoria en training?

Para un modelo de \(N\) parámetros entrenado con Adam en FP32:

ComponenteMemoriaEjemplo (7B)
Pesos del modelo\(4N\) bytes (FP32)28 GB
Gradientes\(4N\) bytes28 GB
Optimizer states (Adam: m, v)\(8N\) bytes56 GB
Activaciones (forward)Variable (batch × seq × hidden)~10-50 GB
Total\(\geq 16N\) bytes + activaciones~120-160 GB

Con mixed precision (FP16/BF16): pesos 2N + gradientes 2N + optimizer master 4N + states 8N = 16N bytes. Para 70B params → ~1.1 TB mínimo. Se necesitan ≥14 H100s solo para memoria.

Data Parallelism (DP)

En Data Parallelism, cada GPU tiene una copia completa del modelo. Los datos de entrenamiento se dividen entre GPUs, cada una computa gradientes locales, y luego se sincronizan (all-reduce) antes de actualizar los pesos.

Mini-batch global GPU 0 Modelo completo + micro-batch 0 GPU 1 Modelo completo + micro-batch 1 GPU 2 Modelo completo + micro-batch 2 🔄 All-Reduce: sincronizar gradientes → promedio Cada GPU calcula gradientes locales → se promedian → todos actualizan pesos
Data Parallelism: el modelo se replica en cada GPU, los datos se dividen
1
Replicar modelo: cada GPU recibe una copia idéntica del modelo y los optimizer states.
2
Dividir datos: el mini-batch se divide en micro-batches, uno por GPU.
3
Forward + backward local: cada GPU computa loss y gradientes con su micro-batch.
4
All-reduce: promediar gradientes de todas las GPUs (NCCL ring/tree all-reduce).
5
Actualizar pesos: cada GPU aplica el mismo update, manteniendo modelos sincronizados.
# ═══════════════════════════════════════════════════
# PyTorch DDP — Data Parallelism distribuido
# ═══════════════════════════════════════════════════
import torch
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data import DataLoader, DistributedSampler

def train(rank, world_size):
    # 1. Inicializar proceso distribuido
    dist.init_process_group("nccl", rank=rank, world_size=world_size)
    torch.cuda.set_device(rank)
    
    # 2. Crear modelo y wrappear con DDP
    model = MyModel().cuda(rank)
    model = DDP(model, device_ids=[rank])
    
    # 3. DataLoader con DistributedSampler
    sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)
    dataloader = DataLoader(dataset, batch_size=32, sampler=sampler)
    
    optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4)
    
    for epoch in range(num_epochs):
        sampler.set_epoch(epoch)  # Shuffle diferente cada epoch
        for batch in dataloader:
            inputs = batch['input'].cuda(rank)
            targets = batch['target'].cuda(rank)
            
            output = model(inputs)
            loss = criterion(output, targets)
            
            optimizer.zero_grad()
            loss.backward()        # DDP sincroniza gradientes automáticamente
            optimizer.step()
    
    dist.destroy_process_group()

# Lanzar con: torchrun --nproc_per_node=4 train.py
# O: python -m torch.distributed.launch --nproc_per_node=4 train.py
# ═══════════════════════════════════════════════════
# TensorFlow MirroredStrategy — Data Parallelism
# ═══════════════════════════════════════════════════
import tensorflow as tf

# 1. Crear strategy (auto-detecta GPUs)
strategy = tf.distribute.MirroredStrategy()
print(f"Número de replicas: {strategy.num_replicas_in_sync}")

# 2. Crear modelo dentro del scope de la strategy
with strategy.scope():
    model = tf.keras.Sequential([
        tf.keras.layers.Dense(512, activation='relu'),
        tf.keras.layers.Dense(10)
    ])
    model.compile(
        optimizer=tf.keras.optimizers.Adam(1e-4),
        loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
        metrics=['accuracy']
    )

# 3. Crear dataset distribuido
batch_size_per_replica = 32
global_batch_size = batch_size_per_replica * strategy.num_replicas_in_sync

dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train))
dataset = dataset.shuffle(10000).batch(global_batch_size).prefetch(tf.data.AUTOTUNE)

# 4. Entrenar — TF distribuye automáticamente
model.fit(dataset, epochs=10)

# Para multi-nodo:
# strategy = tf.distribute.MultiWorkerMirroredStrategy()
⚠️ Limitación de Data Parallelism: el modelo completo debe caber en cada GPU. Para modelos de 70B+ parámetros, esto no es posible con una sola GPU (ni siquiera H200 con 141 GB). Se necesita Model Parallelism.

Model Parallelism

En Model Parallelism, el modelo se divide entre múltiples GPUs. Cada GPU solo tiene una parte del modelo. Existen dos variantes principales.

La necesidad de model parallelism surge cuando el modelo es demasiado grande para caber en una sola GPU, incluso con mixed precision. Un modelo de 70B parámetros en FP16 ocupa ~140 GB solo para los pesos, sin contar gradientes, optimizer states ni activaciones. Como ninguna GPU actual tiene tanta memoria (la H200 llega a 141 GB, pero el overhead la hace insuficiente), es necesario distribuir el modelo entre varias GPUs. A diferencia del data parallelism —donde cada GPU tiene el modelo completo y los datos se dividen—, en model parallelism cada GPU tiene solo una fracción del modelo, y la comunicación entre GPUs es necesaria incluso durante un solo paso de forward. Esto hace que la latencia y el ancho de banda de la red sean mucho más críticos.

Tensor Parallelism (TP)

✂️ Tensor Parallelism

Divide capas individuales (tensores de pesos) entre GPUs. Por ejemplo, una capa linear de dimensión \(d \times d\) se divide en \(N\) partes, cada GPU computa su fragmento y luego se agrega.

  • Cuándo: modelos grandes, GPUs dentro del mismo nodo (requiere bandwidth alta: NVLink)
  • Implementación: Megatron-LM (NVIDIA), tensor_parallel en DeepSpeed
  • Comunicación: all-reduce dentro de cada capa → requiere NVLink (900 GB/s intra-nodo)
  • Típico: TP=8 (8 GPUs por nodo, una capa dividida en 8)

Shoeybi, M. et al. (2019). "Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism". arXiv:1909.08053.

Pipeline Parallelism (PP)

🔗 Pipeline Parallelism

Divide el modelo en stages (grupos de capas consecutivas), cada stage en una GPU diferente. Los micro-batches fluyen como en un pipeline industrial, permitiendo que múltiples GPUs trabajen simultáneamente.

  • Cuándo: modelos muy profundos, distribución entre nodos (tolera mayor latencia)
  • Implementación: GPipe (Google), PipeDream (Microsoft), DeepSpeed pipeline
  • Problema: "pipeline bubbles" — GPUs idle al inicio/fin del pipeline
  • Solución: micro-batching (más micro-batches → menos bubbles)

Huang, Y. et al. (2019). "GPipe: Efficient Training of Giant Neural Networks using Pipeline Parallelism". NeurIPS'19.

Narayanan, D. et al. (2019). "PipeDream: Generalized Pipeline Parallelism for DNN Training". SOSP'19.

Pipeline Parallelism (4 stages × 4 micro-batches) GPU 0 (Stage 0) GPU 1 (Stage 1) GPU 2 (Stage 2) GPU 3 (Stage 3) F₀ F₁ F₂ F₃ idle F₀ F₁ F₂ F₃ idle F₀ F₁ F₂ F₃ idle (bubble) F₀ F₁ F₂ F₃ B₀ B₁ Forward passes (Fᵢ) Backward (Bᵢ) Las zonas "idle" son pipeline bubbles — se minimizan con más micro-batches
Pipeline Parallelism: el modelo se divide en stages, datos fluyen como en un pipeline

3D Parallelism y FSDP

Cuando un modelo es suficientemente grande —cientos de miles de millones de parámetros—, ninguna de las técnicas anteriores es suficiente por sí sola. Data parallelism necesita que el modelo quepa en cada GPU; tensor parallelism satura a pocos GPUs por la comunicación all-reduce dentro de cada operación; y pipeline parallelism introduce burbujas que limitan la eficiencia. La solución es combinar las tres en lo que se denomina 3D parallelism: una cuadrícula tridimensional donde cada eje corresponde a una dimensión de partición diferente.

Esta idea fue formalizada por NVIDIA en su framework Megatron-LM v2 (2021). La clave es asignar cada eje de paralelismo al nivel de interconexión adecuado: TP dentro del nodo (NVLink, alta velocidad), PP entre nodos cercanos, y DP en la dimensión más externa (tolera mayor latencia). Esta asignación jerárquica minimiza la comunicación en los enlaces más lentos.

🧊 3D Parallelism (DP × TP × PP)

Los LLMs modernos combinan las tres técnicas simultáneamente. Configuración típica para entrenar un modelo de 70B en 256 GPUs (32 nodos × 8 GPUs):

  • TP = 8: cada capa se divide entre las 8 GPUs del nodo (NVLink intra-nodo)
  • PP = 4: el modelo se divide en 4 stages, cada stage en un grupo de 8 GPUs
  • DP = 8: 8 réplicas del pipeline completo, datos divididos entre réplicas
  • Total: 8 × 4 × 8 = 256 GPUs

Narayanan, D. et al. (2021). "Efficient Large-Scale Language Model Training on GPU Clusters Using Megatron-LM". SC'21.

FSDP (PyTorch) / ZeRO (DeepSpeed) es un híbrido entre data parallelism y model parallelism. En lugar de replicar el modelo completo en cada GPU, fragmenta (shard) los pesos, gradientes y optimizer states entre todas las GPUs:

StageQué fragmentaMemoria por GPU
ZeRO Stage 1Optimizer states\(\approx 4N + 4N + \frac{8N}{P}\)
ZeRO Stage 2+ Gradientes\(\approx 4N + \frac{4N+8N}{P}\)
ZeRO Stage 3 / FSDP+ Pesos del modelo\(\approx \frac{16N}{P}\) (todo fragmentado)

Con \(P\) GPUs, FSDP/ZeRO-3 reduce la memoria por GPU \(P\) veces. 32 GPUs con un modelo de 7B: de ~112 GB/GPU (DP) a ~3.5 GB/GPU (FSDP).

Rajbhandari, S. et al. (2020). "ZeRO: Memory Optimizations Toward Training Trillion Parameter Models". SC'20.

# ═══════════════════════════════════════════════════
# PyTorch FSDP — Fully Sharded Data Parallel
# ═══════════════════════════════════════════════════
import torch
from torch.distributed.fsdp import (
    FullyShardedDataParallel as FSDP,
    MixedPrecision,
    ShardingStrategy,
)
from torch.distributed.fsdp.wrap import transformer_auto_wrap_policy
from transformers import AutoModelForCausalLM

# 1. Configurar mixed precision
mp_policy = MixedPrecision(
    param_dtype=torch.bfloat16,
    reduce_dtype=torch.bfloat16,
    buffer_dtype=torch.bfloat16,
)

# 2. Definir qué capas se fragmentan
auto_wrap_policy = transformer_auto_wrap_policy(
    transformer_layer_cls={transformers.models.llama.modeling_llama.LlamaDecoderLayer}
)

# 3. Crear modelo FSDP
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
model = FSDP(
    model,
    sharding_strategy=ShardingStrategy.FULL_SHARD,  # ZeRO-3
    mixed_precision=mp_policy,
    auto_wrap_policy=auto_wrap_policy,
    device_id=torch.cuda.current_device(),
)

# 4. Training loop normal — FSDP gestiona fragmentación automáticamente
optimizer = torch.optim.AdamW(model.parameters(), lr=2e-5)
for batch in dataloader:
    loss = model(**batch).loss
    loss.backward()
    optimizer.step()
    optimizer.zero_grad()

# Lanzar: torchrun --nproc_per_node=8 --nnodes=4 train_fsdp.py

Frameworks de entrenamiento distribuido

El ecosistema de entrenamiento distribuido ha madurado enormemente desde 2020. Mientras que antes cada organización construía sus propias soluciones, hoy existen frameworks de código abierto que encapsulan las técnicas de paralelismo descritas arriba y las hacen accesibles con pocas líneas de configuración.

La elección del framework depende fundamentalmente de tres factores: la escala del modelo (modelos de <10B suelen basta con DDP/FSDP, mientras que modelos de 100B+ necesitan Megatron-DeepSpeed), el hardware disponible (GPUs NVIDIA vs TPUs Google), y la complejidad que estés dispuesto a asumir. La siguiente tabla resume las opciones más relevantes en 2024.

FrameworkOrganizaciónParallelismMejor para
PyTorch DDPMetaData ParallelMulti-GPU estándar
PyTorch FSDPMetaData + ShardingModelos grandes (7B–70B)
DeepSpeedMicrosoftZeRO 1-3 + PP + TPModelos muy grandes, ZeRO-Offload
Megatron-LMNVIDIATP + PP + DP (3D)Pre-training LLMs a escala máxima
HuggingFace AccelerateHugging FaceWrapper sobre DDP/FSDP/DeepSpeedSimplicidad, fine-tuning
Ray TrainAnyscaleData ParallelIntegración con Ray ecosystem
JAX (pjit/xmap)GoogleSPMD, automatic shardingTPU pods, máxima eficiencia
tf.distributeGoogleMirrored, MultiWorker, TPUEcosistema TensorFlow/Keras
Colossal-AIHPC-AI TechGemini, secuencia parallelismEficiencia memoria, sequence TP

DeepSpeed (Microsoft) es el framework más completo para entrenamiento distribuido eficiente. Además de ZeRO (stages 1-3), incluye:

  • ZeRO-Offload: mueve optimizer states y gradientes a CPU RAM (entrena modelos grandes en pocas GPUs).
  • ZeRO-Infinity: extiende offload a NVMe SSD (entrena modelos de trillones de params).
  • DeepSpeed-MoE: soporte nativo para Mixture of Experts.
  • FlexGen: inferencia eficiente con offloading.
  • 1-bit Adam: compresión de comunicación para reducir tráfico de red.
# deepspeed_config.json
{
    "bf16": {"enabled": true},
    "zero_optimization": {
        "stage": 3,
        "offload_optimizer": {"device": "cpu"},
        "offload_param": {"device": "none"},
        "overlap_comm": true,
        "contiguous_gradients": true,
        "reduce_scatter": true
    },
    "gradient_accumulation_steps": 4,
    "train_micro_batch_size_per_gpu": 2,
    "wall_clock_breakdown": false
}
# Lanzar: deepspeed --num_gpus=8 train.py --deepspeed ds_config.json

Rajbhandari, S. et al. (2020). "ZeRO: Memory Optimizations Toward Training Trillion Parameter Models". SC'20.

Ren, J. et al. (2021). "ZeRO-Offload: Democratizing Billion-Scale Model Training". USENIX ATC'21.

Accelerate simplifica el entrenamiento distribuido abstrayendo DDP, FSDP y DeepSpeed detrás de una API unificada. Permite cambiar entre strategies sin cambiar código:

# ═══════════════════════════════════════════════════
# HuggingFace Accelerate — wrapper unificado
# ═══════════════════════════════════════════════════
from accelerate import Accelerator

accelerator = Accelerator(
    mixed_precision='bf16',       # o 'fp16'
    gradient_accumulation_steps=4,
)

# Preparar modelo, optimizer, dataloader
model, optimizer, dataloader = accelerator.prepare(
    model, optimizer, dataloader
)

for batch in dataloader:
    with accelerator.accumulate(model):
        outputs = model(**batch)
        loss = outputs.loss
        accelerator.backward(loss)
        optimizer.step()
        optimizer.zero_grad()

# Configurar: accelerate config (wizard interactivo)
# Lanzar: accelerate launch --num_processes=8 train.py

¿Cuándo usar qué técnica?

La regla de oro es empezar siempre con la técnica más simple que funcione. Data parallelism con DDP debería ser el primer recurso; solo cuando el modelo no cabe en una GPU (o la velocidad es insuficiente) se justifica pasar a sharding (FSDP/ZeRO) y, más allá, a combinaciones de paralelismo más complejas. Cada nivel de complejidad introduce overhead de comunicación, dificultades de debugging y puntos de fallo adicionales.

Para fine-tuning de LLMs, la combinación de LoRA + cuantización (QLoRA) ha democratizado enormemente el acceso: permite adaptar modelos de 70B en una o dos GPUs consumer (24 GB VRAM). Consulta el submódulo de Optimización avanzada para detalles sobre estas técnicas de eficiencia paramétrica.

EscenarioTécnica recomendadaDetalle
Modelo cabe en 1 GPU, quiero más velocidadData Parallelism (DDP)La más sencilla. Escala lineal con GPUs.
Modelo cabe en 1 GPU, quiero batch size grandeDDP + Gradient AccumulationSimula batch grande sin más memoria.
Modelo NO cabe en 1 GPU (7B–13B)FSDP / ZeRO Stage 3Fragmenta pesos entre GPUs. Mínimo cambio de código.
Modelo grande (30B–70B)FSDP + TP o 3D ParallelismTensor parallelism intra-nodo + FSDP entre nodos.
Modelo muy grande (100B+)3D Parallelism (Megatron + DeepSpeed)TP × PP × DP. Requiere ingeniería de infraestructura.
Fine-tuning de LLM grandeLoRA + FSDP/DeepSpeedLoRA reduce los parámetros entrenables → cabe en menos GPUs.
TPU podsJAX pjit / TF TPUStrategySPMD: automatic sharding optimizado para TPU mesh.
Pocos recursos (1-2 GPUs)QLoRA + DeepSpeed ZeRO-OffloadOffload a CPU, quantización 4-bit. Fine-tune 70B en 2×24GB.

🧩 Widget: Selector de estrategia de paralelismo

Recomienda la estrategia óptima según tu hardware y modelo.

Papers y recursos fundamentales

El entrenamiento distribuido es una de las áreas de investigación más activas en sistemas para deep learning. Los siguientes papers constituyen las referencias canónicas que todo practicante debería conocer. Están ordenados cronológicamente para reflejar la evolución del campo, desde los primeros trabajos en data parallelism hasta las técnicas de sharding que hacen posible entrenar modelos de cientos de miles de millones de parámetros.

📚 Papers esenciales de entrenamiento distribuido

  • Data Parallelism: Li, M. et al. (2020). "PyTorch Distributed: Experiences on Accelerating Data Parallel Training". arXiv:2006.15704
  • Megatron-LM: Shoeybi, M. et al. (2019). "Training Multi-Billion Parameter Language Models Using Model Parallelism". arXiv:1909.08053
  • GPipe: Huang, Y. et al. (2019). "Efficient Training of Giant Neural Networks using Pipeline Parallelism". arXiv:1811.06965
  • PipeDream: Narayanan, D. et al. (2019). "Generalized Pipeline Parallelism for DNN Training". arXiv:1806.03377
  • ZeRO: Rajbhandari, S. et al. (2020). "Memory Optimizations Toward Training Trillion Parameter Models". arXiv:1910.02054
  • ZeRO-Offload: Ren, J. et al. (2021). "Democratizing Billion-Scale Model Training". arXiv:2101.06840
  • FSDP: Zhao, Y. et al. (2023). "PyTorch FSDP: Experiences on Scaling Fully Sharded Data Parallel". arXiv:2304.11277
  • Flash Attention: Dao, T. et al. (2022). "IO-Aware Exact Attention with IO-Awareness". arXiv:2205.14135
  • DeepSpeed: github.com/microsoft/DeepSpeed
  • Megatron-DeepSpeed: github.com/microsoft/Megatron-DeepSpeed
  • Lilian Weng — "How to Train Really Large Models on Many GPUs": lilianweng.github.io (excelente artículo divulgativo)

💡 Para entender los fundamentos de las redes neuronales sobre las que se construyen estos modelos distribuidos, consulta los submódulos de Perceptrón y MLP y Large Language Models. Para técnicas de eficiencia como LoRA y quantización mencionadas en esta sección, ver Optimización avanzada.