Equivalencia numérica entre backends heterogéneos
CUDA, ROCm, Adreno y las CPU nunca coincidirán bit a bit. Que el enjambre aún produzca un modelo coherente es una propiedad diseñada, no suerte.
Exacto vs equivalente — dos propiedades distintas
- Dentro de un backend — exacto (3.6e-12): repartir expertos entre nodos y combinarlos es la misma suma ponderada reagrupada; la única diferencia es el orden de acumulación en coma flotante. Verificado por oráculo.
- Entre backends — equivalente (1e-3…1e-6): la misma operación en hardware distinto arrastra un error relativo por operación de ~1e-3–1e-6, y nunca es cero. El enjambre vive en este régimen.
"Exacto" es lo que la descomposición garantiza dentro de un dispositivo. "Equivalente" es lo que da el hardware heterogéneo. El trabajo del enjambre es evitar que la equivalencia se componga en divergencia.
No es teoría — medido en hardware
El mismo FFN de expertos de layer-0 de Qwen3.5-122B, computado por linkcpp-expert-worker en un MI250 (ROCm), la ARM CPU de un teléfono (SM-S938N) y una referencia numpy en x86 — mismas entradas, mismos pesos, distintos juegos de instrucciones y órdenes de reducción:

| Par de backends | max|Δ| | cosine |
|---|---|---|
| ROCm (GPU) vs numpy (x86) | 7.9e-7 | 0.99996 |
| ARM CPU del teléfono vs numpy (x86) | 1.4e-6 | 0.99992 |
| GPU ROCm vs ARM CPU del teléfono | 1.5e-6 | 0.99990 |
Tres juegos de instrucciones, una computación — cada par equivalente (cosine ≈ 0.9999), ningún par bit-idéntico (Δ ≈ 1e-6). Los residuos son pequeños porque la autoridad del router fijó las entradas y la selección de expertos.
Una corrida posterior sobre hardware real NVIDIA GB10 Grace Blackwell cerró la matriz en el último backend: CUDA ↔ ROCm cayó en cosine 1.0000000000 (max abs 3.5e-10, efectivamente bit-idéntico, ya que ambos backends de GPU comparten fuentes de kernel), y CUDA ↔ Grace ARM CPU en cosine 0.99975 — el mismo patrón GPU↔CPU visto arriba.
La suma en coma flotante no es asociativa
- Orden de reducción del matmul — tensor cores, tiles MFMA, workgroups OpenCL y lanes SIMD acumulan en órdenes y teselados distintos.
- Fusión FMA —
a*b+credondeado una vez (FMA) o dos, fusionado distinto según backend. - Precisión de acumulación — almacenamiento F16/BF16 con acumuladores F32 vs F16 (la mayor palanca de la divergencia).
- Aproximaciones trascendentes — variantes polinómicas/de tabla de exp (softmax), silu/sigmoid (swiglu), rsqrt (norms).
- Ruta dequant + matmul — decuantizar-y-multiplicar vs kernels cuantizados fusionados redondean los intermedios de forma distinta.
- Kernels no deterministas — las reducciones atomic/split-K pueden variar entre ejecuciones en el mismo dispositivo.
Nada de esto es un bug. Es el precio que paga la ruta rápida de cada acelerador.
Una autoridad para las decisiones, precisión suficiente para la acumulación
AUTORIDAD DEL ROUTER — el invariante central. La única decisión discreta dentro de la red es el enrutamiento MoE (top-8 de 256). Si cada backend re-ejecutara el router, los tokens fronterizos elegirían expertos distintos y divergirían de verdad. Kvasir ejecuta el router una vez, en el backbone, y envía a los workers solo los ids de expertos seleccionados. Un enjambre heterogéneo puede diferir en la *magnitud* de la salida de cada experto — nunca difiere en *qué expertos corren*. Esto convierte una divergencia discreta catastrófica en un error continuo acotado, y es la regla de coherencia del sharding heterogéneo de expertos.
- Argmax discreto: decodificar es un argmax sobre logits. Un temblor de 1e-3 voltea un token solo cuando dos candidatos distan menos de 1e-3 — en la mayoría de posiciones el margen es mucho mayor, así que los tokens salen idénticos; los raros volteos ocurren en posiciones tan ambiguas como otra semilla.
- El combine es suma: los resultados parciales se funden como suma ponderada por probabilidad. Errores independientes de ~1e-4 se suman incoherentemente — crecen como √k, no k — y no hay cancelación de valores grandes, así que el residuo queda bien condicionado.
Modos de divergencia y defensas
| Modo de divergencia | Mecanismo | Regla |
|---|---|---|
| Desajuste de enrutamiento | Los backends eligen top-8 distintos en tokens fronterizos | Autoridad del router — decidido una vez en el backbone, ids despachados |
| Bifurcación de trayectoria | El temblor de logits por token acaba volteando uno; la secuencia se bifurca como otra semilla | Decodificación/muestreo fijados a un nodo |
| Acumulación en profundidad | 49 capas × ~1e-4 cada una → hasta 1e-2 en los logits finales | Acumulación F32 en fronteras y combine |
| Auto-no-determinismo | Los kernels atomic/split-K varían entre ejecuciones | Kernels de combine deterministas; la verificación usa tolerancias |
| Desajuste de precisión | Un nodo acumula en F16, otro en F32 | Precisión de acumulación anunciada como capacidad; nodos F32 preferidos para rangos de salida |
El protocolo de medición
- Delta por operación — mismas entradas, error relativo A vs B en matmul, swiglu, softmax, norm.
- Deriva en la frontera de capa — delta del residual tras una capa, apilada para ver si la profundidad acumula como √L o L.
- Divergencia de logits extremo a extremo — L∞, L2 y divergencia KL sobre el forward completo.
- Acuerdo de decisiones — acuerdo top-1 de tokens más acuerdo top-8 de enrutamiento (validando por qué la autoridad del router es necesaria).
- Estabilidad de generación — N tokens greedy; el primer índice donde A y B divergen.
- Nivel de tarea — deltas de perplexity y puntuaciones de eval: la única métrica que el usuario siente.
Un aprobado es una tolerancia — "acuerdo top-1 ≥ 99.x%, KL ≤ ε". Un nodo fuera de tolerancia se marca como no apto para rangos sensibles, no se rechaza de plano.
El acuerdo de bits es imposible — e innecesario
Un clúster homogéneo puede asumir exactitud de bits; un enjambre no — su premisa es *el hardware que aparezca*. Así que Kvasir trata la equivalencia numérica exactamente como la compatibilidad de protocolo: un contrato de primera clase, medido. Los backends y la precisión de acumulación se anuncian como capacidades del nodo, la autoridad del router se impone como invariante, y cada verificación usa tolerancias en vez de igualdad de bits. Equivalencia numérica medida + decisiones discretas de autoridad única — eso es lo que permite que un modelo corra en cada GPU de la tierra a la vez. Eso es el enjambre.