Phase 02 - Lesson 10

Compensación sesgo-varianza

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

Cada error del modelo proviene de una de tres fuentes: sesgo, varianza o ruido. Sólo puedes controlar los dos primeros.

Tipo: Aprender Idioma: Python Requisitos previos: Fase 2, Lecciones 01-09 (conceptos básicos de ML, regresión, clasificación, evaluación) Tiempo: ~75 minutos

Objetivos de aprendizaje

  • Deducir la descomposición sesgo-varianza del error de predicción esperado y explicar el papel del ruido irreducible
  • Diagnosticar si un modelo sufre de un alto sesgo o una alta varianza utilizando patrones de error de prueba y entrenamiento.
  • Explicar cómo las técnicas de regularización (L1, L2, abandono, parada anticipada) cambian el sesgo por la varianza.
  • Implementar experimentos que visualicen la compensación entre sesgo y varianza entre modelos de complejidad creciente.

El problema

Entrenaste a un modelo. Tiene algún error en los datos de prueba. ¿De dónde viene ese error?

Si su modelo es demasiado simple (regresión lineal en un conjunto de datos curvo), constantemente perderá el patrón real. Eso es parcialidad. Si su modelo es demasiado complejo (polinomio de grado 20 en 15 puntos de datos), se ajustará perfectamente a los datos de entrenamiento pero dará predicciones muy diferentes sobre datos nuevos. Eso es variación.

No se pueden minimizar ambos al mismo tiempo para una capacidad de modelo fija. Si se reduce el sesgo, la varianza aumenta. Si se reduce la varianza, el sesgo aumenta. Comprender esta compensación es la habilidad de diagnóstico más útil en el machine learning. Le indica si debe hacer que su modelo sea más complejo o menos complejo, si desea obtener más datos o diseñar mejores características, si regularizar más o menos.

El concepto

Sesgo: error sistemático

El sesgo mide qué tan lejos está la predicción promedio de su modelo del valor real. Si entrenó el mismo modelo en muchos conjuntos de entrenamiento diferentes extraídos de la misma distribución y promedió las predicciones, el sesgo es la brecha entre ese promedio y la verdad.

Un sesgo alto significa que el modelo es demasiado rígido para capturar el patrón real. Una línea recta ajustada a una parábola siempre perderá la curva, sin importar cuántos datos le proporciones. Esto es insuficiente.

High bias (underfitting):
  Model always predicts roughly the same wrong thing.
  Training error: HIGH
  Test error: HIGH
  Gap between them: SMALL

Variación: sensibilidad a los datos de entrenamiento

La varianza mide cuánto cambian tus predicciones cuando entrenas con diferentes subconjuntos de datos. Si pequeños cambios en el conjunto de entrenamiento provocan grandes cambios en el modelo, la varianza es alta.

Una varianza alta significa que el modelo ajusta el ruido en los datos de entrenamiento, no en la señal subyacente. Un polinomio de grado 20 pasará por cada punto de entrenamiento, pero oscilará violentamente entre ellos. Esto es un sobreajuste.

High variance (overfitting):
  Model fits training data perfectly but fails on new data.
  Training error: LOW
  Test error: HIGH
  Gap between them: LARGE

La descomposición

Para cualquier punto x, el error de predicción esperado bajo pérdida al cuadrado se descompone exactamente:

Expected Error = Bias^2 + Variance + Irreducible Noise

where:
  Bias^2   = (E[f_hat(x)] - f(x))^2
  Variance = E[(f_hat(x) - E[f_hat(x)])^2]
  Noise    = E[(y - f(x))^2]             (sigma^2)
  • f(x) es la función verdadera
  • f_hat(x) es la predicción de tu modelo
  • E[...] es la expectativa sobre diferentes conjuntos de entrenamiento
  • y es la etiqueta observada (función verdadera más ruido)

El término ruido es irreducible. Ningún modelo puede funcionar mejor que sigma^2 con datos ruidosos. Su trabajo es encontrar el equilibrio adecuado entre el sesgo^2 y la varianza.

Complejidad del modelo frente a error

