English · Español
05 — Derivación del ring all-reduce; cuándo aplica cada estrategia de paralelismo¶
🇪🇸 El "2S" del ring all-reduce no es magia: sale de un argumento de información — cada worker tiene que enviar y recibir aproximadamente todo el tensor para que la suma esté en todas partes. Esta página deriva el coste, lo conecta con el deep-dive de hardware (X4) y da la tabla de decisión para elegir DP / TP / PP / ZeRO / FSDP según el tamaño del modelo y el batch.
Referencia cruzada a X4 (no duplicar)¶
El módulo de extensión hardware-deep-dive ya cubre el lado de ancho de banda de NVLink / InfiniBand. Re-léelo:
docs/extension-track/X4-hardware-deep-dive/theory/03-interconnects-and-topology.md— cifras de ancho de banda de los enlaces, clases de topología.docs/extension-track/X4-hardware-deep-dive/theory/04-datacenter-economics.md— $ por byte-segundo.
Este capítulo es el complemento del lado algoritmo: de dónde sale el factor 2S y por qué es el mismo en cualquier topología que admita un recorrido en anillo.
El límite inferior teórico-informativo¶
Considera \(N\) workers cada uno con un tensor \(x_i \in \mathbb{R}^d\) de tamaño \(S\) bytes. El objetivo del all-reduce es que cada worker termine con \(y = \sum_i x_i\).
Afirmación. Cualquier algoritmo all-reduce, sobre cualquier topología de comunicación, requiere al menos \(\frac{N-1}{N} S \approx S\) bytes enviados por worker (para \(N\) grande).
Esbozo. El worker \(i\) termina con información sobre cada \(x_{j \neq i}\). La única manera de que esa información llegue es vía bytes recibidos. Por un argumento de conteo, como mínimo \(\sum_{j \neq i} \text{bytes}_{ij} \ge S\) — es decir, el worker \(i\) debe recibir ~\(S\) bytes. Por simetría del protocolo, también debe enviar ~\(S\) bytes (la red es el mismo conjunto de bytes desde el otro lado).
Por tanto \(S\) enviado + \(S\) recibido = \(2S\) por worker es el suelo. El ring all-reduce alcanza este suelo (asintóticamente). Por eso es el algoritmo canónico.
La construcción del anillo — derivación explícita¶
Workers dispuestos en un anillo lógico: \(0 \to 1 \to \ldots \to N-1 \to 0\). Divide cada \(x_i\) en \(N\) chunks de tamaño \(S/N\), indexados \(x_i[0], x_i[1], \ldots, x_i[N-1]\).
Fase 1: reduce-scatter (N-1 pasos)¶
En el paso \(k\) (para \(k = 0, \ldots, N-2\)), el worker \(i\) envía el chunk \(x_i[(i - k) \bmod N]\) a su vecino derecho, recibe el chunk \(x_{i-1}[(i - 1 - k) \bmod N]\) de su vecino izquierdo, y lo suma a su copia local de ese chunk.
Tras \(N-1\) pasos, cada chunk ha acumulado contribuciones de todos los workers. En concreto, el worker \(i\) ahora tiene el chunk totalmente reducido \((i + 1) \bmod N\).
Bytes enviados por worker en la Fase 1: \((N-1) \cdot S/N \approx S\) para \(N\) grande.
Fase 2: all-gather (N-1 pasos más)¶
Ahora distribuye los chunks totalmente reducidos. En el paso \(k\), el worker \(i\) envía su chunk totalmente reducido actual a su vecino derecho, recibe el siguiente chunk totalmente reducido de su izquierdo. Tras \(N-1\) pasos, cada worker tiene los \(N\) chunks totalmente reducidos → all-reduce completo.
Bytes enviados por worker en la Fase 2: \((N-1) \cdot S/N \approx S\).
Total por worker: \(\approx 2S\). Coincide con el límite inferior.
¿Y la latencia?¶
Cada fase tiene \(N-1\) pasos secuenciales con un round-trip de red cada uno: latencia \(= 2 (N-1) \cdot \tau\) donde \(\tau\) es la latencia por paso. Para \(S\) pequeño esto domina. El tree all-reduce intercambia el ancho de banda óptimo por latencia \(O(\log N)\); NCCL elige entre ellos según el tamaño del payload (ver X4 §03).
Por qué importa para el tutor de gramática §A13¶
A nuestra escala, \(|\theta| = 500\)k params, \(S = 1\) MB. En gloo / loopback la latencia por paso \(\tau \approx 50\,\mu s\), ancho de banda de red \(\approx 1\) GB/s efectivo. Para \(N = 4\) workers de CPU:
- Bytes por worker por all-reduce: \(\approx 2\) MB.
- Tiempo de ancho de banda: \(2 / 1000 = 2\) ms.
- Tiempo de latencia: \(2 \cdot 3 \cdot 50\,\mu s = 300\,\mu s\).
All-reduce total: ~2.3 ms. Por step. Para un forward+backward que tarda ~50 ms, el overhead de comm es ~5%. Aceptable.
Para el modelo hipotético de 7B en el clúster (el ejemplo trabajado de X1 / X4): la misma fórmula da ~30 ms solo NVLink, 1+ s en Ethernet lento, que es la anécdota original de "DDP no escala más allá de N=8 en redes baratas".
La forma es constante; solo cambian los números. Por eso derivarlo una vez, sobre el modelo microscópico, transfiere.
¿Cuándo aplica cada estrategia de paralelismo?¶
Una tabla de decisión para el ingeniero en activo:
| Estrategia | Mejor cuando | Comm por step | Perfil de memoria |
|---|---|---|---|
| Data parallel (DDP) | El modelo cabe en un worker; tienes batch de sobra | \(2S_\theta\) por step (all-reduce) | Cada worker guarda params + grads + states completos |
| ZeRO-1 / FSDP-light | Los estados del optimizador dominan la memoria (Adam = 8×params); el modelo aún cabe | \(2S_\theta\) pero por etapas | Optimizador con shard entre N workers |
| ZeRO-2 / FSDP-mid | El optimizador + grads dominan | \(2S_\theta\) + grad-scatter | Grads + opt con shard |
| ZeRO-3 / FSDP-full | El modelo en sí no cabe | Más all-gathers por step | Params, grads, opt todos con shard |
| Tensor parallel | Un solo matmul no cabe en un worker (d_model grande); solo intra-nodo |
All-reduce dentro de la capa | Params seccionados por el eje del matmul |
| Pipeline parallel | El modelo tiene muchas capas y no caben; inter-nodo tolerable | Activation send/recv por etapa | Un bloque de capas por worker |
| 3D parallel | Escala frontera (≥ 100B params en ≥ 256 GPUs); requiere scheduling de comm cuidadoso | Todo lo anterior | Todo lo anterior |
La receta estándar:
- Empieza con DDP (o su equivalente moral en single-host).
- Cuando los estados del optimizador te dan OOM, añade ZeRO-1.
- Cuando los grads también dan OOM, ZeRO-2.
- Cuando los params no caben, ZeRO-3 / FSDP.
- Cuando un solo matmul es demasiado grande para un dispositivo, añade TP dentro de un nodo.
- Cuando el modelo tiene demasiadas capas para caber incluso con lo anterior, añade PP entre nodos.
El tutor de gramática §A13 nunca alcanza el paso 2. El ejemplo de 7B-en-8-H100s (X4 §04) está en el paso 3-4. Las ejecuciones de frontera 100B+ (X1) están en el paso 6.
El coste auxiliar: complejidad del código¶
Un factor sutil que no entra en las matemáticas de ancho de banda: cada paso añade complejidad de ingeniería. La corrección de FSDP requiere alineamiento de buckets de gradientes, ZeRO-3 requiere ordenamiento de param-prefetch, TP requiere colocación cuidadosa de colectivas en el forward de la capa. Cada paso aproximadamente duplica la superficie de "cosas que pueden producir silenciosamente gradientes incorrectos".
Por eso el lab de la Fase 35 es vocabulario, no implementación: el coste-de-bugs escala con la elección de estrategia, y elegir mal es mucho más caro de lo que sugiere la diferencia de ancho de banda.
Lo que este capítulo NO cubre¶
- Internos del kernel NCCL: DMA GPU-direct, selección adaptativa ring-vs-tree, SHARP. Territorio de producción / X4.
- Políticas de sharding híbrido (FSDP HYBRID_SHARD): FSDP intra-nodo + DDP inter-nodo. Real, usado en entrenamiento de frontera (X1).
- Compresión de gradientes (1-bit Adam, signSGD): intercambia error de compresión por reducción de comm. Solo investigación a nuestra escala.
- Scheduling de pipeline bubble (1F1B, 1F1B intercalado): el ordenamiento activation-send/recv que hace PP usable. Merece una lectura aparte; X1 lo menciona.
Referencias¶
- Patarasuk & Yuan, "Bandwidth Optimal All-reduce Algorithms for Clusters of Workstations" (J. Parallel Distrib. Comput., 2009). La derivación original de la optimalidad de ancho de banda del anillo.
- Rajbhandari et al., "ZeRO: Memory Optimizations Toward Training Trillion Parameter Models" (SC'20). Las tres etapas de ZeRO con el trade-off exacto memoria-vs-comm.
- Shoeybi et al., "Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism" (2019). La receta de TP.
Siguiente: ../lab/03-megatron-fsdp-reading.md.