Capítulo 3: Esquecimento Catastrófico
Preservando Conhecimento Durante o Fine-Tuning
O esquecimento catastrófico é um dos maiores desafios no fine-tuning. Compreender esse fenômeno ajuda você a criar estratégias de treinamento melhores.
O que é Esquecimento Catastrófico?
O esquecimento catastrófico ocorre quando uma rede neural perde conhecimentos previamente aprendidos após ser treinada com novos dados.
Exemplo de Cenário
Um LLM pré-treinado sabe:
- Como traduzir idiomas
- Conhecimento geral de mundo
- Raciocínio matemático
- Geração de código
Após o fine-tuning com dados de suporte ao cliente:
- ✅ Excelente em suporte ao cliente
- ❌ Pode ter dificuldades com tradução
- ❌ Pode perder parte do conhecimento geral
- ❌ A qualidade da geração de código pode cair
Por Que Isso Acontece?
Interferência nos Pesos
Redes neurais armazenam conhecimento em seus pesos. Quando você treina com novos dados:
Original weights (W) → encode general knowledge
New training → updates W to (W')
W' optimizes for new task → may break old task representations
Mudança de Distribuição
O modelo se adapta à distribuição específica dos seus dados, podendo perder a capacidade de generalização.
Medindo o Esquecimento Catastrófico
Avaliação Antes/Depois
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 '↓'})")
Testes Específicos de Capacidade
# 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]}...")
Estratégias de Mitigação
1. Use Taxas de Aprendizado Menores
# 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 Treinamento
# 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 Regularização
Decaimento de Peso (Weight Decay)
training_args = TrainingArguments(
weight_decay=0.01, # Penalize large weight changes
)
Consolidação 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. Mistura/Repetição de Dados
# 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 em Vez Disso
A mitigação mais eficaz: não atualize todos os 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!
Vantagem do PEFT
Por Que PEFT Previne o Esquecimento
Evidência Empírica
| Método | Desempenho na Tarefa | Retenção em Benchmarks |
|---|---|---|
| Full FT | 95% | 70-85% |
| LoRA | 93% | 95-99% |
| QLoRA | 92% | 95-99% |
Métodos PEFT normalmente retêm 95%+ do desempenho de base em tarefas não relacionadas.
Estratégia de Avaliação
Protocolo de Avaliação Abrangente
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
}
Resumo das Melhores Práticas
Para Minimizar o Esquecimento Catastrófico:
| Estratégia | Dificuldade | Eficácia |
|---|---|---|
| Use PEFT (LoRA/QLoRA) | Fácil | ⭐⭐⭐⭐⭐ |
| Taxa de aprendizado menor | Fácil | ⭐⭐⭐ |
| Menos épocas | Fácil | ⭐⭐⭐ |
| Mistura de dados | Média | ⭐⭐⭐⭐ |
| Decaimento de peso | Fácil | ⭐⭐ |
| Early stopping | Fácil | ⭐⭐⭐ |
Abordagem Recomendada
- Comece com PEFT (LoRA ou QLoRA)
- Se PEFT não for suficiente, tente o fine-tuning completo com:
- Taxa de aprendizado baixa (1e-5)
- Poucas épocas (1-2)
- Mistura de dados
- Avaliação abrangente
Principais Pontos
✅ Esquecimento catastrófico é quando modelos perdem conhecimento após o fine-tuning
✅ Isso ocorre porque os pesos são modificados para se ajustar à nova distribuição de dados
✅ Métodos PEFT evitam em grande parte o esquecimento mantendo os pesos base congelados
✅ Para fine-tuning completo: use LR baixo, poucas épocas, mistura de dados
✅ Sempre avalie tanto o desempenho na tarefa quanto a retenção de capacidades
✅ O trade-off é: especialização na tarefa vs. capacidade geral
Próximos Passos
Teste seu conhecimento com o Quiz do Módulo 2, depois continue para Módulo 3: Fine-Tuning Eficiente em Parâmetros.
Verificação Rápida
Antes de avançar, certifique-se de que você consegue responder:
- O que é esquecimento catastrófico e por que ele ocorre?
- Como métodos PEFT ajudam a prevenir o esquecimento catastrófico?
- Quais são três estratégias para minimizar o esquecimento no fine-tuning completo?