graph LR
    A[Simple Model] -->|increase complexity| B[Sweet Spot]
    B -->|increase complexity| C[Complex Model]

    style A fill:#f9f,stroke:#333
    style B fill:#9f9,stroke:#333
    style C fill:#f99,stroke:#333

La clásica curva en forma de U:

Complejidad Sesgo Variación Error total
Demasiado bajo ALTA BAJO ALTA (insuficiencia)
Perfecto MODERADO MODERADO MÁS BAJO
Demasiado alto BAJO ALTA ALTO (sobreajuste)

Regularización como control de varianza de sesgo

La regularización aumenta deliberadamente el sesgo para reducir la varianza. Restringe el modelo para que no pueda perseguir el ruido.

  • L2 (Ridge): Reduce todos los pesos hacia cero. Mantiene todas las características pero reduce su influencia.
  • L1 (Lasso): Empuja algunos pesos exactamente a cero. Realiza la selección de características.
  • Abandono: Desactiva aleatoriamente las neuronas durante el entrenamiento. Fuerzas representaciones redundantes.
  • Detención anticipada: Detiene el entrenamiento antes de que el modelo se ajuste completamente a los datos de entrenamiento.

La intensidad de la regularización (lambda, tasa de abandono, número de épocas) controla directamente dónde se ubica en la curva de sesgo-varianza. Más regularización significa más sesgo, menos variación.

Doble descenso: la perspectiva moderna

La teoría clásica dice: después del punto óptimo, una mayor complejidad siempre duele. Pero las investigaciones realizadas desde 2019 han demostrado algo inesperado. Si sigue aumentando la capacidad del modelo mucho más allá del umbral de interpolación (donde el modelo tiene suficientes parámetros para ajustarse perfectamente a los datos de entrenamiento), el error de prueba puede disminuir nuevamente.

graph LR
    A[Underfit Zone] --> B[Classical Sweet Spot]
    B --> C[Interpolation Threshold]
    C --> D[Double Descent - Error Drops Again]

    style A fill:#fdd,stroke:#333
    style B fill:#dfd,stroke:#333
    style C fill:#fdd,stroke:#333
    style D fill:#dfd,stroke:#333

Este fenómeno de "doble descenso" explica por qué las redes neuronales masivamente sobreparametrizadas (con muchos más parámetros que ejemplos de entrenamiento) todavía se generalizan bien. El equilibrio clásico entre sesgo y varianza no es incorrecto, pero es incompleto para el régimen moderno.

Observaciones clave sobre el doble descenso:

  • Sucede en modelos lineales, árboles de decisión y redes neuronales.
  • Más datos pueden resultar perjudiciales en la región de interpolación (doble descenso por muestra)
  • Más épocas de entrenamiento también pueden causarlo (doble descenso por época)
  • La regularización suaviza el pico pero no lo elimina.

¿Por qué sucede esto? En el umbral de interpolación, el modelo tiene la capacidad suficiente para ajustarse a todos los puntos de entrenamiento. Se ve obligado a adoptar una solución muy específica que pasa por cada punto, y pequeñas perturbaciones en los datos provocan grandes cambios en el ajuste. Aquí es donde la variación alcanza su punto máximo. Más allá del umbral, el modelo tiene muchas soluciones posibles que se ajustan perfectamente a los datos. El algoritmo de aprendizaje (por ejemplo, descenso de gradiente con regularización implícita) tiende a elegir el más simple entre ellos. Este sesgo implícito hacia soluciones simples es la razón por la que se generalizan los modelos sobreparametrizados.

Régimen Parámetros vs Muestras Comportamiento
Subparametrizado pag << norte Se aplica la compensación clásica
Umbral de interpolación p ~ norte Picos de varianza, picos de error de prueba
Sobreparametrizado pag >> norte Se activa la regularización implícita, el error de prueba disminuye

A efectos prácticos: si utiliza redes neuronales o conjuntos de árboles grandes, no se detenga en el umbral de interpolación. O permanecer muy por debajo (con regularización explícita) o superarlo. El peor lugar para estar está justo en el umbral.

Diagnóstico de su modelo

flowchart TD
    A[Compare train error vs test error] --> B{Large gap?}
    B -->|Yes| C[High variance - overfitting]
    B -->|No| D{Both errors high?}
    D -->|Yes| E[High bias - underfitting]
    D -->|No| F[Good fit]

    C --> G[More data / Regularize / Simpler model]
    E --> H[More features / Complex model / Less regularization]
    F --> I[Deploy]
