Saltar al contenido principal

Capítulo 2: PEFT vs Fine-Tuning Completo

Comprendiendo los Compromisos​

Elegir entre PEFT y el fine-tuning completo requiere comprender sus respectivas fortalezas y limitaciones.


Comparación Integral​

AspectoFine-Tuning CompletoPEFT
Memoria4-6x tamaño del modelo0.1-0.5x tamaño del modelo
VelocidadMás lento2-3x más rápido
Techo de CalidadMás altoLigeramente menor
Riesgo de OlvidoAltoNinguno
HardwareGPUs costosasGPUs de consumidor
Intercambio de AdaptadoresNoSí
Sobrecarga en InferenciaNingunaMínima (o fusionar)

Comparación de Memoria​

Desglose Detallado​

def calculate_memory(params_billions, method):
"""Calculate approximate training memory."""
params = params_billions * 1e9

if method == "full_ft":
# Weights + Gradients + Optimizer (2 states) + Activations
weights = params * 2 # bf16
gradients = params * 2
optimizer = params * 4 * 2 # fp32, 2 states
activations = params * 0.5 # Rough estimate
return (weights + gradients + optimizer + activations) / 1e9

elif method == "lora":
# Frozen weights + small LoRA gradients/optimizer
weights = params * 2
lora_params = params * 0.01 # ~1% trainable
lora_training = lora_params * (2 + 2 + 8) # grad + optimizer
return (weights + lora_training) / 1e9

elif method == "qlora":
# 4-bit weights + LoRA training
weights = params * 0.5 # 4-bit
lora_params = params * 0.01
lora_training = lora_params * (2 + 2 + 8)
return (weights + lora_training) / 1e9

# Results for 7B model
print(f"Full FT: {calculate_memory(7, 'full_ft'):.1f} GB") # ~77 GB
print(f"LoRA: {calculate_memory(7, 'lora'):.1f} GB") # ~15 GB
print(f"QLoRA: {calculate_memory(7, 'qlora'):.1f} GB") # ~4 GB

Comparación de Calidad​

Resultados Empíricos​

La investigación muestra consistentemente que PEFT logra una calidad comparable:

TareaFine-Tuning CompletoLoRADiferencia
Clasificación de Texto94.2%93.8%-0.4%
Resumen45.3 ROUGE44.9 ROUGE-0.9%
Seguimiento de Instrucciones8.2/108.0/10-2.4%
Generación de Código67.1%65.8%-1.9%

Cuándo PEFT se Queda Corto​

PEFT puede tener un rendimiento inferior en:

  • Cambios de dominio significativos: Pre-entrenamiento → dominio muy especializado
  • Nuevos formatos de salida: Muy diferentes a cualquier dato de entrenamiento
  • Calidad máxima posible: Cuando cada 0.1% es importante
  • Nuevos comportamientos complejos: Patrones profundamente incrustados
# Example: PEFT might struggle with
# 1. Medical model from general LLM (major domain shift)
# 2. Entirely new language not in pretraining
# 3. Competition benchmarks where every point counts

Comparación de Velocidad de Entrenamiento​

Métricas de Rendimiento​

MétodoTiempo por ÉpocaVelocidad Relativa
Fine-Tuning Completo60 min1x
LoRA25 min2.4x
QLoRA30 min2x

Por Qué PEFT es Más Rápido​

  1. Menos cálculos de gradientes: Solo se calculan gradientes para los parámetros entrenables
  2. Menor ancho de banda de memoria: Menos bytes a transferir
  3. Actualizaciones de optimizador más pequeñas: Menos estados a mantener
# Gradient computation scales with trainable parameters
# Full FT: 7 billion gradient computations
# LoRA: 70 million gradient computations (100x fewer)

Comparación de Flexibilidad​

PEFT: Múltiples Adaptadores​

# Load base model once
base_model = AutoModelForCausalLM.from_pretrained("llama-3.1-8b")

# Create different adapters
adapters = {
"customer_support": "adapters/support/",
"code_review": "adapters/code/",
"translation": "adapters/translate/",
}

# Runtime adapter switching
for task, adapter_path in adapters.items():
model = PeftModel.from_pretrained(base_model, adapter_path)
# Use model for task
model.unload() # Remove adapter

Fine-Tuning Completo: Modelos Separados​

# Each task requires loading a different full model
models = {
"customer_support": "models/support-full/", # 15GB
"code_review": "models/code-full/", # 15GB
"translation": "models/translate-full/", # 15GB
}
# Total: 45GB storage, high switching cost

