Fine-Tuning de Modelos de Lenguaje con LoRA y QLoRA en Python y Unsloth: Guía Práctica para GPUs de 8GB

El ajuste fino (fine-tuning) tradicional de un modelo de lenguaje de miles de millones de parámetros exigía hasta hace poco una infraestructura prohibitiva. Modificar todos los pesos de un modelo de 7B o 13B parámetros en precisión completa (FP32) requería almacenar no solo los tensores del modelo, sino también los gradientes del optimizador AdamW (que triplican el peso en memoria), demandando clústeres de múltiples tarjetas Nvidia A100 u H100 de 80 GB de VRAM cada una.

Esta barrera económica quedó pulverizada con la introducción de PEFT (Parameter-Efficient Fine-Tuning) y, muy especialmente, con LoRA (Low-Rank Adaptation) y QLoRA (Quantized LoRA). Al congelar los pesos pre-entrenados del modelo e inyectar matrices de bajo rango entrenables en las capas de atención, es posible reducir el consumo de memoria en más de un 85% preservando más del 99% de la calidad final. Utilizando la librería ultrarrápida Unsloth, hoy cualquier desarrollador puede ajustar un modelo de 8B parámetros en una tarjeta gráfica doméstica de 8 GB o en una instancia gratuita de Google Colab T4. Basándonos en las investigaciones de arXiv Computer Science (Dettmers et al., QLoRA Paper) y los repositorios de Hugging Face PEFT Library, en este tutorial aprenderás el flujo completo paso a paso.

1. Por Qué LoRA y QLoRA Cambiaron el Juego: La Matemática de Matrices de Bajo Rango

Cuando un modelo pre-entrenado se ajusta a un nuevo dominio (por ejemplo, redactar contratos legales o diagnosticar fallos de software), no es necesario modificar la estructura total de sus miles de millones de conexiones neuronales. La hipótesis central de LoRA demuestra que las actualizaciones de los pesos durante la adaptación tienen un rango intrínseco muy bajo.

En lugar de actualizar una matriz de pesos gigantesca $W$ de dimensión $d \times k$, LoRA congela $W$ y aprende dos matrices microscópicas $A$ y $B$ de rango $r$ (donde $r$ suele ser un número pequeño como 8, 16 o 32) tales que $\Delta W = B \times A$. Esto reduce la cantidad de parámetros entrenables en más de un 99.8%. Posteriormente, QLoRA introdujo la cuantización de 4 bits en formato NormalFloat (NF4) y doble cuantización, permitiendo cargar el modelo base congelado consumiendo menos de 5 GB de memoria.

Código fuente en Python y desarrollo de algoritmos de inteligencia artificial

Ajuste fino de modelos de lenguaje mediante matrices de bajo rango y cuantización de 4 bits.

2. Unsloth: Kernels Manuales de OpenAI Triton y Ahorro Masivo de VRAM

La librería Unsloth ha transformado el ecosistema del fine-tuning de la misma forma que FlashAttention optimizó la inferencia. Sus creadores reescribieron las funciones de atención y las operaciones de normalización (RMSNorm, RoPE y CrossEntropyLoss) en código manual de bajo nivel usando OpenAI Triton.

El resultado es que Unsloth es hasta 5 veces más rápido y consume un 70% menos de memoria VRAM que la combinación estándar de Hugging Face TRL + PEFT, eliminando fugas de memoria y permitiendo longitudes de contexto de hasta 8.192 tokens en hardware de gama media sin ralentizaciones.

3. Preparación del Dataset: Formatos Alpaca, ShareGPT y ChatML para Alineación

La calidad del modelo ajustado depende en un 90% de la pureza de los datos. Para tareas conversacionales o de seguimiento de instrucciones se utiliza el formato estandarizado ChatML o ShareGPT:

[
  {
    "conversations": [
      {"from": "human", "value": "¿Cómo revoco un token JWT comprometido en un microservicio?"},
      {"from": "gpt", "value": "Para revocar un JWT sin estado, implementa una lista negra en memoria distribuida (Redis) con un TTL equivalente a la expiración del token..."}
    ]
  }
]

Es preferible contar con 1.000 ejemplos curados minuciosamente por expertos humanos con razonamiento paso a paso que con 50.000 ejemplos ruidosos descargados de raspados web indiscriminados.

4. Código Paso a Paso: Configuración de Hiperparámetros y Entrenamiento en Python

A continuación se muestra el script minimalista y production-ready con Unsloth para ajustar LLaMA 3.1 8B:

from unsloth import FastLanguageModel
import torch
from trl import SFTTrainer
from transformers import TrainingArguments

# 1. Cargar modelo pre-entrenado de 4 bits
max_seq_length = 2048
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit",
    max_seq_length=max_seq_length,
    load_in_4bit=True
)