Síntoma Diagnóstico Arreglar
Alto error de tren, alto error de prueba Sesgo Más funciones, modelo complejo, menos regularización
Error de tren bajo, error de prueba alto Variación Más datos, regularización, modelo más simple, abandono
Error de tren bajo, error de prueba bajo Buen ajuste Envíalo
El error del tren disminuye, el error de prueba aumenta Sobreadaptación en curso Parada anticipada

Estrategias prácticas

Cuando el problema es el sesgo:

  • Agregar características polinómicas o de interacción
  • Utilice un modelo más flexible (conjunto de árboles en lugar de lineal)
  • Reducir la fuerza de regularización.
  • Entrena por más tiempo (si aún no ha convergido)

Cuando la variación es el problema:

  • Obtener más datos de entrenamiento
  • Usar embolsado (bosques aleatorios)
  • Aumentar la regularización (mayor lambda, más abandono)
  • Selección de funciones (eliminar funciones ruidosas)
  • Utilice validación cruzada para detectarlo temprano

Métodos de conjunto y reducción de varianza

Los métodos de conjunto son la herramienta más práctica para luchar contra la variación.

Bagging (Bootstrap Aggregating) entrena múltiples modelos en diferentes muestras de arranque de los datos de entrenamiento y luego promedia sus predicciones. Cada modelo individual tiene una gran variación, pero el promedio tiene una variación mucho menor. Los bosques aleatorios se aplican en bolsas a los árboles de decisión.

Por qué funciona matemáticamente: si se promedia N predicciones independientes, cada una con varianza sigma^2, la varianza del promedio es sigma^2 / N. Los modelos no son verdaderamente independientes (todos ven datos similares), por lo que la reducción es menor que 1/N, pero sigue siendo sustancial.

Boosting reduce el sesgo al construir modelos secuencialmente, donde cada nuevo modelo se centra en los errores del conjunto hasta el momento. El aumento de gradiente y AdaBoost son los ejemplos principales. Boosting puede sobreajustarse si agrega demasiados modelos, por lo que necesita detenerlo o regularizarlo temprano.

Método Efecto primario Cambio de sesgo Cambio de variación
Bagging Reduce la variación Sin cambios Disminuciones
Boosting Reduce el sesgo Disminuciones Puede aumentar
Apilamiento Reduce ambos Depende del metaaprendiz Depende de los modelos base
Abandono Embolsado implícito Ligero aumento Disminuciones

Regla práctica: si su modelo base tiene una variación alta (árboles profundos, polinomios de alto grado), utilice embolsado. Si su modelo base tiene un sesgo alto (muñones poco profundos, modelos lineales simples), utilice el refuerzo.

Curvas de aprendizaje

Las curvas de aprendizaje trazan el error de entrenamiento y validación en función del tamaño del conjunto de entrenamiento. Son la herramienta de diagnóstico más práctica que tienes. A diferencia de una comparación de un solo tren/prueba, las curvas de aprendizaje le muestran la trayectoria de su modelo y le indican si más datos serán útiles.

flowchart TD
    subgraph HB["High Bias Learning Curve"]
        direction LR
        HB1["Small N: both errors high"]
        HB2["Large N: both errors converge to HIGH error"]
        HB1 --> HB2
    end

    subgraph HV["High Variance Learning Curve"]
        direction LR
        HV1["Small N: train low, test high (big gap)"]
        HV2["Large N: gap shrinks but slowly"]
        HV1 --> HV2
    end

    subgraph GF["Good Fit Learning Curve"]
        direction LR
        GF1["Small N: some gap"]
        GF2["Large N: both converge to LOW error"]
        GF1 --> GF2
    end

Cómo leerlos:

