Monitoreo y Depuración del Entrenamiento
Por Qué Importa el Monitoreo
Una ejecución de fine-tuning puede tomar desde 30 minutos hasta varias horas. Sin monitoreo adecuado, puedes descubrir problemas solo después de que la ejecución termine — desperdiciando cómputo y tiempo. Un buen monitoreo te permite detectar sobreajuste, identificar problemas de datos y cancelar ejecuciones malas temprano. Esta lección cubre las métricas que debes rastrear, los patrones que debes reconocer y las herramientas que hacen todo esto visible.
Métricas Esenciales de Entrenamiento
Pérdida de Entrenamiento (Training Loss)
La métrica principal. Mide qué tan bien el modelo predice el siguiente token en los datos de entrenamiento. Una curva de pérdida saludable muestra una caída inicial pronunciada seguida de una disminución gradual.
Qué observar:
- Disminución constante: Bien. El modelo está aprendiendo.
- Meseta temprana: La tasa de aprendizaje puede ser muy baja, o la tarea es demasiado simple para el rango LoRA.
- Oscilación: La tasa de aprendizaje es demasiado alta o el tamaño de batch es demasiado pequeño.
- Pico repentino: Posible corrupción de datos en ese batch, o inestabilidad numérica.
Pérdida de Validación (Validation Loss)
Mide el rendimiento en datos que el modelo no ha visto durante el entrenamiento. La brecha entre la pérdida de entrenamiento y la de validación es tu indicador de sobreajuste.
Patrón saludable: La pérdida de entrenamiento y validación disminuyen juntas, con la de validación ligeramente más alta.
Patrón de sobreajuste: La pérdida de entrenamiento sigue disminuyendo mientras la de validación comienza a aumentar. Esto significa que el modelo está memorizando ejemplos de entrenamiento en lugar de aprender patrones generalizables.
# En TrainingArguments, habilitar evaluacion
training_args = TrainingArguments(
eval_strategy="steps",
eval_steps=50, # Evaluar cada 50 pasos
load_best_model_at_end=True, # Recargar el mejor checkpoint
metric_for_best_model="eval_loss",
greater_is_better=False,
)
Programación de Tasa de Aprendizaje
Rastrea la tasa de aprendizaje para verificar que tu programador funciona correctamente. Una programación coseno debe mostrar una curva suave del pico a casi cero. Una programación lineal debe mostrar un declive recto.
Norma del Gradiente
La magnitud de los gradientes te dice sobre la estabilidad del entrenamiento. Normas de gradiente que se disparan a valores muy altos indican inestabilidad. Normas que colapsan a casi cero indican gradientes que se desvanecen.
# Habilitar registro de norma de gradiente
training_args = TrainingArguments(
logging_steps=10,
logging_first_step=True,
max_grad_norm=1.0, # Recortar gradientes por encima de esta norma
)
Detectando y Corrigiendo el Sobreajuste
El sobreajuste es el problema más común en fine-tuning, especialmente con datasets pequeños.
Señales de Sobreajuste
- La pérdida de validación aumenta mientras la de entrenamiento disminuye
- Las salidas del modelo se vuelven copias casi exactas de ejemplos de entrenamiento
- La calidad del modelo se degrada en entradas fuera de distribución
- La pérdida de entrenamiento alcanza valores muy bajos (por debajo de 0.1) inusualmente rápido
Remedios
- Reducir épocas. Si el sobreajuste comienza en la época 2, entrena por 1.5 épocas.
- Aumentar dropout. Sube
lora_dropoutde 0.05 a 0.1. - Reducir rango. Un rango LoRA más bajo (r=8 en lugar de r=16) reduce la capacidad del modelo.
- Agregar más datos. La mejor solución si es posible.
- Usar early stopping. Detener el entrenamiento cuando la pérdida de validación no ha mejorado por N pasos de evaluación.
from transformers import EarlyStoppingCallback
trainer = SFTTrainer(
# ... otros argumentos
callbacks=[EarlyStoppingCallback(early_stopping_patience=5)],
)
Depurando Problemas Comunes
Pérdida NaN
La pérdida NaN (Not a Number) significa que ha ocurrido un desbordamiento numérico. Esto típicamente mata la ejecución de entrenamiento.
Causas comunes y soluciones:
- Tasa de aprendizaje demasiado alta. Reducir de 2e-4 a 5e-5.
- Problemas de precisión mixta. Cambiar de fp16 a bf16 (si tu GPU lo soporta). bf16 tiene un rango dinámico más grande y es menos propenso al desbordamiento.
- Problemas de datos. Verificar ejemplos con texto extremadamente largo o caracteres inusuales que producen valores de pérdida muy altos.
- Explosión de gradientes. Reducir
max_grad_normde 1.0 a 0.3.
# Depurar perdida NaN paso a paso
training_args = TrainingArguments(
learning_rate=5e-5, # Tasa de aprendizaje mas baja
bf16=True, # Usar bfloat16 en lugar de fp16
max_grad_norm=0.3, # Recorte agresivo de gradientes
logging_steps=1, # Registrar cada paso para encontrar donde ocurre NaN
)
Explosión de Gradientes
Síntomas: La pérdida se dispara repentinamente, las normas de gradiente se vuelven muy grandes (>100), el entrenamiento puede recuperarse o colapsar.
Soluciones:
- Bajar
max_grad_norm(prueba 0.3 o incluso 0.1) - Reducir tasa de aprendizaje
- Aumentar pasos de calentamiento para dejar que el modelo se ajuste gradualmente
Errores de Formateo de Datos
Los bugs más insidiosos. El modelo entrena sin errores, pero produce basura porque la plantilla de conversación era incorrecta.
Cómo verificar:
# Siempre inspecciona ejemplos formateados antes de entrenar
sample = dataset["train"][0]
formatted = tokenizer.apply_chat_template(
sample["messages"],
tokenize=False,
)
print("=== Ejemplo formateado ===")
print(formatted)
print("=== IDs de tokens ===")
tokens = tokenizer.encode(formatted)
print(tokens[:50]) # Primeros 50 tokens
print(f"Total de tokens: {len(tokens)}")
Verifica que:
- Los tokens especiales (BOS, EOS, marcadores de rol) están presentes y son correctos
- La respuesta del modelo no está siendo enmascarada durante el entrenamiento
- Los tokens de relleno no están mezclados en el contenido
El Modelo Produce Salida Repetitiva
El modelo genera la misma frase una y otra vez, o entra en un bucle.
Causas:
- Sobreajuste en datos de entrenamiento repetitivos
- La pérdida de entrenamiento llegó demasiado baja (sobre-optimización)
- Parámetros de generación incorrectos (temperature=0 sin penalización)
Soluciones:
- Verificar datos de entrenamiento por duplicados
- Reducir épocas de entrenamiento
- Usar
repetition_penalty=1.1durante la generación
Configurando TensorBoard
TensorBoard es la solución de monitoreo más simple — viene integrada con Hugging Face:
training_args = TrainingArguments(
report_to="tensorboard",
logging_dir="./logs",
logging_steps=10,
)
Lanzar TensorBoard:
tensorboard --logdir ./logs
Esto abre un panel en http://localhost:6006 donde puedes ver curvas de pérdida, tasa de aprendizaje, normas de gradiente y más en tiempo real.
Configurando Weights and Biases
W&B proporciona más funcionalidades: comparación de experimentos, barridos de hiperparámetros, colaboración en equipo y rastreo de artefactos de modelo.
pip install wandb
wandb login # Ingresar tu clave API
import wandb
wandb.init(
project="llm-fine-tuning",
name="llama3-8b-legal-v1",
config={
"model": "Llama-3.1-8B",
"rank": 16,
"alpha": 32,
"learning_rate": 2e-4,
"dataset_size": len(dataset["train"]),
}
)
training_args = TrainingArguments(
report_to="wandb",
logging_steps=10,
)
W&B automáticamente registra todas las métricas de entrenamiento, métricas del sistema (memoria GPU, utilización) y te permite agregar registro personalizado:
# Registrar predicciones de muestra durante entrenamiento
class PredictionCallback(TrainerCallback):
def on_evaluate(self, args, state, control, **kwargs):
# Generar predicciones en algunos ejemplos
model.training = False # Cambiar a modo evaluacion
test_prompts = ["Explica LoRA", "Que es QLoRA"]
for prompt in test_prompts:
output = generate(model, tokenizer, prompt)
wandb.log({f"prediction/{prompt}": output, "step": state.global_step})
Estrategia de Checkpointing
Guarda checkpoints sabiamente — son tu póliza de seguro:
training_args = TrainingArguments(
save_strategy="steps",
save_steps=100, # Guardar cada 100 pasos
save_total_limit=3, # Mantener solo los 3 mas recientes
load_best_model_at_end=True,
metric_for_best_model="eval_loss",
)
Consejos:
- Para ejecuciones cortas (menos de 500 pasos), guarda cada 50 pasos
- Para ejecuciones largas (más de 2000 pasos), guarda cada 200 pasos
- Siempre mantén al menos el mejor checkpoint basado en la pérdida de evaluación
save_total_limitpreviene llenar el espacio en disco con checkpoints grandes
Lista de Verificación Práctica de Depuración
Cuando una ejecución de entrenamiento produce malos resultados, trabaja a través de esta lista:
- Inspecciona datos en bruto. Lee 10 ejemplos de entrenamiento aleatorios. ¿Son correctos?
- Verifica formato. Imprime un ejemplo formateado con todos los tokens especiales visibles. ¿Coinciden con la plantilla esperada del modelo?
- Verifica tokenización. ¿Se están truncando los ejemplos? ¿Cuál es la distribución de longitud de tokens?
- Revisa curvas de pérdida. ¿Está disminuyendo la pérdida de entrenamiento? ¿Está divergiendo la de evaluación?
- Prueba manualmente. Genera salidas del modelo en diferentes checkpoints. ¿Mejora la calidad?
- Compara con el modelo base. ¿Es el modelo fine-tuned realmente mejor que el modelo base en tu tarea?
En la próxima lección, abordamos el tema frecuentemente pasado por alto de la evaluación — cómo medir sistemáticamente si tu modelo fine-tuned realmente mejoró.