Skip to content

English · Español

00 — Por qué una fase de representación numérica antes del álgebra lineal

🇪🇸 La intuición central: la aritmética de coma flotante no es la matemática que aprendiste en la escuela. Es una aproximación con un puñado de reglas raras (denormales, NaN, overflow, asociatividad rota) que, cuando se rompen, no avisan: producen loss = inf, gradientes muertos o predicciones absurdas. Fase 2 te enseña esas reglas antes de que las necesites a la fuerza.


La mentira que cuentan los libros de texto

Un libro de álgebra lineal trata los números reales como exactamente reales. Suma dos, multiplica, divide, toma un logaritmo — el resultado es el resultado. Sin sorpresas.

Esto vale sobre el papel. Es falso en una CPU.

Un float de 32 bits (fp32) guarda aproximadamente 7 dígitos decimales de precisión. Solo hay 2^32 valores fp32 representables; todo lo demás se redondea al más cercano. 0.1 no es representable exactamente. 0.2 tampoco. Su suma no es 0.3. Esto no es un bug — es el diseño.

>>> 0.1 + 0.2 == 0.3
False

Cuando escribas código en la Fase 7 para calcular gradientes, la regla de la cadena pasará por docenas de operaciones. Cada una redondea. Cada una puede amplificar un error previo. Si nunca has pensado en el sustrato, tus gradientes derivarán en silencio, tu pérdida divergirá, te pasarás una tarde depurando "el optimizador" cuando el problema es que calculaste log(1 + 1e-8) y obtuviste cero.

La tesis de la Fase 2

La Fase 2 entrena un hábito:

Antes de escribir exp(x) o log(p) o 1 - q o sum(arr), pregunta: ¿qué magnitudes tienen realmente x, p, q y los elementos de arr? ¿La operación de coma flotante preservará la precisión que necesito, o la destruirá silenciosamente?

Al final de la Fase 2 deberías ser capaz de leer una expresión numérica y etiquetar cada subexpresión con su modo de fallo — "esto está bien", "esto desborda para x > 89", "esto pierde 6 dígitos cuando b ≈ a", "esto da NaN si algún elemento es -inf" — antes de ejecutarla.

Qué es "el sustrato" en realidad

El sustrato es IEEE-754: un estándar de 1985 que fija, bit a bit, cómo los ordenadores almacenan y operan con números reales aproximados. Cada CPU, GPU y acelerador construido desde entonces respeta (algún subconjunto de) IEEE-754 por ley de compatibilidad aritmética — el comportamiento de tu modelo debe ser idéntico entre fabricantes.

Un número fp32 son 32 bits divididos en:

  • 1 bit de signo (0 = positivo, 1 = negativo).
  • 8 bits de exponente (desplazado en 127 para permitir exponentes negativos).
  • 23 bits de mantisa (el "significand" — los dígitos reales, en binario).

El valor es (-1)^sign × 1.mantissa × 2^(exponent − 127). El "1." es implícito para números normales; esto da un bit gratis de precisión.

La teoría 01-ieee754-anatomy.md hace la decodificación completa, más las excepciones para cero, denormales, ±Inf, NaN y modos de redondeo. Memorizarás la disposición al final.

Por qué esto importa para IA (AI) en particular — a través de la lente de §A13

El alcance microscópico de este proyecto (§A13) es la gramática verbal inglesa: 20 verbos × 5 tiempos × 3 personas + pares en español ≈ 600 formas. El modelo diminuto de Borja, en cada pase hacia delante, calculará una distribución de probabilidad sobre esas ~600 formas — un softmax sobre un vector de logits de longitud 600. Cinco escollos numéricos concretos aterrizan en ese único cómputo:

  1. El exp del softmax desborda fp32 cuando algún logit es ≳ 89. Un modelo con logits sin normalizar produce rutinariamente esos valores al principio del entrenamiento. El ingenuo exp(logits) / sum(exp(logits)) devuelve inf / inf = NaN. El truco -max (teoría 02) lo arregla.
  2. Las propias probabilidades son diminutas. Uniforme sobre 600 formas es 1/600 ≈ 0.00167. Las probabilidades entrenadas para formas de baja verosimilitud pueden ser 1e-20 o menores. log(p) para p = 1e-20 es -46; restar dos números así pierde todo bit significativo si son casi iguales — cancelación catastrófica (teoría 03).
  3. Sumar 600 probabilidades diminutas acumula error. Una suma ingenua de 600 valores de magnitud 1e-10 aterriza en algún lugar con error relativo O(600 × ε). La suma de Kahan (teoría 03) preserva O(ε) total.
  4. El orden de reducción no es asociativo. Sumar [a, b, c] de izquierda a derecha vs de derecha a izquierda da resultados fp32 distintos cuando las magnitudes difieren. Los tests de CI para "el mismo modelo produce la misma salida" dependen de congelar el orden de reducción. Esto muerde fuerte en entrenamiento distribuido (Fase 35).
  5. La cross-entropy −log p_correct explota cuando p_correct ≈ 0. Una predicción segura-y-equivocada produce una probabilidad cercana a cero para la etiqueta verdadera (digamos que el modelo asigna probabilidad 1e-30 a worked cuando worked es la respuesta correcta); el log negativo es enorme; el gradiente es enorme; los pesos se mueven enormemente en un paso. "La pérdida explota en el paso 1" es casi siempre esto.

Cada uno de estos es un fenómeno de Fase 2. Ninguno requiere conocimiento de IA para entenderlo. Todos romperán un modelo en fases posteriores si la Fase 2 no caló.

El camino por la Fase 2

  • Teoría 01 hace la anatomía: disposiciones de bits, denormales, NaN, ±Inf, redondeo. La exposición plana a la que vuelves siempre.
  • Teoría 02 hace el único algoritmo numérico más importante del aprendizaje profundo (deep learning): el truco -max para un softmax estable. Derivado desde primeros principios, aplicado a un vector de longitud 5 que clasifica tiempos verbales (infinitive / present / past / past-participle / future).
  • Teoría 03 hace la suma: cancelación catastrófica, Kahan, Neumaier. Aplicado a sumar la masa de probabilidad por forma de 600 conjugaciones verbales.
  • Teoría 04 repasa el zoo de precisiones (BF16, TF32, FP8, INT8/INT4) — disposiciones de bits y compromisos. Léelo como anticipación de la Fase 26.
  • Laboratorios 00–03 te hacen hacer las mediciones tú mismo. Decodificar patrones de bits a mano. Romper el softmax ingenuo sobre logits de tiempos. Medir la mejora de Kahan en una suma de 10⁶ elementos de magnitud ~1/600. Redondear a int8 y vuelta.

Lo que esta fase NO es

La Fase 2 no es un curso de análisis numérico. No cubrimos aritmética de intervalos, posits ni formatos DSP de coma fija. No demostramos cotas de error para factorizaciones matriciales (la Fase 3 las toca de pasada). No optimizamos para hardware específico (la Fase 24 cubre kernels conscientes de SIMD).

La Fase 2 es una fase de alfabetización: al final, puedes leer código de coma flotante y ver los modos de fallo que otros solo descubren en tiempo de depuración.

Párate aquí si

Te tienta saltarte la Fase 2 porque "llevo años programando en Python; sé de la precisión de los float". No lo hagas. La prueba no es "¿puedes decir la palabra denormal?". La prueba es: dado un vector de logits de longitud 600 con un elemento en 92 y los demás en -3, ¿puedes predecir — sin ejecutarlo — cuál de las tres implementaciones de softmax en tu pantalla produce una distribución válida? Si todavía no puedes, la Fase 2 es para ti.

Recapitulación en un párrafo

La aritmética de coma flotante es un sistema numérico aproximado y no asociativo con modos de fallo bien definidos (overflow, underflow, denormales, NaN, cancelación catastrófica). Cada fase posterior de este currículo opera sobre tensores fp32/fp64 y hereda esos modos de fallo. La Fase 2 te enseña a predecir los fallos leyendo código, anclada a un ejemplo recurrente: softmax + cross-entropy sobre el vocabulario de ~600 formas de conjugaciones verbales inglesas definido en §A13.

Lo que esta fase NO cubre

  • Gradientes a través de primitivas numéricas (Fase 4 / 7).
  • Un módulo src/minigrad/numerics.py reutilizable (Fase 7, cuando el consumidor de autograd existe).
  • Cuantización real de producción (Fase 26).
  • Hardware de coma flotante en GPU (Fase 23+).
  • Bibliotecas de aritmética multi-precisión (fuera de alcance).

Siguiente: theory/01-ieee754-anatomy.md.