ML Atlas

Machine learning desde cero · Lección 3.6 · 19 de 33 lecciones listas · 12 min

Parada temprana

En pocas palabras

Una red entrenada demasiado tiempo memoriza etiquetas erróneas. Con un 20 % de etiquetas al azar, 100 épocas bajan la exactitud de prueba de 86,1 % a 76,3 %.

Calentamiento Dos preguntas de lecciones anteriores. Un minuto, y no bloquea la lección.
De la lección 3.5: Ajustar hiperparámetros sin hacer trampa ¿Cómo evaluar con justicia un modelo cuyos hiperparámetros elegiste con validación cruzada?

Ver la respuesta

Respuesta correcta: Comprobarlo con una prueba reservada o con validación cruzada anidada alrededor del ajuste

La prueba reservada y la validación cruzada anidada no participaron en la elección. En el código la validación cruzada normal da un 94,0 % y la anidada un 91,9 %.

De la lección 3.4: Regularización: ridge y lasso ¿En qué se diferencia la penalización ridge de la penalización lasso?

Ver la respuesta

Respuesta correcta: Ridge lleva todos los pesos hacia cero y lasso deja algunos exactamente en cero

Ridge penaliza los cuadrados de los pesos y no anula ninguno; lasso penaliza los valores absolutos y anula los pesos uno a uno. En el lab ridge con α = 398 tiene 10 pesos distintos de cero, lasso con α = 15,8 solo 3.

Una red neuronal aprende en épocas: una época es una pasada por todos los ejemplos de entrenamiento. Tras cada época la pérdida de entrenamiento suele bajar. La pregunta de la lección 3.1 vuelve con otra forma: ¿cuántas épocas son demasiadas? La parada temprana la responde con el conjunto de validación: el entrenamiento se detiene cuando la pérdida de validación deja de bajar, y el modelo vuelve a su mejor época.

Predice y comprueba Una red neuronal pequeña aprende a reconocer dígitos manuscritos con 299 imágenes. En un 20 % de ellas la etiqueta es un dígito al azar en lugar del verdadero. La pérdida de validación más baja llega en la época 28. Aun así entrenas 100 épocas en lugar de parar en la mejor. ¿Qué pasa con la exactitud en la prueba?
¿Qué tan seguro estás?

Experimento interactivo

Este experimento interactivo funciona en un navegador con JavaScript activado. El texto que lo rodea describe lo que muestra.

Ver la respuesta

Respuesta correcta: Baja de 86,1 % a 76,3 %, porque la red memoriza también las etiquetas erróneas

Los pesos de la época 28 sacan un 86,1 % con las 997 imágenes de prueba; tras 100 épocas, un 76,3 %: 9,7 puntos menos. Mientras tanto la pérdida de validación sube de 0,48 a 0,84, y de las 51 etiquetas erróneas la red acaba repitiéndolas todas.

Prueba

  • El lab abre con etiquetas limpias. Cambia a las etiquetas al azar y deja una paciencia de 5. ¿En qué época se detiene el entrenamiento, qué pesos se conservan y es esa la mejor época de todo el recorrido?
  • Sube la paciencia a 10. ¿Qué cambia en la época conservada y en la exactitud de prueba?
  • Vuelve a las etiquetas limpias. ¿Cuánto cuesta ahora entrenar hasta el final?

Cuando lo hayas comprobado en el lab, pongamos nombre a lo que ves.

La idea en palabras sencillas

Al principio del entrenamiento la red aprende lo que comparten muchas imágenes: la forma de un cero, un ocho, un siete. Las pérdidas de entrenamiento y de validación bajan juntas. Después la red empieza a ajustar ejemplos sueltos, incluidos los que tienen una etiqueta errónea. La pérdida de entrenamiento sigue bajando y la de validación empieza a subir. Es el sobreajuste de la lección 3.1, solo que a lo largo de las épocas en lugar del número de parámetros.

La parada temprana vigila la pérdida de validación. Recuerda la época con la pérdida más baja y cuenta las épocas sin mejora. Cuando llegan a la paciencia, el entrenamiento se detiene y la red vuelve a los pesos de la mejor época. En el lab, con una paciencia de 10, el entrenamiento se detiene en la época 38 y se conservan los pesos de la época 28: 86,1 % en la prueba en lugar de 76,3 % tras 100 épocas.

Demasiada poca paciencia también perjudica. La curva de validación oscila de una época a otra. Con una paciencia de 5 el entrenamiento se detiene ya en la época 23 y conserva los pesos de la época 18 (85,0 % en la prueba), aunque la mejor era la época 28.

