Capítulo 3: Olvido Catastrófico
Preservar el Conocimiento Durante el Fine-Tuning
El olvido catastrófico es uno de los mayores desafíos en el fine-tuning. Comprenderlo le ayuda a diseñar mejores estrategias de entrenamiento.
¿Qué es el Olvido Catastrófico?
El olvido catastrófico ocurre cuando una red neuronal pierde conocimientos previamente aprendidos después de ser entrenada con nuevos datos.
Escenario de Ejemplo
Un LLM preentrenado sabe:
- Cómo traducir idiomas
- Conocimiento general del mundo
- Razonamiento matemático
- Generación de código
Después de hacer fine-tuning con datos de soporte al cliente:
- ✅ Excelente en soporte al cliente
- ❌ Puede tener dificultades con la traducción
- ❌ Puede perder algo de conocimiento general
- ❌ La calidad de la generación de código puede disminuir
¿Por Qué Sucede?
Interferencia de Pesos
Las redes neuronales almacenan el conocimiento en sus pesos. Cuando se entrena con nuevos datos:
Original weights (W) → encode general knowledge
New training → updates W to (W')
W' optimizes for new task → may break old task representations
Cambio de Distribución
El modelo se adapta a la distribución específica de sus datos, perdiendo potencialmente la capacidad de generalización.
Medición del Olvido Catastrófico
Evaluación Antes/Después
from lm_eval import evaluator
from lm_eval.models.huggingface import HFLM
def evaluate_model(model_path, tasks=["hellaswag", "arc_easy", "mmlu"]):
"""Evaluate model on standard benchmarks."""
model = HFLM(pretrained=model_path)
results = evaluator.simple_evaluate(
model=model,
tasks=tasks,
num_fewshot=0,
)
return results
# Before fine-tuning
baseline_results = evaluate_model("meta-llama/Llama-3.1-8B")
print("Baseline:", baseline_results)
# After fine-tuning
finetuned_results = evaluate_model("./my-finetuned-model")
print("Fine-tuned:", finetuned_results)
# Compare
for task in ["hellaswag", "arc_easy", "mmlu"]:
baseline = baseline_results["results"][task]["acc"]
finetuned = finetuned_results["results"][task]["acc"]
diff = finetuned - baseline
print(f"{task}: {diff:+.2%} ({'↑' if diff > 0 else '↓'})")
Pruebas Específicas por Tarea
# Create a test suite for capabilities you want to preserve
test_cases = [
{"prompt": "Translate to French: Hello, how are you?",
"expected_contains": "Bonjour"},
{"prompt": "What is 15 * 17?",
"expected_contains": "255"},
{"prompt": "Write a Python function to reverse a string",
"expected_contains": "def"},
]
def test_capabilities(model, tokenizer, test_cases):
"""Test if model retains specific capabilities."""
for test in test_cases:
output = model.generate(
tokenizer.encode(test["prompt"], return_tensors="pt"),
max_new_tokens=100
)
response = tokenizer.decode(output[0], skip_special_tokens=True)
passed = test["expected_contains"] in response
print(f"{'✅' if passed else '❌'} {test['prompt'][:50]}...")
Estrategias de Mitigación
1. Use Tasas de Aprendizaje Más Bajas
# Full fine-tuning: lower LR preserves more knowledge
training_args = TrainingArguments(
learning_rate=1e-5, # Lower than default
# vs 2e-5 or higher for PEFT
)
2. Menos Épocas de Entrenamiento
# Less training = less forgetting
training_args = TrainingArguments(
num_train_epochs=1, # Start with 1
# Monitor validation performance
# Only increase if underfitting
)
3. Técnicas de Regularización
Decaimiento de Pesos
training_args = TrainingArguments(
weight_decay=0.01, # Penalize large weight changes
)
Consolidación Elástica de Pesos (EWC)
# EWC adds a penalty for changing important weights
# (Research technique, not directly in HF Trainer)
loss = cross_entropy_loss + lambda * sum(
importance[i] * (theta[i] - theta_star[i])^2
for i in parameters
)
4. Mezcla / Repetición de Datos
# Mix original pre-training style data with fine-tuning data
from datasets import concatenate_datasets
# Your specific data
finetuning_data = load_dataset("your/dataset")
# General instruction data to maintain capabilities
general_data = load_dataset("databricks/dolly-15k", split="train[:1000]")
# Mix them (e.g., 80% specific, 20% general)
mixed_dataset = concatenate_datasets([
finetuning_data,
general_data.shuffle().select(range(len(finetuning_data) // 4))
])
5. Use PEFT en su Lugar
La mitigación más efectiva: no actualice todos los pesos
from peft import LoraConfig, get_peft_model
# Only update small adapters, preserving base model
lora_config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
)
model = get_peft_model(base_model, lora_config)
# Base model weights frozen → no catastrophic forgetting!
Ventaja de PEFT
Por Qué PEFT Previene el Olvido
Evidencia Empírica
| Método | Rendimiento en la Tarea | Retención en Benchmark |
|---|---|---|
| Full FT | 95% | 70-85% |
| LoRA | 93% | 95-99% |
| QLoRA | 92% | 95-99% |
Los métodos PEFT suelen retener más del 95% del rendimiento base en tareas no relacionadas.
Estrategia de Evaluación
Protocolo de Evaluación Integral
def comprehensive_evaluation(model_path, baseline_path):
"""Evaluate both task performance and capability retention."""
# 1. Task-specific evaluation (your fine-tuning goal)
task_score = evaluate_on_task(model_path, your_test_set)
# 2. General capability benchmarks
benchmarks = ["hellaswag", "arc_easy", "mmlu", "gsm8k"]
baseline_scores = {}
finetuned_scores = {}
for bench in benchmarks:
baseline_scores[bench] = evaluate_benchmark(baseline_path, bench)
finetuned_scores[bench] = evaluate_benchmark(model_path, bench)
# 3. Calculate retention
retention = {}
for bench in benchmarks:
retention[bench] = finetuned_scores[bench] / baseline_scores[bench]
avg_retention = sum(retention.values()) / len(retention)
print(f"Task Performance: {task_score:.2%}")
print(f"Average Capability Retention: {avg_retention:.2%}")
# 4. Trade-off analysis
if task_score > 0.90 and avg_retention > 0.95:
print("✅ Good balance achieved")
elif task_score > 0.90 and avg_retention < 0.90:
print("⚠️ High task performance but significant forgetting")
else:
print("❌ Consider adjusting training")
return {
"task_score": task_score,
"retention": retention,
"avg_retention": avg_retention
}
Resumen de Buenas Prácticas
Para Minimizar el Olvido Catastrófico:
| Estrategia | Dificultad | Efectividad |
|---|---|---|
| Usar PEFT (LoRA/QLoRA) | Fácil | ⭐⭐⭐⭐⭐ |
| Tasa de aprendizaje baja | Fácil | ⭐⭐⭐ |
| Menos épocas | Fácil | ⭐⭐⭐ |
| Mezcla de datos | Media | ⭐⭐⭐⭐ |
| Decaimiento de pesos | Fácil | ⭐⭐ |
| Early stopping | Fácil | ⭐⭐⭐ |
Enfoque Recomendado
- Comience con PEFT (LoRA o QLoRA)
- Si PEFT no es suficiente, pruebe fine-tuning completo con:
- Tasa de aprendizaje baja (1e-5)
- Épocas limitadas (1-2)
- Mezcla de datos
- Evaluación integral
Puntos Clave
✅ El olvido catastrófico ocurre cuando los modelos pierden conocimiento después del fine-tuning
✅ Sucede porque los pesos se modifican para ajustarse a la nueva distribución de datos
✅ Los métodos PEFT evitan en gran medida el olvido al mantener los pesos base congelados
✅ Para fine-tuning completo: use LR bajo, pocas épocas, mezcla de datos
✅ Siempre evalúe tanto el rendimiento en la tarea COMO la retención de capacidades
✅ El equilibrio es: especialización en la tarea vs. capacidad general
Próximos Pasos
Ponga a prueba sus conocimientos con el Quiz del Módulo 2, luego continúe con Módulo 3: Fine-Tuning Eficiente en Parámetros.
Verificación Rápida
Antes de continuar, asegúrese de poder responder:
- ¿Qué es el olvido catastrófico y por qué ocurre?
- ¿Cómo ayudan los métodos PEFT a prevenir el olvido catastrófico?
- ¿Cuáles son tres estrategias para minimizar el olvido en el fine-tuning completo?