Entrenamiento con Unsloth
Por Que Existe Unsloth
El stack de entrenamiento estandar de Hugging Face funciona, pero deja rendimiento sobre la mesa. Unsloth reescribe partes clave del pipeline de entrenamiento con kernels CUDA personalizados y gestion de memoria optimizada, logrando un entrenamiento 2x mas rapido y hasta 60% menos uso de memoria — sin ningun cambio en la calidad del modelo. Si estas haciendo fine-tuning en hardware de consumo o quieres minimizar costos de GPU en la nube, Unsloth es la herramienta que debes aprender.
Que Hace Rapido a Unsloth
La velocidad de Unsloth proviene de varias optimizaciones:
- Kernels Triton personalizados para la perdida de entropia cruzada y capas LoRA, eliminando asignaciones de memoria innecesarias
- Operaciones fusionadas que combinan multiples pasos (embedding RoPE, normalizacion de capa, paso forward de LoRA) en llamadas unicas a la GPU
- Gestion inteligente de memoria que reutiliza buffers en lugar de asignar nuevos
- Paso backward optimizado que calcula gradientes mas eficientemente para parametros LoRA
Estas optimizaciones se aplican automaticamente cuando cargas un modelo a traves de la API de Unsloth. No necesitas cambiar tu codigo de entrenamiento mas alla del paso de carga del modelo.
Instalacion
pip install unsloth
Para versiones especificas de CUDA o si encuentras problemas:
# Para CUDA 12.1
pip install unsloth[cu121-ampere-torch250]
# Para CUDA 11.8
pip install unsloth[cu118-torch250]
Unsloth tambien funciona en notebooks de Google Colab y Kaggle sin configuracion especial.
Modelos Soportados
Unsloth soporta las familias de modelos de pesos abiertos mas populares:
- Llama 3 / 3.1 / 3.2 (1B, 3B, 8B, 70B)
- Mistral / Mixtral (7B, 8x7B)
- Qwen 2 / 2.5 (0.5B a 72B)
- Gemma 2 (2B, 9B, 27B)
- Phi-3 / Phi-4 (3.8B, 14B)
Unsloth proporciona versiones pre-cuantizadas en 4 bits de estos modelos que se cargan mas rapido que cuantizar desde cero:
# Modelos pre-cuantizados de Unsloth (recomendado)
"unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit"
"unsloth/Mistral-7B-Instruct-v0.3-bnb-4bit"
"unsloth/Qwen2.5-7B-Instruct-bnb-4bit"
"unsloth/gemma-2-9b-it-bnb-4bit"
FastLanguageModel: Carga y Configuracion
Unsloth reemplaza la carga de modelo estandar de HF con FastLanguageModel:
from unsloth import FastLanguageModel
import torch
# Cargar modelo y tokenizador
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit",
max_seq_length=2048,
dtype=None, # Auto-detectar (bfloat16 en Ampere+, float16 en otros)
load_in_4bit=True, # QLoRA
)
Esta unica llamada maneja todo: carga del modelo, cuantizacion, configuracion del tokenizador y optimizacion de memoria.
Aplicando LoRA
model = FastLanguageModel.get_peft_model(
model,
r=16,
lora_alpha=32,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
lora_dropout=0.0, # Unsloth recomienda 0 para velocidad
bias="none",
use_gradient_checkpointing="unsloth", # Version optimizada de Unsloth
random_state=42,
)
Diferencia clave: Unsloth recomienda lora_dropout=0.0 porque sus kernels optimizados son mas rapidos sin dropout. Si necesitas regularizacion, usa una tasa de aprendizaje mas baja o early stopping en su lugar.
El flag use_gradient_checkpointing="unsloth" habilita el gradient checkpointing personalizado de Unsloth que es 30% mas rapido que la implementacion estandar.
Configuracion de Entrenamiento
Unsloth usa el SFTTrainer estandar de Hugging Face, asi que el codigo de entrenamiento es casi identico:
from trl import SFTTrainer
from transformers import TrainingArguments
from datasets import load_dataset
# Cargar dataset
dataset = load_dataset("json", data_files={
"train": "data/train.jsonl",
"validation": "data/val.jsonl",
})
training_args = TrainingArguments(
output_dir="./output/llama3-unsloth",
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=8,
learning_rate=2e-4,
lr_scheduler_type="linear",
warmup_steps=10,
optim="adamw_8bit",
weight_decay=0.01,
bf16=True,
logging_steps=10,
eval_strategy="steps",
eval_steps=50,
save_strategy="steps",
save_steps=100,
save_total_limit=3,
seed=42,
)
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
args=training_args,
train_dataset=dataset["train"],
eval_dataset=dataset["validation"],
max_seq_length=2048,
packing=False,
dataset_text_field=None,
)
# Entrenar
trainer.train()
Ejemplo Completo: Fine-Tuning de Llama 3 con Datos Personalizados
Aqui hay un script completo y autocontenido:
"""
Script completo de fine-tuning con Unsloth para Llama 3.1 8B.
Requiere: pip install unsloth trl datasets
Hardware: Funciona con 16GB de VRAM (T4, RTX 4060, etc.)
"""
from unsloth import FastLanguageModel
from trl import SFTTrainer
from transformers import TrainingArguments
from datasets import load_dataset
import torch
# === 1. Cargar Modelo ===
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit",
max_seq_length=2048,
dtype=None,
load_in_4bit=True,
)
# === 2. Aplicar LoRA ===
model = FastLanguageModel.get_peft_model(
model,
r=16,
lora_alpha=32,
target_modules=[
"q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj",
],
lora_dropout=0.0,
bias="none",
use_gradient_checkpointing="unsloth",
random_state=42,
)
# === 3. Cargar Dataset ===
dataset = load_dataset("json", data_files={
"train": "data/train.jsonl",
"validation": "data/val.jsonl",
})
# === 4. Entrenamiento ===
trainer = SFTTrainer(
model=model,
tokenizer=tokenizer,
args=TrainingArguments(
output_dir="./output/llama3-custom",
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=8,
learning_rate=2e-4,
lr_scheduler_type="linear",
warmup_steps=10,
optim="adamw_8bit",
weight_decay=0.01,
bf16=True,
logging_steps=10,
eval_strategy="steps",
eval_steps=50,
save_strategy="steps",
save_steps=100,
save_total_limit=3,
seed=42,
),
train_dataset=dataset["train"],
eval_dataset=dataset["validation"],
max_seq_length=2048,
)
trainer.train()
# === 5. Guardar Adaptador LoRA ===
model.save_pretrained("./output/llama3-custom/final")
tokenizer.save_pretrained("./output/llama3-custom/final")
# === 6. Probar el Modelo ===
FastLanguageModel.for_inference(model) # Habilitar modo de inferencia rapida
messages = [
{"role": "user", "content": "Explica que es el fine-tuning."}
]
inputs = tokenizer.apply_chat_template(
messages, return_tensors="pt", add_generation_prompt=True
).to("cuda")
outputs = model.generate(
input_ids=inputs,
max_new_tokens=256,
temperature=0.7,
do_sample=True,
)
print(tokenizer.decode(outputs[0][inputs.shape[1]:], skip_special_tokens=True))
Comparacion: Unsloth vs Hugging Face Vanilla
Benchmarks en una RTX 3090 (24GB), Llama 3.1 8B, QLoRA r=16, batch size 2:
| Metrica | Hugging Face | Unsloth | Mejora | |---------|-------------|---------|--------| | Velocidad de entrenamiento | 1.2 it/s | 2.5 it/s | 2.1x mas rapido | | VRAM pico | 14.2 GB | 8.1 GB | 43% menos | | Tiempo total (1000 pasos) | 14 min | 6.7 min | 2.1x mas rapido | | Perdida final | 0.847 | 0.845 | Equivalente |
La calidad (medida por la perdida final y evaluacion humana) es identica — Unsloth no corta esquinas en las matematicas, simplemente computa las mismas matematicas de manera mas eficiente.
Cuando Usar Unsloth
Usa Unsloth cuando:
- Estas entrenando en GPUs de consumo (16-24GB de VRAM)
- Quieres minimizar costos de GPU en la nube
- Estas haciendo iteracion rapida y necesitas rapido retorno
- Estas entrenando en la capa gratuita de Colab/Kaggle
Usa Hugging Face vanilla cuando:
- Necesitas entrenamiento multi-GPU (el soporte multi-GPU de Unsloth es mas limitado)
- Necesitas bucles de entrenamiento personalizados que modifiquen el paso de entrenamiento
- Estas usando una arquitectura de modelo que Unsloth no soporta aun
- Necesitas integracion con DeepSpeed o FSDP
Guardado y Exportacion
Unsloth hace la exportacion facil:
# Guardar como adaptador LoRA (mas pequeno, para fusion posterior)
model.save_pretrained("output/lora-adapter")
# Guardar modelo fusionado en float16
model.save_pretrained_merged("output/merged-f16", tokenizer, save_method="merged_16bit")
# Guardar como GGUF para Ollama/llama.cpp
model.save_pretrained_gguf("output/gguf", tokenizer, quantization_method="q4_k_m")
# Subir a Hugging Face Hub
model.push_to_hub_merged("tu-usuario/tu-modelo", tokenizer)
model.push_to_hub_gguf("tu-usuario/tu-modelo-gguf", tokenizer, quantization_method="q4_k_m")
Esta es una de las mayores conveniencias de Unsloth — convertir a GGUF directamente desde el script de entrenamiento, sin un paso de conversion separado.
En la proxima leccion, cubrimos como monitorear tus ejecuciones de entrenamiento y depurar los problemas mas comunes que surgen durante el fine-tuning.