Phase 01 - Lesson 06

Probabilidad y Distribuciones

This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.

La probabilidad es el lenguaje que la IA usa para expresar la incertidumbre.

Tipo: Learn Lenguaje: Python Requisitos previos: Fase 1, Lecciones 01-04 Tiempo: ~75 minutos

Objetivos de Aprendizaje

  • Implementar PMFs y PDFs desde cero para las distribuciones de Bernoulli, categórica, Poisson, uniforme y normal
  • Calcular el valor esperado, la varianza y usar el Teorema Central del Límite para explicar por que las Gaussianas dominan
  • Construir las funciones softmax y log-softmax con el truco de estabilidad numérica (restar el logit máximo)
  • Calcular la pérdida de entropía cruzada a partir de logits y conectarla con la log-verosimilitud negativa

El Problema

Un clasificador devuelve [0.03, 0.91, 0.06]. Un modelo de lenguaje elige la siguiente palabra entre 50.000 candidatas. Un modelo de difusión genera imágenes muestreando de distribuciones aprendidas. Todo esto es probabilidad en acción.

Cada predicción que hace un modelo es una distribución de probabilidad. Cada función de pérdida mide cuan lejos esta la distribución predicha de la verdadera. Cada paso de entrenamiento ajusta parámetros para hacer que una distribución se parezca más a otra. Sin probabilidad, no puedes leer un solo artículo de ML, depurar un solo modelo ni entender por que tu pérdida de entrenamiento es NaN.

El Concepto

Eventos, Espacios Muestrales y Probabilidad

El espacio muestral S es el conjunto de todos los resultados posibles. Un evento es un subconjunto del espacio muestral. La probabilidad asigna a los eventos números entre 0 y 1.

Lanzamiento de moneda:
  S = {H, T}
  P(H) = 0.5,  P(T) = 0.5

Lanzamiento de un dado:
  S = {1, 2, 3, 4, 5, 6}
  P(par) = P({2, 4, 6}) = 3/6 = 0.5

Tres axiomas definen toda la probabilidad:

  1. P(A) >= 0 para cualquier evento A
  2. P(S) = 1 (algo siempre sucede)
  3. P(A o B) = P(A) + P(B) cuando A y B no pueden ocurrir juntos

Todo lo demas (teorema de Bayes, esperanzas, distribuciones) se deriva de estas tres reglas.

Probabilidad Condicional e Independencia

P(A|B) es la probabilidad de A dado que B sucedió.

P(A|B) = P(A y B) / P(B)

Ejemplo: baraja de cartas
  P(Rey | Carta de figura) = P(Rey y Carta de figura) / P(Carta de figura)
                      = (4/52) / (12/52)
                      = 4/12 = 1/3

Dos eventos son independientes cuando saber uno no dice nada sobre el otro:

Independiente:   P(A|B) = P(A)
Equivalente a: P(A y B) = P(A) * P(B)

Los lanzamientos de moneda son independientes. Sacar cartas sin reemplazo no lo es.

Funciones de Masa de Probabilidad vs Funciones de Densidad de Probabilidad

Las variables aleatorias discretas tienen una función de masa de probabilidad (PMF). Cada resultado tiene una probabilidad especifica que puedes leer directamente.

PMF: P(X = k)

Dado justo:
  P(X = 1) = 1/6
  P(X = 2) = 1/6
  ...
  P(X = 6) = 1/6

  Suma de todas las probabilidades = 1

Las variables aleatorias continuas tienen una función de densidad de probabilidad (PDF). La densidad en un solo punto no es una probabilidad. La probabilidad surge de integrar la densidad sobre un intervalo.

PDF: f(x)

P(a <= X <= b) = integral de f(x) de a a b

f(x) puede ser mayor que 1 (densidad, no probabilidad)
integral de -inf a +inf de f(x) dx = 1

Esta distinción importa en ML. Las salidas de clasificación son PMFs (elecciones discretas). Los espacios latentes de VAE usan PDFs (continuos).

Distribuciones Comunes

Bernoulli: un ensayo, dos resultados. Modela la clasificación binaria.

P(X = 1) = p
P(X = 0) = 1 - p
Media = p,  Varianza = p(1-p)

Categórica: un ensayo, k resultados. Modela la clasificación multiclase (salida softmax).

P(X = i) = p_i,  donde la suma de p_i = 1
Ejemplo: P(gato) = 0.7,  P(perro) = 0.2,  P(pajaro) = 0.1