Comparación en Inferencia​

PEFT con Adaptadores​

# Slight overhead from adapter computation
# Latency: ~5-10% slower per token

# Option 1: Keep adapter separate
model = PeftModel.from_pretrained(base, adapter)
output = model.generate(input_ids)

# Option 2: Merge for zero overhead
model = model.merge_and_unload() # No adapter overhead
output = model.generate(input_ids)

PEFT Fusionado = Velocidad de Fine-Tuning Completo​

Después de fusionar:

W_merged = W_base + B × A # One-time computation
# Inference is identical to full fine-tuned model

Análisis de Costos​

Costos de Entrenamiento​

MétodoGPU NecesariaTiempoCosto (On-Demand)
Fine-Tuning Completo (7B)A100-80GB4 hr$24
LoRA (7B)A100-40GB1.5 hr$6
QLoRA (7B)RTX 40902 hr$2

Consideraciones a Largo Plazo​

Escenario: Fine-tuning para 10 tareas diferentes

Fine-Tuning Completo:
- 10 ejecuciones de entrenamiento en GPUs costosas
- 10 modelos completos para almacenar (150GB)
- Cargar un modelo diferente por tarea

PEFT:
- 10 ejecuciones de entrenamiento en GPUs más económicas
- 1 modelo base + 10 adaptadores (15GB + 200MB)
- Cambio rápido de adaptador

Marco de Decisión​

Elija PEFT Cuando:​

✅ La memoria de GPU es limitada (< 40GB)
✅ Se necesita experimentar rápidamente
✅ Se requieren múltiples variantes de tareas
✅ Se desea preservar las capacidades del modelo base
✅ El costo es un factor significativo
✅ La producción requiere intercambio de adaptadores

Elija Fine-Tuning Completo Cuando:​

✅ La máxima calidad es crítica
✅ Se requiere un cambio de dominio significativo
✅ Los recursos no son una limitación
✅ Se necesita un modelo de propósito único
✅ Se desplegará como modelo fusionado de todos modos
✅ La investigación requiere control total


Estrategias Híbridas​

Comience con PEFT, Mejore si es Necesario​

# Phase 1: Quick experimentation with LoRA
lora_model = train_with_lora(dataset_small)
evaluate(lora_model) # Check if quality is sufficient

# Phase 2: If PEFT isn't enough, try full FT
if quality_gap > threshold:
full_ft_model = train_full(dataset_full)

PEFT para Iteración, Fine-Tuning Completo para el Final​

# Iterate on data/hyperparameters with PEFT (fast, cheap)
for experiment in experiments:
model = train_lora(config=experiment)
score = evaluate(model)
if score > best_score:
best_config = experiment

# Final training with full FT using best settings
final_model = train_full(config=best_config)

Recomendaciones Prácticas​

Para la Mayoría de los Casos: Comience con PEFT​

# Default recommendation for most practitioners
from peft import LoraConfig, get_peft_model

config = LoraConfig(
r=16,
lora_alpha=32,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.05,
)

model = get_peft_model(base_model, config)
# Train and evaluate

Para Producción: Considere Fusionar​

# After training, merge for deployment
model = model.merge_and_unload()
model.save_pretrained("./production-model")
# Now behaves exactly like full fine-tuned model

Puntos Clave​

✅ PEFT logra entre el 90-99% de la calidad del fine-tuning completo con 80-95% menos memoria

✅ El fine-tuning completo tiene un techo de calidad más alto pero a un costo significativo

✅ PEFT permite el intercambio de adaptadores; el fine-tuning completo crea modelos fijos

✅ PEFT fusionado tiene un rendimiento de inferencia idéntico al fine-tuning completo

✅ Comience con PEFT, pase a fine-tuning completo solo si es necesario

✅ Considere el costo total incluyendo almacenamiento, intercambio y iteración


Próximos Pasos​

Continúe a Capítulo 3: Descripción General de Métodos PEFT para explorar todas las técnicas PEFT disponibles.


Comprobación Rápida​

Antes de continuar, asegúrese de poder responder:

  1. ¿Cuánta memoria ahorra PEFT en comparación con el fine-tuning completo?
  2. ¿Cuándo podría el fine-tuning completo superar a PEFT?
  3. ¿Cuál es la ventaja de los adaptadores PEFT fusionados?