# 2. Configurar adaptadores LoRA
model = FastLanguageModel.get_peft_model(
    model,
    r=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
    lora_alpha=16,
    lora_dropout=0, # Optimizado para Unsloth
    bias="none"
)

# 3. Lanzar el entrenamiento
trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=max_seq_length,
    args=TrainingArguments(
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        warmup_steps=10,
        max_steps=100,
        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()
Consola de monitoreo de entrenamiento y compilación de modelos

Monitoreo en tiempo real de gradientes y curvas de pérdida durante el proceso de optimización.

5. Evaluación y Diagnóstico: Monitoreo de Loss y Mitigación del Olvido Catastrófico

Un riesgo recurrente en el fine-tuning es el Olvido Catastrófico (Catastrophic Forgetting): el modelo se vuelve brillante en tu tarea especializada pero pierde la capacidad de redactar con sentido común o razonar lógicamente en tareas básicas.

Para prevenir esto, se debe monitorear la curva de pérdida de validación (Validation Loss). Si la pérdida de entrenamiento cae por debajo de 0.6 mientras la validación se estanca o sube, el modelo está sufriendo sobreajuste (overfitting). La solución consiste en mezclar un 10% de ejemplos de razonamiento general en tu dataset de entrenamiento.

6. Tabla Comparativa: Full Fine-Tuning vs. LoRA vs. QLoRA vs. Prompt Tuning

Resumen técnico de costes, memoria y flexibilidad de las técnicas de adaptación:

Método VRAM Requerida (Modelo 8B) % Parámetros Entrenables Retención de Conocimiento Coste de Hardware
Full Fine-Tuning >= 80 GB VRAM 100% (Todos los pesos) Riesgo alto de olvido Muy Alto ($$$$)
LoRA (16 bits) 16 – 24 GB VRAM 0.1% – 0.5% ⭐⭐⭐⭐⭐ Sobresaliente Moderado ($$)
QLoRA (4 bits + Unsloth) 6 – 8 GB VRAM 0.1% – 0.5% ⭐⭐⭐⭐⭐ Sobresaliente Mínimo / Tarjetas de consumo ($)
Prompt Tuning / Soft Prompts < 6 GB VRAM < 0.01% Capacidad de adaptación limitada Muy Bajo ($)

7. Exportación y Fusión: Unir Matrices LoRA y Convertir a Formato GGUF para Ollama

Una vez concluido el entrenamiento, no necesitas cargar las matrices LoRA separadas durante la inferencia en producción. Unsloth permite fusionar (merge) los adaptadores directamente en los pesos base y exportar el binario a formato GGUF cuantizado con una sola instrucción:

# Guardar y fusionar en formato GGUF de 4 bits para Ollama
model.save_pretrained_gguf("mi_modelo_personalizado", tokenizer, quantization_method="q4_k_m")

Este archivo binario resultante puede cargarse inmediatamente en tu servidor local. Para aprender a configurarlo en tu máquina, consulta nuestra guía sobre cómo correr modelos locales con Ollama y LM Studio.

Tarjeta gráfica y procesador de cálculo vectorial

La fusión de adaptadores LoRA produce modelos independientes listos para inferencia ultraveloz.

8. Preguntas Frecuentes sobre Fine-Tuning con LoRA y QLoRA

¿Cuánto tiempo tarda en entrenarse un modelo LLaMA 3.1 8B con QLoRA y Unsloth?
Para un dataset representativo de 2.000 ejemplos conversacionales bien curados, el entrenamiento toma aproximadamente entre 25 y 45 minutos en una tarjeta Nvidia RTX 3080 o 4070 (12 GB de VRAM), o cerca de una hora en la GPU T4 gratuita de Google Colab.

¿Cuándo debo elegir Fine-Tuning en lugar de RAG?
Utiliza RAG cuando necesites acceder a documentos vivos que cambian con frecuencia (precios, stock, leyes) y requieras citar fuentes exactas. Utiliza Fine-Tuning cuando desees cambiar permanentemente la personalidad, el formato de salida estricto (por ejemplo, hablar solo en SQL específico o JSON especializado) o enseñar un dialecto o lenguaje no dominado por el modelo base.

¿Qué rango (rank $r$) debo configurar en LoRA?
Para la gran mayoría de tareas de estilo y seguimiento de instrucciones, un rango de $r=16$ con $\alpha=16$ proporciona el balance idóneo entre capacidad expresiva y velocidad. Aumentar el rango a $r=64$ o $r=128$ solo se justifica en adaptaciones de dominios sumamente complejos (como aprendizaje de nuevos idiomas completos), incrementando el riesgo de sobreajuste.