Uniforme: todos los resultados igualmente probables. Usada para la inicialización aleatoria.

Discreta: P(X = k) = 1/n para k en {1, ..., n}
Continua: f(x) = 1/(b-a) para x en [a, b]

Normal (Gaussiana): la curva de campana. Parametrizada por la media (mu) y la varianza (sigma^2).

f(x) = (1 / sqrt(2*pi*sigma^2)) * exp(-(x - mu)^2 / (2*sigma^2))

Normal estandar: mu = 0, sigma = 1
  68% de los datos dentro de 1 sigma
  95% dentro de 2 sigma
  99.7% dentro de 3 sigma

Poisson: conteos de eventos raros en un intervalo fijo. Modela tasas de eventos.

P(X = k) = (lambda^k * e^(-lambda)) / k!
Media = lambda,  Varianza = lambda

Valor Esperado y Varianza

El valor esperado es el promedio ponderado de los resultados.

Discreta:   E[X] = suma de x_i * P(X = x_i)
Continua: E[X] = integral de x * f(x) dx

La varianza mide la dispersión alrededor de la media.

Var(X) = E[(X - E[X])^2] = E[X^2] - (E[X])^2
Desviacion estandar = sqrt(Var(X))

En ML, el valor esperado aparece como la función de pérdida (pérdida promedio sobre la distribución de los datos). La varianza te informa sobre la estabilidad del modelo. Una varianza alta en los gradientes significa entrenamiento ruidoso.

Distribuciones Conjuntas y Marginales

Una distribución conjunta P(X, Y) describe dos variables aleatorias en conjunto.

Ejemplo de PMF conjunta (X = clima, Y = paraguas):

Y=0 (sin paraguas) Y=1 (con paraguas) Marginal P(X)
X=0 (sol) 0.40 0.10 P(X=0) = 0.50
X=1 (lluvia) 0.05 0.45 P(X=1) = 0.50
Marginal P(Y) P(Y=0) = 0.45 P(Y=1) = 0.55 1.00

La distribución marginal suma la otra variable:

P(X = x) = suma sobre todo y de P(X = x, Y = y)

Los totales de fila y columna en la tabla anterior son las marginales.

Por que la Distribución Normal Aparece en Todas Partes

El Teorema Central del Límite: la suma (o el promedio) de muchas variables aleatorias independientes converge a una distribución normal, sin importar la distribución original.

Lanza 1 dado:  distribucion uniforme (plana)
Promedio de 2 dados:  triangular (con pico)
Promedio de 30 dados: curva de campana casi perfecta

Esto funciona para CUALQUIER distribucion inicial.

Por eso:

  • Los errores de medición son aproximadamente normales (muchas fuentes pequeñas e independientes)
  • Las inicializaciones de pesos en redes neuronales usan distribuciones normales
  • El ruido del gradiente en SGD es aproximadamente normal (suma de muchos gradientes de muestra)
  • La distribución normal es la distribución de máxima entropía para una media y varianza dadas

Log-Probabilidades

Las probabilidades en bruto causan problemas numéricos. Multiplicar muchas probabilidades pequeñas juntas rápidamente sufre subdesbordamiento hasta cero.

P(oracion) = P(palabra1) * P(palabra2) * ... * P(palabra_n)
            = 0.01 * 0.003 * 0.02 * ...
            -> 0.0 (subdesbordamiento tras ~30 terminos)

Las log-probabilidades resuelven esto. Las multiplicaciones se convierten en sumas.

log P(oracion) = log P(palabra1) + log P(palabra2) + ... + log P(palabra_n)
                = -4.6 + -5.8 + -3.9 + ...
                -> numero finito (sin subdesbordamiento)

Reglas:

  • log(a * b) = log(a) + log(b)
  • las log-probabilidades son siempre <= 0 (ya que 0 < P <= 1)
  • Más negativo = menos probable
  • La pérdida de entropía cruzada es la log-probabilidad negativa de la clase correcta

Softmax como Distribución de Probabilidad

Las redes neuronales devuelven puntajes en bruto (logits). El softmax los convierte en una distribución de probabilidad válida.

softmax(z_i) = exp(z_i) / sum(exp(z_j) para todo j)