Escenario Error de entrenamiento Error de validación Brecha Lo que significa Qué hacer
Alto sesgo Alto Alto Pequeño El modelo no puede capturar el patrón Más funciones, modelo complejo, menos regularización
Alta variación Bajo Alto Grande Modelo memoriza datos de entrenamiento Más datos, regularización, modelo más sencillo
Buen ajuste Moderado Moderado Pequeño Modelo generaliza bien Envíalo
Alta variación, mejorando Bajo Disminuyendo con más datos Contracción Problema de varianza que los datos pueden solucionar Recoger más datos
Sesgo alto, plano Alto Alto y plano Pequeño y plano Más datos NO ayudarán Cambiar la arquitectura del modelo

La idea crítica: si ambas curvas se han estancado y la brecha es pequeña pero ambos errores son altos, más datos son inútiles. Necesitas un modelo mejor. Si la brecha es grande y sigue reduciéndose, más datos ayudarán.

Cómo generar curvas de aprendizaje

Hay dos enfoques:

Enfoque 1: variar el tamaño del conjunto de entrenamiento, modelo fijo. Mantener constantes el modelo y los hiperparámetros. Entrene en subconjuntos cada vez más grandes de datos de entrenamiento. Mida el error de entrenamiento y el error de validación en cada tamaño. Esta es la curva de aprendizaje estándar.

Enfoque 2: variar la complejidad del modelo, datos fijos. Mantener los datos constantes. Barrer un parámetro de complejidad (grado polinómico, profundidad del árbol, número de capas). Mida el error de entrenamiento y el error de validación en cada complejidad. Esta es una curva de validación y muestra directamente la compensación entre sesgo y varianza.

Ambos enfoques se complementan. El primero le indica si más datos ayudarán. El segundo le indica si un modelo diferente será útil. Ejecute ambos antes de tomar decisiones sobre su próximo paso.

flowchart TD
    A[Model underperforming] --> B[Generate learning curve]
    B --> C{Gap between train and val?}
    C -->|Large gap, val still decreasing| D[More data will help]
    C -->|Small gap, both high| E[More data will NOT help]
    C -->|Large gap, val flat| F[Regularize or simplify]
    E --> G[Generate validation curve]
    G --> H[Try more complex model]

Constrúyelo

El código en code/bias_variance.py ejecuta el experimento completo de descomposición de sesgo-varianza. Aquí está el enfoque, paso a paso.

Paso 1: generar datos sintéticos a partir de una función conocida

Usamos f(x) = sin(1.5x) + 0.5x con ruido gaussiano. Conocer la función verdadera nos permite calcular el sesgo y la varianza exactos.

def true_function(x):
    return np.sin(1.5 * x) + 0.5 * x

def generate_data(n_samples=30, noise_std=0.5, x_range=(-3, 3), seed=None):
    rng = np.random.RandomState(seed)
    x = rng.uniform(x_range[0], x_range[1], n_samples)
    y = true_function(x) + rng.normal(0, noise_std, n_samples)
    return x, y

Paso 2: Muestreo Bootstrap y ajuste polinómico

Para cada grado de polinomio, dibujamos muchos conjuntos de entrenamiento de arranque, ajustamos el polinomio y registramos predicciones en una cuadrícula de prueba fija. Esto nos da una distribución de predicciones en cada punto de prueba.

def fit_polynomial(x_train, y_train, degree, lam=0.0):
    X = np.column_stack([x_train ** d for d in range(degree + 1)])
    if lam > 0:
        penalty = lam * np.eye(X.shape[1])
        penalty[0, 0] = 0
        w = np.linalg.solve(X.T @ X + penalty, X.T @ y_train)
    else:
        w = np.linalg.lstsq(X, y_train, rcond=None)[0]
    return w

Nos ajustamos a 200 muestras de arranque diferentes. Cada muestra de arranque se extrae de la misma distribución subyacente pero contiene puntos diferentes.

Paso 3: Calcular el sesgo^2, descomposición de la varianza

Con 200 conjuntos de predicciones en cada punto de prueba, podemos calcular la descomposición directamente a partir de la definición:

mean_pred = predictions.mean(axis=0)
bias_sq = np.mean((mean_pred - y_true) ** 2)
variance = np.mean(predictions.var(axis=0))
total_error = np.mean(np.mean((predictions - y_true) ** 2, axis=1))
  • mean_pred es E[f_hat(x)] estimado a partir de muestras de arranque
  • bias_sq es la brecha al cuadrado entre la predicción promedio y la verdad
  • variance es la distribución promedio de predicciones entre muestras de arranque
  • total_error debería ser aproximadamente igual al sesgo^2 + varianza + ruido