Jak to policzono
  • Dígitos: Optical Recognition of Handwritten Digits, UCI, licencia CC BY 4.0. 1797 imágenes de 8×8 píxeles.
  • Partición estratificada: 299 imágenes para aprender, 501 para validación, 997 para la prueba. En la versión con ruido cada etiqueta de entrenamiento se sustituye, con probabilidad del 20 %, por un dígito al azar: cambiaron 51 etiquetas (un dígito al azar a veces coincide con el verdadero).
  • Red 64 → 32 → 10, ReLU, entropía cruzada, SGD con momento 0,9, paso 0,05, lotes de 32 imágenes, 100 épocas. Pérdida de validación calculada tras cada época.
  • La validación y la prueba tienen las etiquetas verdaderas. El ruido está solo en los datos de entrenamiento.

Por qué funciona

Un ejemplo con etiqueta errónea es difícil para la red: la imagen parece un tres, pero la etiqueta dice «siete». Para bajar la pérdida en un ejemplo así, la red tiene que aprender una regla que solo encaja con él. Suele hacerlo tarde, cuando ya domina los patrones fáciles y comunes. En el lab la red repite 10 de las 51 etiquetas erróneas en la época 28, y las 51 tras 100 épocas. Con sus propios datos de entrenamiento tiene entonces un 99,7 % de exactitud: coincide incluso con las etiquetas falsas.

Las reglas ajustadas a etiquetas erróneas estropean las respuestas con imágenes nuevas. El conjunto de validación tiene las etiquetas verdaderas, así que su pérdida sube justo cuando la red empieza a aprender el ruido. Por eso es ella, y no la pérdida de entrenamiento, la que dice cuándo parar.

No es casualidad de una sola ejecución. En el código de abajo el mismo experimento se repite en scikit-learn con otras 10 particiones y sorteos del ruido: la mejor época cae entre la 13 y la 23, y entrenar hasta 100 épocas baja la exactitud de prueba en las 10 ejecuciones, de media de 87,2 % a 76,4 %. La mejor época del lab (28) queda fuera de ese rango porque también depende de los pesos iniciales y del orden de los lotes: la misma red del lab con otras 9 semillas aleatorias da lo mejor entre las épocas 12 y 25, y entrenar hasta 100 épocas baja la exactitud de prueba cada vez.

Error frecuente

Verdadero o falso: «entrenar más tiempo siempre da un modelo mejor». Falso. Entrenar más tiempo siempre se ajusta mejor a los datos de entrenamiento, pero no a los nuevos. Con etiquetas al azar, 100 épocas dan un 99,7 % de exactitud en entrenamiento y un 76,3 % en la prueba, mientras que parar en la época 28 da un 86,1 % en la prueba.

Una nota en sentido contrario: con etiquetas limpias entrenar hasta el final casi no estropea nada. La pérdida de validación más baja llega en la época 30 (93,9 % en la prueba), y tras 100 épocas la exactitud es del 94,5 %. La parada temprana no siempre salva exactitud, pero siempre ahorra tiempo y protege de unos datos peores de lo que crees.

Test

Tres preguntas para comprobar lo aprendido. Elige una respuesta o despliega la solución bajo cada pregunta. Con el teclado: las flechas eligen, Enter o Espacio confirma.

1. ¿En qué se basa la parada temprana para decidir cuándo detener el entrenamiento?
Ver la respuesta

Respuesta correcta: En la pérdida de validación: se para cuando deja de bajar

La pérdida de entrenamiento baja casi hasta el final, incluso cuando la red aprende ruido. La pérdida de validación, calculada con datos de fuera del entrenamiento, sube cuando el modelo empieza a sobreajustar.

2. Con un 20 % de etiquetas al azar, la red tiene un 99,7 % en entrenamiento y un 76,3 % en la prueba tras 100 épocas. ¿Qué significa?
Ver la respuesta

Respuesta correcta: La red ha memorizado también las etiquetas erróneas, y eso estropea sus respuestas con datos nuevos

Una exactitud de entrenamiento alta con ruido en las etiquetas significa que la red ha ajustado también el ruido. Los pesos de la época 28 sacan un 86,1 % en la prueba.

3. Una paciencia de 5 detiene el entrenamiento en la época 23 y conserva la época 18, aunque la pérdida más baja está en la 28. ¿Por qué?
Ver la respuesta

Respuesta correcta: Porque la curva de validación oscila, y poca paciencia confunde una oscilación con el mínimo

La pérdida de validación no baja de forma regular: unas cuantas épocas peores seguidas pueden ser azar. Con una paciencia de 10 el entrenamiento llega a la época 28.