Propiedades:
  - Todas las salidas estan en (0, 1)
  - Todas las salidas suman 1
  - Preserva el orden relativo de las entradas
  - exp() amplifica las diferencias entre logits

El truco del softmax: resta el logit máximo antes de exponenciar para evitar el desbordamiento.

z = [100, 101, 102]
exp(102) = desbordamiento

z_shifted = z - max(z) = [-2, -1, 0]
exp(0) = 1  (seguro)

Mismo resultado, sin desbordamiento.

El log-softmax combina softmax y log para la estabilidad numérica. PyTorch usa esto internamente para la pérdida de entropía cruzada.

Muestreo

Muestrear significa extraer valores aleatorios de una distribución. En ML:

  • El dropout muestrea aleatoriamente que neuronas poner en cero
  • El aumento de datos muestrea transformaciones aleatorias
  • Los modelos de lenguaje muestrean el siguiente token de la distribución predicha
  • Los modelos de difusión muestrean ruido y lo eliminan progresivamente

Muestrear de distribuciones arbitrarias requiere técnicas como el muestreo por transformada inversa, el muestreo por rechazo o el truco de reparametrización (usado en VAEs).

Construye

Paso 1: Fundamentos de probabilidad

import math
import random

def factorial(n):
    result = 1
    for i in range(2, n + 1):
        result *= i
    return result

def combinations(n, k):
    return factorial(n) // (factorial(k) * factorial(n - k))

def conditional_probability(p_a_and_b, p_b):
    return p_a_and_b / p_b

p_king_given_face = conditional_probability(4/52, 12/52)
print(f"P(King | Face card) = {p_king_given_face:.4f}")

Paso 2: PMF y PDF desde cero

def bernoulli_pmf(k, p):
    return p if k == 1 else (1 - p)

def categorical_pmf(k, probs):
    return probs[k]

def poisson_pmf(k, lam):
    return (lam ** k) * math.exp(-lam) / factorial(k)

def uniform_pdf(x, a, b):
    if a <= x <= b:
        return 1.0 / (b - a)
    return 0.0

def normal_pdf(x, mu, sigma):
    coeff = 1.0 / (sigma * math.sqrt(2 * math.pi))
    exponent = -0.5 * ((x - mu) / sigma) ** 2
    return coeff * math.exp(exponent)

Paso 3: Valor esperado y varianza

def expected_value(values, probabilities):
    return sum(v * p for v, p in zip(values, probabilities))

def variance(values, probabilities):
    mu = expected_value(values, probabilities)
    return sum(p * (v - mu) ** 2 for v, p in zip(values, probabilities))

die_values = [1, 2, 3, 4, 5, 6]
die_probs = [1/6] * 6
mu = expected_value(die_values, die_probs)
var = variance(die_values, die_probs)
print(f"Die: E[X] = {mu:.4f}, Var(X) = {var:.4f}, SD = {var**0.5:.4f}")

Paso 4: Muestreo de distribuciones

def sample_bernoulli(p, n=1):
    return [1 if random.random() < p else 0 for _ in range(n)]

def sample_categorical(probs, n=1):
    cumulative = []
    total = 0
    for p in probs:
        total += p
        cumulative.append(total)
    samples = []
    for _ in range(n):
        r = random.random()
        for i, c in enumerate(cumulative):
            if r <= c:
                samples.append(i)
                break
    return samples

def sample_normal_box_muller(mu, sigma, n=1):
    samples = []
    for _ in range(n):
        u1 = random.random()
        u2 = random.random()
        z = math.sqrt(-2 * math.log(u1)) * math.cos(2 * math.pi * u2)
        samples.append(mu + sigma * z)
    return samples

Paso 5: Softmax y log-probabilidades

def softmax(logits):
    max_logit = max(logits)
    shifted = [z - max_logit for z in logits]
    exps = [math.exp(z) for z in shifted]
    total = sum(exps)
    return [e / total for e in exps]

def log_softmax(logits):
    max_logit = max(logits)
    shifted = [z - max_logit for z in logits]
    log_sum_exp = max_logit + math.log(sum(math.exp(z) for z in shifted))
    return [z - log_sum_exp for z in logits]

def cross_entropy_loss(logits, target_index):
    log_probs = log_softmax(logits)
    return -log_probs[target_index]

Paso 6: Demostración del Teorema Central del Límite

def demonstrate_clt(dist_fn, n_samples, n_averages):
    averages = []
    for _ in range(n_averages):
        samples = [dist_fn() for _ in range(n_samples)]
        averages.append(sum(samples) / len(samples))
    return averages

Paso 7: Visualización

import matplotlib.pyplot as plt

xs = [mu + sigma * (i - 500) / 100 for i in range(1001)]
ys = [normal_pdf(x, mu, sigma) for x, mu, sigma in ...]
plt.plot(xs, ys)

Las implementaciones completas con todas las visualizaciones están en code/probability.py.

Usa

Con NumPy y SciPy, todo lo anterior se reduce a una sola línea:

import numpy as np
from scipy import stats

normal = stats.norm(loc=0, scale=1)
samples = normal.rvs(size=10000)
print(f"Mean: {np.mean(samples):.4f}, Std: {np.std(samples):.4f}")
print(f"P(X < 1.96) = {normal.cdf(1.96):.4f}")

logits = np.array([2.0, 1.0, 0.1])
from scipy.special import softmax, log_softmax
probs = softmax(logits)
log_probs = log_softmax(logits)
print(f"Softmax: {probs}")
print(f"Log-softmax: {log_probs}")

Tu construiste todo esto desde cero. Ahora sabes que están haciendo las llamadas de la biblioteca.

Ejercicios

  1. Implementa el muestreo por transformada inversa para la distribución exponencial. Verifica muestreando 10.000 valores y comparando el histograma con la PDF verdadera.

  2. Construye una tabla de distribución conjunta para dos dados cargados. Calcula las distribuciones marginales y verifica si los dados son independientes.

  3. Calcula la pérdida de entropía cruzada para un clasificador de 5 clases que devuelve los logits [2.0, 0.5, -1.0, 3.0, 0.1] cuando la clase correcta es el índice 3. Luego verifica tu respuesta con el nn.CrossEntropyLoss de PyTorch.

  4. Escribe una función que reciba una lista de log-probabilidades y devuelva la secuencia más probable, la log-probabilidad total y la probabilidad en bruto equivalente. Pruebala con una oración de 50 palabras donde cada palabra tiene probabilidad 0.01.

Términos Clave

Término Lo que dice la gente Lo que realmente significa
Espacio muestral "Todas las posibilidades" El conjunto S de todo resultado posible de un experimento
PMF "La función de probabilidad" Una función que da la probabilidad exacta de cada resultado discreto, sumando 1
PDF "La curva de probabilidad" Una función de densidad para variables continuas. Integrala sobre un intervalo para obtener la probabilidad
Probabilidad condicional "Probabilidad dado algo" P(A|B) = P(A y B) / P(B). La base del razonamiento bayesiano y del teorema de Bayes
Independencia "No se afectan mutuamente" P(A y B) = P(A) * P(B). Saber un evento no dice nada sobre el otro
Valor esperado "El promedio" La suma ponderada por probabilidad de todos los resultados. La función de pérdida es un valor esperado
Varianza "Cuan dispersa" La desviación cuadrática esperada respecto a la media. Varianza alta = estimaciones ruidosas e inestables
Distribución normal "La curva de campana" f(x) = (1/sqrt(2pisigma^2)) * exp(-(x-mu)^2/(2*sigma^2)). Aparece en todas partes debido al TCL
Teorema Central del Límite "Los promedios se vuelven normales" El promedio de muchas muestras independientes converge a una distribución normal sin importar la fuente
Distribución conjunta "Dos variables juntas" P(X, Y) describe la probabilidad de cada combinación de resultados de X e Y
Distribución marginal "Suma la otra variable" P(X) = suma_y P(X, Y). Recupera la distribución de una variable a partir de la conjunta
Log-probabilidad "Log de la probabilidad" log P(x). Convierte productos en sumas, evitando el subdesbordamiento numérico en secuencias largas
Softmax "Convierte puntajes en probabilidades" softmax(z_i) = exp(z_i) / sum(exp(z_j)). Asigna logits de valor real a una distribución de probabilidad válida
Entropía cruzada "La función de pérdida" -sum(p_true * log(p_predicted)). Mide cuan diferentes son dos distribuciones. Menor es mejor
Logits "Salidas en bruto del modelo" Puntajes no normalizados antes del softmax. Nombrados en referencia a la función logística
Muestreo "Extraer valores aleatorios" Generar valores conforme a una distribución de probabilidad. Como los modelos generan su salida

Lectura Adicional

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).