Saltar al contenido principal

Capítulo 1: Enfoque Tradicional de Fine-Tuning

Actualización de Todos los Parámetros del Modelo​

El fine-tuning tradicional implica actualizar cada parámetro entrenable del modelo durante el entrenamiento. Esto proporciona la máxima flexibilidad para adaptar los modelos a nuevas tareas.


Cómo Funciona el Fine-Tuning Completo​

El Bucle de Entrenamiento​

  1. Forward Pass: Los datos fluyen a través de todo el modelo
  2. Cálculo de la Pérdida: Comparar la predicción con el objetivo
  3. Backward Pass: Calcular los gradientes para todos los parámetros
  4. Actualización de Pesos: Aplicar los gradientes para actualizar todos los pesos
  5. Repetir: Continuar hasta la convergencia

Ejemplo Completo de Entrenamiento​

import torch
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
TrainingArguments,
Trainer,
DataCollatorForLanguageModeling,
)
from datasets import load_dataset

# Load model and tokenizer
model_name = "meta-llama/Llama-3.1-8B"
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token

# Load model - all parameters trainable by default
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.bfloat16, # Use bf16 for memory efficiency
device_map="auto",
)

# Verify all parameters are trainable
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
total_params = sum(p.numel() for p in model.parameters())
print(f"Trainable: {trainable_params:,} / {total_params:,} = 100%")

# Prepare dataset
dataset = load_dataset("databricks/dolly-15k", split="train[:1000]")

def format_instruction(example):
return {
"text": f"### Instruction:\n{example['instruction']}\n\n### Response:\n{example['response']}"
}

dataset = dataset.map(format_instruction)

def tokenize(example):
return tokenizer(
example["text"],
truncation=True,
max_length=512,
padding="max_length",
)

tokenized_dataset = dataset.map(tokenize, remove_columns=dataset.column_names)

# Training configuration
training_args = TrainingArguments(
output_dir="./llama-full-ft",
num_train_epochs=3,
per_device_train_batch_size=1, # Limited by memory
gradient_accumulation_steps=16, # Simulate batch size of 16
learning_rate=2e-5,
weight_decay=0.01,
warmup_ratio=0.03,
logging_steps=10,
save_strategy="epoch",
bf16=True, # Use bfloat16
gradient_checkpointing=True, # Save memory
optim="adamw_torch_fused", # Efficient optimizer
)

# Create trainer
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
data_collator=DataCollatorForLanguageModeling(tokenizer, mlm=False),
)

# Train
trainer.train()

# Save
model.save_pretrained("./llama-full-ft-final")
tokenizer.save_pretrained("./llama-full-ft-final")

Componentes Clave Explicados​

Tasa de Aprendizaje​

learning_rate = 2e-5 # Common range: 1e-5 to 5e-5

Para el fine-tuning completo, utilice tasas de aprendizaje más bajas que en PEFT:

  • Demasiado alta: El modelo diverge o "olvida" el pre-entrenamiento
  • Demasiado baja: El entrenamiento es lento, puede que no se adapte lo suficiente

Decaimiento de Pesos (Weight Decay)​

weight_decay = 0.01 # Regularization to prevent overfitting

El decaimiento de pesos previene el sobreajuste penalizando los pesos grandes.

Warmup​

warmup_ratio = 0.03 # 3% of training steps

Aumenta gradualmente la tasa de aprendizaje al inicio para un entrenamiento estable.

Gradient Checkpointing​

gradient_checkpointing = True # Trade compute for memory

Vuelve a calcular las activaciones durante el backward pass en lugar de almacenarlas—ahorra ~30% de memoria.


Opciones de Optimizador​

OptimizadorMemoriaVelocidadCalidad
AdamWAltaRápidaMejor
Adam 8-bitMediaMediaBuena
SGDBajaLentaRequiere ajuste
AdafactorBajaMediaBuena
# Standard AdamW
optim = "adamw_torch"

# Fused AdamW (faster)
optim = "adamw_torch_fused"

# 8-bit Adam (less memory)
optim = "adamw_8bit"

# Adafactor (no momentum states)
optim = "adafactor"

Dinámica del Entrenamiento​

Curva de Pérdida​

Epoch 1: La pérdida de entrenamiento disminuye rápidamente
(El modelo se adapta a los nuevos datos)

Epoch 2: La pérdida de entrenamiento se estabiliza
(Vigile la pérdida de validación para detectar sobreajuste)

Epoch 3: Posible sobreajuste
(La pérdida de entrenamiento sigue bajando, la de validación puede aumentar)

Monitoreo del Entrenamiento​

# Using Weights & Biases
training_args = TrainingArguments(
# ... other args ...
report_to="wandb",
run_name="llama-full-ft-experiment-1",
)

Métricas clave a observar:

  • Pérdida de Entrenamiento: Debe disminuir
  • Pérdida de Validación: Debe disminuir, pero vigile si diverge de la de entrenamiento
  • Norma del Gradiente: Picos pueden indicar inestabilidad
  • Tasa de Aprendizaje: Verifique que el warmup y el decaimiento funcionen

Entrenamiento en Precisión Mixta​

¿Por Qué Usar Precisión Mixta?​

# Half the memory, often faster training
bf16 = True # Preferred for newer GPUs (Ampere+)
# OR
fp16 = True # For older GPUs
PrecisiónMemoriaRangoEstabilidad
float324 bytesCompletoMáxima
bfloat162 bytesCompletoAlta
float162 bytesLimitadoMedia
Float16 Stability

Float16 tiene un rango más estrecho y puede causar desbordamientos o subdesbordamientos. BFloat16 mantiene el rango de float32 con menor precisión, lo que la hace más estable.


Guardado y Carga​

Durante el Entrenamiento (Checkpoints)​

training_args = TrainingArguments(
save_strategy="steps",
save_steps=500,
save_total_limit=3, # Keep only last 3 checkpoints
)

Después del Entrenamiento​

# Save the full model
model.save_pretrained("./final-model")
tokenizer.save_pretrained("./final-model")

# Later, load it
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("./final-model")

Ventajas del Fine-Tuning Completo​

Máxima Personalización​

Todos los parámetros pueden ajustarse a su tarea.

Potencialmente la Mayor Calidad​

Sin restricciones de pesos congelados.

Simplicidad​

No se necesita configuración de adaptadores.

Salida Unificada​

Archivo de modelo único, sin sobrecarga de adaptadores en inferencia.


Desventajas​

Altos Requisitos de Memoria​

Se debe almacenar el modelo, los gradientes y los estados del optimizador.

Riesgo de Olvido Catastrófico​

Puede perder el conocimiento pre-entrenado.

Costoso​

Requiere recursos significativos de GPU.

Entrenamiento Lento​

Cada parámetro debe ser actualizado.


Cuándo Usar Fine-Tuning Completo​

Caso de UsoRecomendación
Se requiere la máxima calidad✅ Fine-Tuning Completo
Recursos limitados❌ Use PEFT
Experimentación rápida❌ Use PEFT
Producción a gran escala⚠️ Considere los trade-offs
Investigación/benchmarking✅ Fine-Tuning Completo

Puntos Clave​

✅ El fine-tuning completo actualiza todos los parámetros del modelo

✅ Requiere memoria significativa de GPU (modelo + gradientes + optimizador)

✅ Use precisión mixta y gradient checkpointing para reducir memoria

✅ Tasas de aprendizaje más bajas que PEFT (1e-5 a 5e-5)

✅ Monitoree el sobreajuste con la pérdida de validación

✅ Mejor opción para máxima personalización cuando los recursos lo permiten


Próximos Pasos​

Continúe a Capítulo 2: Requisitos Computacionales para comprender las necesidades exactas de memoria y cómputo.


Comprobación Rápida​

Antes de continuar, asegúrese de poder responder:

  1. ¿Cuáles son los cuatro componentes principales que se almacenan en la memoria de la GPU durante el entrenamiento?
  2. ¿Por qué a menudo se prefiere bfloat16 sobre float16?
  3. ¿Cuál es el rango típico de tasa de aprendizaje para el fine-tuning completo?