Paso 4: Curvas de aprendizaje

Las curvas de aprendizaje barren el tamaño del conjunto de entrenamiento mientras mantienen fija la complejidad del modelo. Muestran si su modelo tiene datos limitados o capacidad limitada.

def demo_learning_curves():
    sizes = [10, 15, 20, 30, 50, 75, 100, 150, 200, 300]
    degree = 5

    for n in sizes:
        train_errors = []
        test_errors = []
        for seed in range(50):
            x_train, y_train = generate_data(n_samples=n, seed=seed * 100)
            w = fit_polynomial(x_train, y_train, degree)
            train_pred = predict_polynomial(x_train, w)
            train_mse = np.mean((train_pred - y_train) ** 2)
            test_pred = predict_polynomial(x_test, w)
            test_mse = np.mean((test_pred - y_test) ** 2)
            train_errors.append(train_mse)
            test_errors.append(test_mse)
        # Average over runs gives the learning curve point

Para un modelo de alta varianza (grado 5 con datos pequeños), verá:

  • El error de entrenamiento comienza bajo y aumenta a medida que más datos dificultan la memorización
  • El error de prueba comienza alto y disminuye a medida que el modelo recibe más señal
  • La brecha se reduce con más datos

Para un modelo de alto sesgo (grado 1), ambos errores convergen rápidamente al mismo valor alto y tener más datos no ayuda.

Paso 5: Barrido de regularización

El código también incluye demo_regularization_sweep(), que corrige un polinomio de alto grado (grado 15) y barre la fuerza de regularización Ridge de 0,001 a 100. Esto muestra la compensación entre sesgo y varianza desde un ángulo diferente: en lugar de variar la complejidad del modelo, variamos la fuerza de la restricción.

def demo_regularization_sweep():
    alphas = [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0, 50.0, 100.0]
    for alpha in alphas:
        results = bias_variance_decomposition([15], lam=alpha)
        r = results[15]
        print(f"alpha={alpha:.3f}  bias={r['bias_sq']:.4f}  var={r['variance']:.4f}")

En alfa bajo, el polinomio de grado 15 casi no tiene restricciones. La varianza domina porque el modelo persigue el ruido en cada muestra de arranque. Con un alfa alto, la penalización es tan fuerte que el modelo se convierte efectivamente en una función casi constante. Predomina el sesgo. El alfa óptimo se encuentra entre estos extremos.

Esta es la misma curva en U de distintos grados polinómicos, pero controlada por un mando continuo en lugar de uno discreto. En la práctica, la regularización es la forma preferida de controlar la compensación porque permite un control detallado sin cambiar el conjunto de características.

Úsalo

sklearn proporciona learning_curve y validation_curve para automatizar estos diagnósticos sin escribir bucles de arranque.

Curva de validación: complejidad del modelo de barrido

from sklearn.model_selection import validation_curve
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import Ridge

degrees = list(range(1, 16))
train_scores_all = []
val_scores_all = []

for d in degrees:
    pipe = make_pipeline(PolynomialFeatures(d), Ridge(alpha=0.01))
    train_scores, val_scores = validation_curve(
        pipe, X, y, param_name="polynomialfeatures__degree",
        param_range=[d], cv=5, scoring="neg_mean_squared_error"
    )
    train_scores_all.append(-train_scores.mean())
    val_scores_all.append(-val_scores.mean())

Esto le proporciona directamente la curva de compensación sesgo-varianza. Cuando la puntuación de validación es peor en relación con la puntuación del tren, domina la varianza. Cuando ambos son malos, domina el sesgo.

Curva de aprendizaje: tamaño del conjunto de entrenamiento de barrido

from sklearn.model_selection import learning_curve

pipe = make_pipeline(PolynomialFeatures(5), Ridge(alpha=0.01))
train_sizes, train_scores, val_scores = learning_curve(
    pipe, X, y, train_sizes=np.linspace(0.1, 1.0, 10),
    cv=5, scoring="neg_mean_squared_error"
)
train_mse = -train_scores.mean(axis=1)
val_mse = -val_scores.mean(axis=1)

Trama train_mse y val_mse contra train_sizes. La forma te dice todo sobre tu modelo.

Validación cruzada con barrido de regularización

from sklearn.model_selection import cross_val_score

alphas = [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]
for alpha in alphas:
    pipe = make_pipeline(PolynomialFeatures(10), Ridge(alpha=alpha))
    scores = cross_val_score(pipe, X, y, cv=5, scoring="neg_mean_squared_error")
    print(f"alpha={alpha:>7.3f}  MSE={-scores.mean():.4f} +/- {scores.std():.4f}")

Esto barre la fuerza de la regularización para un modelo de complejidad fija. Verá la misma compensación entre sesgo y varianza: un alfa bajo significa una varianza alta, un alfa alto significa un sesgo alto.

Poniéndolo todo junto: un flujo de trabajo de diagnóstico completo

En la práctica, estos diagnósticos se ejecutan en secuencia:

  1. Entrena tu modelo. Calcular el error del tren y de la prueba.
  2. Si ambos son altos: tienes un problema de sesgo. Salta al paso 4.
  3. Si el tren es bajo pero la prueba es alta: tienes un problema de variación. Genere una curva de aprendizaje para ver si más datos ayudarán. Si no, regularizar.
  4. Genere una curva de validación que recorra su principal parámetro de complejidad. Encuentra el punto óptimo.
  5. En el punto óptimo, genere una curva de aprendizaje. Si la brecha aún es grande, se necesitan más datos o regularización.
  6. Pruebe Ridge/Lasso con diferentes valores alfa usando cross_val_score. Elija el alfa donde el error de validación cruzada sea menor.

Esto requiere de 10 a 15 minutos de cálculo para la mayoría de los conjuntos de datos tabulares y ahorra horas de conjeturas.

Envíalo

Esta lección produce: outputs/prompt-model-diagnostics.md

Ejercicios

  1. Ejecute la descomposición con noise_std=0 (sin ruido). ¿Qué sucede con el término de error irreducible? ¿Cambia la complejidad óptima?

  2. Aumente el tamaño del conjunto de entrenamiento de 30 a 300. ¿Cómo afecta esto al componente de varianza? ¿Se desplaza el grado del polinomio óptimo?

  3. Agregue regularización L2 (regresión Ridge) al experimento. Para un polinomio fijo de alto grado (grado 15), barra lambda de 0 a 100. Trace el sesgo^2 y la varianza como funciones de lambda.

  4. Modifique la función verdadera de un polinomio a sin(x). ¿Cómo cambia la descomposición sesgo-varianza? ¿Existe todavía un grado óptimo claro?

  5. Implemente un contenedor de agregación (embolsado) de arranque simple: entrene 10 modelos en muestras de arranque y predicciones promedio. Demuestre que esto reduce la varianza sin aumentar mucho el sesgo.

Términos clave

Término Lo que dice la gente Lo que realmente significa
Sesgo "El modelo es demasiado simple" Error sistemático por suposiciones erróneas. La brecha entre la predicción promedio del modelo y la verdad.
Variación "El modelo se está sobreajustando" Error de sensibilidad a los datos de entrenamiento. Cuánto cambian las predicciones en diferentes conjuntos de entrenamiento.
Error irreductible "Ruido en los datos" Error por aleatoriedad en el verdadero proceso de generación de datos. Ningún modelo puede eliminarlo.
Desacondicionamiento "No aprender lo suficiente" El modelo tiene un alto sesgo. Omite el patrón real incluso en los datos de entrenamiento.
Sobreajuste "Memorizando los datos" El modelo tiene una gran variación. Se adapta al ruido en los datos de entrenamiento que no se generaliza.
Regularización "Restringiendo el modelo" Agregar una penalización para reducir la complejidad del modelo, cambiar el sesgo por una variación más baja.
Doble descenso "Más parámetros pueden ayudar" El error de prueba vuelve a disminuir cuando la capacidad del modelo supera con creces el umbral de interpolación.
Complejidad del modelo "Qué flexible es el modelo" La capacidad de un modelo para ajustarse a patrones arbitrarios. Controlado por arquitectura, características o regularización.

Lectura adicional

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