Ideas clave

  • Una época es una pasada por los datos de entrenamiento; la pérdida de entrenamiento casi siempre baja, la de validación no.
  • La parada temprana detiene el entrenamiento cuando la pérdida de validación no mejora durante unas épocas (la paciencia) y vuelve a los mejores pesos.
  • Entrenar demasiado con etiquetas erróneas enseña el ruido a la red: la prueba baja de 86,1 % a 76,3 %.
  • Demasiada poca paciencia detiene el entrenamiento en una oscilación casual de la curva.

Más a fondo: fórmula, código, práctica

Las matemáticas

Pérdida de validación tras la época e: L_val(e) = −(1/m) · Σᵢ log p_e(yᵢ | xᵢ) con m imágenes de validación (entropía cruzada).

La regla con paciencia P: e = argmin_{e ≤ t} L_val(e); el entrenamiento se detiene en la primera época t con t − e ≥ P y devuelve los pesos w(e). Si esa época no llega, devuelve w(e) de todo el recorrido.

La parada temprana actúa de forma parecida a la penalización de la lección 3.4. Con descenso de gradiente y un paso pequeño, los pesos empiezan cerca de cero y se alejan de él con cada época. Menos épocas significan pesos más pequeños: para un modelo lineal con pérdida cuadrática, parar tras t pasos tiene más o menos el mismo efecto que ridge con un α del orden de 1 / (paso · t).

En código (Python)

El mismo experimento en scikit-learn: 10 particiones y sorteos del ruido distintos, una red 64 → 32 → 10 entrenada época a época, guardando los pesos de la época con la pérdida de validación más baja.

import copy
import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import log_loss

X, y = load_digits(return_X_y=True)
X = X / 16
def run(seed):  # 300 dígitos para aprender, 500 para validación, los otros 997 para la prueba
    used, te = train_test_split(np.arange(len(y)), train_size=800, stratify=y, random_state=seed)
    tr, va = train_test_split(used, test_size=500, stratify=y[used], random_state=seed)
    rng = np.random.default_rng(seed)
    noisy = y[tr].copy()
    flip = rng.random(len(tr)) < 0.2  # 20 % de las etiquetas de entrenamiento sustituidas por un dígito al azar
    noisy[flip] = rng.integers(0, 10, flip.sum())
    net = MLPClassifier(hidden_layer_sizes=(32,), solver="sgd", learning_rate_init=0.05, momentum=0.9, batch_size=32, alpha=0, random_state=seed)
    best, best_loss = None, np.inf
    for epoch in range(1, 101):
        net.partial_fit(X[tr], noisy, classes=np.arange(10))
        loss = log_loss(y[va], net.predict_proba(X[va]), labels=np.arange(10))
        if loss < best_loss:
            best, best_loss, best_epoch = copy.deepcopy(net), loss, epoch  # la parada temprana conserva los pesos de la mejor época
    return best_epoch, best.score(X[te], y[te]), net.score(X[te], y[te])
r = np.array([run(s) for s in range(10)])
print(f"10 splits and noise draws: lowest validation loss at epoch {r[:, 0].min():.0f} to {r[:, 0].max():.0f}; test at that epoch {r[:, 1].mean():.1%}, after 100 epochs {r[:, 2].mean():.1%}; lower after 100 in {(r[:, 2] < r[:, 1]).sum()} of 10")

Resultado

10 splits and noise draws: lowest validation loss at epoch 13 to 23; test at that epoch 87.2%, after 100 epochs 76.4%; lower after 100 in 10 of 10

Las particiones, los pesos iniciales y el ruido son otros que en el lab, así que los números también. El cuadro es el mismo: la mejor época llega pronto (entre la 13 y la 23), y entrenar hasta 100 épocas baja la exactitud de prueba en las 10 ejecuciones, de media de 87,2 % a 76,4 %.

Para profesionales
  • En Keras: EarlyStopping(monitor="val_loss", patience=10, restore_best_weights=True). Sin restore_best_weights=True se quedan los pesos de la última época, no los de la mejor.
  • En PyTorch el bucle lo escribes tú: tras cada época calcula la pérdida de validación y guarda una copia de los pesos cuando sea la más baja.
  • En scikit-learn: MLPClassifier(early_stopping=True, n_iter_no_change=...) aparta una parte de los datos de entrenamiento para validación; vigila la exactitud de validación, no la pérdida. En gradient boosting la misma idea se llama n_iter_no_change o early_stopping_rounds.
  • El número de épocas elegido en validación también es un hiperparámetro: el resultado de validación en la mejor época está algo inflado (lección 3.5), así que haz la evaluación final con una prueba reservada.

Profundiza en el Atlas

Entradas de la enciclopedia sobre las ideas de esta lección: