Guía de fine-tuning de LLM: LoRA, QLoRA, Unsloth y Axolotl

Traducción automática Este artículo se tradujo automáticamente a partir de la versión original en inglés.

La mayoría de los fallos de fine-tuning son fallos de decisión. Un equipo entrena antes de demostrar que prompting, retrieval o constrained decoding no pueden resolver el problema. Otro evalúa sobre la distribución de entrenamiento o descubre después del entrenamiento que el artefacto resulta difícil de servir.

Esta guía trata la adaptación como un experimento con una salida operativa. Empieza por el límite de decisión y después recorre un camino a través de los datos, LoRA o QLoRA, la evaluación específica de la tarea, la exportación y el serving.

Para una decisión rápida sobre la intervención, consulta Fine-Tuning vs RAG vs Prompting.

¿Deberías hacer fine-tuning?

Antes de gastar horas de GPU, decide si el fine-tuning es la herramienta adecuada para el problema que tienes delante.

Diagrama de decisiónDiagrama de decisión

Fine-tuning frente a RAG

El fine-tuning puede cambiar cómo utiliza el modelo el lenguaje del dominio, pero es un mecanismo deficiente para actualizar hechos que cambian o que deben citarse. Retrieval y fine-tuning resuelven partes distintas del problema y a menudo deben formar parte del mismo sistema.

CaracterísticaFine-tuningRAG (Retrieval-Augmented Generation)
Función principalModifica los pesos internos para enseñar habilidades, estilos o comportamientosProporciona contexto externo y actualizado durante la inferencia
Más adecuado para• Estilos conversacionales específicos
• Seguir instrucciones complejas
• Razonamiento de dominio
• Datos que cambian rápidamente (noticias, cotizaciones)
• Reducir alucinaciones (grounding)
• Citar fuentes
Gestión del conocimientoCambia el comportamiento estadístico de los pesos; no garantiza el recuerdo exactoRecupera registros o pasajes que pueden actualizarse y citarse
Frecuencia de actualizaciónRequiere reentrenamiento para actualizarloSe actualiza inmediatamente con documentos nuevos

Fine-tuning frente a prompt engineering

Los LLMs modernos responden bien a prompts y ejemplos claros. Prueba esas opciones antes de invertir en fine-tuning.

AspectoFine-tuningPrompt engineering
Coste de configuraciónAlto (curación de datos, cómputo de GPU, iteración)Bajo (refinamiento iterativo del prompt)
FlexibilidadRequiere otro ciclo de entrenamiento y publicaciónCambia con el prompt
Formato/estiloPuede hacer más probable un comportamiento repetidoA menudo basta para el estilo y formatos sencillos
LatenciaPuede acortar instrucciones repetidasDepende de la longitud del prompt y de la caché del proveedor
Más adecuado paraComportamientos complejos, distillation, coste a escalaIteración rápida, requisitos cambiantes

[!TIP] Prueba prompting primero Empieza con un prompt y ejemplos representativos. Si solo falla la sintaxis de salida, añade constrained decoding antes de cambiar los pesos.

Fine-tuning frente a constrained decoding

Bibliotecas como xgrammar y outlines restringen la generación a un JSON Schema, una expresión regular o una gramática. Según la restricción y el backend, compilan un autómata o una gramática y enmascaran los tokens siguientes no válidos. No se requiere actualizar los pesos.

Esto garantiza que la salida pertenezca al lenguaje compatible. La garantía no dice nada sobre si los valores son verdaderos, completos o semánticamente adecuados. Un function call sintácticamente válido aún puede contener el ID de cliente equivocado.

AspectoConstrained decodingFine-tuning
ConfiguraciónInmediata: definir el esquema y desplegarRequiere curación de datos, cómputo de GPU e iteración
GarantíaSintaxis válida para la restricción compatibleComportamiento aprendido; el cumplimiento del esquema puede variar
FlexibilidadCambiar el esquema en cualquier momento sin reentrenarQueda fijado tras el entrenamiento
LatenciaLigera sobrecarga (el modelo puede «luchar» contra el esquema)Menor (el modelo produce el formato de forma natural)
Más adecuado paraJSON, opciones, gramáticas y sintaxis de tool callsComportamientos de tarea repetidos que le faltan al modelo base

Un orden práctico:

  1. Empieza con prompting y ejemplos few-shot para el formato básico.
  2. Añade constrained decoding (xgrammar o outlines) cuando la sintaxis sea inconsistente.
  3. Haz fine-tuning solo cuando necesites cambios de comportamiento que un esquema no pueda imponer.

Referencia rápida: relacionar problemas y soluciones

DesafíoPrimer mecanismo que probar¿Por qué?
Falta de conocimientoRAGLos modelos alucinan hechos. Retrieval proporciona contexto fundamentado y actualizado
Formato o tono incorrectosPrompt engineeringLos modelos modernos siguen bien las instrucciones de estilo mediante ejemplos few-shot
Sintaxis de salida no válidaConstrained decodingImpone un esquema o una gramática compatibles durante la generación
Fallos repetidos en una tareaFine-tuning (SFT)Aprende de ejemplos de entrada/salida seleccionados
Desajuste en preferencias por paresPreference optimizationUsa ejemplos chosen/rejected una vez medido el comportamiento de la tarea
Latencia o coste a escalaDistillation (SFT)Entrena un modelo student más pequeño con las salidas de un teacher más grande
Reducir el tamaño del modeloQuantizationSin entrenamiento: comprime los pesos (FP16→INT4) para acelerar la inferencia

Haz que el caso de negocio sea medible

El fine-tuning puede reducir los tokens recurrentes de los prompts o permitir que un modelo más pequeño alcance el objetivo, pero ninguno de esos ahorros es automático. Calcula el punto de equilibrio con tu tráfico y tus precios:

[ \text{solicitudes de equilibrio} = \frac{\text{coste de entrenamiento + evaluación + despliegue}} {\text{coste por solicitud de la baseline} - \text{coste por solicitud del modelo ajustado}} ]

Si el denominador es pequeño, negativo o se basa en una suposición de calidad no demostrada, el proyecto todavía no tiene justificación económica.

[!TIP] La configuración híbrida Una arquitectura habitual combina un modelo más pequeño adaptado a la tarea con retrieval para los hechos cambiantes. Trata el modelo grande con prompting como baseline y conserva el modelo pequeño solo si alcanza los mismos umbrales de calidad y seguridad específicos de la tarea.


Tipos de fine-tuning

El fine-tuning puede adoptar tres formas principales. Se diferencian por el tipo de datos que necesitan y por lo que enseñan al modelo.

Tipos de fine-tuningTipos de fine-tuning

1. Continued pre-training (self-supervised)

Entrenas el modelo base con más texto sin procesar, utilizando el token siguiente de cada secuencia como objetivo de entrenamiento. Es aprendizaje self-supervised: el texto proporciona sus propios objetivos, igual que en la ejecución de pre-training original.

Cuándo usarlo:

  • El dominio tiene vocabulario que el modelo base nunca ha visto (medicina, derecho, bases de código internas).
  • Tienes grandes cantidades de texto de dominio, pero no pares etiquetados de (entrada, salida).
  • El modelo base se maneja mal con la terminología específica del dominio.

Ejemplo: entrenar con millones de notas clínicas para que el modelo aprenda abreviaturas médicas, nombres de fármacos y flujos de trabajo clínicos.

2. Supervised fine-tuning (SFT)

SFT entrena con pares etiquetados de (entrada, salida). Muestras al modelo la salida exacta que quieres para cada entrada.

Cuándo usarlo:

  • Tienes una tarea específica con un formato limpio de entrada/salida.
  • Tienes datos etiquetados de calidad, aunque sean pocos.
  • Necesitas un comportamiento predecible con una forma de entrada conocida.

Ejemplo: entrenar con pares de (descripción de consulta SQL, código SQL) para text-to-SQL.

{
    "input": "Get all users who signed up last month",
    "output": "SELECT * FROM users WHERE signup_date >= DATE_SUB(NOW(), INTERVAL 1 MONTH)"
}

3. Instruction tuning

Instruction tuning es un caso especial de SFT diseñado para que los modelos sigan una amplia variedad de instrucciones en lenguaje natural. Los datos de entrenamiento son pares de (instrucción, respuesta) de muchas tareas diferentes.

Cuándo usarlo:

  • Quieres un asistente de propósito general (como ChatGPT o Claude).
  • El modelo debe gestionar solicitudes variadas y abiertas.
  • Estás creando una interfaz de chat.

Ejemplo: entrenar con miles de instrucciones diversas como «Resume este artículo», «Escribe un poema sobre X» o «Explica Y con palabras sencillas».

Comparación

AspectoContinued pre-trainingSFTInstruction tuning
DatosTexto sin procesarPares de (entrada, salida)Pares de (instrucción, respuesta)
EtiquetasNinguna (no supervisado)Específicas de la tareaTareas diversas
ObjetivoConocimiento del dominioComportamiento de una tarea específicaSeguir cualquier instrucción
Volumen de datosNormalmente, el corpus más grandeDeterminado por la cobertura de la tarea y la diversidad de erroresNormalmente más amplio que el SFT específico de una tarea

[!NOTE] Lo que se hace realmente SFT e instruction tuning utilizan el mismo objetivo de next-token; la diferencia está en la amplitud y la construcción del dataset. Continued pre-training es un experimento separado y debe ir seguido de pruebas tanto de las mejoras en el dominio como de la regresión de las capacidades generales.


El pipeline de fine-tuning en 7 etapas

El fine-tuning es un pipeline, no un único comando. Cada etapa tiene sus propios modos de fallo, y saltarse una suele manifestarse más adelante como un modelo deficiente.

Pipeline de 7 etapasPipeline de 7 etapas

Cada etapa se apoya en la anterior:

  1. Preparación de datos — Define la unidad de evaluación, divide los datos y después límpialos y dales formato
  2. Selección del modelo — Elige el modelo base adecuado y carga los pesos
  3. Configuración del entrenamiento — Configura el hardware, los hiperparámetros y la estrategia de optimización
  4. Fine-tuning — Ejecuta entrenamiento SFT, DPO u ORPO
  5. Evaluación — Mide el rendimiento con benchmarks y valida la calidad
  6. Despliegue — Exporta y sirve el modelo
  7. Monitorización — Haz seguimiento del rendimiento, mantén el sistema e itera

[!WARNING] Los datos son los cimientos El entrenamiento reproduce los defectos sistemáticos de los ejemplos. Inspecciona las etiquetas, las fugas de datos, la cobertura y el cumplimiento de políticas antes de dedicar tiempo a explorar optimizadores.


Etapa 1: Preparación de datos

Muchos proyectos de fine-tuning fallan aquí, no durante el entrenamiento. La preparación de datos moderna es mucho más que ejecutar una regex sobre CSVs.

Pipeline de datosPipeline de datos

El pipeline de datos en 5 etapas

Herramientas como DataTrove y Distilabel pueden ayudar a escala. Deja que la taxonomía de fallos y el contrato de datos guíen el diseño del pipeline; la elección de la herramienta viene después.

1. Ingesta y filtrado

  • Acción: elimina rechazos («I cannot answer that»), UTF-8 corrupto e idiomas que no sean el objetivo.
  • Herramientas: Trafilatura para la extracción y los modelos de identificación de idioma de fastText para identificar el idioma; los modelos distribuidos lid.176 reconocen 176 idiomas.

2. Política de datos sensibles

  • Acción: decide qué puede aprender el modelo y, según corresponda, redacta, tokeniza o excluye los campos personales y confidenciales.
  • Herramientas: Microsoft Presidio o scrubadub.
  • Motivo: un detector es solo un control; los requisitos de procedencia, consentimiento, conservación, acceso y eliminación siguen siendo aplicables.

3. Deduplicación (MinHash LSH)

  • Acción: elimina los casi duplicados para evitar que el modelo los memorice.
  • Herramientas: DataTrove gestiona bien el procesamiento a escala de terabytes.

4. Aumento sintético, si es necesario

  • Acción: utiliza un modelo teacher más potente (GPT-4o, DeepSeek-V3) para reescribir los datos sin procesar como pares limpios de instrucción-respuesta.
  • Herramientas: Distilabel.
  • Validación: toma una muestra de las salidas del teacher, compruébalas con la misma rúbrica que las etiquetas humanas y mantén separadas las particiones sintéticas y escritas por personas durante la evaluación.

5. Formato

  • Acción: convierte los datos a un formato estándar (Alpaca o ShareGPT).

Ejemplos de formatos de datos

Formato Alpaca (seguimiento de instrucciones):

{
    "instruction": "Summarize the following text.",
    "input": "The text to be summarized...",
    "output": "This is the summary."
}

Formato ShareGPT/ChatML (conversacional):

{
    "conversations": [
        { "from": "user", "value": "Hello, who are you?" },
        { "from": "assistant", "value": "I am a helpful AI assistant." }
    ]
}

Lo que importa realmente

  • Cobertura antes que volumen. Añade ejemplos que representen modos de fallo distintos, no repeticiones del caso mayoritario y sencillo.
  • Limpieza. Elimina texto irrelevante, normaliza los espacios y mantén el formato coherente.
  • Equilibrio. Conserva los casos raros importantes e informa del rendimiento por partición.
  • Separación. Divide por fuente, usuario, documento o fecha cuando dividir filas aleatoriamente pueda filtrar casi duplicados.
  • Procedencia. Registra el origen, la licencia o permiso, el historial de transformaciones y la vía de eliminación para cada versión del dataset.

Etapa 2: Selección del modelo y hardware

Elegir el modelo base y entender el mínimo de GPU determinan lo que realmente puedes entrenar.

Empieza por el modelo base más pequeño que ya supere las comprobaciones no negociables de la baseline. Confirma:

  • los términos de licencia y redistribución para el producto previsto;
  • el comportamiento en idioma, dominio, tool use y seguridad antes de la adaptación;
  • la compatibilidad del tokenizer y la chat template con el dataset;
  • el contexto máximo y el comportamiento de truncado que necesitan los ejemplos reales;
  • la compatibilidad tanto con el framework de entrenamiento como con el motor de serving objetivo.

El fine-tuning es una etapa de adaptación, no una reparación para un modelo base inadecuado. Si el modelo falla en capacidades que el dataset no cubre, elige otro modelo base antes de ejecutar más epochs.

Dimensiona la ejecución, no la categoría comercial

No existe una tabla estable de «tamaño del modelo → GPU». La memoria máxima cambia con la precisión de los pesos, el optimizador, el número de parámetros entrenables, la longitud de secuencia, el micro-batch, activation checkpointing, la implementación de attention y la sobrecarga del framework. Empieza con una estimación de memoria y después ejecuta una prueba corta con la longitud máxima sobre el stack exacto.

Componente de memoriaFine-tuning completoLoRAQLoRA
Pesos basePrecisión de entrenamientoCongelados, normalmente BF16/FP16Congelados, normalmente NF4 de 4 bits
GradientesTodos los pesos entrenablesPesos del adapterPesos del adapter
Estados del optimizadorTodos los pesos entrenablesPesos del adapterPesos del adapter
ActivacionesDepende del batch y de la longitud de secuencia en todos los métodosMisma dependenciaMisma dependencia

El artículo original de QLoRA consiguió ajustar un modelo LLaMA de 65B en una única GPU de 48 GB con su configuración específica. Es un límite orientativo, no una promesa de que cualquier arquitectura actual de 70B, longitud de contexto, kernel o trainer vaya a caber en el mismo dispositivo.

Cálculo de memoria

Para un modelo con PP parámetros, solo los pesos requieren aproximadamente 2P2P bytes en BF16/FP16 o 0.5P0.5P bytes a cuatro bits, antes de contar los metadatos de quantization y los buffers del runtime. El entrenamiento completo al estilo Adam añade gradientes, estados del optimizador y, a menudo, pesos maestros de mayor precisión. LoRA evita la mayor parte de la memoria de los estados entrenables; QLoRA además reduce la huella de los pesos base congelados. Las activaciones aún pueden dominar con longitudes de secuencia grandes.

Usa este flujo de trabajo:

  1. Elige la secuencia más larga y el micro-batch que debas admitir.
  2. Estima los pesos y el estado entrenable, dejando margen para activaciones y kernels.
  3. Ejecuta un paso de forward/backward con la longitud máxima.
  4. Registra la memoria máxima allocated y reserved.
  5. Solo entonces escala el tamaño del batch, el rank, la longitud de secuencia o el número de GPUs.

Etapa 3: Métodos de entrenamiento (PEFT y LoRA)

Fine-tuning completo frente a PEFT

El fine-tuning completo (FFT) actualiza todos los pesos, por lo que los gradientes y el estado del optimizador escalan con el modelo entero. La memoria máxima no puede inferirse solo a partir del número de parámetros, pero es muy superior a la necesaria para cargar los pesos durante la inferencia.

El fine-tuning eficiente en parámetros (PEFT) entrena únicamente un subconjunto pequeño de parámetros y congela el resto. Las matemáticas resultan mucho más manejables.

LoRA: el punto de partida

LoRA (Low-Rank Adaptation) congela una matriz preentrenada y representa su actualización aprendida mediante dos matrices más pequeñas. El artículo original lo motiva con la hipótesis de que las actualizaciones útiles de adaptación tienen un rank intrínseco bajo.

Arquitectura de LoRAArquitectura de LoRA

Para una matriz congelada W0Rdout×dinW_0 \in \mathbb{R}^{d_{out} \times d_{in}}, LoRA aprende:

  • ARr×dinA \in \mathbb{R}^{r \times d_{in}}
  • BRdout×rB \in \mathbb{R}^{d_{out} \times r}

La capa adaptada es:

W=W0+αrBAW' = W_0 + \frac{\alpha}{r}BA

El adapter tiene r(din+dout)r(d_{in}+d_{out}) parámetros entrenables, frente a dindoutd_{in}d_{out} para esa matriz. Para una matriz cuadrada de 4.096 elementos de ancho y rank 16, supone una reducción de 128× para la matriz, no de 10.000× para un modelo arbitrario. La cifra de 10.000× del artículo de LoRA correspondía a una configuración específica de GPT-3 175B que adaptaba matrices seleccionadas.

Comparación de métodos PEFT

MétodoQué cambiaElígelo cuando
LoRAModelo base congelado más actualizaciones entrenables de bajo rankEl modelo base cabe con margen y quieres artefactos pequeños específicos de la tarea
QLoRALoRA con el modelo base congelado almacenado en formato de 4 bitsLa memoria de los pesos base es el factor limitante
DoRASepara la magnitud de los pesos de una dirección actualizada por LoRAUna baseline medida con LoRA deja una brecha de calidad que justifica una complejidad adicional
Fine-tuning completoTodos los pesos del modeloPEFT no alcanza el objetivo y la mejora de calidad justifica el entrenamiento distribuido y los checkpoints completos

Cuándo elegir cada uno

  • LoRA: empieza por aquí. Es rápido, eficiente en memoria y cuenta con buen soporte.
  • QLoRA: cuando el mismo experimento con LoRA no quepa por culpa de los pesos base congelados.
  • DoRA: después de que una comparación apples-to-apples con LoRA muestre una mejora útil.
  • Fine-tuning completo: solo después de demostrar mediante evaluación que PEFT es un cuello de botella, no asumirlo.

DoRA: LoRA con descomposición de pesos

DoRA (Weight-Decomposed Low-Rank Adaptation) separa la magnitud de cada vector de pesos de su dirección. El artículo de DoRA aplica una actualización LoRA al componente direccional y aprende la magnitud por separado.

Arquitectura de DoRAArquitectura de DoRA

Cómo funciona:

En lugar de tratar los pesos como una única entidad, DoRA divide los pesos preentrenados en dos componentes:

  1. Magnitud — un valor entrenable por vector de pesos.
  2. Dirección — un vector normalizado actualizado mediante matrices de bajo rank.

En notación compacta por columnas:

W=mV+BAV+BAcW' = m \frac{V + BA}{\lVert V + BA \rVert_c}

