GPT Diffusion

Fine-tuning barato con Unsloth: LoRA en 30 minutos

2026-04-25 · Tutoriales #llm#open-weights#open-source#python#fine-tuning

TL;DR

  • Unsloth hace que el fine-tuning con LoRA sea 2-5x más rápido y use menos VRAM que HuggingFace Transformers puro.
  • Puedes fine-tunear un modelo de 7B en una RTX 3090 (24GB) en 30 minutos.
  • Coste estimado: $0.50-1.00 por run en Google Colab Pro o RunPod.

¿Qué es LoRA?

LoRA (Low-Rank Adaptation) no reentrena todo el modelo. Entrena una capa delgada de parámetros encima del modelo base. El resultado:

  • Entrenas 0.1-1% de los parámetros totales
  • Necesitas 3-5x menos VRAM que full fine-tuning
  • El modelo original se mantiene intacto
  • Puedes intercambiar adapters LoRA como plugins

Setup

Opción A: Google Colab (más fácil)

Abre un notebook con GPU T4 (gratis) o A100 (Colab Pro):

!pip install unsloth

Opción B: Local

pip install unsloth torch --index-url https://download.pytorch.org/whl/cu121

Requiere GPU NVIDIA con CUDA. 16GB+ VRAM para modelos de 7B.

Paso 1: Cargar modelo

from unsloth import FastLanguageModel

model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/llama-4-scout-17b",
    max_seq_length=2048,
    load_in_4bit=True,  # Cuantización 4-bit para ahorrar VRAM
    dtype=None,  # Auto-detect
)

El flag load_in_4bit=True es clave: carga el modelo en 4-bit, reduciendo VRAM de ~34GB a ~10GB.

Paso 2: Añadir LoRA

model = FastLanguageModel.get_peft_model(
    model,
    r=16,  # Rank del adapter (8, 16, 32, 64)
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                     "gate_proj", "up_proj", "down_proj"],
    lora_alpha=16,
    lora_dropout=0,
    bias="none",
    use_gradient_checkpointing="unsloth",  # Optimización de VRAM
)

rank (r): Controla la capacidad del adapter. r=16 es suficiente para la mayoría de tareas. r=64 para tareas complejas (más VRAM).

Paso 3: Preparar dataset

Necesitas datos en formato de conversación. Ejemplo para un asistente técnico:

train_dataset = [
    {
        "conversations": [
            {"role": "user", "content": "¿Cómo configuro nginx como reverse proxy?"},
            {"role": "assistant", "content": "1. Instala nginx..."},
        ]
    },
    # ... más ejemplos
]

Mínimo recomendado: 100-500 ejemplos para tasks específicas. 1000+ para cambios de estilo o dominio.

Formato con HuggingFace datasets:

from datasets import load_dataset

dataset = load_dataset("json", data_files="train.jsonl")

def formatting_prompts_func(examples):
    convos = examples["conversations"]
    texts = [
        tokenizer.apply_chat_template(convo, tokenize=False, add_generation_prompt=False)
        for convo in convos
    ]
    return {"text": texts}

dataset = dataset.map(formatting_prompts_func, batched=True)

Paso 4: Entrenar

from trl import SFTTrainer
from transformers import TrainingArguments

trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=2048,
    args=TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=5,
        num_train_epochs=3,
        learning_rate=2e-4,
        fp16=not torch.cuda.is_bf16_supported(),
        bf16=torch.cuda.is_bf16_supported(),
        logging_steps=10,
        output_dir="outputs",
    ),
)

trainer.train()

Tiempo estimado con 500 ejemplos, RTX 3090: ~20-30 minutos.

Paso 5: Probar

FastLanguageModel.for_inference(model)

messages = [{"role": "user", "content": "¿Cómo configuro nginx?"}]
inputs = tokenizer.apply_chat_template(
    messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
).to("cuda")

outputs = model.generate(inputs, max_new_tokens=256, temperature=0.7)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

Paso 6: Exportar

Opción A: Guardar LoRA adapter solo

model.save_pretrained("my-lora-adapter")
tokenizer.save_pretrained("my-lora-adapter")

Tamaño: ~50-200MB (frente a 10-30GB del modelo completo).

Opción B: Merge con modelo base

model.save_pretrained_merged("my-merged-model", tokenizer)

Opción C: Exportar a GGUF para llama.cpp

model.save_pretrained_gguf("my-model", tokenizer, quantization_method="q4_k_m")

Esto genera un archivo GGUF que puedes usar con llama.cpp u Ollama directamente.

Errores comunes

Loss no baja: Learning rate demasiado alto o dataset demasiado pequeño. Prueba lr=1e-4 y añade más datos.

Overfitting: El modelo repite frases del training data. Reduce num_train_epochs a 1-2 y añade regularización.

OOM: Reduce per_device_train_batch_size a 1 y aumenta gradient_accumulation_steps. O reduce max_seq_length.

El modelo “olvida”: LoRA intenso puede degradar capacidades generales. Usa r=8-16 (no 64+) y no entrenes demasiadas epochs.

¿Cuándo fine-tunear vs RAG vs prompting?

SituaciónMejor opción
Cambiar estilo/tonoFine-tuning LoRA
Añadir conocimiento nuevoRAG
Formato de salida específicoPrompting + few-shot
Dominio muy especializado (médico, legal)Fine-tuning + RAG
Task repetitiva con patrón claroFine-tuning LoRA

Regla: Si puedes resolverlo con prompting, no fine-tunees. Si necesitas que el modelo sea diferente (no que sepa cosas diferentes), fine-tuning.

Coste real

SetupCoste por run (500 ejemplos)Tiempo
Google Colab T4 (gratis)$01-2h
Google Colab A100~$115min
RunPod RTX 4090~$0.5020min
Local RTX 3090~$0 (electricidad)30min

Fine-tuning ya no es un lujo. Es accesible para cualquier dev con una GPU consumer.


Fuentes: Unsloth docs (unsloth.ai), HuggingFace TRL docs, experiencia propia.

Cargando comentarios...