Saltar al contenido principal

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étodoRendimiento en la TareaRetención en Benchmark
Full FT95%70-85%
LoRA93%95-99%
QLoRA92%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:​

EstrategiaDificultadEfectividad
Usar PEFT (LoRA/QLoRA)Fácil⭐⭐⭐⭐⭐
Tasa de aprendizaje bajaFácil⭐⭐⭐
Menos épocasFácil⭐⭐⭐
Mezcla de datosMedia⭐⭐⭐⭐
Decaimiento de pesosFácil⭐⭐
Early stoppingFácil⭐⭐⭐

Enfoque Recomendado​

  1. Comience con PEFT (LoRA o QLoRA)
  2. 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:

  1. ¿Qué es el olvido catastrófico y por qué ocurre?
  2. ¿Cómo ayudan los métodos PEFT a prevenir el olvido catastrófico?
  3. ¿Cuáles son tres estrategias para minimizar el olvido en el fine-tuning completo?