donde:

  • m = magnitud (entrenable)
  • VV = matriz direccional congelada
  • BABA = actualización direccional aprendida de bajo rank
  • c\lVert \cdot \rVert_c = normalización por columnas

Qué obtienes a cambio de esa estructura adicional:

  • Más grados de libertad que con LoRA estándar, porque la magnitud puede cambiar de forma independiente.
  • Mejores resultados que LoRA en varias configuraciones descritas por el artículo que lo propone.
  • Parámetros y cómputo adicionales, por lo que la mejora debe verificarse en tu tarea y en tu ruta de serving.

Fusión de adapters para aprendizaje multitarea

Los adapters separados permiten que un único modelo base congelado dé soporte a varias tareas. Puedes enrutar las solicitudes a un adapter, servir varios adapters desde un mismo motor cuando sea compatible o crear un candidato fusionado offline. La fusión puede introducir interferencias, así que evalúa el artefacto fusionado en lugar de asumir que los adapters de origen se componen sin problemas.

Métodos habituales de fusión:

  1. Concatenación — combina los parámetros de los adapters y aumenta el rank efectivo. Es rápida y sencilla.
  2. Combinación lineal — suma ponderada de adapters. Proporciona controles.
  3. SVD — descomposición matricial para fusionar. Es más flexible, pero más lenta.

Ejemplo: un adapter para summarization y otro para traducción, fusionados en un único modelo multitarea.


Etapa 4: Fine-tuning y preference alignment

SFT aprende demostraciones. Preference optimization aprende, en cambio, a partir de comparaciones como «la respuesta elegida A es mejor que la respuesta rechazada B». Úsalo solo cuando una preferencia por pares sea la etiqueta adecuada para el error; la corrección factual y el cumplimiento de políticas suelen requerir evaluadores más sólidos que una preferencia global.

Métodos de alignmentMétodos de alignment

RLHF basado en PPO

La receta original era un pipeline de tres etapas:

  1. SFT — aprender la tarea.
  2. Reward model — entrenarlo con preferencias humanas (chosen frente a rejected).
  3. PPO (Proximal Policy Optimization) — reinforcement learning para optimizar la policy.

El coste operativo procede de sus distintos componentes:

  • Es complicado de implementar y mantener.
  • Es caro: se entrenan varios modelos.
  • El muestreo on-policy y la optimización de la recompensa requieren controles cuidadosos de estabilidad y de reward hacking.

DPO

DPO (Direct Preference Optimization) elimina el reward model explícito y el RL loop. El artículo de DPO deriva un objetivo reparametrizado para maximizar la recompensa con una restricción de divergencia KL, de modo que la optimización puede realizarse a partir de pares de preferencias en lugar de reinforcement learning:

{
    "prompt": "Explain quantum computing",
    "chosen": "Quantum computing uses qubits...",   # Preferred response
    "rejected": "Well, it's complicated..."        # Non-preferred response
}

Qué cambia operativamente:

  • Ruta de código más sencilla (sin reward model separado ni RL loop).
  • Objetivo offline sobre pares de preferencias, en lugar de reinforcement learning on-policy.
  • Una policy de referencia o probabilidades log de referencia equivalentes en la formulación estándar.

DPO es más fácil de prototipar que un pipeline PPO completo, pero no es una mejora automática de calidad. Los resultados dependen de la policy inicial, la calidad de los pares, la configuración de la loss, los efectos de longitud y el protocolo de evaluación. Compáralo con un checkpoint SFT en los mismos conjuntos de preferencias y tareas reservados para evaluación.

ORPO

ORPO (Odds-Ratio Preference Optimization) combina la loss de negative log-likelihood de SFT con una penalización de odds ratio sobre las respuestas rechazadas. Elimina el modelo de referencia separado y puede combinar el aprendizaje de la tarea y la preference optimization en una única ejecución.

Cómo funciona: ORPO utiliza una loss combinada que hace dos cosas a la vez:

  1. Maximiza la likelihood de la respuesta elegida (aprende la tarea).
  2. Penaliza la respuesta rechazada con un término de odds ratio (aprende las preferencias).

Hiperparámetros que conviene conocer:

from trl import ORPOConfig

config = ORPOConfig(
    learning_rate=8e-6,  # Very low, as recommended by the ORPO paper
    beta=0.1,            # Controls strength of preference penalty
    # ... other params
)
  • Learning rate: el artículo utilizó valores bajos en sus experimentos; ajústalo a tu modelo, batch y datos en lugar de copiar un valor como regla.
  • Beta: controla el término de preferencias con respecto al término SFT.

El compromiso:

  • Una etapa de entrenamiento en lugar de dos.
  • Sin reward model.
  • Sin forward pass del modelo de referencia.
  • Una ejecución acoplada: si el aprendizaje de la tarea o el comportamiento de preferencias empeoran, no hay un checkpoint SFT intermedio de ese mismo pipeline que inspeccionar.

Elige en función del diseño de datos y evaluación:

  • Usa DPO cuando ya tengas un checkpoint SFT satisfactorio y quieras un experimento offline de preferencias más sencillo.
  • Prueba ORPO cuando un objetivo sin modelo de referencia y de una sola etapa encaje con tus datos y restricciones operativas.
  • Usa RLHF basado en PPO cuando el muestreo online frente a una recompensa aprendida explícita forme parte del requisito y puedas monitorizar la explotación de la recompensa.

Ninguno es una opción predeterminada para todas las tareas. Conserva una baseline solo con SFT e informa tanto de las métricas de tarea como de las métricas de preferencias.


Frameworks de fine-tuning

Los frameworks se solapan y cambian rápidamente. Elige según la ruta de ejecución que debas admitir, fija las versiones y mantén la configuración de entrenamiento suficientemente portable para reproducirla fuera de un notebook.

Unsloth: velocidad y eficiencia de memoria

Unsloth se integra con Hugging Face trl y transformers y proporciona kernels optimizados, checkpointing y rutas de fine-tuning cuantizado para los modelos compatibles.

  • Kernels de GPU Triton personalizados para attention, RoPE y cross-entropy que evitan la sobrecarga de PyTorch.
  • Backprop eficiente en memoria que recomputa las activaciones durante el backward pass en lugar de mantenerlas en memoria.
  • Operaciones fused que agrupan varios pasos (layer norm + linear y similares) en una sola llamada a la GPU.
  • Quantization de 4 bits integrada directamente en la ruta QLoRA con dequantization optimizada.

[!IMPORTANT] El orden de importación importa Sigue el orden de importación del ejemplo de Unsloth correspondiente a la versión que fijes. Unsloth aplica parches durante la importación, por lo que importarlo antes de trl y transformers evita perder optimizaciones o encontrar errores específicos de la versión.

# Correct order
from unsloth import FastLanguageModel  # Must be first!
from trl import SFTTrainer
from transformers import TrainingArguments

# Avoid this order with Unsloth's patched path
from trl import SFTTrainer
from unsloth import FastLanguageModel

Más adecuado para: entrenamiento con una sola GPU, prototipado, notebooks de Colab y cualquiera que controle la factura de GPU.

Las cifras publicadas de velocidad y memoria varían según el modelo, la longitud de secuencia, el batch, la precisión y el hardware. Mide los tokens por segundo y la memoria máxima en tu propia ejecución en lugar de tratar una proporción destacada como una propiedad del framework.

Axolotl: entrenamiento basado en configuración

# config.yaml - no code required
base_model: meta-llama/Meta-Llama-3-8B
adapter: qlora
lora_r: 32
lora_alpha: 16
datasets:
    - path: data/my_data.jsonl
      type: alpaca
sample_packing: true

Ejecuta con: accelerate launch -m axolotl.cli.train config.yaml

Más adecuado para: ejecuciones declarativas y reproducibles, y opciones de launcher integradas para entrenamiento distribuido. La configuración se puede revisar, versionar y reutilizar en ejecuciones locales y distribuidas.

Comparación de frameworks

HerramientaÚtil cuandoVerifica antes de comprometerte
UnslothQuieres una ruta optimizada para modelos compatibles con ejemplos concisosMatriz de modelos, GPU, quantization y soporte distribuido
AxolotlQuieres configuraciones declarativas y recetas distribuidas integradasEsquema exacto de configuración y launcher de la release fijada
TRLQuieres acceso directo a los trainers SFT y de preferencias de Hugging FaceFormato del dataset, chat template, enmascarado de la loss e integración con PEFT
TorchtuneQuieres recetas y componentes nativos de PyTorchCobertura de recetas para el modelo y compatibilidad de exportación

Demo práctica: fine-tuning con Unsloth

Este es un extracto representativo de entrenamiento de mi repositorio unsloth-finetune-demo. La demo hace fine-tuning de Nemotron-Nano para function calling. Antes de este extracto, el src/unsloth_demo/data.py de la demo carga y da formato al dataset; después, su ruta de entrenamiento crea los objetos versionados train_dataset y eval_dataset.

Pipeline de entrenamientoPipeline de entrenamiento

Inicio rápido

# Clone and setup
git clone https://github.com/slavadubrov/unsloth-finetune-demo.git
cd unsloth-finetune-demo

# Install with uv (recommended)
uv sync

# Run fine-tuning (quick test)
uv run finetune --max-samples 1000

Configuración

Las partes interesantes están en config.py:

# Model & Dataset
MODEL_NAME = "nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1"  # 4B params, 128K context
DATASET_NAME = "glaiveai/glaive-function-calling-v2"   # 113K examples

# LoRA Configuration
LORA_R = 16        # Adapter capacity; tune against held-out results
LORA_ALPHA = 32    # Update scaling; alpha/r is the classic LoRA scale
MAX_SEQ_LENGTH = 4096

# Candidate modules for this Llama-family model
LORA_TARGET_MODULES = [
    "q_proj", "k_proj", "v_proj", "o_proj",
    "gate_proj", "up_proj", "down_proj",
]

[!NOTE] La proporción alpha-rank alpha/r escala la actualización LoRA clásica. alpha = 2r es una heurística inicial habitual en cierta documentación de herramientas, no una garantía de estabilidad. Explora rank, alpha, learning rate y módulos objetivo solo después de fijar los datos y la baseline.

Código de entrenamiento principal

from unsloth import FastLanguageModel
from trl import SFTConfig, SFTTrainer

# Load model with 4-bit quantization
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1",
    max_seq_length=4096,
    load_in_4bit=True,
)

# Add LoRA adapters
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"],
    use_gradient_checkpointing="unsloth",  # Lower activation memory; extra compute
)

# The preceding data step must create these versioned dataset objects.
# Each row has the chat messages and tool schemas expected by current TRL.

# Train with the current TRL configuration surface.
trainer = SFTTrainer(
    model=model,
    processing_class=tokenizer,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    args=SFTConfig(
        output_dir="outputs/nemotron-function-calling",
        max_length=4096,
        packing=True,
        per_device_train_batch_size=2,
        gradient_accumulation_steps=4,
        learning_rate=2e-4,
        num_train_epochs=3,
        bf16=True,
    ),
)
trainer.train()

Fine-tuning con Axolotl

[!NOTE] Demo en preparación Estoy trabajando en una demo práctica de Axolotl. Mientras tanto, la guía de paralelismo n-D de Accelerate de Hugging Face es una buena referencia para las estrategias de entrenamiento multi-GPU.

Para configuraciones config-first y distribuidas, Axolotl hace que el flujo de trabajo sea reproducible:

# axolotl_config.yaml
base_model: meta-llama/Meta-Llama-3-8B
model_type: LlamaForCausalLM

# QLoRA configuration
load_in_4bit: true
adapter: qlora
lora_r: 32
lora_alpha: 16
lora_dropout: 0.05
lora_target_modules:
    - q_proj
    - k_proj
    - v_proj
    - o_proj
    - gate_proj
    - up_proj
    - down_proj

# Dataset
datasets:
    - path: data/training_data.jsonl
      type: alpaca

# Training settings
sequence_len: 4096
sample_packing: true # Benchmark with your length distribution
micro_batch_size: 2
gradient_accumulation_steps: 4
learning_rate: 0.0002
num_epochs: 3

# Current Axolotl key; verify support on the pinned release
bf16: true
attn_implementation: flash_attention_2

Ejecuta el entrenamiento:

axolotl train axolotl_config.yaml

Etapa 5: Evaluación

Congela el contrato de evaluación antes de la primera ejecución. Como mínimo, compara el checkpoint ajustado con el modelo base exacto sin ajustar, usando el mismo prompt, la misma configuración de decoding y el mismo entorno de herramientas. Informa de la calidad agregada solo después de comprobar las particiones de fallos que el proyecto pretendía mejorar.

Haz seguimiento de cuatro grupos:

  1. Tarea objetivo: exact match, éxito de ejecución, rúbrica humana u otro resultado vinculado al caso de uso.
  2. Regresión: capacidades generales y particiones de tareas previamente compatibles que la adaptación podría dañar.
  3. Seguridad y políticas: rechazos, filtración de datos, prompt injection o restricciones específicas del dominio.
  4. Operaciones: latencia, throughput, memoria, tamaño del artefacto y coste en la configuración de serving prevista.

Benchmarks automatizados

Usa lm-evaluation-harness para tareas estandarizadas relevantes, no como sustituto de la evaluación del producto:

lm_eval --model hf \
    --model_args pretrained=./outputs/merged-model \
    --tasks hellaswag,arc_easy,mmlu \
    --batch_size 8

LLM-as-judge

Para la calidad subjetiva, un modelo más grande puede ayudar con la puntuación, pero calibra sus resultados con ejemplos revisados por personas y oculta la identidad de los candidatos:

judge_prompt = """
Rate this response from 1-5 on:
- Relevance
- Accuracy
- Formatting

Response: {model_output}
Expected: {ground_truth}
"""

Evaluación específica del dominio

Reserva ejemplos reales por fuente, usuario, documento o fecha para impedir que los casi duplicados se filtren entre las particiones. En function calling, valida la trayectoria completa: selección de herramientas, argumentos, resultado de ejecución, recuperación y respuesta final. Informa de intervalos de confianza o de recuentos pareados de victorias/derrotas cuando la muestra sea pequeña e inspecciona cada regresión en una partición crítica.


Etapa 6: Despliegue y formatos de salida

Elige el artefacto según el motor de serving y el plan de rollback, no solo por el tamaño de los archivos:

Formatos de salidaFormatos de salida

1. Adapter LoRA

uv run finetune  # Saves ~100-500MB adapter
  • Tamaño: proporcional a los módulos objetivo, el rank, las capas y el dtype; a menudo mucho menor que el modelo base.
  • Más adecuado para: desarrollo, adapters de tarea versionados y motores compatibles directamente con LoRA.
  • Ventaja adicional: puedes intercambiar adapters sin volver a descargar el modelo base.

2. Modelo fusionado

uv run finetune --merge  # Creates a standalone full model
  • Tamaño: aproximadamente el del checkpoint base completo con la precisión de salida elegida.
  • Más adecuado para: motores o rutas de distribución que no admiten el adapter por separado.
  • Compromiso: artefacto más grande y rollout más lento; carga más sencilla como modelo único.

3. Formato GGUF

uv run finetune --gguf q4_k_m  # Creates ~2-4GB quantized model
  • Tamaño: depende del modelo; aproximadamente pesos de cuatro bits más metadatos para las variantes Q4.
  • Más adecuado para: inferencia en CPU, Ollama, llama.cpp y despliegues en edge.
  • Opciones: q4_k_m (más pequeño), q5_k_m (mayor fidelidad de los pesos), q8_0 (más grande y con mayor fidelidad). Mide el impacto en la tarea después de la conversión.

Etapa 7: Serving y monitorización

Con vLLM

# Serve the base and expose a PEFT adapter as a model name. This parser and
# template pair is for a Llama 3.1-compatible function-calling adapter.
vllm serve nvidia/Llama-3.1-Nemotron-Nano-4B-v1.1 \
    --enable-lora \
    --lora-modules function-calling=./outputs/adapter \
    --enable-auto-tool-choice \
    --tool-call-parser llama3_json \
    --chat-template examples/tool_chat_template_llama3.1_json.jinja \
    --host 0.0.0.0 \
    --port 8000 \
    --max-model-len 4096

Consulta mediante la API compatible con OpenAI:

from openai import OpenAI

client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")
response = client.chat.completions.create(
    model="function-calling",
    messages=[{"role": "user", "content": "Book a flight to Tokyo"}],
    tools=[
        {
            "type": "function",
            "function": {
                "name": "book_flight",
                "description": "Book a flight to a city.",
                "strict": True,
                "parameters": {
                    "type": "object",
                    "properties": {
                        "destination": {"type": "string"},
                    },
                    "required": ["destination"],
                    "additionalProperties": False,
                },
            },
        }
    ],
    tool_choice="auto",
)

La guía de tool calling de vLLM requiere auto tool choice y un parser compatible con el modelo; utiliza la chat template compatible del modelo cuando la configuración de su tokenizer no proporcione una. Con tool_choice="auto", los argumentos restringidos también requieren strict: true en al menos una función (y tener activada la configuración strict-tool-calling de vLLM, que es la predeterminada); utiliza un esquema parameters compatible con strict. Sin esa activación, vLLM extrae las llamadas del texto sin procesar, por lo que los argumentos pueden estar mal formados o incumplir el esquema.

Con Ollama (local)

# Create Modelfile
echo 'FROM ./outputs/unsloth-nemotron-function-calling-gguf/model-q4_k_m.gguf' > Modelfile

# Import to Ollama
ollama create my-function-model -f Modelfile

# Run
ollama run my-function-model

Con llama.cpp (CPU)

./llama-cli -m ./outputs/model-q4_k_m.gguf \
    -p "What's the weather in Tokyo?" \
    --ctx-size 4096

Monitoriza el modelo publicado

El ciclo de vida no termina cuando la loss de entrenamiento es buena. Registra la revisión del modelo base, el tokenizer y la chat template, el hash del adapter, la versión del dataset, la configuración de entrenamiento y el informe de evaluación como una única unidad de release. En producción, monitoriza el éxito de la tarea, las salidas no válidas, los fallos de políticas, la latencia y el drift de entrada usando las mismas particiones que offline. Mantén cargable el artefacto anterior y define un umbral de rollback antes del lanzamiento.


Conclusiones principales

  1. Haz fine-tuning solo después de que una baseline sin ajustar y una taxonomía de fallos demuestren que la adaptación de pesos aborda el problema.
  2. Retrieval gestiona la evidencia cambiante; constrained decoding gestiona la sintaxis; ninguno de los dos queda sustituido por SFT.
  3. LoRA reduce el estado entrenable. QLoRA además comprime los pesos base congelados. No atribuyas las cifras de memoria de QLoRA a LoRA.
  4. La cobertura de datos, la integridad de las particiones, la procedencia y el enmascarado de la loss importan más que copiar una configuración de optimizador de moda.
  5. DPO, ORPO y RLHF basado en PPO son diseños experimentales distintos, no una escala de calidad con una opción predeterminada universal.
  6. Evalúa el comportamiento objetivo, las regresiones, la seguridad y las operaciones frente al mismo modelo base.
  7. Elige la salida en forma de adapter, modelo fusionado o GGUF según los requisitos de serving y rollback antes de entrenar.

Referencias

Artículos y trabajos de investigación

Herramientas de procesamiento de datos

Constrained decoding

  • xgrammar — constrained decoding con FSMs
  • outlines — generación estructurada para LLMs

Frameworks de entrenamiento

  • Unsloth — framework optimizado de fine-tuning
  • Axolotl — entrenamiento basado en configuración y launchers distribuidos
  • TRL — biblioteca de Hugging Face para SFT y preference training
  • Torchtune — biblioteca de fine-tuning nativa de PyTorch

Inferencia y despliegue

  • Adapters LoRA de vLLM — sirve uno o varios adapters con el modelo base
  • Tool calling de vLLM — adapta auto tool choice, parser, chat template y esquema de la solicitud al modelo
  • Ollama — runner local de LLM para Mac/Windows/Linux
  • llama.cpp — inferencia en CPU/GPU con formato GGUF

Evaluación

Guías y recursos